How to log exception to appinsights using serilog? - asp.net-core

Net core application. I am trying to log exceptions but this is not working as expected. Below is my configuration
Program.cs
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((hostContext, loggerConfiguration) =>
{
loggerConfiguration.ReadFrom.Configuration(hostContext.Configuration);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry(Configuration["APPINSIGHTS_CONNECTIONSTRING"]);
services.AddApplicationInsightsTelemetry();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<ExceptionMiddleware>();
app.UseSerilogRequestLogging();
}
}
ExceptionMiddleware.cs
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
//private readonly ILogger _logger;
private readonly ILogger _logger = Serilog.Log.ForContext<ExceptionMiddleware>();
public ExceptionMiddleware(RequestDelegate next, ILogger logger)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
// _logger.Error($"Something went wrong: {ex}");
_logger.Error(ex.Message, $"Something went wrong:");
await HandleExceptionAsync(httpContext, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var user = string.Empty;
if (context.User.Claims.Any())
user = context.User.Claims?.FirstOrDefault(cl => cl.Type.Contains("preferred_username"))?.Value ?? "Anonymous User";
context.Response.ContentType = "application/json";
context.Response.StatusCode = ConfigurateExceptionTypes(exception);
await context.Response.WriteAsync(new Models.ErrorDetails()
{
UserName = user,
StatusCode = context.Response.StatusCode,
Message = exception.Message
}.ToString());
}
private static int ConfigurateExceptionTypes(Exception exception)
{
int httpStatusCode;
switch (exception)
{
case var _ when exception is ValidationException:
httpStatusCode = (int)HttpStatusCode.BadRequest;
break;
default:
httpStatusCode = (int)HttpStatusCode.InternalServerError;
break;
}
return httpStatusCode;
}
}
AppSettings.json
"Serilog": {
"Using": [],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "ApplicationInsights",
"Args": {
"instrumentationKey": "",
"restrictedToMinimumLevel": "Information",
"telemetryConverter": "Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights"
}
}
],
"Enrich": [
"FromLogContext",
"WithMachineName",
"WithProcessId",
"WithThreadId"
]
}
This is not logging exceptions as expected. I can see status code 500 in app insights but I want to see exception message logged as well. Can someone help me to understand what could be I am missing here. Any help would be appreciated. Thanks

Try adding this values in your appsettings.json:
"Serilog":
{
"Using":
["Serilog",
"Serilog.Sinks.ApplicationInsights",
"Serilog.Sinks.Console"],
...
}

Just try to configure Logger in Startup.cs
var log = new LoggerConfiguration()
.WriteTo
.ApplicationInsights(serviceProvider.GetRequiredService<TelemetryConfiguration>(), TelemetryConverter.Traces)
.CreateLogger();
Whether you choose Events or Traces, if the LogEvent contains any exceptions it will always be sent as ExceptionTelemetry.
In Application Insights you can configure whether the exceptions appear as Exceptions vs Traces
See here

Related

SignalR: Websocket closed with error: InternalServerError

On the front side when the user adds a new mp3. In addition to writing this to the database, I also need to transfer that mp3 to the client side. But my client side is Worker Service. I need to transfer this mp3 to that Worker Service via SignalR.
My SignalR server project codes :
Startup hub endpoint :
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}");
endpoints.MapHub<TrackHub>("/hubs/track");
});
Hub :
public class TrackHub : Hub
{
public static Dictionary<int, string> ActiveUsers = new Dictionary<int, string>();
public TrackHub()
{
}
public async Task SendMessage(string message)
{
var connectionId = Context.ConnectionId;
await Clients.Others.SendAsync("ReceiveMessage", message + connectionId);
}
public override async Task OnConnectedAsync()
{
await Clients.All.SendAsync("ActiveUsers");
}
public override async Task OnDisconnectedAsync(Exception exception)
{
await Clients.All.SendAsync("ActiveUsers");
}
}
HubContext
public class TrackBusiness
{
private readonly IHubContext<TrackHub> _hubContext;
public TrackBusiness(IHubContext<TrackHub> hubContext)
{
_hubContext = hubContext;
}
public Task SendMessage()
{
return _hubContext.Clients.All.SendAsync("Receive");
}
}
And my client side - worker service project :
public class SocketService : ISocketService
{
private HubConnection? _connection;
private readonly IConfiguration _configuration;
private readonly ILogger<SocketService> _logger;
public event OnNewTrackAddedEventHandler NewTrackAdded;
public event OnDeviceDeletedEventHandler DeviceDeleted;
public SocketService(IConfiguration configuration, ILogger<SocketService> logger)
{
_configuration = configuration;
_logger = logger;
}
public async Task Start()
{
_connection = new HubConnectionBuilder()
.WithUrl(_configuration.GetValue<string>("SocketUrl"))
.WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.Zero, TimeSpan.FromSeconds(10) })
.Build();
_connection.Reconnected += connectionId =>
{
if (_connection.State == HubConnectionState.Connected)
{
_logger.LogInformation("Socket reconnected");
}
if (_connection.State == HubConnectionState.Reconnecting)
{
_logger.LogInformation("Socket try to reconnect");
}
return Task.CompletedTask;
};
_connection.On<string, byte[]>("SendMessage", (imei, track) =>
{
NewTrackAdded.Invoke(imei, track);
});
_connection.On<string>("DeviceDeleted", (imei) =>
{
DeviceDeleted.Invoke(imei);
});
try
{
await _connection.StartAsync();
_logger.LogInformation("Socket started");
}
catch (Exception e)
{
_logger.LogWarning("Socket can't connect : {0}", e.Message);
}
}
}
My appSettings :
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ApiUrl": "localhost",
"SocketUrl": "http://localhost:29082/hubs/track"
}
But I run into this error when I start the project. Can you help with the problem?

Value cannot be null - In-Memory Database .Net

I am trying to use a In-Memory Database, but I get this message:
System.ArgumentNullException: 'Value cannot be null. (Parameter
'source')'
I read a lot some similar question related with this issue, but every article is related with the connection String, and I think I must not use a ConnectionString because is a In-Memory Database. What Do I do wrong? I leave my code:
DbInitializer.cs - In this class appears the error
public static class DbInitializer
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var _context = new AppDBContext(serviceProvider.GetRequiredService<DbContextOptions<AppDBContext>>()))
{
if (_context.AgentsRole.Any()) //In this line appears the error
return;
_context.AgentsRole.AddRange(
new Agent { Id = 1, Role_Name = "David Lopez", Is_Active = true, Role_Description = "This is a test for David Lopez" },
new Agent { Id = 2, Role_Name = "James Norris", Is_Active = false, Role_Description = "This is a test for James Norris" },
new Agent { Id = 3, Role_Name = "Jhon Norris", Is_Active = true, Role_Description = "This is a test for Jhon Norris" },
new Agent { Id = 4, Role_Name = "James Norr", Is_Active = true, Role_Description = "This is a test for James Norr" }
);
_context.SaveChanges();
}
}
}
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDBContext>(options=> options.UseInMemoryDatabase(databaseName: "InMemory_DB"));
services.AddControllers();
services.AddSwaggerGen();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My Test1 Api v1");
});
}
}
Program.cs:
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<AppDBContext>();
DbInitializer.Initialize(services);
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Controller.cs:
[ApiController]
[Route("api/[controller]")]
public class AgentRoleController : ControllerBase
{
private readonly ILogger<AgentRoleController> _logger;
private readonly AppDBContext _context;
public AgentRoleController(ILogger<AgentRoleController> logger, AppDBContext context)
{
_logger = logger;
_context = context;
}
[HttpGet]
[SwaggerOperation("GetAgentsRole")]
[SwaggerResponse((int)HttpStatusCode.OK)]
[SwaggerResponse((int)HttpStatusCode.NotFound)]
public IEnumerable<Agent> Get()
{
return _context.AgentsRole;
}
}
AppDBContext.cs:
public class AppDBContext : DbContext
{
public AppDBContext(DbContextOptions<AppDBContext> options)
:base(options)
{
}
public DbSet<Agent> AgentsRole;
}
The solution is in AppDBContext.cs, I missed the initialization of AgentsRole, the solution is:
public class AppDBContext : DbContext
{
public AppDBContext(DbContextOptions<AppDBContext> options)
:base(options)
{
}
public DbSet<Agent> AgentsRole { get; set; } // I added this Part!
}

Certificate Authentication events not triggered in ASP .NET Core 3.1 API

I want to implement certificate authentication on my .NET Core 3.1 API. I followed the steps outlined by Microsoft here:https://learn.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-5.0
But, I don't think the events "OnCertificateValidated" and "OnAuthenticationFailed" even fire. Breakpoints are never hit, and I even tried adding code that should break in there just to test, but it never fails (most likely because it never reaches there)
I'm trying to validate the Client Certificate CN and I want to only allow certain CNs to be able to call my API.
You can find my code below. What am I doing wrong?
Startup
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.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService =
context.HttpContext.RequestServices.GetRequiredService<ICertificateValidationService>();
if (validationService.ValidateCertificate(context.ClientCertificate))
{
context.Success();
}
else
{
context.Fail($"Unrecognized client certificate: {context.ClientCertificate.GetNameInfo(X509NameType.SimpleName, false)}");
}
int test = Convert.ToInt32("test");
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
int test = Convert.ToInt32("test");
context.Fail($"Invalid certificate");
return Task.CompletedTask;
}
};
});
services.AddHealthChecks();
services.AddControllers(setupAction =>
{
setupAction.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status406NotAcceptable));
setupAction.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status500InternalServerError));
setupAction.ReturnHttpNotAcceptable = true;
}).AddXmlDataContractSerializerFormatters();
services.AddScoped<IJobServiceRepository, JobServiceRepository>();
services.AddScoped<ICaptureServiceRepository, CaptureServiceRepository>();
services.Configure<KTAEndpointConfig>(Configuration.GetSection("KTAEndpointConfig"));
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddVersionedApiExplorer(setupAction =>
{
setupAction.GroupNameFormat = "'v'VV";
});
services.AddApiVersioning(setupAction =>
{
setupAction.AssumeDefaultVersionWhenUnspecified = true;
setupAction.DefaultApiVersion = new ApiVersion(1, 0);
setupAction.ReportApiVersions = true;
});
var apiVersionDecriptionProvider = services.BuildServiceProvider().GetService<IApiVersionDescriptionProvider>();
services.AddSwaggerGen(setupAction =>
{
foreach (var description in apiVersionDecriptionProvider.ApiVersionDescriptions)
{
setupAction.SwaggerDoc($"TotalAgilityOpenAPISpecification{description.GroupName}", new Microsoft.OpenApi.Models.OpenApiInfo()
{
Title = "TotalAgility API",
Version = description.ApiVersion.ToString(),
Description = "Kofax TotalAgility wrapper API to allow creating KTA jobs and uploading documents",
Contact = new Microsoft.OpenApi.Models.OpenApiContact()
{
Email = "shivam.sharma#rbc.com",
Name = "Shivam Sharma"
}
});
setupAction.OperationFilter<AddRequiredHeaderParameter>();
var xmlCommentsFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlCommentsFullPath = Path.Combine(AppContext.BaseDirectory, xmlCommentsFile);
setupAction.IncludeXmlComments(xmlCommentsFullPath);
}
setupAction.DocInclusionPredicate((documentName, apiDescription) =>
{
var actionApiVersionModel = apiDescription.ActionDescriptor
.GetApiVersionModel(ApiVersionMapping.Explicit | ApiVersionMapping.Implicit);
if (actionApiVersionModel == null)
{
return true;
}
if (actionApiVersionModel.DeclaredApiVersions.Any())
{
return actionApiVersionModel.DeclaredApiVersions.Any(v =>
$"TotalAgilityOpenAPISpecificationv{v.ToString()}" == documentName);
}
return actionApiVersionModel.ImplementedApiVersions.Any(v =>
$"TotalAgilityOpenAPISpecificationv{v.ToString()}" == documentName);
});
});
services.AddHttpsRedirection((httpsOpts) =>
{
//httpsOpts.HttpsPort = 443;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider apiVersionDescriptionProvider)
{
app.UseApiExceptionHandler();
app.UseHeaderLogContextMiddleware();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSwagger(setupAction =>
{
setupAction.SerializeAsV2 = true;
});
app.UseSwaggerUI(setupAction =>
{
foreach (var decription in apiVersionDescriptionProvider.ApiVersionDescriptions)
{
setupAction.SwaggerEndpoint($"/swagger/TotalAgilityOpenAPISpecification{decription.GroupName}/swagger.json",
decription.GroupName.ToUpperInvariant());
}
//setupAction.SwaggerEndpoint("/swagger/TotalAgilityOpenAPISpecification/swagger.json",
//"TotalAgility API");
setupAction.RoutePrefix = "";
});
app.UseSerilogRequestLogging();
app.UseHeaderValidation();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireAuthorization();
endpoints.MapHealthChecks("/health");
});
}
}
CertificateValidationService
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
namespace TotalAgility_API.Services
{
public class CertificateValidationService : ICertificateValidationService
{
private readonly IConfiguration _configuration;
private readonly ILogger<CertificateValidationService> _logger;
public CertificateValidationService(IConfiguration configuration, ILogger<CertificateValidationService> logger)
{
_logger = logger;
_configuration = configuration;
}
public bool ValidateCertificate(X509Certificate2 clientCert)
{
List<string> allowedCNs = new List<string>();
_configuration.GetSection("AllowedClientCertCNList").Bind(allowedCNs);
string cn = clientCert.GetNameInfo(X509NameType.SimpleName, false);
if (allowedCNs.Contains(cn))
{
return true;
}
else
{
_logger.LogWarning("Invalid Cert CN: {CN}", cn);
return false;
}
}
}
}
appsettings.json
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
}
},
"AllowedHosts": "*",
"AllowedClientCertCNList": [
"1",
"2",
"3",
"4"
]
}
Any help would be appreciated here. I'm new to this and I'm don't know how to proceed.
I had a similar issue on IIS Express where only "OnChallenge" fired but not "OnCertificateValidated" or "OnAuthenticationFailed", and kept getting 403 status responses.
This answer from a different question solved it for my case (IIS Express). Set the access sslFlags in .vs\config\applicationhost.config to use client certificate:
<access sslFlags="Ssl, SslNegotiateCert, SslRequireCert" />

Quartz - .NET Core - Null Reference Exception

I'm trying to implement the Quartz for .NET Core.
At the moment I have the following:
public class Startup
{
**private IScheduler _scheduler { get; set; }//quartz**
public Startup(IConfiguration configuration)
{
Configuration = configuration;
**_scheduler = ConfigureQuartz();//quartz**
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<Context>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("notebook14"));
});
...
...
...
**#region for Quartz DI
services.AddScoped<Job>();
services.AddSingleton(provider => _scheduler);
#endregion**
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
});
}
**#region for Quartz
private IScheduler ConfigureQuartz()
{
NameValueCollection properties = new NameValueCollection()
{
{"quartz.serializer.type","binary"}
};
StdSchedulerFactory factory = new StdSchedulerFactory(properties);
_scheduler = factory.GetScheduler().Result;
_scheduler.Start();
return _scheduler;
}
#endregion**
...and Program.cs because I would like to start a schedule at first deploy and then run the task every day:
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
UserManager<AppUser> userManager = services.GetRequiredService<UserManager<AppUser>>();
RoleManager<AppRole> roleManager = services.GetRequiredService<RoleManager<AppRole>>();
**IScheduler scheduler = services.GetRequiredService<IScheduler>();
Start.StartSchedule(scheduler);**
Init.AssignAdmin(userManager, roleManager).Wait();
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
...and Start.cs, where I have created the job and the trigger :
public class Start
{
public static Context _context { get; set; }
public Start(Context context)
{
_context = context;
}
public async static void StartSchedule(IScheduler _scheduler)
{
IJobDetail job = JobBuilder.Create<Job>().WithIdentity("Generate", "FreeSlots").Build();
ITrigger trigger = TriggerBuilder.Create().WithIdentity("Trigger", "FreeSlots").StartNow()
.WithDailyTimeIntervalSchedule(t=>t.StartingDailyAt(new TimeOfDay(10,59)))
.Build();
await _scheduler.ScheduleJob(job, trigger);
}
}
...and finally, the Job itself:
public class Job : IJob
{
public Task Execute(IJobExecutionContext context)
{
try
{
Console.WriteLine("TRIGGERED!");
List<AppUser> doctors = Start._context.Users.Where(x => x.Type == AppUser.UserType.Doctor).ToList();
DateTime First = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 8, 0, 0);
List<Appointments> appointments = new List<Appointments>()
{
new Appointments(){Date=First, Time=First,Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(1),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(2),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(3),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(4),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(5),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(6),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(7),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(8),Status=Appointments.SlotStatus.Free},
};
foreach (AppUser doc in doctors)
{
foreach (Appointments slot in appointments)
{
slot.DoctorId = doc.Id;
Start._context.Appointments.Add(slot);
Start._context.SaveChanges();
var message = "Slot for " + slot.DoctorId.ToString() + " " + slot.Time + " " + slot.Status;
Console.WriteLine(message);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return Task.CompletedTask;
}
}
The problem is that I get a null reference exception when the Job is executed:
Does anybody have any ideas? Is there a way to make this work? Thank you in advance!

Add client ip to graylog output with Gelf.Extensions.Logging package

I am using the Gelf.Extensions.Logging package to send log info to graylog from an asp.net core 3 website, and I would like additional fields like current user name, client ip, user agent.
In startup.cs, I have the following, but I don't know how to add the data to AdditionalFields that I want - I'm not even sure that this would be the right place, as I can't see how to inject the http context at this early stage.
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>()
.ConfigureLogging((context, builder) => builder.AddGelf(options =>
{
options.AdditionalFields["machine_name"] = Environment.MachineName;
options.AdditionalFields["environment_name"] = context.HostingEnvironment.EnvironmentName;
options.AdditionalFields["app_version"] = Assembly.GetEntryAssembly()?.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
}));
});
My appsettings.json is like so:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
"System": "Warning"
},
"GELF": {
"Host": "graylog",
"Port": 12202,
"Protocol": "HTTP",
"LogSource": "DataEntry",
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
"System": "Warning"
}
}
},
"AllowedHosts": "*",
/* snip */
}
It turns out the recommended approach here it to use a middleware like this example to add information about the current request as fields:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
// Register the middleware like so:
app.UseAppEnvironmentInfo();
}
}
public static class RequestAppEnvironmentInfoMiddlewareExtensions
{
public static IApplicationBuilder UseAppEnvironmentInfo(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<AppEnvironmentInfoMiddleware>();
}
}
public class AppEnvironmentInfoMiddleware
{
private readonly RequestDelegate _next;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<AppEnvironmentInfoMiddleware> _logger;
public AppEnvironmentInfoMiddleware(RequestDelegate next,
IHttpContextAccessor httpContextAccessor, ILogger<AppEnvironmentInfoMiddleware> logger)
{
_next = next;
_httpContextAccessor = httpContextAccessor;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
using (_logger.BeginScope(("machine_name", Environment.MachineName)))
using (_logger.BeginScope(("environment_name", context.HostingEnvironment.EnvironmentName)))
using (_logger.BeginScope(("app_version", Assembly.GetEntryAssembly()?.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion)))
{
await _next.Invoke(context);
}
}
}