@@ -254,6 +254,7 @@ namespace Shadowsocks.Controller | |||
{ | |||
_config.isVerboseLogging = enabled; | |||
SaveConfig(_config); | |||
NLogConfig.LoadConfiguration(); // reload nlog | |||
VerboseLoggingStatusChanged?.Invoke(this, new EventArgs()); | |||
} | |||
@@ -477,6 +478,9 @@ namespace Shadowsocks.Controller | |||
Encryption.RNG.Reload(); | |||
// some logic in configuration updated the config when saving, we need to read it again | |||
_config = Configuration.Load(); | |||
NLogConfig.LoadConfiguration(); | |||
StatisticsConfiguration = StatisticsStrategyConfiguration.Load(); | |||
privoxyRunner = privoxyRunner ?? new PrivoxyRunner(); | |||
@@ -1,10 +1,11 @@ | |||
<?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> | |||
<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> | |||
<rules> | |||
<logger name="*" minlevel="Info" writeTo="file, richText" /> | |||
<logger name="*" minlevel="Info" writeTo="file"/> | |||
</rules> | |||
</nlog> |
@@ -36,10 +36,14 @@ namespace Shadowsocks.Model | |||
public bool autoCheckUpdate; | |||
public bool checkPreRelease; | |||
public bool isVerboseLogging; | |||
//public NLogConfig.LogLevel logLevel; | |||
public LogViewerConfig logViewer; | |||
public ProxyConfig proxy; | |||
public HotkeyConfig hotkey; | |||
[JsonIgnore] | |||
NLogConfig nLogConfig; | |||
private static readonly string CONFIG_FILE = "gui-config.json"; | |||
[JsonIgnore] | |||
public string localHost => GetLocalHost(); | |||
@@ -104,6 +108,28 @@ namespace Shadowsocks.Model | |||
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; | |||
} | |||
catch (Exception e) | |||
@@ -122,7 +148,7 @@ namespace Shadowsocks.Model | |||
}, | |||
logViewer = new LogViewerConfig(), | |||
proxy = new ProxyConfig(), | |||
hotkey = new HotkeyConfig() | |||
hotkey = new HotkeyConfig(), | |||
}; | |||
} | |||
} | |||
@@ -145,6 +171,16 @@ namespace Shadowsocks.Model | |||
sw.Write(jsonString); | |||
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) | |||
{ | |||
@@ -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) | |||
{ | |||
// todo: initialize the NLog configuartion | |||
TouchAndApplyNLogConfig(); | |||
Model.NLogConfig.TouchAndApplyNLogConfig(); | |||
// .NET Framework 4.7.2 on Win7 compatibility | |||
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 void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) | |||
{ | |||
@@ -61,7 +61,7 @@ namespace Shadowsocks.Util | |||
public enum WindowsThemeMode { Dark, Light } | |||
// Support on Windows 10 1903+ | |||
public static WindowsThemeMode GetWindows10SystemThemeSetting(bool isVerbose) | |||
public static WindowsThemeMode GetWindows10SystemThemeSetting() | |||
{ | |||
WindowsThemeMode themeMode = WindowsThemeMode.Dark; | |||
try | |||
@@ -81,11 +81,10 @@ namespace Shadowsocks.Util | |||
} | |||
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; | |||
} | |||
@@ -41,13 +41,16 @@ namespace Shadowsocks.View | |||
TextAnnotation outboundAnnotation = new TextAnnotation(); | |||
#endregion | |||
public LogForm(ShadowsocksController controller, string filename=null) | |||
public LogForm(ShadowsocksController controller) | |||
{ | |||
this.controller = controller; | |||
this.filename = filename; | |||
InitializeComponent(); | |||
Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); | |||
var nLogConfig = NLogConfig.LoadXML(); | |||
this.filename = nLogConfig.GetLogFileName(); | |||
LogViewerConfig config = controller.GetConfigurationCopy().logViewer; | |||
topMostTrigger = config.topMost; | |||
@@ -173,7 +176,7 @@ namespace Shadowsocks.View | |||
string line = ""; | |||
StringBuilder appendText = new StringBuilder(1024); | |||
while ((line = reader.ReadLine()) != null) | |||
appendText.Append(line + Environment.NewLine); | |||
appendText.AppendLine(line); | |||
LogMessageTextBox.AppendText(appendText.ToString()); | |||
LogMessageTextBox.ScrollToCaret(); | |||
@@ -197,7 +200,7 @@ namespace Shadowsocks.View | |||
while ((line = reader.ReadLine()) != null) | |||
{ | |||
changed = true; | |||
appendText.Append(line + Environment.NewLine); | |||
appendText.AppendLine(line); | |||
} | |||
if (changed) | |||
@@ -222,7 +222,7 @@ namespace Shadowsocks.View | |||
{ | |||
Color colorMask = Color.White; | |||
Utils.WindowsThemeMode currentWindowsThemeMode = Utils.GetWindows10SystemThemeSetting(controller.GetCurrentConfiguration().isVerboseLogging); | |||
Utils.WindowsThemeMode currentWindowsThemeMode = Utils.GetWindows10SystemThemeSetting(); | |||
if (isProxyEnabled) | |||
{ | |||
@@ -132,6 +132,7 @@ | |||
<Compile Include="Encryption\Stream\StreamOpenSSLEncryptor.cs" /> | |||
<Compile Include="Encryption\Stream\StreamSodiumEncryptor.cs" /> | |||
<Compile Include="Model\HotKeyConfig.cs" /> | |||
<Compile Include="Model\NLogConfig.cs" /> | |||
<Compile Include="Model\ProxyConfig.cs" /> | |||
<Compile Include="Model\SysproxyConfig.cs" /> | |||
<Compile Include="Properties\Resources.Designer.cs"> | |||
@@ -1,7 +1,7 @@ | |||
| |||
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 | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shadowsocks-csharp", "shadowsocks-csharp\shadowsocks-csharp.csproj", "{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}" | |||
EndProject | |||
@@ -12,21 +12,30 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShadowsocksTest", "test\Sha | |||
EndProject | |||
Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
Debug|Any CPU = Debug|Any CPU | |||
Debug|x86 = Debug|x86 | |||
Release|Any CPU = Release|Any CPU | |||
Release|x86 = Release|x86 | |||
EndGlobalSection | |||
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.Build.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.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.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.Build.0 = Release|x86 | |||
EndGlobalSection | |||
GlobalSection(SolutionProperties) = preSolution | |||
HideSolutionNode = FALSE | |||
EndGlobalSection | |||
GlobalSection(ExtensibilityGlobals) = postSolution | |||
SolutionGuid = {F7E7D35B-4FDA-4385-95CF-09DADED042EA} | |||
EndGlobalSection | |||
EndGlobal |