• netcore3.0 Logging 日志系统(二)


    上一篇介绍了netcore的日志系统,接下来看下netcore里面提供了哪写日志功能:

    一、 DebugLogger

      

    /// <summary>
        /// A logger that writes messages in the debug output window only when a debugger is attached.
        /// </summary>
        internal partial class DebugLogger : ILogger
        {
            private readonly string _name;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="DebugLogger"/> class.
            /// </summary>
            /// <param name="name">The name of the logger.</param>
            public DebugLogger(string name)
            {
                _name = name;
            }
    
            /// <inheritdoc />
            public IDisposable BeginScope<TState>(TState state)
            {
                return NullScope.Instance;
            }
    
            /// <inheritdoc />
            public bool IsEnabled(LogLevel logLevel)
            {
                // If the filter is null, everything is enabled
                // unless the debugger is not attached
                return Debugger.IsAttached && logLevel != LogLevel.None;
            }
    
            /// <inheritdoc />
            public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
            {
                if (!IsEnabled(logLevel))
                {
                    return;
                }
    
                if (formatter == null)
                {
                    throw new ArgumentNullException(nameof(formatter));
                }
    
                var message = formatter(state, exception);
    
                if (string.IsNullOrEmpty(message))
                {
                    return;
                }
    
                message = $"{ logLevel }: {message}";
    
                if (exception != null)
                {
                    message += Environment.NewLine + Environment.NewLine + exception;
                }
    
                DebugWriteLine(message, _name);
            }
        }
    /// <summary>
        /// The provider for the <see cref="DebugLogger"/>.
        /// </summary>
        [ProviderAlias("Debug")]
        public class DebugLoggerProvider : ILoggerProvider
        {
            /// <inheritdoc />
            public ILogger CreateLogger(string name)
            {
                return new DebugLogger(name);
            }
    
            public void Dispose()
            {
            }
        }

    扩展方法:

    /// <summary>
        /// Extension methods for the <see cref="ILoggerFactory"/> class.
        /// </summary>
        public static class DebugLoggerFactoryExtensions
        {
            /// <summary>
            /// Adds a debug logger named 'Debug' to the factory.
            /// </summary>
            /// <param name="builder">The extension method argument.</param>
            public static ILoggingBuilder AddDebug(this ILoggingBuilder builder)
            {
                builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, DebugLoggerProvider>());
    
                return builder;
            }
        }

    二、 ConsoleLogger

      

    internal class ConsoleLogger : ILogger
        {
            private static readonly string _loglevelPadding = ": ";
            private static readonly string _messagePadding;
            private static readonly string _newLineWithMessagePadding;
    
            // ConsoleColor does not have a value to specify the 'Default' color
            private readonly ConsoleColor? DefaultConsoleColor = null;
    
            private readonly string _name;
            private readonly ConsoleLoggerProcessor _queueProcessor;
    
            [ThreadStatic]
            private static StringBuilder _logBuilder;
    
            static ConsoleLogger()
            {
                var logLevelString = GetLogLevelString(LogLevel.Information);
                _messagePadding = new string(' ', logLevelString.Length + _loglevelPadding.Length);
                _newLineWithMessagePadding = Environment.NewLine + _messagePadding;
            }
    
            internal ConsoleLogger(string name, ConsoleLoggerProcessor loggerProcessor)
            {
                if (name == null)
                {
                    throw new ArgumentNullException(nameof(name));
                }
    
                _name = name;
                _queueProcessor = loggerProcessor;
            }
    
            internal IExternalScopeProvider ScopeProvider { get; set; }
    
            internal ConsoleLoggerOptions Options { get; set; }
    
            public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
            {
                if (!IsEnabled(logLevel))
                {
                    return;
                }
    
                if (formatter == null)
                {
                    throw new ArgumentNullException(nameof(formatter));
                }
    
                var message = formatter(state, exception);
    
                if (!string.IsNullOrEmpty(message) || exception != null)
                {
                    WriteMessage(logLevel, _name, eventId.Id, message, exception);
                }
            }
    
            public virtual void WriteMessage(LogLevel logLevel, string logName, int eventId, string message, Exception exception)
            {
                var format = Options.Format;
                Debug.Assert(format >= ConsoleLoggerFormat.Default && format <= ConsoleLoggerFormat.Systemd);
    
                var logBuilder = _logBuilder;
                _logBuilder = null;
    
                if (logBuilder == null)
                {
                    logBuilder = new StringBuilder();
                }
    
                LogMessageEntry entry;
                if (format == ConsoleLoggerFormat.Default)
                {
                    entry = CreateDefaultLogMessage(logBuilder, logLevel, logName, eventId, message, exception);
                }
                else if (format == ConsoleLoggerFormat.Systemd)
                {
                    entry = CreateSystemdLogMessage(logBuilder, logLevel, logName, eventId, message, exception);
                }
                else
                {
                    entry = default;
                }
                _queueProcessor.EnqueueMessage(entry);
    
                logBuilder.Clear();
                if (logBuilder.Capacity > 1024)
                {
                    logBuilder.Capacity = 1024;
                }
                _logBuilder = logBuilder;
            }
    
            private LogMessageEntry CreateDefaultLogMessage(StringBuilder logBuilder, LogLevel logLevel, string logName, int eventId, string message, Exception exception)
            {
                // Example:
                // INFO: ConsoleApp.Program[10]
                //       Request received
    
                var logLevelColors = GetLogLevelConsoleColors(logLevel);
                var logLevelString = GetLogLevelString(logLevel);
                // category and event id
                logBuilder.Append(_loglevelPadding);
                logBuilder.Append(logName);
                logBuilder.Append("[");
                logBuilder.Append(eventId);
                logBuilder.AppendLine("]");
    
                // scope information
                GetScopeInformation(logBuilder, multiLine: true);
    
                if (!string.IsNullOrEmpty(message))
                {
                    // message
                    logBuilder.Append(_messagePadding);
    
                    var len = logBuilder.Length;
                    logBuilder.AppendLine(message);
                    logBuilder.Replace(Environment.NewLine, _newLineWithMessagePadding, len, message.Length);
                }
    
                // Example:
                // System.InvalidOperationException
                //    at Namespace.Class.Function() in File:line X
                if (exception != null)
                {
                    // exception message
                    logBuilder.AppendLine(exception.ToString());
                }
    
                var timestampFormat = Options.TimestampFormat;
    
                return new LogMessageEntry(
                    message: logBuilder.ToString(),
                    timeStamp: timestampFormat != null ? DateTime.Now.ToString(timestampFormat) : null,
                    levelString: logLevelString,
                    levelBackground: logLevelColors.Background,
                    levelForeground: logLevelColors.Foreground,
                    messageColor: DefaultConsoleColor,
                    logAsError: logLevel >= Options.LogToStandardErrorThreshold
                );
            }
    
            private LogMessageEntry CreateSystemdLogMessage(StringBuilder logBuilder, LogLevel logLevel, string logName, int eventId, string message, Exception exception)
            {
                // systemd reads messages from standard out line-by-line in a '<pri>message' format.
                // newline characters are treated as message delimiters, so we must replace them.
                // Messages longer than the journal LineMax setting (default: 48KB) are cropped.
                // Example:
                // <6>ConsoleApp.Program[10] Request received
    
                // loglevel
                var logLevelString = GetSyslogSeverityString(logLevel);
                logBuilder.Append(logLevelString);
    
                // timestamp
                var timestampFormat = Options.TimestampFormat;
                if (timestampFormat != null)
                {
                    logBuilder.Append(DateTime.Now.ToString(timestampFormat));
                }
    
                // category and event id
                logBuilder.Append(logName);
                logBuilder.Append("[");
                logBuilder.Append(eventId);
                logBuilder.Append("]");
    
                // scope information
                GetScopeInformation(logBuilder, multiLine: false);
    
                // message
                if (!string.IsNullOrEmpty(message))
                {
                    logBuilder.Append(' ');
                    // message
                    AppendAndReplaceNewLine(logBuilder, message);
                }
    
                // exception
                // System.InvalidOperationException at Namespace.Class.Function() in File:line X
                if (exception != null)
                {
                    logBuilder.Append(' ');
                    AppendAndReplaceNewLine(logBuilder, exception.ToString());
                }
    
                // newline delimiter
                logBuilder.Append(Environment.NewLine);
    
                return new LogMessageEntry(
                    message: logBuilder.ToString(),
                    logAsError: logLevel >= Options.LogToStandardErrorThreshold
                );
    
                static void AppendAndReplaceNewLine(StringBuilder sb, string message)
                {
                    var len = sb.Length;
                    sb.Append(message);
                    sb.Replace(Environment.NewLine, " ", len, message.Length);
                }
            }
    
            public bool IsEnabled(LogLevel logLevel)
            {
                return logLevel != LogLevel.None;
            }
    
            public IDisposable BeginScope<TState>(TState state) => ScopeProvider?.Push(state) ?? NullScope.Instance;
    
            private static string GetLogLevelString(LogLevel logLevel)
            {
                switch (logLevel)
                {
                    case LogLevel.Trace:
                        return "trce";
                    case LogLevel.Debug:
                        return "dbug";
                    case LogLevel.Information:
                        return "info";
                    case LogLevel.Warning:
                        return "warn";
                    case LogLevel.Error:
                        return "fail";
                    case LogLevel.Critical:
                        return "crit";
                    default:
                        throw new ArgumentOutOfRangeException(nameof(logLevel));
                }
            }
    
            private static string GetSyslogSeverityString(LogLevel logLevel)
            {
                // 'Syslog Message Severities' from https://tools.ietf.org/html/rfc5424.
                switch (logLevel)
                {
                    case LogLevel.Trace:
                    case LogLevel.Debug:
                        return "<7>"; // debug-level messages
                    case LogLevel.Information:
                        return "<6>"; // informational messages
                    case LogLevel.Warning:
                        return "<4>"; // warning conditions
                    case LogLevel.Error:
                        return "<3>"; // error conditions
                    case LogLevel.Critical:
                        return "<2>"; // critical conditions
                    default:
                        throw new ArgumentOutOfRangeException(nameof(logLevel));
                }
            }
    
            private ConsoleColors GetLogLevelConsoleColors(LogLevel logLevel)
            {
                if (Options.DisableColors)
                {
                    return new ConsoleColors(null, null);
                }
    
                // We must explicitly set the background color if we are setting the foreground color,
                // since just setting one can look bad on the users console.
                switch (logLevel)
                {
                    case LogLevel.Critical:
                        return new ConsoleColors(ConsoleColor.White, ConsoleColor.Red);
                    case LogLevel.Error:
                        return new ConsoleColors(ConsoleColor.Black, ConsoleColor.Red);
                    case LogLevel.Warning:
                        return new ConsoleColors(ConsoleColor.Yellow, ConsoleColor.Black);
                    case LogLevel.Information:
                        return new ConsoleColors(ConsoleColor.DarkGreen, ConsoleColor.Black);
                    case LogLevel.Debug:
                        return new ConsoleColors(ConsoleColor.Gray, ConsoleColor.Black);
                    case LogLevel.Trace:
                        return new ConsoleColors(ConsoleColor.Gray, ConsoleColor.Black);
                    default:
                        return new ConsoleColors(DefaultConsoleColor, DefaultConsoleColor);
                }
            }
    
            private void GetScopeInformation(StringBuilder stringBuilder, bool multiLine)
            {
                var scopeProvider = ScopeProvider;
                if (Options.IncludeScopes && scopeProvider != null)
                {
                    var initialLength = stringBuilder.Length;
    
                    scopeProvider.ForEachScope((scope, state) =>
                    {
                        var (builder, paddAt) = state;
                        var padd = paddAt == builder.Length;
                        if (padd)
                        {
                            builder.Append(_messagePadding);
                            builder.Append("=> ");
                        }
                        else
                        {
                            builder.Append(" => ");
                        }
                        builder.Append(scope);
                    }, (stringBuilder, multiLine ? initialLength : -1));
    
                    if (stringBuilder.Length > initialLength && multiLine)
                    {
                        stringBuilder.AppendLine();
                    }
                }
            }
    
            private readonly struct ConsoleColors
            {
                public ConsoleColors(ConsoleColor? foreground, ConsoleColor? background)
                {
                    Foreground = foreground;
                    Background = background;
                }
    
                public ConsoleColor? Foreground { get; }
    
                public ConsoleColor? Background { get; }
            }
        }
    /// <summary>
        /// A provider of <see cref="ConsoleLogger"/> instances.
        /// </summary>
        [ProviderAlias("Console")]
        public class ConsoleLoggerProvider : ILoggerProvider, ISupportExternalScope
        {
            private readonly IOptionsMonitor<ConsoleLoggerOptions> _options;
            private readonly ConcurrentDictionary<string, ConsoleLogger> _loggers;
            private readonly ConsoleLoggerProcessor _messageQueue;
    
            private IDisposable _optionsReloadToken;
            private IExternalScopeProvider _scopeProvider = NullExternalScopeProvider.Instance;
    
            /// <summary>
            /// Creates an instance of <see cref="ConsoleLoggerProvider"/>.
            /// </summary>
            /// <param name="options">The options to create <see cref="ConsoleLogger"/> instances with.</param>
            public ConsoleLoggerProvider(IOptionsMonitor<ConsoleLoggerOptions> options)
            {
                _options = options;
                _loggers = new ConcurrentDictionary<string, ConsoleLogger>();
    
                ReloadLoggerOptions(options.CurrentValue);
                _optionsReloadToken = _options.OnChange(ReloadLoggerOptions);
    
                _messageQueue = new ConsoleLoggerProcessor();
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    _messageQueue.Console = new WindowsLogConsole();
                    _messageQueue.ErrorConsole = new WindowsLogConsole(stdErr: true);
                }
                else
                {
                    _messageQueue.Console = new AnsiLogConsole(new AnsiSystemConsole());
                    _messageQueue.ErrorConsole = new AnsiLogConsole(new AnsiSystemConsole(stdErr: true));
                }
            }
    
            private void ReloadLoggerOptions(ConsoleLoggerOptions options)
            {
                foreach (var logger in _loggers)
                {
                    logger.Value.Options = options;
                }
            }
    
            /// <inheritdoc />
            public ILogger CreateLogger(string name)
            {
                return _loggers.GetOrAdd(name, loggerName => new ConsoleLogger(name, _messageQueue)
                {
                    Options = _options.CurrentValue,
                    ScopeProvider = _scopeProvider
                });
            }
    
            /// <inheritdoc />
            public void Dispose()
            {
                _optionsReloadToken?.Dispose();
                _messageQueue.Dispose();
            }
    
            /// <inheritdoc />
            public void SetScopeProvider(IExternalScopeProvider scopeProvider)
            {
                _scopeProvider = scopeProvider;
    
                foreach (var logger in _loggers)
                {
                    logger.Value.ScopeProvider = _scopeProvider;
                }
    
            }
        }

    扩展方法:

    public static class ConsoleLoggerExtensions
        {
            /// <summary>
            /// Adds a console logger named 'Console' to the factory.
            /// </summary>
            /// <param name="builder">The <see cref="ILoggingBuilder"/> to use.</param>
            public static ILoggingBuilder AddConsole(this ILoggingBuilder builder)
            {
                builder.AddConfiguration();
    
                builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, ConsoleLoggerProvider>());
                LoggerProviderOptions.RegisterProviderOptions<ConsoleLoggerOptions, ConsoleLoggerProvider>(builder.Services);
                return builder;
            }
    
            /// <summary>
            /// Adds a console logger named 'Console' to the factory.
            /// </summary>
            /// <param name="builder">The <see cref="ILoggingBuilder"/> to use.</param>
            /// <param name="configure">A delegate to configure the <see cref="ConsoleLogger"/>.</param>
            public static ILoggingBuilder AddConsole(this ILoggingBuilder builder, Action<ConsoleLoggerOptions> configure)
            {
                if (configure == null)
                {
                    throw new ArgumentNullException(nameof(configure));
                }
    
                builder.AddConsole();
                builder.Services.Configure(configure);
    
                return builder;
            }
        }

    三、 EventLogLogger

      

    /// <summary>
        /// A logger that writes messages to Windows Event Log.
        /// </summary>
        internal class EventLogLogger : ILogger
        {
            private readonly string _name;
            private readonly EventLogSettings _settings;
            private readonly IExternalScopeProvider _externalScopeProvider;
    
            private const string ContinuationString = "...";
            private readonly int _beginOrEndMessageSegmentSize;
            private readonly int _intermediateMessageSegmentSize;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="EventLogLogger"/> class.
            /// </summary>
            /// <param name="name">The name of the logger.</param>
            /// <param name="settings">The <see cref="EventLogSettings"/>.</param>
            /// <param name="externalScopeProvider">The <see cref="IExternalScopeProvider"/>.</param>
            public EventLogLogger(string name, EventLogSettings settings, IExternalScopeProvider externalScopeProvider)
            {
                _name = name ?? throw new ArgumentNullException(nameof(name));
                _settings = settings ?? throw new ArgumentNullException(nameof(settings));
    
                _externalScopeProvider = externalScopeProvider;
                EventLog = settings.EventLog;
    
                // Examples:
                // 1. An error occu...
                // 2. ...esponse stream
                _beginOrEndMessageSegmentSize = EventLog.MaxMessageSize - ContinuationString.Length;
    
                // Example:
                // ...rred while writ...
                _intermediateMessageSegmentSize = EventLog.MaxMessageSize - 2 * ContinuationString.Length;
            }
    
            public IEventLog EventLog { get; }
    
            /// <inheritdoc />
            public IDisposable BeginScope<TState>(TState state)
            {
                return _externalScopeProvider?.Push(state);
            }
    
            /// <inheritdoc />
            public bool IsEnabled(LogLevel logLevel)
            {
                return logLevel != LogLevel.None &&
                    (_settings.Filter == null || _settings.Filter(_name, logLevel));
            }
    
            /// <inheritdoc />
            public void Log<TState>(
                LogLevel logLevel,
                EventId eventId,
                TState state,
                Exception exception,
                Func<TState, Exception, string> formatter)
            {
                if (!IsEnabled(logLevel))
                {
                    return;
                }
    
                if (formatter == null)
                {
                    throw new ArgumentNullException(nameof(formatter));
                }
    
                var message = formatter(state, exception);
    
                if (string.IsNullOrEmpty(message))
                {
                    return;
                }
    
                var builder = new StringBuilder()
                                .Append("Category: ")
                                .AppendLine(_name)
                                .Append("EventId: ")
                                .Append(eventId.Id)
                                .AppendLine();
    
                _externalScopeProvider?.ForEachScope((scope, sb) =>
                {
                    if (scope is IEnumerable<KeyValuePair<string, object>> properties)
                    {
                        foreach (var pair in properties)
                        {
                            sb.Append(pair.Key).Append(": ").AppendLine(pair.Value?.ToString());
                        }
                    }
                    else if (scope != null)
                    {
                        sb.AppendLine(scope.ToString());
                    }
                },
                builder);
    
                builder.AppendLine()
                .AppendLine(message);
    
                if (exception != null)
                {
                    builder.AppendLine().AppendLine("Exception: ").Append(exception).AppendLine();
                }
    
                WriteMessage(builder.ToString(), GetEventLogEntryType(logLevel), EventLog.DefaultEventId ?? eventId.Id);
            }
    
            // category '0' translates to 'None' in event log
            private void WriteMessage(string message, EventLogEntryType eventLogEntryType, int eventId)
            {
                if (message.Length <= EventLog.MaxMessageSize)
                {
                    EventLog.WriteEntry(message, eventLogEntryType, eventId, category: 0);
                    return;
                }
    
                var startIndex = 0;
                string messageSegment = null;
                while (true)
                {
                    // Begin segment
                    // Example: An error occu...
                    if (startIndex == 0)
                    {
                        messageSegment = message.Substring(startIndex, _beginOrEndMessageSegmentSize) + ContinuationString;
                        startIndex += _beginOrEndMessageSegmentSize;
                    }
                    else
                    {
                        // Check if rest of the message can fit within the maximum message size
                        // Example: ...esponse stream
                        if ((message.Length - (startIndex + 1)) <= _beginOrEndMessageSegmentSize)
                        {
                            messageSegment = ContinuationString + message.Substring(startIndex);
                            EventLog.WriteEntry(messageSegment, eventLogEntryType, eventId, category: 0);
                            break;
                        }
                        else
                        {
                            // Example: ...rred while writ...
                            messageSegment =
                                ContinuationString
                                + message.Substring(startIndex, _intermediateMessageSegmentSize)
                                + ContinuationString;
                            startIndex += _intermediateMessageSegmentSize;
                        }
                    }
    
                    EventLog.WriteEntry(messageSegment, eventLogEntryType, eventId, category: 0);
                }
            }
    
            private EventLogEntryType GetEventLogEntryType(LogLevel level)
            {
                switch (level)
                {
                    case LogLevel.Information:
                    case LogLevel.Debug:
                    case LogLevel.Trace:
                        return EventLogEntryType.Information;
                    case LogLevel.Warning:
                        return EventLogEntryType.Warning;
                    case LogLevel.Critical:
                    case LogLevel.Error:
                        return EventLogEntryType.Error;
                    default:
                        return EventLogEntryType.Information;
                }
            }
        }
    /// <summary>
        /// The provider for the <see cref="EventLogLogger"/>.
        /// </summary>
        [ProviderAlias("EventLog")]
        public class EventLogLoggerProvider : ILoggerProvider, ISupportExternalScope
        {
            internal readonly EventLogSettings _settings;
    
            private IExternalScopeProvider _scopeProvider;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="EventLogLoggerProvider"/> class.
            /// </summary>
            public EventLogLoggerProvider()
                : this(settings: null)
            {
            }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="EventLogLoggerProvider"/> class.
            /// </summary>
            /// <param name="settings">The <see cref="EventLogSettings"/>.</param>
            public EventLogLoggerProvider(EventLogSettings settings)
            {
                _settings = settings ?? new EventLogSettings();
            }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="EventLogLoggerProvider"/> class.
            /// </summary>
            /// <param name="options">The <see cref="IOptions{EventLogSettings}"/>.</param>
            public EventLogLoggerProvider(IOptions<EventLogSettings> options)
                : this(options.Value)
            {
            }
    
            /// <inheritdoc />
            public ILogger CreateLogger(string name)
            {
                return new EventLogLogger(name, _settings, _scopeProvider);
            }
    
            /// <inheritdoc />
            public void Dispose()
            {
                if (_settings.EventLog is WindowsEventLog windowsEventLog)
                {
                    windowsEventLog.DiagnosticsEventLog.Dispose();
                }
            }
    
            /// <inheritdoc />
            public void SetScopeProvider(IExternalScopeProvider scopeProvider)
            {
                _scopeProvider = scopeProvider;
            }
        }

    扩展方法:

    public static class EventLoggerFactoryExtensions
        {
            /// <summary>
            /// Adds an event logger named 'EventLog' to the factory.
            /// </summary>
            /// <param name="builder">The extension method argument.</param>
            /// <returns>The <see cref="ILoggingBuilder"/> so that additional calls can be chained.</returns>
            public static ILoggingBuilder AddEventLog(this ILoggingBuilder builder)
            {
                if (builder == null)
                {
                    throw new ArgumentNullException(nameof(builder));
                }
    
                builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, EventLogLoggerProvider>());
    
                return builder;
            }
    
            /// <summary>
            /// Adds an event logger. Use <paramref name="settings"/> to enable logging for specific <see cref="LogLevel"/>s.
            /// </summary>
            /// <param name="builder">The extension method argument.</param>
            /// <param name="settings">The <see cref="EventLogSettings"/>.</param>
            /// <returns>The <see cref="ILoggingBuilder"/> so that additional calls can be chained.</returns>
            public static ILoggingBuilder AddEventLog(this ILoggingBuilder builder, EventLogSettings settings)
            {
                if (builder == null)
                {
                    throw new ArgumentNullException(nameof(builder));
                }
    
                if (settings == null)
                {
                    throw new ArgumentNullException(nameof(settings));
                }
    
                builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider>(new EventLogLoggerProvider(settings)));
    
                return builder;
            }
    
            /// <summary>
            /// Adds an event logger. Use <paramref name="configure"/> to enable logging for specific <see cref="LogLevel"/>s.
            /// </summary>
            /// <param name="builder">The extension method argument.</param>
            /// <param name="configure">A delegate to configure the <see cref="EventLogSettings"/>.</param>
            /// <returns>The <see cref="ILoggingBuilder"/> so that additional calls can be chained.</returns>
            public static ILoggingBuilder AddEventLog(this ILoggingBuilder builder, Action<EventLogSettings> configure)
            {
                if (configure == null)
                {
                    throw new ArgumentNullException(nameof(configure));
                }
    
                builder.AddEventLog();
                builder.Services.Configure(configure);
    
                return builder;
            }
        }

    internal class ConsoleLogger : ILogger    {        private static readonly string _loglevelPadding = ": ";        private static readonly string _messagePadding;        private static readonly string _newLineWithMessagePadding;
            // ConsoleColor does not have a value to specify the 'Default' color        private readonly ConsoleColor? DefaultConsoleColor = null;
            private readonly string _name;        private readonly ConsoleLoggerProcessor _queueProcessor;
            [ThreadStatic]        private static StringBuilder _logBuilder;
            static ConsoleLogger()        {            var logLevelString = GetLogLevelString(LogLevel.Information);            _messagePadding = new string(' ', logLevelString.Length + _loglevelPadding.Length);            _newLineWithMessagePadding = Environment.NewLine + _messagePadding;        }
            internal ConsoleLogger(string name, ConsoleLoggerProcessor loggerProcessor)        {            if (name == null)            {                throw new ArgumentNullException(nameof(name));            }
                _name = name;            _queueProcessor = loggerProcessor;        }
            internal IExternalScopeProvider ScopeProvider { get; set; }
            internal ConsoleLoggerOptions Options { get; set; }
            public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)        {            if (!IsEnabled(logLevel))            {                return;            }
                if (formatter == null)            {                throw new ArgumentNullException(nameof(formatter));            }
                var message = formatter(state, exception);
                if (!string.IsNullOrEmpty(message) || exception != null)            {                WriteMessage(logLevel, _name, eventId.Id, message, exception);            }        }
            public virtual void WriteMessage(LogLevel logLevel, string logName, int eventId, string message, Exception exception)        {            var format = Options.Format;            Debug.Assert(format >= ConsoleLoggerFormat.Default && format <= ConsoleLoggerFormat.Systemd);
                var logBuilder = _logBuilder;            _logBuilder = null;
                if (logBuilder == null)            {                logBuilder = new StringBuilder();            }
                LogMessageEntry entry;            if (format == ConsoleLoggerFormat.Default)            {                entry = CreateDefaultLogMessage(logBuilder, logLevel, logName, eventId, message, exception);            }            else if (format == ConsoleLoggerFormat.Systemd)            {                entry = CreateSystemdLogMessage(logBuilder, logLevel, logName, eventId, message, exception);            }            else            {                entry = default;            }            _queueProcessor.EnqueueMessage(entry);
                logBuilder.Clear();            if (logBuilder.Capacity > 1024)            {                logBuilder.Capacity = 1024;            }            _logBuilder = logBuilder;        }
            private LogMessageEntry CreateDefaultLogMessage(StringBuilder logBuilder, LogLevel logLevel, string logName, int eventId, string message, Exception exception)        {            // Example:            // INFO: ConsoleApp.Program[10]            //       Request received
                var logLevelColors = GetLogLevelConsoleColors(logLevel);            var logLevelString = GetLogLevelString(logLevel);            // category and event id            logBuilder.Append(_loglevelPadding);            logBuilder.Append(logName);            logBuilder.Append("[");            logBuilder.Append(eventId);            logBuilder.AppendLine("]");
                // scope information            GetScopeInformation(logBuilder, multiLine: true);
                if (!string.IsNullOrEmpty(message))            {                // message                logBuilder.Append(_messagePadding);
                    var len = logBuilder.Length;                logBuilder.AppendLine(message);                logBuilder.Replace(Environment.NewLine, _newLineWithMessagePadding, len, message.Length);            }
                // Example:            // System.InvalidOperationException            //    at Namespace.Class.Function() in File:line X            if (exception != null)            {                // exception message                logBuilder.AppendLine(exception.ToString());            }
                var timestampFormat = Options.TimestampFormat;
                return new LogMessageEntry(                message: logBuilder.ToString(),                timeStamp: timestampFormat != null ? DateTime.Now.ToString(timestampFormat) : null,                levelString: logLevelString,                levelBackground: logLevelColors.Background,                levelForeground: logLevelColors.Foreground,                messageColor: DefaultConsoleColor,                logAsError: logLevel >= Options.LogToStandardErrorThreshold            );        }
            private LogMessageEntry CreateSystemdLogMessage(StringBuilder logBuilder, LogLevel logLevel, string logName, int eventId, string message, Exception exception)        {            // systemd reads messages from standard out line-by-line in a '<pri>message' format.            // newline characters are treated as message delimiters, so we must replace them.            // Messages longer than the journal LineMax setting (default: 48KB) are cropped.            // Example:            // <6>ConsoleApp.Program[10] Request received
                // loglevel            var logLevelString = GetSyslogSeverityString(logLevel);            logBuilder.Append(logLevelString);
                // timestamp            var timestampFormat = Options.TimestampFormat;            if (timestampFormat != null)            {                logBuilder.Append(DateTime.Now.ToString(timestampFormat));            }
                // category and event id            logBuilder.Append(logName);            logBuilder.Append("[");            logBuilder.Append(eventId);            logBuilder.Append("]");
                // scope information            GetScopeInformation(logBuilder, multiLine: false);
                // message            if (!string.IsNullOrEmpty(message))            {                logBuilder.Append(' ');                // message                AppendAndReplaceNewLine(logBuilder, message);            }
                // exception            // System.InvalidOperationException at Namespace.Class.Function() in File:line X            if (exception != null)            {                logBuilder.Append(' ');                AppendAndReplaceNewLine(logBuilder, exception.ToString());            }
                // newline delimiter            logBuilder.Append(Environment.NewLine);
                return new LogMessageEntry(                message: logBuilder.ToString(),                logAsError: logLevel >= Options.LogToStandardErrorThreshold            );
                static void AppendAndReplaceNewLine(StringBuilder sb, string message)            {                var len = sb.Length;                sb.Append(message);                sb.Replace(Environment.NewLine, " ", len, message.Length);            }        }
            public bool IsEnabled(LogLevel logLevel)        {            return logLevel != LogLevel.None;        }
            public IDisposable BeginScope<TState>(TState state) => ScopeProvider?.Push(state) ?? NullScope.Instance;
            private static string GetLogLevelString(LogLevel logLevel)        {            switch (logLevel)            {                case LogLevel.Trace:                    return "trce";                case LogLevel.Debug:                    return "dbug";                case LogLevel.Information:                    return "info";                case LogLevel.Warning:                    return "warn";                case LogLevel.Error:                    return "fail";                case LogLevel.Critical:                    return "crit";                default:                    throw new ArgumentOutOfRangeException(nameof(logLevel));            }        }
            private static string GetSyslogSeverityString(LogLevel logLevel)        {            // 'Syslog Message Severities' from https://tools.ietf.org/html/rfc5424.            switch (logLevel)            {                case LogLevel.Trace:                case LogLevel.Debug:                    return "<7>"; // debug-level messages                case LogLevel.Information:                    return "<6>"; // informational messages                case LogLevel.Warning:                    return "<4>"; // warning conditions                case LogLevel.Error:                    return "<3>"; // error conditions                case LogLevel.Critical:                    return "<2>"; // critical conditions                default:                    throw new ArgumentOutOfRangeException(nameof(logLevel));            }        }
            private ConsoleColors GetLogLevelConsoleColors(LogLevel logLevel)        {            if (Options.DisableColors)            {                return new ConsoleColors(null, null);            }
                // We must explicitly set the background color if we are setting the foreground color,            // since just setting one can look bad on the users console.            switch (logLevel)            {                case LogLevel.Critical:                    return new ConsoleColors(ConsoleColor.White, ConsoleColor.Red);                case LogLevel.Error:                    return new ConsoleColors(ConsoleColor.Black, ConsoleColor.Red);                case LogLevel.Warning:                    return new ConsoleColors(ConsoleColor.Yellow, ConsoleColor.Black);                case LogLevel.Information:                    return new ConsoleColors(ConsoleColor.DarkGreen, ConsoleColor.Black);                case LogLevel.Debug:                    return new ConsoleColors(ConsoleColor.Gray, ConsoleColor.Black);                case LogLevel.Trace:                    return new ConsoleColors(ConsoleColor.Gray, ConsoleColor.Black);                default:                    return new ConsoleColors(DefaultConsoleColor, DefaultConsoleColor);            }        }
            private void GetScopeInformation(StringBuilder stringBuilder, bool multiLine)        {            var scopeProvider = ScopeProvider;            if (Options.IncludeScopes && scopeProvider != null)            {                var initialLength = stringBuilder.Length;
                    scopeProvider.ForEachScope((scope, state) =>                {                    var (builder, paddAt) = state;                    var padd = paddAt == builder.Length;                    if (padd)                    {                        builder.Append(_messagePadding);                        builder.Append("=> ");                    }                    else                    {                        builder.Append(" => ");                    }                    builder.Append(scope);                }, (stringBuilder, multiLine ? initialLength : -1));
                    if (stringBuilder.Length > initialLength && multiLine)                {                    stringBuilder.AppendLine();                }            }        }
            private readonly struct ConsoleColors        {            public ConsoleColors(ConsoleColor? foreground, ConsoleColor? background)            {                Foreground = foreground;                Background = background;            }
                public ConsoleColor? Foreground { get; }
                public ConsoleColor? Background { get; }        }    }

  • 相关阅读:
    NOIP2012 借教室
    bzoj1816 扑克牌
    TYVJ1359 收入计划
    NOIP2015 跳石头
    易错点
    散列表
    数学模板
    12. 17 哈理工网络赛
    哈理工 网络赛
    三角形
  • 原文地址:https://www.cnblogs.com/lanpingwang/p/12541135.html
Copyright © 2020-2023  润新知