Skip to content

Commit

Permalink
Merge pull request #800 from sitkoru/dynamic-serilog
Browse files Browse the repository at this point in the history
feat(serilog): use configuration to change serilog settings
  • Loading branch information
pogromistik authored Mar 22, 2023
2 parents be0769b + fd49911 commit 0db6be5
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 48 deletions.
78 changes: 69 additions & 9 deletions apps/Sitko.Core.Apps.Blazor/Pages/Logging.razor
Original file line number Diff line number Diff line change
@@ -1,12 +1,72 @@
@page "/Logging"
@using Thinktecture.Extensions.Configuration
@using Serilog.Events
@using Microsoft.Extensions.Logging
@using System.Threading
@using Microsoft.Extensions.Configuration
@using Sitko.Core.App.Logging
@inherits BaseComponent
@inject ISerilogConfiguration loggingConfiguration
<PageContainer Title="Logging">
<ChildContent>
<Button OnClick="@(() => loggingConfiguration.SetLevel(LogEventLevel.Debug))">Set debug</Button>
<Button OnClick="@(() => loggingConfiguration.SetLevel(LogEventLevel.Information))">Set info</Button>
<Button OnClick="@(() => loggingConfiguration.ResetLevel())">Reset</Button>
</ChildContent>
</PageContainer>
<MudPageLayout Title="Logging">
<MudButton Variant="Variant.Filled" Color="Color.Secondary" OnClick="@(() => SetLevel(LogEventLevel.Debug))">Set debug</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Info" OnClick="@(() => SetLevel(LogEventLevel.Information))">Set info</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Warning" OnClick="@(() => SetLevel(LogEventLevel.Warning))">Set warning</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Error" OnClick="@(() => SetLevel(LogEventLevel.Error))">Set error</MudButton>
<MudButton Color="Color.Secondary" Variant="Variant.Outlined" OnClick="@(() => ResetLevel())">Reset</MudButton>

@if (!string.IsNullOrEmpty(debugView))
{
<pre>
@debugView
</pre>
}
</MudPageLayout>

@code
{
private Task? logTask;
private readonly CancellationTokenSource cts = new();
private string? debugView;

protected override void Initialize()
{
base.Initialize();
logTask = StartLoggingAsync();
}

private async Task StartLoggingAsync()
{
while (!cts.IsCancellationRequested)
{
await Task.Delay(5000);
Logger.LogDebug("Debug");
Logger.LogInformation("Info");
Logger.LogWarning("Warning");
Logger.LogError("Error");
}
}

protected override async Task DisposeAsync(bool disposing)
{
await base.DisposeAsync(disposing);
if (logTask is not null)
{
cts.Cancel();
await logTask;
}
}

private Task SetLevel(LogEventLevel level)
{
SerilogDynamicConfigurationProvider.Instance.SetLevel(level);
var root = (IConfigurationRoot)GetRequiredService<IConfiguration>();
debugView = root.GetDebugView();
return Task.CompletedTask;
}

private Task ResetLevel()
{
SerilogDynamicConfigurationProvider.Instance.ResetLevel();
var root = (IConfigurationRoot)GetRequiredService<IConfiguration>();
debugView = root.GetDebugView();
return Task.CompletedTask;
}
}
72 changes: 67 additions & 5 deletions apps/Sitko.Core.Apps.MudBlazorDemo/Pages/Logging.razor
Original file line number Diff line number Diff line change
@@ -1,10 +1,72 @@
@page "/Logging"
@using Thinktecture.Extensions.Configuration
@using Serilog.Events
@using Microsoft.Extensions.Logging
@using System.Threading
@using Microsoft.Extensions.Configuration
@using Sitko.Core.App.Logging
@inherits BaseComponent
@inject ISerilogConfiguration LoggingConfiguration
<MudPageLayout Title="Logging">
<MudButton Variant="Variant.Filled" Color="Color.Error" OnClick="@(() => LoggingConfiguration.SetLevel(LogEventLevel.Debug))">Set debug</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Info" OnClick="@(() => LoggingConfiguration.SetLevel(LogEventLevel.Information))">Set info</MudButton>
<MudButton Color="Color.Secondary" Variant="Variant.Outlined" OnClick="@(() => LoggingConfiguration.ResetLevel())">Reset</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Secondary" OnClick="@(() => SetLevel(LogEventLevel.Debug))">Set debug</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Info" OnClick="@(() => SetLevel(LogEventLevel.Information))">Set info</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Warning" OnClick="@(() => SetLevel(LogEventLevel.Warning))">Set warning</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Error" OnClick="@(() => SetLevel(LogEventLevel.Error))">Set error</MudButton>
<MudButton Color="Color.Secondary" Variant="Variant.Outlined" OnClick="@(() => ResetLevel())">Reset</MudButton>

@if (!string.IsNullOrEmpty(debugView))
{
<pre>
@debugView
</pre>
}
</MudPageLayout>

@code
{
private Task? logTask;
private readonly CancellationTokenSource cts = new();
private string? debugView;

protected override void Initialize()
{
base.Initialize();
logTask = StartLoggingAsync();
}

private async Task StartLoggingAsync()
{
while (!cts.IsCancellationRequested)
{
await Task.Delay(5000);
Logger.LogDebug("Debug");
Logger.LogInformation("Info");
Logger.LogWarning("Warning");
Logger.LogError("Error");
}
}

protected override async Task DisposeAsync(bool disposing)
{
await base.DisposeAsync(disposing);
if (logTask is not null)
{
cts.Cancel();
await logTask;
}
}

private Task SetLevel(LogEventLevel level)
{
SerilogDynamicConfigurationProvider.Instance.SetLevel(level);
var root = (IConfigurationRoot)GetRequiredService<IConfiguration>();
debugView = root.GetDebugView();
return Task.CompletedTask;
}

private Task ResetLevel()
{
SerilogDynamicConfigurationProvider.Instance.ResetLevel();
var root = (IConfigurationRoot)GetRequiredService<IConfiguration>();
debugView = root.GetDebugView();
return Task.CompletedTask;
}
}
1 change: 0 additions & 1 deletion src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@
<PackageVersion Include="Serilog.Sinks.Elasticsearch" Version="9.0.0"/>
<PackageVersion Include="Serilog.Sinks.Graylog" Version="2.3.0"/>
<PackageVersion Include="Serilog.Sinks.Async" Version="1.5.0"/>
<PackageVersion Include="Thinktecture.Extensions.Serilog.Configuration" Version="2.0.0"/>
<PackageVersion Include="NewRelic.LogEnrichers.Serilog" Version="1.1.0"/>
<PackageVersion Include="Serilog.Sinks.NewRelic.Logs" Version="1.2.0"/>
</ItemGroup>
Expand Down
4 changes: 3 additions & 1 deletion src/Sitko.Core.App/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Serilog;
using Serilog.Events;
using Sitko.Core.App.Localization;
using Sitko.Core.App.Logging;
using Sitko.FluentValidation;
using Tempus;

Expand Down Expand Up @@ -119,6 +120,8 @@ protected void ConfigureConfiguration(IApplicationContext appContext, IConfigura
{
moduleRegistration.ConfigureAppConfiguration(appContext, builder);
}

builder.Add(new SerilogDynamicConfigurationSource());
}

protected virtual LoggerConfiguration ConfigureLogging(IApplicationContext applicationContext,
Expand Down Expand Up @@ -450,4 +453,3 @@ public Application AddModule<TModule, TModuleOptions>(
configureOptions?.Invoke(moduleOptions);
}, optionsKey);
}

15 changes: 6 additions & 9 deletions src/Sitko.Core.App/HostedApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using Serilog.Extensions.Logging;
using Sitko.Core.App.Helpers;
using Sitko.Core.App.Logging;
using Thinktecture.Extensions.Configuration;

namespace Sitko.Core.App;

Expand Down Expand Up @@ -101,7 +100,6 @@ protected IHostBuilder ConfigureHostBuilder(Action<IHostBuilder>? configure = nu
InitApplication();

LogInternal("Create main host builder");
var serilogConfiguration = new SerilogConfiguration();
var hostBuilder = CreateHostBuilder(Args)
.UseDefaultServiceProvider(options =>
{
Expand All @@ -127,27 +125,27 @@ protected IHostBuilder ConfigureHostBuilder(Action<IHostBuilder>? configure = nu
hostBuilder.ConfigureAppConfiguration((_, builder) =>
{
ConfigureConfiguration(bootApplicationContext, builder);
LoggingExtensions.ConfigureSerilogConfiguration(builder, serilogConfiguration);
})
.ConfigureServices((_, services) =>
{
RegisterApplicationServices<HostedApplicationContext>(bootApplicationContext, services);
services.AddHostedService<ApplicationLifetimeService>();
}).ConfigureLogging((_, builder) =>
}).ConfigureLogging((builderContext, builder) =>
{
LogInternal("Configure logging");
LoggingExtensions.ConfigureSerilog(bootApplicationContext, builder, serilogConfiguration,
var runtimeContext = GetContext(builderContext.HostingEnvironment, builderContext.Configuration);
LoggingExtensions.ConfigureSerilog(runtimeContext, builder,
configuration =>
{
configuration = configuration.Enrich.WithMachineName();
if (bootApplicationContext.Options.EnableConsoleLogging == true)
if (runtimeContext.Options.EnableConsoleLogging == true)
{
configuration = configuration.WriteTo.Console(
outputTemplate: bootApplicationContext.Options.ConsoleLogFormat,
outputTemplate: runtimeContext.Options.ConsoleLogFormat,
formatProvider: CultureInfo.InvariantCulture);
}

return ConfigureLogging(bootApplicationContext, configuration);
return ConfigureLogging(runtimeContext, configuration);
});
});
configure?.Invoke(hostBuilder);
Expand Down Expand Up @@ -253,4 +251,3 @@ public HostedApplicationContext(Application application, IConfiguration configur
protected override void ConfigureApplicationOptions(ApplicationOptions options) =>
options.EnableConsoleLogging ??= environment.IsDevelopment();
}

19 changes: 2 additions & 17 deletions src/Sitko.Core.App/Logging/LoggingExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,23 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using Serilog;
using Thinktecture;
using Thinktecture.Extensions.Configuration;

namespace Sitko.Core.App.Logging;

public class LoggingExtensions
{
public static void ConfigureSerilogConfiguration(IConfigurationBuilder configurationBuilder,
SerilogConfiguration serilogConfiguration) =>
configurationBuilder.AddLoggingConfiguration(serilogConfiguration, "Serilog");

public static void ConfigureSerilog(IApplicationContext appContext, ILoggingBuilder builder,
SerilogConfiguration serilogConfiguration, Func<LoggerConfiguration, LoggerConfiguration> configureLogging)
Func<LoggerConfiguration, LoggerConfiguration> configureLogging)
{
builder.Services.AddSingleton<ISerilogConfiguration>(serilogConfiguration);
builder.AddConfiguration(appContext.Configuration.GetSection("Logging"));
var loggerConfiguration = new LoggerConfiguration();
loggerConfiguration.ReadFrom.Configuration(appContext.Configuration);
loggerConfiguration
.Enrich.FromLogContext()
.Enrich.WithProperty("App", appContext.Name)
.Enrich.WithProperty("AppVersion", appContext.Version)
.Enrich.WithProperty("AppEnvironment", appContext.Environment);


loggerConfiguration = configureLogging(loggerConfiguration);


Log.Logger = loggerConfiguration.CreateLogger();
builder.ClearProviders();
builder.AddSerilog();
}
}

36 changes: 36 additions & 0 deletions src/Sitko.Core.App/Logging/SerilogDynamicConfigurationProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Microsoft.Extensions.Configuration;
using Serilog.Events;

namespace Sitko.Core.App.Logging;

public class SerilogDynamicConfigurationProvider : ConfigurationProvider
{
private const string DefaultCategory = "Default";
public static readonly SerilogDynamicConfigurationProvider Instance = new();

public void SetLevel(LogEventLevel level, string? category = null)
{
category ??= DefaultCategory;
Set(GetKey(category), level.ToString());
OnReload();
}

private static string GetKey(string category)
{
var key = "Serilog:MinimumLevel:";
if (category != DefaultCategory)
{
key += "Override:";
}

key += category;
return key;
}

public void ResetLevel(string? category = null)
{
category ??= DefaultCategory;
Set(GetKey(category), null);
OnReload();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Microsoft.Extensions.Configuration;

namespace Sitko.Core.App.Logging;

public class SerilogDynamicConfigurationSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder) => SerilogDynamicConfigurationProvider.Instance;
}
1 change: 0 additions & 1 deletion src/Sitko.Core.App/Sitko.Core.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
<PackageReference Include="Sitko.FluentValidation" />
<PackageReference Include="Tempus" />
<PackageReference Include="Scrutor" />
<PackageReference Include="Thinktecture.Extensions.Serilog.Configuration" />
<PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" />
Expand Down
6 changes: 1 addition & 5 deletions src/Sitko.Core.Blazor.Wasm/WasmApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Sitko.Core.App.Logging;
using Sitko.Core.Blazor.Components;
using Sitko.Core.Blazor.Forms;
using Thinktecture.Extensions.Configuration;

namespace Sitko.Core.Blazor.Wasm;

Expand Down Expand Up @@ -76,9 +75,7 @@ private WebAssemblyHostBuilder ConfigureHostBuilder(Action<WebAssemblyHostBuilde
});
// Logging
LogInternal("Configure logging");
var serilogConfiguration = new SerilogConfiguration();
LoggingExtensions.ConfigureSerilogConfiguration(hostBuilder.Configuration, serilogConfiguration);
LoggingExtensions.ConfigureSerilog(applicationContext, hostBuilder.Logging, serilogConfiguration,
LoggingExtensions.ConfigureSerilog(applicationContext, hostBuilder.Logging,
configuration =>
{
configuration = configuration.WriteTo.BrowserConsole(
Expand Down Expand Up @@ -150,4 +147,3 @@ protected override IApplicationContext GetContext(IServiceProvider serviceProvid
serviceProvider.GetRequiredService<IWebAssemblyHostEnvironment>(),
serviceProvider.GetRequiredService<IConfiguration>());
}

0 comments on commit 0db6be5

Please sign in to comment.