diff --git a/Neo.ConsoleService/ConsoleColorSet.cs b/Neo.ConsoleService/ConsoleColorSet.cs new file mode 100644 index 000000000..c5cc9e4fb --- /dev/null +++ b/Neo.ConsoleService/ConsoleColorSet.cs @@ -0,0 +1,41 @@ +using System; + +namespace Neo.ConsoleService +{ + public class ConsoleColorSet + { + public ConsoleColor Foreground; + public ConsoleColor Background; + + /// + /// Create a new color set with the current console colors + /// + public ConsoleColorSet() : this(Console.ForegroundColor, Console.BackgroundColor) { } + + /// + /// Create a new color set + /// + /// Foreground color + public ConsoleColorSet(ConsoleColor foreground) : this(foreground, Console.BackgroundColor) { } + + /// + /// Create a new color set + /// + /// Foreground color + /// Background color + public ConsoleColorSet(ConsoleColor foreground, ConsoleColor background) + { + Foreground = foreground; + Background = background; + } + + /// + /// Apply the current set + /// + public void Apply() + { + Console.ForegroundColor = Foreground; + Console.BackgroundColor = Background; + } + } +} diff --git a/neo-cli/CLI/Logger.cs b/neo-cli/CLI/Logger.cs new file mode 100644 index 000000000..43d178547 --- /dev/null +++ b/neo-cli/CLI/Logger.cs @@ -0,0 +1,96 @@ +using Neo.ConsoleService; +using Neo.Plugins; +using System; +using System.IO; +using System.Text; +using static System.IO.Path; + +namespace Neo.CLI +{ + internal class Logger : Plugin, ILogPlugin + { + private static readonly ConsoleColorSet DebugColor = new ConsoleColorSet(ConsoleColor.Cyan); + private static readonly ConsoleColorSet InfoColor = new ConsoleColorSet(ConsoleColor.White); + private static readonly ConsoleColorSet WarningColor = new ConsoleColorSet(ConsoleColor.Yellow); + private static readonly ConsoleColorSet ErrorColor = new ConsoleColorSet(ConsoleColor.Red); + private static readonly ConsoleColorSet FatalColor = new ConsoleColorSet(ConsoleColor.Red); + + public override string Name => "SystemLog"; + public override string ConfigFile => Combine(GetDirectoryName(Path), "config.json"); + public override string Path => GetType().Assembly.Location; + + private static void GetErrorLogs(StringBuilder sb, Exception ex) + { + sb.AppendLine(ex.GetType().ToString()); + sb.AppendLine(ex.Message); + sb.AppendLine(ex.StackTrace); + if (ex is AggregateException ex2) + { + foreach (Exception inner in ex2.InnerExceptions) + { + sb.AppendLine(); + GetErrorLogs(sb, inner); + } + } + else if (ex.InnerException != null) + { + sb.AppendLine(); + GetErrorLogs(sb, ex.InnerException); + } + } + + void ILogPlugin.Log(string source, LogLevel level, object message) + { + if (!Settings.Default.Logger.Active) + return; + + if (message is Exception ex) + { + var sb = new StringBuilder(); + GetErrorLogs(sb, ex); + message = sb.ToString(); + } + + lock (typeof(Logger)) + { + DateTime now = DateTime.Now; + var log = $"[{now.TimeOfDay:hh\\:mm\\:ss\\.fff}] {message}"; + + if (Settings.Default.Logger.ConsoleOutput) + { + var currentColor = new ConsoleColorSet(); + + switch (level) + { + case LogLevel.Debug: DebugColor.Apply(); break; + case LogLevel.Error: ErrorColor.Apply(); break; + case LogLevel.Fatal: FatalColor.Apply(); break; + case LogLevel.Info: InfoColor.Apply(); break; + case LogLevel.Warning: WarningColor.Apply(); break; + } + + Console.WriteLine(log); + currentColor.Apply(); + } + + if (!string.IsNullOrEmpty(Settings.Default.Logger.Path)) + { + StringBuilder sb = new StringBuilder(source); + foreach (char c in GetInvalidFileNameChars()) + sb.Replace(c, '-'); + var path = Combine(Settings.Default.Logger.Path, sb.ToString()); + Directory.CreateDirectory(path); + path = Combine(path, $"{now:yyyy-MM-dd}.log"); + try + { + File.AppendAllLines(path, new[] { $"[{level}]{log}" }); + } + catch (IOException) + { + Console.WriteLine("Error writing the log file: " + path); + } + } + } + } + } +} diff --git a/neo-cli/CLI/MainService.cs b/neo-cli/CLI/MainService.cs index 685b45cc4..85c78c41d 100644 --- a/neo-cli/CLI/MainService.cs +++ b/neo-cli/CLI/MainService.cs @@ -1,5 +1,4 @@ using Akka.Actor; -using Microsoft.Extensions.Configuration; using Neo.ConsoleService; using Neo.Cryptography.ECC; using Neo.IO; @@ -356,19 +355,10 @@ public async void Start(string[] args) case "--noverify": verifyImport = false; break; - case "/testnet": - case "--testnet": - case "-t": - ProtocolSettings.Initialize(new ConfigurationBuilder().AddJsonFile("protocol.testnet.json").Build()); - Settings.Initialize(new ConfigurationBuilder().AddJsonFile("config.testnet.json").Build()); - break; - case "/mainnet": - case "--mainnet": - case "-m": - ProtocolSettings.Initialize(new ConfigurationBuilder().AddJsonFile("protocol.mainnet.json").Build()); - Settings.Initialize(new ConfigurationBuilder().AddJsonFile("config.mainnet.json").Build()); - break; } + + _ = new Logger(); + NeoSystem = new NeoSystem(Settings.Default.Storage.Engine); foreach (var plugin in Plugin.Plugins) diff --git a/neo-cli/Settings.cs b/neo-cli/Settings.cs index 46c0dda3a..bbcb726b0 100644 --- a/neo-cli/Settings.cs +++ b/neo-cli/Settings.cs @@ -6,6 +6,7 @@ namespace Neo { public class Settings { + public LoggerSettings Logger { get; } public StorageSettings Storage { get; } public P2PSettings P2P { get; } public UnlockWalletSettings UnlockWallet { get; } @@ -39,6 +40,7 @@ public static Settings Default public Settings(IConfigurationSection section) { + this.Logger = new LoggerSettings(section.GetSection("Logger")); this.Storage = new StorageSettings(section.GetSection("Storage")); this.P2P = new P2PSettings(section.GetSection("P2P")); this.UnlockWallet = new UnlockWalletSettings(section.GetSection("UnlockWallet")); @@ -46,6 +48,20 @@ public Settings(IConfigurationSection section) } } + public class LoggerSettings + { + public string Path { get; } + public bool ConsoleOutput { get; } + public bool Active { get; } + + public LoggerSettings(IConfigurationSection section) + { + this.Path = string.Format(section.GetValue("Path", "Logs_{0}"), ProtocolSettings.Default.Magic.ToString("X8")); + this.ConsoleOutput = section.GetValue("ConsoleOutput", false); + this.Active = section.GetValue("Active", false); + } + } + public class StorageSettings { public string Engine { get; } diff --git a/neo-cli/config.json b/neo-cli/config.json index 239c1c70e..62df1df84 100644 --- a/neo-cli/config.json +++ b/neo-cli/config.json @@ -1,5 +1,10 @@ { "ApplicationConfiguration": { + "Logger": { + "Path": "Logs_{0}", + "ConsoleOutput": false, + "Active": false + }, "Storage": { "Engine": "LevelDBStore" }, diff --git a/neo-cli/config.mainnet.json b/neo-cli/config.mainnet.json index 239c1c70e..62df1df84 100644 --- a/neo-cli/config.mainnet.json +++ b/neo-cli/config.mainnet.json @@ -1,5 +1,10 @@ { "ApplicationConfiguration": { + "Logger": { + "Path": "Logs_{0}", + "ConsoleOutput": false, + "Active": false + }, "Storage": { "Engine": "LevelDBStore" }, diff --git a/neo-cli/config.testnet.json b/neo-cli/config.testnet.json index d310712ee..688dddac3 100644 --- a/neo-cli/config.testnet.json +++ b/neo-cli/config.testnet.json @@ -1,5 +1,10 @@ { "ApplicationConfiguration": { + "Logger": { + "Path": "Logs_{0}", + "ConsoleOutput": false, + "Active": false + }, "Storage": { "Engine": "LevelDBStore" }, diff --git a/neo-cli/neo-cli.csproj b/neo-cli/neo-cli.csproj index 1501d527e..2e51c0fad 100644 --- a/neo-cli/neo-cli.csproj +++ b/neo-cli/neo-cli.csproj @@ -28,7 +28,7 @@ - +