Skip to content

Commit

Permalink
Merge pull request #63 from mattwcole/reload-options
Browse files Browse the repository at this point in the history
Auto reload options
  • Loading branch information
mattwcole committed Nov 22, 2021
2 parents 9eb5aee + ee3d9fc commit 34886a1
Show file tree
Hide file tree
Showing 18 changed files with 376 additions and 144 deletions.
7 changes: 7 additions & 0 deletions Gelf.Extensions.Logging.sln
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gelf.Extensions.Logging.Sam
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gelf.Extensions.Logging.Samples.AspNetCore2", "samples\Gelf.Extensions.Logging.Samples.AspNetCore2\Gelf.Extensions.Logging.Samples.AspNetCore2.csproj", "{C3D38DAC-25E5-4590-A47D-08A97520C4CB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gelf.Extensions.Logging.Samples.AspNetCore5", "samples\Gelf.Extensions.Logging.Samples.AspNetCore5\Gelf.Extensions.Logging.Samples.AspNetCore5.csproj", "{5F202815-647E-488A-9B2C-A746775DBF6B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -64,6 +66,10 @@ Global
{C3D38DAC-25E5-4590-A47D-08A97520C4CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3D38DAC-25E5-4590-A47D-08A97520C4CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3D38DAC-25E5-4590-A47D-08A97520C4CB}.Release|Any CPU.Build.0 = Release|Any CPU
{5F202815-647E-488A-9B2C-A746775DBF6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F202815-647E-488A-9B2C-A746775DBF6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F202815-647E-488A-9B2C-A746775DBF6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F202815-647E-488A-9B2C-A746775DBF6B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -75,6 +81,7 @@ Global
{C55B368D-E4C1-42D0-97C2-4AD2F443743B} = {7D9416E1-13A5-4A86-A3F1-2289369D7193}
{7599B625-DD65-4B68-ACF3-6E9400C0A99B} = {7D9416E1-13A5-4A86-A3F1-2289369D7193}
{C3D38DAC-25E5-4590-A47D-08A97520C4CB} = {7D9416E1-13A5-4A86-A3F1-2289369D7193}
{5F202815-647E-488A-9B2C-A746775DBF6B} = {7D9416E1-13A5-4A86-A3F1-2289369D7193}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C6D74A71-1746-4865-AAE2-77625B3E8935}
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ Logger options are taken from the "GELF" provider section in `appsettings.json`

For a full list of options e.g. UDP/HTTP(S) settings, see [`GelfLoggerOptions`](src/Gelf.Extensions.Logging/GelfLoggerOptions.cs). See the [samples](/samples) directory full examples. For more information on providers and logging in general, see the aspnetcore [logging documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging).

### Auto Reloading Config

Settings can be changed at runtime and will be applied without the need for restarting your app. In the case of invalid config (e.g. missing hostname) the change will be ignored.

### Additional Fields

By default, `logger` and `exception` fields are included on all messages (the `exception` field is only added when an exception is passed to the logger). There are a number of other ways to attach data to logs.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace Gelf.Extensions.Logging.Samples.AspNetCore5.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = {
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

private readonly ILogger<WeatherForecastController> _logger;

public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}

[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
_logger.LogInformation("Getting weather at {weather_time}", DateTime.Now);
_logger.LogDebug("A debug level log");

var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Gelf.Extensions.Logging\Gelf.Extensions.Logging.csproj" />
</ItemGroup>

</Project>
29 changes: 29 additions & 0 deletions samples/Gelf.Extensions.Logging.Samples.AspNetCore5/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace Gelf.Extensions.Logging.Samples.AspNetCore5
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => webBuilder
.UseStartup<Startup>()
.ConfigureLogging((context, loggingBuilder) => loggingBuilder
.AddGelf(options =>
{
options.LogSource = context.HostingEnvironment.ApplicationName;
options.AdditionalFields["machine_name"] = Environment.MachineName;
options.AdditionalFields["app_version"] = Assembly.GetEntryAssembly()
!.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
!.InformationalVersion;
})));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:49923",
"sslPort": 44374
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Gelf.Extensions.Logging.Samples.AspNetCore5": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
50 changes: 50 additions & 0 deletions samples/Gelf.Extensions.Logging.Samples.AspNetCore5/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;

namespace Gelf.Extensions.Logging.Samples.AspNetCore5
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1",
new OpenApiInfo {Title = "Gelf.Extensions.Logging.Samples.AspNetCore5", Version = "v1"});
});
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c =>
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Gelf.Extensions.Logging.Samples.AspNetCore5 v1"));
}

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Gelf.Extensions.Logging.Samples.AspNetCore5
{
public class WeatherForecast
{
public DateTime Date { get; set; }

public int TemperatureC { get; set; }

public int TemperatureF => 32 + (int) (TemperatureC / 0.5556);

public string Summary { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
},
"GELF": {
"Host": "localhost",
"Protocol": "HTTP",
"Port": "12202",
"AdditionalFields": {
"protocol": "http"
},
"LogLevel": {
"Gelf.Extensions.Logging.Samples.AspNetCore5.Controllers": "Debug"
}
}
},
"AllowedHosts": "*"
}
30 changes: 30 additions & 0 deletions src/Gelf.Extensions.Logging/Debouncer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Gelf.Extensions.Logging
{
internal static class Debouncer
{
public static Action<T> Debounce<T>(Action<T> action, TimeSpan delay)
{
CancellationTokenSource? cts = null;

return parameter =>
{
try
{
cts?.Cancel();
}
catch (ObjectDisposedException)
{
}
var newCts = cts = new CancellationTokenSource();
Task.Delay(delay, newCts.Token)
.ContinueWith(_ => action(parameter), newCts.Token)
.ContinueWith(_ => newCts.Dispose(), newCts.Token);
};
}
}
}
14 changes: 7 additions & 7 deletions src/Gelf.Extensions.Logging/GelfLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ public class GelfLogger : ILogger

private readonly string _name;
private readonly GelfMessageProcessor _messageProcessor;
private readonly GelfLoggerOptions _options;

public GelfLogger(string name, GelfMessageProcessor messageProcessor, GelfLoggerOptions options)
{
_name = name;
_messageProcessor = messageProcessor;
_options = options;
Options = options;
}

internal IExternalScopeProvider? ScopeProvider { get; set; }
internal GelfLoggerOptions Options { get; set; }

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
Exception? exception, Func<TState, Exception?, string> formatter)
Expand All @@ -45,7 +45,7 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
var message = new GelfMessage
{
ShortMessage = formatter(state, exception),
Host = _options.LogSource,
Host = Options.LogSource,
Logger = _name,
Exception = exception?.ToString(),
Level = GetLevel(logLevel),
Expand Down Expand Up @@ -93,7 +93,7 @@ private static double GetTimestamp()
private IEnumerable<KeyValuePair<string, object>> GetAdditionalFields<TState>(
LogLevel logLevel, EventId eventId, TState state, Exception? exception)
{
var additionalFields = _options.AdditionalFields
var additionalFields = Options.AdditionalFields
.Concat(GetFactoryAdditionalFields(logLevel, eventId, exception))
.Concat(GetScopeAdditionalFields())
.Concat(GetStateAdditionalFields(state));
Expand All @@ -111,7 +111,7 @@ private IEnumerable<KeyValuePair<string, object>> GetAdditionalFields<TState>(
Debug.Fail($"GELF message has additional field with invalid key \"{field.Key}\".");
}
}
else if (_options.IncludeMessageTemplates)
else if (Options.IncludeMessageTemplates)
{
yield return new KeyValuePair<string, object>("message_template", field.Value);
}
Expand All @@ -121,13 +121,13 @@ private IEnumerable<KeyValuePair<string, object>> GetAdditionalFields<TState>(
private IEnumerable<KeyValuePair<string, object>> GetFactoryAdditionalFields(
LogLevel logLevel, EventId eventId, Exception? exception)
{
return _options.AdditionalFieldsFactory?.Invoke(logLevel, eventId, exception) ??
return Options.AdditionalFieldsFactory?.Invoke(logLevel, eventId, exception) ??
Enumerable.Empty<KeyValuePair<string, object>>();
}

private IEnumerable<KeyValuePair<string, object>> GetScopeAdditionalFields()
{
if (!_options.IncludeScopes)
if (!Options.IncludeScopes)
{
return Enumerable.Empty<KeyValuePair<string, object>>();
}
Expand Down
2 changes: 1 addition & 1 deletion src/Gelf.Extensions.Logging/GelfLoggerOptionsSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Gelf.Extensions.Logging
{
public class GelfLoggerOptionsSetup : ConfigureFromConfigurationOptions<GelfLoggerOptions>
internal class GelfLoggerOptionsSetup : ConfigureFromConfigurationOptions<GelfLoggerOptions>
{
public GelfLoggerOptionsSetup(ILoggerProviderConfiguration<GelfLoggerProvider> providerConfiguration)
: base(providerConfiguration.Configuration)
Expand Down
Loading

0 comments on commit 34886a1

Please sign in to comment.