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());
                    }
                }
            }
  • 相关阅读:
    SD卡测试
    测试人员可能会遇到的问题
    HDU 1024 Max Sum Plus Plus
    HDU 1176 免费馅饼
    HDU 1257 最少拦截系统
    HDU 1087 Super Jumping! Jumping! Jumping!
    poj 1328 Radar Installation
    poj 1753 Flip Game
    HDU 1003 Max Sum
    HDU 5592 ZYB's Premutation(BestCoder Round #65 C)
  • 原文地址:https://www.cnblogs.com/chucklu/p/13279012.html
Copyright © 2011-2022 走看看