public static void TestLogging() { Contract.Requires <InvalidOperationException>( configured, "The logger system must be initialised before the logging can be tested"); var log = LogManager.GetLogger(nameof(Logging)); log.Prompt("Log test PROMPT"); log.Fatal("Log test FATAL"); log.Error("Log test ERROR"); log.Warn("Log test WARN"); log.Success("Log test SUCCESS"); log.Info("Log test INFO"); log.Debug("Log test DEBUG"); log.Trace("Log test TRACE"); log.Verbose("Log test VERBOSE"); LoggedConsole.WriteFatalLine("Clean wrapper FATAL", new Exception("I'm a fake")); LoggedConsole.Log.Fatal("Clean log FATAL", new Exception("I'm a fake")); LoggedConsole.WriteErrorLine("Clean wrapper ERROR"); LoggedConsole.Log.Error("Clean log ERROR"); LoggedConsole.WriteWarnLine("Clean wrapper WARN"); LoggedConsole.Log.Warn("Clean log WARN"); LoggedConsole.WriteSuccessLine("Clean wrapper SUCCESS"); LoggedConsole.Log.Success("Clean log SUCCESS"); LoggedConsole.WriteLine("Clean wrapper INFO"); LoggedConsole.Log.Info("Clean log INFO"); }
public void TestLogging() { var log = LogManager.GetLogger(typeof(Logging)); log.Prompt("Log test PROMPT"); log.Fatal("Log test FATAL"); log.Error("Log test ERROR"); log.Warn("Log test WARN"); log.Success("Log test SUCCESS"); log.Info("Log test INFO"); log.Debug("Log test DEBUG"); log.Trace("Log test TRACE"); log.Verbose("Log test VERBOSE"); LoggedConsole.WriteFatalLine("Clean wrapper FATAL", new Exception("I'm a fake")); LoggedConsole.Log.Fatal("Clean log FATAL", new Exception("I'm a fake")); LoggedConsole.WriteErrorLine("Clean wrapper ERROR"); LoggedConsole.Log.Error("Clean log ERROR"); LoggedConsole.WriteWarnLine("Clean wrapper WARN"); LoggedConsole.Log.Warn("Clean log WARN"); LoggedConsole.WriteSuccessLine("Clean wrapper SUCCESS"); LoggedConsole.Log.Success("Clean log SUCCESS"); LoggedConsole.WriteLine("Clean wrapper INFO"); LoggedConsole.Log.Info("Clean log INFO"); }
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs) { Contract.Requires(unhandledExceptionEventArgs != null); Contract.Requires(unhandledExceptionEventArgs.ExceptionObject != null); const string fatalMessage = "Fatal error:\n "; var ex = (Exception)unhandledExceptionEventArgs.ExceptionObject; ExceptionLookup.ExceptionStyle style; bool found; Exception inner = ex; // TODO: it looks like all exceptions will always be wrapped in a TargetInvocationException now so we always want to unwrap at least once switch (ex) { case TargetInvocationException _: case AggregateException _: // unwrap inner = ex.InnerException ?? ex; Log.Debug($"Unwrapped {ex.GetType().Name} exception to show a {inner.GetType().Name}"); found = ExceptionLookup.ErrorLevels.TryGetValue(inner.GetType(), out style); break; default: found = ExceptionLookup.ErrorLevels.TryGetValue(ex.GetType(), out style); break; } found = found && style.Handle; // if found, print message only if usage printing disabled if (found && !style.PrintUsage) { // this branch prints the message, but the stack trace is only output in the log NoConsole.Log.Fatal(fatalMessage, ex); LoggedConsole.WriteFatalLine(fatalMessage + inner.Message); } else if (found && ex.GetType() != typeof(Exception)) { // this branch prints the message, and command usage, but the stack trace is only output in the log NoConsole.Log.Fatal(fatalMessage, ex); // the static CommandLineApplication is not set when CommandLineException is thrown var command = inner is CommandParsingException exception ? exception.Command.Name : CommandLineApplication?.Name; var message = fatalMessage + inner.Message; PrintUsage(message, Usages.Single, command ?? string.Empty); } else { // otherwise its a unhandled exception, log and raise // trying to print cleaner errors in console, so printing a full one to log, and the inner to the console // this results in duplication in the log though NoConsole.Log.Fatal("Unhandled exception ->\n", ex); Log.Fatal("Unhandled exception ->\n", inner); PrintAggregateException(ex); } int returnCode = style?.ErrorCode ?? ExceptionLookup.SpecialExceptionErrorLevel; // finally return error level NoConsole.Log.Info("ERRORLEVEL: " + returnCode); if (Debugger.IsAttached) { // no don't exit, we want the exception to be raised to Window's Exception handling // this will allow the debugger to appropriately break on the right line Environment.ExitCode = returnCode; } else { // If debugger is not attached, we *do not* want to raise the error to the Windows level // Everything has already been logged, just exit with appropriate errorlevel Environment.Exit(returnCode); } }
/// <summary> /// Rolling log file appender has no concept of cleaning up logs with a date stamp in their name. /// This we have to clean them manually. /// </summary> /// <returns>A task.</returns> private async Task CleanLogs(string logFilePath) { Contract.RequiresNotNull(logFilePath); const int threshold = 60; int target = 50; void CleanFiles() { var logsPath = Path.GetDirectoryName(logFilePath) ?? throw new InvalidOperationException("Could not resolve logs directory path: " + logFilePath); var files = Directory.GetFiles(logsPath, LogPrefix + "*.txt"); if (files.Length > threshold) { var sorted = new SortedDictionary <DateTime, List <string> >(); foreach (var file in files) { var name = Path.GetFileName(file); // assuming a format of log_20180717T130822Z.1.txt int prefixLength = LogPrefix.Length; var datePart = name.Substring(prefixLength, name.IndexOf(".", StringComparison.Ordinal) - prefixLength); var success = DateTime.TryParseExact( datePart, "yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var date); if (!success) { // the default date value will ensure value is added into sorted list // and it will be deleted first! LoggedConsole.WriteWarnLine($"Log file with name `{name}` has invalid date format and is being cleaned"); } if (sorted.ContainsKey(date)) { sorted[date].Add(file); } else { sorted.Add(date, new List <string>() { file }); } } // then delete the last 10 or so (this way we batch deletes) var toDelete = files.Length - target; foreach (var kvp in sorted) { foreach (var file in kvp.Value) { File.Delete(file); toDelete--; if (toDelete <= 0) { return; } } } } } try { // ReSharper disable once RedundantCast await Task.Run((Action)CleanFiles); } catch (Exception ex) { LoggedConsole.WriteFatalLine("Log cleaning failed, this is a bug, please report it.", ex); } }
/// <summary> /// Rolling log file appender has no concept of cleaning up logs with a datestamp in their name. /// This we have to clean them manually. /// </summary> /// <returns>A task.</returns> private static async Task CleanLogs(string logFilePath) { Contract.RequiresNotNull(logFilePath); const int threshold = 60; const int target = 50; void CleanFiles() { var logsPath = Path.GetDirectoryName(logFilePath) ?? throw new InvalidOperationException("Could not resolve logs directory path: " + logFilePath); var files = Directory.GetFiles(logsPath, "log_*.txt"); if (files.Length > threshold) { var sorted = new SortedDictionary <DateTime, List <string> >(); foreach (var file in files) { var name = Path.GetFileName(file); // assuming a format of log_20180717T130822Z.1.txt var datePart = name.Substring(4, name.IndexOf(".", StringComparison.Ordinal) - 4); var date = DateTime.ParseExact( datePart, "yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); if (sorted.ContainsKey(date)) { sorted[date].Add(file); } else { sorted.Add(date, new List <string>() { file }); } } // then delete the last 10 or so (this way we batch deletes) var toDelete = files.Length - target; foreach (var kvp in sorted) { foreach (var file in kvp.Value) { File.Delete(file); toDelete--; if (toDelete <= 0) { return; } } } } } try { await Task.Run((Action)CleanFiles); } catch (Exception ex) { LoggedConsole.WriteFatalLine("Log cleaning failed, this is a bug, please report it.", ex); } }