OP-04: Apply appsettings.json logger overrides¶
| Field | Value |
|---|---|
| Operation ID | OP-04 |
| Trigger | Called internally by SaifLogBase.ConfigureLoggers after the standard ApiLoggerConfig/Event Log configs are built, for web and Windows Service hosts only. |
| Inputs | IConfiguration section SaifLogging:BaseLevel (existing BaseLevel string), IConfiguration section SaifLogging:Loggers, the standard sink config set. |
| Outputs | A possibly-updated BaseLevel string (only when the SaifLogging:BaseLevel key is present), and a sink config set with zero, one, or both standard entries replaced wholesale. |
| Primary components | SaifLogBase.ApplyLoggingSettingOverrides, IConfigurationSectionExtensions.ToLoggerConfig |
| Entry point | SaifLogBase.ApplyLoggingSettingOverrides |
Steps¶
SaifLogBase.ApplyLoggingSettingOverridesgets theSaifLoggingconfiguration section and checks two conditions: theSaifLoggingsection itself must exist (loggingSection.Exists()), and it must contain aBaseLevelchild section (loggingSection.SectionExists(StringValues.BaseLevelConfigSection)). Only when both are true does it assignBaseLevel = loggingSection.GetSection(StringValues.BaseLevelConfigSection).Value— this assignment itself (via the inheritedBaseLevelsetter) normalizes the value throughToLogLevelString(). When either condition is false, the Environment-API-derivedBaseLevelvalue from OP-01/OP-02 is left untouched. This step does not construct or modifyBaseLevelSwitch— the switch (BaseLevelSwitch = new LoggingLevelSwitch(BaseLevel.ToLogEventLevel())) is built later, back inConfigureLoggers, afterApplyLoggingSettingOverridesandInitializeLoggerInfoLookupshave both already run, so it always reflects whateverBaseLevelvalue is current at that point — including this step's override, if one was applied.- Separately, check whether the
SaifLogging:Loggerssection exists; if not, skip the remaining steps — the standard sink configs stand unchanged. - For each child entry, read
Typeand parse it against theLoggerTypeenum (ApiLog,ErrorLog,EventLog); the match is case-sensitive (BR-LOG-03). - An invalid or missing
TypethrowsSaifLogConfigurationException(BR-LOG-05). - Read
Leveland parse it viaToLogLevel(); a missing value throwsArgumentException— there is no default fallback toInfo(BR-LOG-04). - Read
LogPattern; if absent, the resulting config carries anullpattern — it is not backfilled from the standard config, because the override replaces the whole entry. - Replace the matching standard sink config (
ApiLogorEventLog) with the parsed override. AnErrorLogentry parses successfully but is never matched against any standard sink and is silently ignored.
Process flow¶
flowchart TD
A[ApplyLoggingSettingOverrides runs] --> B{"SaifLogging section exists AND<br>contains a BaseLevel child?"}
B -->|No| C["BaseLevel left at its<br>Environment-API-derived value"]
B -->|Yes| D["BaseLevel = SaifLogging:BaseLevel value<br>(normalized via ToLogLevelString)"]
C --> E["SaifLogging:Loggers section present?"]
D --> E
E -->|No| Z[Standard sink configs unchanged]
E -->|Yes| F["For each entry: parse Type case-sensitive"]
F --> G{Type valid?}
G -->|No| G1[SaifLogConfigurationException]
G -->|Yes| H[Parse Level]
H --> I{Level present and valid?}
I -->|No| I1[ArgumentException - no Info fallback]
I -->|Yes| J[Read LogPattern - null if absent]
J --> K{Type matches a standard sink?}
K -->|ApiLog or EventLog| L[Replace standard config wholesale]
K -->|ErrorLog| M[Parsed but silently ignored - no matching sink]
Failure and edge-case behavior¶
- A missing
Levelon anySaifLogging:Loggersoverride entry throwsArgumentException, aborting the callingConfigurecall entirely (BR-LOG-04). - A
nullLogPatternon an override entry propagates to the Event LogoutputTemplateor toLoggingApiSink's constructor, which builds itsMessageTemplateTextFormatterfrom that pattern before any event is dispatched; whetherMessageTemplateTextFormatter's own constructor tolerates anulltemplate argument is not confirmed in this library's source.** If that constructor call throws, the sink itself fails construction and never reachesSend/SendExceptionfor that attempt (BR-LOG-14). - The
SaifLogging:BaseLeveloverride check is independent ofSaifLogging:Loggerssection presence, but it is itself conditional on theSaifLoggingsection existing and containing aBaseLevelkey; an absentSaifLoggingsection or an absentBaseLevelkey within it leaves the Environment-API-derivedBaseLevelvalue untouched, it does not apply a different fallback of its own. - The Console logger never calls this operation;
SaifLogging:Loggershas no effect for console hosts (BR-LOG-12).
Related documentation¶
Note: Statements marked with
**could not be confirmed; treat as unknown until verified.
Sources¶
src/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SaifLogBase.cssrc/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/Extensions/IConfigurationSectionExtensions.cssrc/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/Extensions/LogLevelExtensions.cs