void ApplyDynamicConfiguration(bool initialConfigMustWaitForApplication) { Debug.Assert(_section != null); // It has been Obsolete (Warn) for a long time. Now we throw. if (_section["HandleAspNetLogs"] != null) { throw new CKException("Configuration name \"HandleAspNetLogs\" is obsolete: please use \"HandleDotNetLogs\" instead."); } if (_section["LogUnhandledExceptions"] != null) { throw new CKException("Configuration name \"LogUnhandledExceptions\" is not used anymore, it is now on the GrandOutput: use \"GrandOutput.TrackUnhandledExceptions\" instead (defaults to true)."); } bool dotNetLogs = !String.Equals(_section["HandleDotNetLogs"], "false", StringComparison.OrdinalIgnoreCase); LogFilter defaultFilter = LogFilter.Undefined; bool hasGlobalDefaultFilter = _section["GlobalDefaultFilter"] != null; bool errorParsingGlobalDefaultFilter = hasGlobalDefaultFilter && !LogFilter.TryParse(_section["GlobalDefaultFilter"], out defaultFilter); if (hasGlobalDefaultFilter && !errorParsingGlobalDefaultFilter) { if (initialConfigMustWaitForApplication) { // On first initialization, configure the filter as early as possible. if (defaultFilter.Group != LogLevelFilter.None && defaultFilter.Line != LogLevelFilter.None) { ActivityMonitor.DefaultFilter = defaultFilter; } // If the filter is invalid (a None appears}, keep the default Trace. } else { // If a GlobalDefaultFilter has been successfully parsed and we are reconfiguring and it is different than // the current one, logs the change and applies the configuration. if (defaultFilter != ActivityMonitor.DefaultFilter) { Debug.Assert(_target != null, "Since !initialConfigMustWaitForApplication."); defaultFilter = SetGlobalDefaultFilter(defaultFilter); } } } try { GrandOutputConfiguration c = CreateConfigurationFromSection(_section); if (_target == null) { Debug.Assert(_isDefaultGrandOutput && initialConfigMustWaitForApplication); _target = GrandOutput.EnsureActiveDefault(c); _loggerProvider = new GrandOutputLoggerAdapterProvider(_target); } else { Debug.Assert(_loggerProvider != null); _target.ApplyConfiguration(c, initialConfigMustWaitForApplication); } } catch (Exception ex) { if (_target == null) { // Using the default "Text" log configuration. // If this fails (!), let the exception breaks the whole initialization since this // is really unrecoverable. _target = GrandOutput.EnsureActiveDefault(); _loggerProvider = new GrandOutputLoggerAdapterProvider(_target); } _target.ExternalLog(Core.LogLevel.Fatal, message: $"While applying dynamic configuration.", ex: ex); } Debug.Assert(_loggerProvider != null); _loggerProvider._running = dotNetLogs; // Applying Tags. var rawTags = _section.GetSection("TagFilters").Get <string[][]>(); if (rawTags != null && rawTags.Length > 0) { var tags = new List <(CKTrait, LogClamper)>(); foreach (var bi in rawTags) { if (bi != null && bi[0] != null && bi[1] != null) { var t = ActivityMonitor.Tags.Register(bi[0]); if (!t.IsEmpty && LogClamper.TryParse(bi[1], out var c)) { tags.Add((t, c)); } else { if (t.IsEmpty) { _target.ExternalLog(Core.LogLevel.Warn, message: $"Ignoring TagFilters entry '{bi[0]},{bi[1]}'. Tag is empty"); } else { _target.ExternalLog(Core.LogLevel.Warn, message: $"Ignoring TagFilters entry '{bi[0]},{bi[1]}'. Unable to parse clamp value. Expected a LogFilter (followed by an optional '!'): \"Debug\", \"Trace\", \"Verbose\", \"Monitor\", \"Terse\", \"Release\", \"Off\" or pairs of \"{{Group,Line}}\" levels where Group or Line can be Debug, Trace, Info, Warn, Error, Fatal or Off."); } } } } ActivityMonitor.Tags.SetFilters(tags.ToArray()); } if (hasGlobalDefaultFilter) { // Always log the parse error, but only log and applies if this is the initial configuration. if (errorParsingGlobalDefaultFilter) { _target.ExternalLog(Core.LogLevel.Error, message: $"Unable to parse configuration 'GlobalDefaultFilter'. Expected \"Debug\", \"Trace\", \"Verbose\", \"Monitor\", \"Terse\", \"Release\", \"Off\" or pairs of \"{{Group,Line}}\" levels where Group or Line can be Debug, Trace, Info, Warn, Error, Fatal or Off."); } else if (initialConfigMustWaitForApplication) { SetGlobalDefaultFilter(defaultFilter); } } }