@@ -254,6 +254,7 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
_config.isVerboseLogging = enabled; | _config.isVerboseLogging = enabled; | ||||
SaveConfig(_config); | SaveConfig(_config); | ||||
NLogConfig.LoadConfiguration(); // reload nlog | |||||
VerboseLoggingStatusChanged?.Invoke(this, new EventArgs()); | VerboseLoggingStatusChanged?.Invoke(this, new EventArgs()); | ||||
} | } | ||||
@@ -477,6 +478,9 @@ namespace Shadowsocks.Controller | |||||
Encryption.RNG.Reload(); | Encryption.RNG.Reload(); | ||||
// some logic in configuration updated the config when saving, we need to read it again | // some logic in configuration updated the config when saving, we need to read it again | ||||
_config = Configuration.Load(); | _config = Configuration.Load(); | ||||
NLogConfig.LoadConfiguration(); | |||||
StatisticsConfiguration = StatisticsStrategyConfiguration.Load(); | StatisticsConfiguration = StatisticsStrategyConfiguration.Load(); | ||||
privoxyRunner = privoxyRunner ?? new PrivoxyRunner(); | privoxyRunner = privoxyRunner ?? new PrivoxyRunner(); | ||||
@@ -1,10 +1,11 @@ | |||||
<?xml version="1.0" encoding="utf-8" ?> | <?xml version="1.0" encoding="utf-8" ?> | ||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | |||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" | |||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||||
autoReload="true"> | |||||
<targets> | <targets> | ||||
<target name="file" xsi:type="File" fileName="shadowsocks.log"/> | <target name="file" xsi:type="File" fileName="shadowsocks.log"/> | ||||
<target name="richText" xsi:type="RichTextBox" allowAccessoryFormCreation="false" messageRetention="All" maxLines="5120" autoScroll="true" controlName="" formName=""/> | |||||
</targets> | </targets> | ||||
<rules> | <rules> | ||||
<logger name="*" minlevel="Info" writeTo="file, richText" /> | |||||
<logger name="*" minlevel="Info" writeTo="file"/> | |||||
</rules> | </rules> | ||||
</nlog> | </nlog> |
@@ -36,10 +36,14 @@ namespace Shadowsocks.Model | |||||
public bool autoCheckUpdate; | public bool autoCheckUpdate; | ||||
public bool checkPreRelease; | public bool checkPreRelease; | ||||
public bool isVerboseLogging; | public bool isVerboseLogging; | ||||
//public NLogConfig.LogLevel logLevel; | |||||
public LogViewerConfig logViewer; | public LogViewerConfig logViewer; | ||||
public ProxyConfig proxy; | public ProxyConfig proxy; | ||||
public HotkeyConfig hotkey; | public HotkeyConfig hotkey; | ||||
[JsonIgnore] | |||||
NLogConfig nLogConfig; | |||||
private static readonly string CONFIG_FILE = "gui-config.json"; | private static readonly string CONFIG_FILE = "gui-config.json"; | ||||
[JsonIgnore] | [JsonIgnore] | ||||
public string localHost => GetLocalHost(); | public string localHost => GetLocalHost(); | ||||
@@ -104,6 +108,28 @@ namespace Shadowsocks.Model | |||||
config.proxy.CheckConfig(); | config.proxy.CheckConfig(); | ||||
try | |||||
{ | |||||
config.nLogConfig = NLogConfig.LoadXML(); | |||||
switch (config.nLogConfig.GetLogLevel()) | |||||
{ | |||||
case NLogConfig.LogLevel.Fatal: | |||||
case NLogConfig.LogLevel.Error: | |||||
case NLogConfig.LogLevel.Warn: | |||||
case NLogConfig.LogLevel.Info: | |||||
config.isVerboseLogging = false; | |||||
break; | |||||
case NLogConfig.LogLevel.Debug: | |||||
case NLogConfig.LogLevel.Trace: | |||||
config.isVerboseLogging = true; | |||||
break; | |||||
} | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
logger.Error(e, "Cannot get the log level from NLog config file."); | |||||
} | |||||
return config; | return config; | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
@@ -122,7 +148,7 @@ namespace Shadowsocks.Model | |||||
}, | }, | ||||
logViewer = new LogViewerConfig(), | logViewer = new LogViewerConfig(), | ||||
proxy = new ProxyConfig(), | proxy = new ProxyConfig(), | ||||
hotkey = new HotkeyConfig() | |||||
hotkey = new HotkeyConfig(), | |||||
}; | }; | ||||
} | } | ||||
} | } | ||||
@@ -145,6 +171,16 @@ namespace Shadowsocks.Model | |||||
sw.Write(jsonString); | sw.Write(jsonString); | ||||
sw.Flush(); | sw.Flush(); | ||||
} | } | ||||
try | |||||
{ | |||||
// apply changs to NLog.config | |||||
config.nLogConfig.SetLogLevel(config.isVerboseLogging? NLogConfig.LogLevel.Trace: NLogConfig.LogLevel.Info); | |||||
NLogConfig.SaveXML(config.nLogConfig); | |||||
} | |||||
catch(Exception e) | |||||
{ | |||||
logger.Error(e, "Cannot set the log level"); | |||||
} | |||||
} | } | ||||
catch (IOException e) | catch (IOException e) | ||||
{ | { | ||||
@@ -0,0 +1,117 @@ | |||||
using NLog; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using System.Xml; | |||||
namespace Shadowsocks.Model | |||||
{ | |||||
public class NLogConfig | |||||
{ | |||||
public enum LogLevel | |||||
{ | |||||
Fatal, | |||||
Error, | |||||
Warn, | |||||
Info, | |||||
Debug, | |||||
Trace, | |||||
} | |||||
const string NLOG_CONFIG_FILE_NAME = "NLog.config"; | |||||
const string MIN_LEVEL_ATTRIBUTE = "minlevel"; | |||||
const string FILE_NAME_ATTRIBUTE = "fileName"; | |||||
XmlDocument doc = new XmlDocument(); | |||||
XmlElement logLevelElement; | |||||
XmlElement logFileNameElement; | |||||
/// <summary> | |||||
/// Load the NLog config xml file content | |||||
/// </summary> | |||||
public static NLogConfig LoadXML() | |||||
{ | |||||
NLogConfig config = new NLogConfig(); | |||||
config.doc.Load(NLOG_CONFIG_FILE_NAME); | |||||
config.logLevelElement = (XmlElement)SelectSingleNode(config.doc, "//nlog:logger[@name='*']"); | |||||
config.logFileNameElement = (XmlElement)SelectSingleNode(config.doc, "//nlog:target[@name='file']"); | |||||
return config; | |||||
} | |||||
/// <summary> | |||||
/// Save the content to NLog config xml file | |||||
/// </summary> | |||||
public static void SaveXML(NLogConfig nLogConfig) | |||||
{ | |||||
nLogConfig.doc.Save(NLOG_CONFIG_FILE_NAME); | |||||
} | |||||
/// <summary> | |||||
/// Get the current minLogLevel from xml file | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
public LogLevel GetLogLevel() | |||||
{ | |||||
LogLevel level = LogLevel.Warn; | |||||
string levelStr = logLevelElement.GetAttribute(MIN_LEVEL_ATTRIBUTE); | |||||
Enum.TryParse(levelStr, out level); | |||||
return level; | |||||
} | |||||
/// <summary> | |||||
/// Get the target fileName from xml file | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
public string GetLogFileName() | |||||
{ | |||||
return logFileNameElement.GetAttribute(FILE_NAME_ATTRIBUTE); | |||||
} | |||||
/// <summary> | |||||
/// Set the minLogLevel to xml file | |||||
/// </summary> | |||||
/// <param name="logLevel"></param> | |||||
public void SetLogLevel(LogLevel logLevel) | |||||
{ | |||||
logLevelElement.SetAttribute(MIN_LEVEL_ATTRIBUTE, logLevel.ToString("G")); | |||||
} | |||||
/// <summary> | |||||
/// Set the target fileName to xml file | |||||
/// </summary> | |||||
/// <param name="fileName"></param> | |||||
public void SetLogFileName(string fileName) | |||||
{ | |||||
logFileNameElement.SetAttribute(FILE_NAME_ATTRIBUTE, fileName); | |||||
} | |||||
private static XmlNode SelectSingleNode(XmlDocument doc, string xpath) | |||||
{ | |||||
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); | |||||
manager.AddNamespace("nlog", "http://www.nlog-project.org/schemas/NLog.xsd"); | |||||
//return doc.SelectSingleNode("//nlog:logger[(@shadowsocks='managed') and (@name='*')]", manager); | |||||
return doc.SelectSingleNode(xpath, manager); | |||||
} | |||||
/// <summary> | |||||
/// Extract the pre-defined NLog configuration file is does not exist. Then reload the Nlog configuration. | |||||
/// </summary> | |||||
public static void TouchAndApplyNLogConfig() | |||||
{ | |||||
if (!File.Exists(NLOG_CONFIG_FILE_NAME)) | |||||
{ | |||||
File.WriteAllText(NLOG_CONFIG_FILE_NAME, Properties.Resources.NLog_config); | |||||
LogManager.LoadConfiguration(NLOG_CONFIG_FILE_NAME); | |||||
} | |||||
} | |||||
public static void LoadConfiguration() | |||||
{ | |||||
LogManager.LoadConfiguration(NLOG_CONFIG_FILE_NAME); | |||||
} | |||||
} | |||||
} |
@@ -27,7 +27,7 @@ namespace Shadowsocks | |||||
static void Main(string[] args) | static void Main(string[] args) | ||||
{ | { | ||||
// todo: initialize the NLog configuartion | // todo: initialize the NLog configuartion | ||||
TouchAndApplyNLogConfig(); | |||||
Model.NLogConfig.TouchAndApplyNLogConfig(); | |||||
// .NET Framework 4.7.2 on Win7 compatibility | // .NET Framework 4.7.2 on Win7 compatibility | ||||
System.Net.ServicePointManager.SecurityProtocol |= | System.Net.ServicePointManager.SecurityProtocol |= | ||||
@@ -97,16 +97,6 @@ namespace Shadowsocks | |||||
} | } | ||||
} | } | ||||
private static void TouchAndApplyNLogConfig() | |||||
{ | |||||
string NLogConfigFileName = "NLog.config"; | |||||
if (!File.Exists(NLogConfigFileName)) | |||||
{ | |||||
File.WriteAllText(NLogConfigFileName, Properties.Resources.NLog_config); | |||||
LogManager.LoadConfiguration(NLogConfigFileName); | |||||
} | |||||
} | |||||
private static int exited = 0; | private static int exited = 0; | ||||
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) | private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) | ||||
{ | { | ||||
@@ -61,7 +61,7 @@ namespace Shadowsocks.Util | |||||
public enum WindowsThemeMode { Dark, Light } | public enum WindowsThemeMode { Dark, Light } | ||||
// Support on Windows 10 1903+ | // Support on Windows 10 1903+ | ||||
public static WindowsThemeMode GetWindows10SystemThemeSetting(bool isVerbose) | |||||
public static WindowsThemeMode GetWindows10SystemThemeSetting() | |||||
{ | { | ||||
WindowsThemeMode themeMode = WindowsThemeMode.Dark; | WindowsThemeMode themeMode = WindowsThemeMode.Dark; | ||||
try | try | ||||
@@ -81,11 +81,10 @@ namespace Shadowsocks.Util | |||||
} | } | ||||
catch | catch | ||||
{ | { | ||||
if (isVerbose) | |||||
{ | |||||
logger.Info( | |||||
$"Cannot get Windows 10 system theme mode, return default value 0 (dark mode)."); | |||||
} | |||||
logger.Info( | |||||
$"Cannot get Windows 10 system theme mode, return default value 0 (dark mode)."); | |||||
} | } | ||||
return themeMode; | return themeMode; | ||||
} | } | ||||
@@ -41,13 +41,16 @@ namespace Shadowsocks.View | |||||
TextAnnotation outboundAnnotation = new TextAnnotation(); | TextAnnotation outboundAnnotation = new TextAnnotation(); | ||||
#endregion | #endregion | ||||
public LogForm(ShadowsocksController controller, string filename=null) | |||||
public LogForm(ShadowsocksController controller) | |||||
{ | { | ||||
this.controller = controller; | this.controller = controller; | ||||
this.filename = filename; | |||||
InitializeComponent(); | InitializeComponent(); | ||||
Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); | Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); | ||||
var nLogConfig = NLogConfig.LoadXML(); | |||||
this.filename = nLogConfig.GetLogFileName(); | |||||
LogViewerConfig config = controller.GetConfigurationCopy().logViewer; | LogViewerConfig config = controller.GetConfigurationCopy().logViewer; | ||||
topMostTrigger = config.topMost; | topMostTrigger = config.topMost; | ||||
@@ -173,7 +176,7 @@ namespace Shadowsocks.View | |||||
string line = ""; | string line = ""; | ||||
StringBuilder appendText = new StringBuilder(1024); | StringBuilder appendText = new StringBuilder(1024); | ||||
while ((line = reader.ReadLine()) != null) | while ((line = reader.ReadLine()) != null) | ||||
appendText.Append(line + Environment.NewLine); | |||||
appendText.AppendLine(line); | |||||
LogMessageTextBox.AppendText(appendText.ToString()); | LogMessageTextBox.AppendText(appendText.ToString()); | ||||
LogMessageTextBox.ScrollToCaret(); | LogMessageTextBox.ScrollToCaret(); | ||||
@@ -197,7 +200,7 @@ namespace Shadowsocks.View | |||||
while ((line = reader.ReadLine()) != null) | while ((line = reader.ReadLine()) != null) | ||||
{ | { | ||||
changed = true; | changed = true; | ||||
appendText.Append(line + Environment.NewLine); | |||||
appendText.AppendLine(line); | |||||
} | } | ||||
if (changed) | if (changed) | ||||
@@ -222,7 +222,7 @@ namespace Shadowsocks.View | |||||
{ | { | ||||
Color colorMask = Color.White; | Color colorMask = Color.White; | ||||
Utils.WindowsThemeMode currentWindowsThemeMode = Utils.GetWindows10SystemThemeSetting(controller.GetCurrentConfiguration().isVerboseLogging); | |||||
Utils.WindowsThemeMode currentWindowsThemeMode = Utils.GetWindows10SystemThemeSetting(); | |||||
if (isProxyEnabled) | if (isProxyEnabled) | ||||
{ | { | ||||
@@ -132,6 +132,7 @@ | |||||
<Compile Include="Encryption\Stream\StreamOpenSSLEncryptor.cs" /> | <Compile Include="Encryption\Stream\StreamOpenSSLEncryptor.cs" /> | ||||
<Compile Include="Encryption\Stream\StreamSodiumEncryptor.cs" /> | <Compile Include="Encryption\Stream\StreamSodiumEncryptor.cs" /> | ||||
<Compile Include="Model\HotKeyConfig.cs" /> | <Compile Include="Model\HotKeyConfig.cs" /> | ||||
<Compile Include="Model\NLogConfig.cs" /> | |||||
<Compile Include="Model\ProxyConfig.cs" /> | <Compile Include="Model\ProxyConfig.cs" /> | ||||
<Compile Include="Model\SysproxyConfig.cs" /> | <Compile Include="Model\SysproxyConfig.cs" /> | ||||
<Compile Include="Properties\Resources.Designer.cs"> | <Compile Include="Properties\Resources.Designer.cs"> | ||||
@@ -1,7 +1,7 @@ | |||||
| | ||||
Microsoft Visual Studio Solution File, Format Version 12.00 | Microsoft Visual Studio Solution File, Format Version 12.00 | ||||
# Visual Studio 15 | |||||
VisualStudioVersion = 15.0.26228.10 | |||||
# Visual Studio Version 16 | |||||
VisualStudioVersion = 16.0.29709.97 | |||||
MinimumVisualStudioVersion = 10.0.40219.1 | MinimumVisualStudioVersion = 10.0.40219.1 | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shadowsocks-csharp", "shadowsocks-csharp\shadowsocks-csharp.csproj", "{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}" | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shadowsocks-csharp", "shadowsocks-csharp\shadowsocks-csharp.csproj", "{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}" | ||||
EndProject | EndProject | ||||
@@ -12,21 +12,30 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShadowsocksTest", "test\Sha | |||||
EndProject | EndProject | ||||
Global | Global | ||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
Debug|Any CPU = Debug|Any CPU | |||||
Debug|x86 = Debug|x86 | Debug|x86 = Debug|x86 | ||||
Release|Any CPU = Release|Any CPU | |||||
Release|x86 = Release|x86 | Release|x86 = Release|x86 | ||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|Any CPU.ActiveCfg = Debug|x86 | |||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.ActiveCfg = Debug|x86 | {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.ActiveCfg = Debug|x86 | ||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Build.0 = Debug|x86 | {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Build.0 = Debug|x86 | ||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Deploy.0 = Debug|x86 | {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Deploy.0 = Debug|x86 | ||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|Any CPU.ActiveCfg = Release|x86 | |||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.ActiveCfg = Release|x86 | {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.ActiveCfg = Release|x86 | ||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.Build.0 = Release|x86 | {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.Build.0 = Release|x86 | ||||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|Any CPU.ActiveCfg = Debug|x86 | |||||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|x86.ActiveCfg = Debug|x86 | {45913187-0685-4903-B250-DCEF0479CD86}.Debug|x86.ActiveCfg = Debug|x86 | ||||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|x86.Build.0 = Debug|x86 | {45913187-0685-4903-B250-DCEF0479CD86}.Debug|x86.Build.0 = Debug|x86 | ||||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|Any CPU.ActiveCfg = Release|x86 | |||||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|x86.ActiveCfg = Release|x86 | {45913187-0685-4903-B250-DCEF0479CD86}.Release|x86.ActiveCfg = Release|x86 | ||||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|x86.Build.0 = Release|x86 | {45913187-0685-4903-B250-DCEF0479CD86}.Release|x86.Build.0 = Release|x86 | ||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(SolutionProperties) = preSolution | GlobalSection(SolutionProperties) = preSolution | ||||
HideSolutionNode = FALSE | HideSolutionNode = FALSE | ||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(ExtensibilityGlobals) = postSolution | |||||
SolutionGuid = {F7E7D35B-4FDA-4385-95CF-09DADED042EA} | |||||
EndGlobalSection | |||||
EndGlobal | EndGlobal |