Skip to content

OP-02: Configure the Windows Service logger (SaifWindowsServiceLog)

Field Value
Operation ID OP-02
Trigger Host Windows Service calls SaifWindowsServiceLog.Configure(IEnvironmentClient, IHttpJsonClient) during service startup.
Inputs IEnvironmentClient, IHttpJsonClient.
Outputs A configured Serilog pipeline with an Event Log sink (manageEventSource: true), the Logging API sink (error route unset), and a Console sink; IsConfigured set to true.
Primary components SaifWindowsServiceLog, SaifLogBase, ApiLoggerConfig, EventLogConfig
Entry point SaifWindowsServiceLog.Configure

Steps

  1. Call ConfigureLoggers(environmentClient), which resolves the base log threshold using the same application-section-then-tracingdefaults fallback as the web logger (BR-LOG-01, BR-LOG-02).
  2. Parse the threshold; an unparseable or empty value throws ArgumentException and aborts configuration (BR-LOG-08).
  3. Still inside ConfigureLoggers: build the standard EventLogConfig (Level = LogLevel.Info) and ApiLoggerConfig sink configurations, then apply the SaifLogging:BaseLevel and SaifLogging:Loggers appsettings.json overrides, same as the web logger:
  4. 3.1. Check whether the SaifLogging section exists and contains a BaseLevel child; only then replace BaseLevel with that configured value (normalized via ToLogLevelString()) — an absent section or key leaves the Environment-API-derived BaseLevel from steps 1–2 untouched (BR-LOG-02).
  5. 3.2. Check whether SaifLogging:Loggers exists; for each child entry, parse Type/Level/LogPattern and replace the matching standard ApiLog/EventLog config wholesale, throwing SaifLogConfigurationException for an invalid Type or ArgumentException for a missing Level (BR-LOG-03, BR-LOG-04, BR-LOG-05).

Origin: Steps 3.1–3.2 are implemented in Apply appsettings.json logger overrides (SaifLogBase.ApplyLoggingSettingOverrides) and executed on behalf of this operation. 4. Back in Configure: compute the Event Log source name as {EnvironmentTrackName.ToUpper().First()}{EnvironmentTrackName.ToUpper().Last()}-{ApplicationName}. 5. Read tracingdefaults:loggingapiurl and tracingdefaults:logroute — but not logerrorroute — and push the base URL into the injected IHttpJsonClient (BR-LOG-09). 6. Construct the Serilog logger with the resolved BaseLevelSwitch, an Event Log sink built with manageEventSource: true, a LoggingApiSink, and a Console sink. 7. Set IsConfigured = true.

Process flow

flowchart TD
    A[Configure called] --> B["ConfigureLoggers: resolve base threshold"]
    B --> C{Threshold valid?}
    C -->|No| C1[ArgumentException - Configure aborts]
    C -->|Yes| D["Build standard EventLogConfig + ApiLoggerConfig,<br>apply BaseLevel/Loggers overrides"]
    D --> E["Compute Event Log source name<br>from track name + ApplicationName"]
    E --> F[Read loggingapiurl / logroute only - no logerrorroute]
    F --> G[Push base URL into IHttpJsonClient]
    G --> H["Build Serilog logger: Event Log sink<br>(manageEventSource) + LoggingApiSink + Console sink"]
    H --> I["IsConfigured = true"]

Failure and edge-case behavior

  • Same threshold-resolution failure mode as the web logger: an invalid/missing threshold aborts this Configure call; IsConfigured stays false if this is the first attempt, or keeps its prior true value if a previously-successful Configure is being retried (BR-LOG-08).
  • Because logerrorroute is never read, every error entry this logger posts is sent with a null error route, regardless of what the Environment API holds for that key (BR-LOG-09).
  • An empty EnvironmentTrackName from the host's IEnvironmentClient can throw when composing the Event Log source, since the code upper-cases and takes the first and last characters of the track name.

Sources

  • src/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SaifWindowsServiceLog.cs
  • src/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SaifLogBase.cs