zoukankan      html  css  js  c++  java
  • Serilog settings appsetting 配置的加载

       var loggerConfiguration = new LoggerConfiguration();
                    loggerConfiguration = loggerConfiguration.ReadFrom.AppSettings(filePath: path);
                    var logger = loggerConfiguration.CreateLogger();

    https://github.com/serilog/serilog/blob/dev/src/Serilog/LoggerConfiguration.cs#L133

    ReadFrom的类型是LoggerSettingsConfiguration,构造的时候,把LoggerConfiguration作为参数传递过去。会对应到下文出现的_loggerConfiguration

      /// <summary>
            /// Apply external settings to the logger configuration.
            /// </summary>
            public LoggerSettingsConfiguration ReadFrom => new LoggerSettingsConfiguration(this);

     LoggerSettingsConfiguration类的构造函数

     readonly LoggerConfiguration _loggerConfiguration;
    
            internal LoggerSettingsConfiguration(LoggerConfiguration loggerConfiguration)
            {
                _loggerConfiguration = loggerConfiguration ?? throw new ArgumentNullException(nameof(loggerConfiguration));
            }

    https://github.com/serilog/serilog/blob/dev/src/Serilog/Configuration/ILoggerSettings.cs#L20

     /// <summary>
        /// Implemented on types that apply settings to a logger configuration.
        /// </summary>
        public interface ILoggerSettings
        {
            /// <summary>
            /// Apply the settings to the logger configuration.
            /// </summary>
            /// <param name="loggerConfiguration">The logger configuration to apply settings to.</param>
            void Configure(LoggerConfiguration loggerConfiguration);
        }

    https://github.com/serilog/serilog-settings-appsettings/blob/dev/src/Serilog.Settings.AppSettings/AppSettingsLoggerConfigurationExtensions.cs#L62

    ReadFrom的AppSettings方法,下面代码里的settingConfiguration就是上面的ReadFrom。

    代码里面new AppSettingsSettings(settingPrefix, filePath)作为参数传递,后续方法直接调用了它的Configure方法

    需要注意的是 class AppSettingsSettings : ILoggerSettings

        /// <summary>
            /// Reads the &lt;appSettings&gt; element of App.config or Web.config, searching for for keys
            /// that look like: <code>serilog:*</code>, which are used to configure
            /// the logger. To add a sink, use a key like <code>serilog:write-to:File.path</code> for
            /// each parameter to the sink's configuration method. To add an additional assembly
            /// containing sinks, use <code>serilog:using</code>. To set the level use
            /// <code>serilog:minimum-level</code>.
            /// </summary>
            /// <param name="settingConfiguration">Logger setting configuration.</param>
            /// <param name="settingPrefix">Prefix to use when reading keys in appSettings. If specified the value
            /// will be prepended to the setting keys and followed by :, for example "myapp" will use "myapp:serilog:minumum-level. If null
            /// no prefix is applied.</param>
            /// <param name="filePath">Specify the path to an alternative .config file location. If the file does not exist it will be ignored.
            /// By default, the current application's configuration file will be used.</param>
            /// <returns>An object allowing configuration to continue.</returns>
            public static LoggerConfiguration AppSettings(
                this LoggerSettingsConfiguration settingConfiguration, string settingPrefix = null, string filePath = null)
            {
                if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration));
                if (settingPrefix != null)
                {
                    if (settingPrefix.Contains(":")) throw new ArgumentException("Custom setting prefixes cannot contain the colon (:) character.");
                    if (settingPrefix == "serilog") throw new ArgumentException("The value "serilog" is not a permitted setting prefix. To use the default, do not specify a custom prefix at all.");
                    if (string.IsNullOrWhiteSpace(settingPrefix)) throw new ArgumentException("To use the default setting prefix, do not supply the settingPrefix parameter, instead pass the default null.");
                }
    
                return settingConfiguration.Settings(new AppSettingsSettings(settingPrefix, filePath));
            }

    https://github.com/serilog/serilog/blob/dev/src/Serilog/Configuration/LoggerSettingsConfiguration.cs#L38

    代码里面的settings是上面new AppSettingsSettings(settingPrefix, filePath)的结果。

    /// <summary>
            /// Apply external settings to the logger configuration.
            /// </summary>
            /// <returns>Configuration object allowing method chaining.</returns>
            /// <exception cref="ArgumentNullException">When <paramref name="settings"/> is <code>null</code></exception>
            public LoggerConfiguration Settings(ILoggerSettings settings)
            {
                if (settings == null) throw new ArgumentNullException(nameof(settings));
    
                settings.Configure(_loggerConfiguration);
                return _loggerConfiguration;
            }

    https://github.com/serilog/serilog/blob/dev/src/Serilog/Configuration/LoggerSettingsConfiguration.cs#L26

      readonly LoggerConfiguration _loggerConfiguration;
    
            internal LoggerSettingsConfiguration(LoggerConfiguration loggerConfiguration)
            {
                _loggerConfiguration = loggerConfiguration ?? throw new ArgumentNullException(nameof(loggerConfiguration));
            }

    https://github.com/serilog/serilog-settings-appsettings/blob/dev/src/Serilog.Settings.AppSettings/Settings/AppSettings/AppSettingsSettings.cs#L30

      readonly string _filePath;
            readonly string _settingPrefix;
    
            public AppSettingsSettings(string settingPrefix = null, string filePath = null)
            {
                _filePath = filePath;
                _settingPrefix = settingPrefix == null ? "serilog:" : $"{settingPrefix}:serilog:";
            }

    https://github.com/serilog/serilog-settings-appsettings/blob/dev/src/Serilog.Settings.AppSettings/Settings/AppSettings/AppSettingsSettings.cs#L36

     class AppSettingsSettings : ILoggerSettings实现的接口方法

      public void Configure(LoggerConfiguration loggerConfiguration)
            {
                if (loggerConfiguration == null) throw new ArgumentNullException(nameof(loggerConfiguration));
    
                IEnumerable<KeyValuePair<string, string>> settings;
    
                if (!string.IsNullOrWhiteSpace(_filePath))
                {
                    if (!File.Exists(_filePath))
                    {
                        SelfLog.WriteLine("The specified configuration file `{0}` does not exist and will be ignored.", _filePath);
                        return;
                    }
    
                    var map = new ExeConfigurationFileMap {ExeConfigFilename = _filePath};
                    var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
                    settings = config.AppSettings.Settings
                        .Cast<KeyValueConfigurationElement>()
                        .Select(k => new KeyValuePair<string, string>(k.Key, k.Value));
                }
                else
                {
                    settings = ConfigurationManager.AppSettings.AllKeys
                        .Select(k => new KeyValuePair<string, string>(k, ConfigurationManager.AppSettings[k]));
                }
    
                var pairs = settings
                    .Where(k => k.Key.StartsWith(_settingPrefix))
                    .Select(k => new KeyValuePair<string, string>(
                        k.Key.Substring(_settingPrefix.Length),
                        Environment.ExpandEnvironmentVariables(k.Value)));
    
                loggerConfiguration.ReadFrom.KeyValuePairs(pairs);
            }

     一次性拿到所有的key和value,然后用where过滤一下

    settings = ConfigurationManager.AppSettings.AllKeys
    .Select(k => new KeyValuePair<string, string>(k, ConfigurationManager.AppSettings[k]));

    最后loggerConfiguration.ReadFrom.KeyValuePairs(pairs);

    https://github.com/serilog/serilog/blob/dev/src/Serilog/Configuration/LoggerSettingsConfiguration.cs#L53

    需要注意的是,class KeyValuePairSettings : ILoggerSettings

     /// <summary>
            /// Apply settings specified in the Serilog key-value setting format to the logger configuration.
            /// </summary>
            /// <param name="settings">A list of key-value pairs describing logger settings.</param>
            /// <returns>Configuration object allowing method chaining.</returns>
            /// <remarks>In case of duplicate keys, the last value for the key is kept and the previous ones are ignored.</remarks>
            /// <exception cref="ArgumentNullException">When <paramref name="settings"/> is <code>null</code></exception>
            public LoggerConfiguration KeyValuePairs(IEnumerable<KeyValuePair<string, string>> settings)
            {
                if (settings == null) throw new ArgumentNullException(nameof(settings));
    
                var uniqueSettings = new Dictionary<string, string>();
                foreach (var kvp in settings)
                {
                    uniqueSettings[kvp.Key] = kvp.Value;
                }
                return KeyValuePairs(uniqueSettings);
            }
    
            LoggerConfiguration KeyValuePairs(IReadOnlyDictionary<string, string> settings)
            {
                return Settings(new KeyValuePairSettings(settings));
            }

    并且这里的setting是上面曾经提到过的,但是这次传给方法的参数是class KeyValuePairSettings : ILoggerSettings

     /// <summary>
            /// Apply external settings to the logger configuration.
            /// </summary>
            /// <returns>Configuration object allowing method chaining.</returns>
            /// <exception cref="ArgumentNullException">When <paramref name="settings"/> is <code>null</code></exception>
            public LoggerConfiguration Settings(ILoggerSettings settings)
            {
                if (settings == null) throw new ArgumentNullException(nameof(settings));
    
                settings.Configure(_loggerConfiguration);
                return _loggerConfiguration;
            }

    然后这次触发的Configure方法是KeyValuePairSettings实现的

    https://github.com/serilog/serilog/blob/dev/src/Serilog/Settings/KeyValuePairs/KeyValuePairSettings.cs#L86

      public void Configure(LoggerConfiguration loggerConfiguration)
            {
                if (loggerConfiguration == null) throw new ArgumentNullException(nameof(loggerConfiguration));
    
                var directives = _settings
                    .Where(kvp => _supportedDirectives.Any(kvp.Key.StartsWith))
                    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
    
                var declaredLevelSwitches = ParseNamedLevelSwitchDeclarationDirectives(directives);
    
                if (directives.TryGetValue(MinimumLevelDirective, out var minimumLevelDirective) &&
                    Enum.TryParse(minimumLevelDirective, out LogEventLevel minimumLevel))
                {
                    loggerConfiguration.MinimumLevel.Is(minimumLevel);
                }
    
                foreach (var enrichPropertyDirective in directives.Where(dir =>
                    dir.Key.StartsWith(EnrichWithPropertyDirectivePrefix) && dir.Key.Length > EnrichWithPropertyDirectivePrefix.Length))
                {
                    var name = enrichPropertyDirective.Key.Substring(EnrichWithPropertyDirectivePrefix.Length);
                    loggerConfiguration.Enrich.WithProperty(name, enrichPropertyDirective.Value);
                }
    
                if (directives.TryGetValue(MinimumLevelControlledByDirective, out var minimumLevelControlledByLevelSwitchName))
                {
                    var globalMinimumLevelSwitch = LookUpSwitchByName(minimumLevelControlledByLevelSwitchName, declaredLevelSwitches);
                    loggerConfiguration.MinimumLevel.ControlledBy(globalMinimumLevelSwitch);
                }
    
                foreach (var minimumLevelOverrideDirective in directives.Where(dir =>
                    dir.Key.StartsWith(MinimumLevelOverrideDirectivePrefix) && dir.Key.Length > MinimumLevelOverrideDirectivePrefix.Length))
                {
                    var namespacePrefix = minimumLevelOverrideDirective.Key.Substring(MinimumLevelOverrideDirectivePrefix.Length);
    
                    if (Enum.TryParse(minimumLevelOverrideDirective.Value, out LogEventLevel overriddenLevel))
                    {
                        loggerConfiguration.MinimumLevel.Override(namespacePrefix, overriddenLevel);
                    }
                    else
                    {
                        var overrideSwitch = LookUpSwitchByName(minimumLevelOverrideDirective.Value, declaredLevelSwitches);
                        loggerConfiguration.MinimumLevel.Override(namespacePrefix, overrideSwitch);
                    }
                }
    
                var matchCallables = new Regex(CallableDirectiveRegex);
    
                var callableDirectives = (from wt in directives
                                          where matchCallables.IsMatch(wt.Key)
                                          let match = matchCallables.Match(wt.Key)
                                          select new
                                          {
                                              ReceiverType = CallableDirectiveReceiverTypes[match.Groups["directive"].Value],
                                              Call = new ConfigurationMethodCall
                                              {
                                                  MethodName = match.Groups["method"].Value,
                                                  ArgumentName = match.Groups["argument"].Value,
                                                  Value = wt.Value
                                              }
                                          }).ToList();
    
                if (callableDirectives.Any())
                {
                    var configurationAssemblies = LoadConfigurationAssemblies(directives).ToList();
    
                    foreach (var receiverGroup in callableDirectives.GroupBy(d => d.ReceiverType))
                    {
                        var methods = CallableConfigurationMethodFinder.FindConfigurationMethods(configurationAssemblies, receiverGroup.Key);
    
                        var calls = receiverGroup
                            .Select(d => d.Call)
                            .GroupBy(call => call.MethodName)
                            .ToList();
    
                        ApplyDirectives(calls, methods, CallableDirectiveReceivers[receiverGroup.Key](loggerConfiguration), declaredLevelSwitches);
                    }
                }
            }

    var methods = CallableConfigurationMethodFinder.FindConfigurationMethods(configurationAssemblies, receiverGroup.Key);

    这个应该就是用反射,来找方法

    https://github.com/serilog/serilog/blob/dev/src/Serilog/Settings/KeyValuePairs/KeyValuePairSettings.cs#L227

    代码中的target.Invoke可能出错,如果配置不对的话 https://www.cnblogs.com/chucklu/p/13279668.html

      static void ApplyDirectives(List<IGrouping<string, ConfigurationMethodCall>> directives, IList<MethodInfo> configurationMethods, object loggerConfigMethod, IReadOnlyDictionary<string, LoggingLevelSwitch> declaredSwitches)
            {
                foreach (var directiveInfo in directives)
                {
                    var target = SelectConfigurationMethod(configurationMethods, directiveInfo.Key, directiveInfo);
    
                    if (target != null)
                    {
                        var call = (from p in target.GetParameters().Skip(1)
                                    let directive = directiveInfo.FirstOrDefault(s => s.ArgumentName == p.Name)
                                    select directive == null ? p.DefaultValue : ConvertOrLookupByName(directive.Value, p.ParameterType, declaredSwitches)).ToList();
    
                        call.Insert(0, loggerConfigMethod);
    
                        target.Invoke(null, call.ToArray());
                    }
                }
            }
  • 相关阅读:
    关于前台日期转换和比较大小以及今天前三天日期
    20180409和四岁淘淘探讨死亡
    [转载]谷歌浏览器Chrome下载文件时文件名乱码问题
    [转载]美国科学在线版
    [转载]学习资料-科学类
    小班的淘淘
    Spring Security构建Rest服务-0702-个性化用户认证流程2
    Spring Security构建Rest服务-0701-个性化用户认证流程
    Spring Security构建Rest服务-0700-SpringSecurity开发基于表单的认证
    Spring Security构建Rest服务-0600-SpringSecurity基本原理
  • 原文地址:https://www.cnblogs.com/chucklu/p/13279012.html
Copyright © 2011-2022 走看看