Hot Reload (Update Logger)

Change logging behavior without restarting the server. Two approaches:

  • Dynamic minimum level: configure a logger with a dynamic level switch and adjust it at runtime.
  • Re-register: create a new configuration and register it under the same name to change sinks/properties/level.

Tip: Using a dynamic level via Set-KrLoggerLevel -Dynamic <Level> creates an internal switch you can read/change by logger name with Get-KrLevelSwitch/Set-KrLevelSwitch.

Full source

File: pwsh/tutorial/examples/5.6-Hot-Reload.ps1

<#
    Sample demonstrating hot reload:
    - Dynamically change minimum level with a LoggingLevelSwitch
    - Re-register a logger with the same name to change sinks/properties
    FileName: 5.6-Hot-Reload.ps1
#>

param(
    [int]$Port = 5000,
    [IPAddress]$IPAddress = [IPAddress]::Loopback
)

# Dynamic level switch logger
New-KrLogger |
    Set-KrLoggerLevel -Dynamic Debug |
    Add-KrSinkConsole |
    Add-KrSinkFile -Path '.\logs\hot-reload.log' -RollingInterval Hour |
    Register-KrLogger -Name 'app' -PassThru

# Default logger for server events
New-KrLogger |
    Set-KrLoggerLevel -Value Debug |
    Add-KrSinkConsole |
    Register-KrLogger -Name 'Default'

New-KrServer -Name "Hot Reload" -LoggerName 'Default'
Add-KrEndpoint -Port $Port -IPAddress $IPAddress


Enable-KrConfiguration
# Writes both Debug and Information; visibility depends on level switch
Add-KrMapRoute -Verbs Get -Path "/log" -ScriptBlock {
    Write-KrLog -LoggerName 'app' -Level Debug -Message "Debug event"
    Write-KrLog -LoggerName 'app' -Level Information -Message "Information event"
    Write-KrLog -LoggerName 'app' -Level Warning -Message "Warning event"
    Write-KrLog -LoggerName 'app' -Level Error -Message "Error event"
    Write-KrLog -LoggerName 'app' -Level Fatal -Message "Fatal event"
    Write-KrTextResponse -InputObject "ok - $(Get-KrLoggerLevelSwitch -LoggerName 'app')" -StatusCode 200
}

# Change minimum level via route: /level/{level} e.g., /level/Debug or /level/Warning
Add-KrMapRoute -Verbs Get -Path "/level/{level}" -ScriptBlock {
    $lvl = Get-KrRequestRouteParam -Name 'level'
    $parsed = [Serilog.Events.LogEventLevel]::Information
    if ([Enum]::TryParse([Serilog.Events.LogEventLevel], $lvl, $true, [ref]$parsed)) {
        Write-KrLog -Level Debug -LoggerName 'Default' -Message "Changing level to {lvl}" -Values $lvl
        Set-KrLoggerLevelSwitch -LoggerName 'app' -MinimumLevel $parsed | Out-Null
        Write-KrLog -LoggerName 'app' -Level Information -Message "Level switch set to {level}" -Values $lvl
        Write-KrTextResponse -InputObject "level=$lvl" -StatusCode 200
    } else {
        Write-KrLog -LoggerName 'app' -Level Warning -Message "Invalid level value {level}" -Values $lvl
        Write-KrTextResponse -InputObject "invalid level '$lvl'" -StatusCode 400
    }
}

# Reconfigure 'app' logger at runtime: add a property and tighten minimum level
Add-KrMapRoute -Verbs Post -Path "/reconfigure" -ScriptBlock {
    New-KrLogger |
        Set-KrLoggerLevel -Value Warning |
        Add-KrEnrichProperty -Name 'Reconfigured' -Value $true |
        Add-KrSinkConsole |
        Add-KrSinkFile -Path '.\logs\hot-reload.log' -RollingInterval Hour |
        Register-KrLogger -Name 'app'
    Write-KrTextResponse -InputObject "reconfigured" -StatusCode 200
}

# Start the server
Start-KrServer

# Clean up and close the logger when the server stops
Close-KrLogger


Step-by-step

  1. Configure a logger with a dynamic minimum level using Set-KrLoggerLevel -Dynamic Debug, add sinks (console + file), and register it as app.
  2. Route /log writes events at multiple levels so you can see the current threshold in effect; the response echoes the level via Get-KrLevelSwitch -LoggerName 'app'.
  3. Route /level/{level} changes the level at runtime (Debug, Information, Warning, Error, Fatal) using Set-KrLevelSwitch -LoggerName 'app' -MinimumLevel ....
  4. Route /reconfigure re-registers a new configuration under the same name app (adds a Reconfigured=true property and sets minimum to Warning), replacing the prior logger safely.

Try it

Save the sample locally so it’s easy to run. Copy the contents of pwsh/tutorial/examples/5.6-Hot-Reload.ps1 into a new file in an empty working folder (for example, hot-reload.ps1), then run:

Curl examples:

curl http://127.0.0.1:5000/log
curl http://127.0.0.1:5000/level/Debug
curl http://127.0.0.1:5000/log
curl -X POST http://127.0.0.1:5000/reconfigure
curl http://127.0.0.1:5000/log

Invoke-WebRequest examples:

Invoke-RestMethod -Uri 'http://127.0.0.1:5000/log' -Method Get
Invoke-RestMethod -Uri 'http://127.0.0.1:5000/level/Debug' -Method Get
Invoke-RestMethod -Uri 'http://127.0.0.1:5000/log' -Method Get
Invoke-RestMethod -Uri 'http://127.0.0.1:5000/reconfigure' -Method Post
Invoke-RestMethod -Uri 'http://127.0.0.1:5000/log' -Method Get

Expected: Debug becomes visible after /level/Debug; after /reconfigure, only Warning+ are written and the Reconfigured=true property appears.

Notes

  • Dynamic level: Set-KrLoggerLevel -Dynamic <Level> attaches a per-logger switch that you can later inspect or change by name using Get-KrLevelSwitch / Set-KrLevelSwitch.
  • Per-sink control: sinks can still have their own level switches if you need different thresholds per sink.
  • Re-registering a logger with the same name disposes the previous instance (see LoggerManager).
  • To update the Kestrun framework logger, re-register the default logger name or set -SetAsDefault.

Troubleshooting

Symptom Cause Fix
Level not changing Wrong enum casing/route value Use Debug/Information/Warning/Error/Fatal
Still seeing Debug logs Logger not configured as dynamic Use Set-KrLoggerLevel -Dynamic <Level> initially
No change after POST Logger name mismatch Re-register/change using the exact same name (app)

References


Previous / Next

Go back to Sinks (HTTP/EventLog/Syslog) or continue to PowerShell vs C# Interop. Guide: Logging (Concepts)