Custom ASP.NET Core Logger using Serilog - c#

In my project I use Serilog and ASP.Net Core. The initialization part looks like that:
var provider = services.BuildServiceProvider();
var logFactory = provider.GetRequiredService<ILoggerFactory>();
logFactory.AddSerilog().AddConsole();
return provider;
This will add Serilog to the logging pipeline.
I want to add to the logger an ability to say whether there was logs with type 'Warning' or not in order to make some result message. For example it could be a method that returns simple bool saying about that.
How should I do it in a correct way? Can I somehow override current Core behavior by changing the way the logger handles 'Warning' logs in order to save somewhere the fact that LogWarning method has been called? Or should I implement my own logger (ILogger) as well as ILoggerFactory and ILoggerProvider with needed functionality? But then how can I save Serilog part in that scenario?

Related

Logging Mass Transit with Serilog

I have this console application project where I use EF6 with postgresql, Quartz and Mass Transit and as DI I use Castle Winsdor. The goal of the project is to check periodically a folder (or folders) for new files and process them (mostly by storing data in the DataBase).
I wanted to use a logging service for debug purposes and I came across Serilog. I managed to add it to Quartz and EF, but I have issues adding it to Mass Transit.
What I've done so far:
I've added Serilog as Logging for Castle.Core.Logging
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Auto(Classes.FromThisAssembly());
var factory = container.Resolve<ILoggerFactory>();
container.AddFacility<LoggingFacility>(f => f.LogUsing(factory as SerilogFactory));
}
And then I added it to EF using a Logger Interceptor and to Quartz using Serilog settings.
But now I want to add it to my MassTransit Automatonymous, but I'm having trouble figuring it out.
First of all, I tried to add Serilog from the BusControl Configuration:
BusControl = Bus.Factory.CreateUsingInMemory(cfg =>
{
cfg.UseSerilog(Log.Logger); //Where `Log.Logger` is the Serilog Logger
});
But then I encountered a MassTransit.Logging.ILogger exception that was also discussed here.
In that thread I found that I should add Serilog (or any other logger) in a different way, by configuring the MassTransit LogContext like so
LogContext.ConfigureCurrentLogContext(loggerFactory);. But the thing is, they are now using
Microsoft.Extensions.Logging.Abstractions and I cannot convert my logger from Castle.Core.Logging.ILogger to Microsoft.Extensions.Logging.ILogger.
Is there any way to use my Castle.Core.Logging logger?
You need to use the Serilog.Extensions.Logging NuGet package, which adds ILoggerFactory support to Serilog. You can pass that interface to configure MassTransit via:
LogContext.ConfigureCurrentLogContext(loggerFactory);
MassTransit does not use any Castle facilities, however, there is a NuGet package for configuring MassTransit using ]Castle Windsor](https://masstransit-project.com/usage/containers/castlewindsor.html).
Update: You can view a sample Serilog configuration in this sample

How to add logging to Blazor Server-side component?

I am trying to create a hosted ASP.net Blazor application and trying to get a logger into my controller.
I have this:
public MyController(ILogger logger) {
_logger = logger;
// more initialization
}
But when I run it, I get:
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'MyApp.Server.Controllers.MyController'.
As there are a lot of log messages scrolling by, I guess Blazor already initializes a logger.
How do I access this?
The non-generic ILogger is not registered with the service collection. Instead, you are supposed to inject a generic ILogger<T>. The generic type argument T is used to set up the category name that is linked with the logger instance. It allows you to easily see where a log call came from.
Usually, you specify the type that you are using the logger with as the generic type argument. So in your case, you would use ILogger<MyController>:
public MyController(ILogger<MyController> logger)
{
_logger = logger;
}
Note that there is nothing special to server-side Blazor about this behavior. This is standard ASP.NET Core and the controller is also a normal ASP.NET Core controller.

How can I use ILogger<T> from an Azure Functions V2 function?

I have some services that were initially designed to be called from my ASP.NET Core 2.1 web application. They have dependencies injected to their constructors using Microsoft.Extensions.DependencyInjection package stuff. Some of them have a dependency of ILogger logger.
public GroupService(ILogger<GroupService> logger)
{
...
}
I am building a service provider within the function so that they can still work as expected however I'm wondering what I should do about the logger dependencies. An Azure Function (V2) gets an ILogger injected into it by default but that can't be used in the DI container to create the additional loggers that the services require.
Is there a LoggerFactory registered somewhere "under the covers" that I can get access to to be used in my DI container? I think that would allow me to add additional loggers that log to the functions output window or am I completely misunderstanding how logging in a function would work?
Do I just need to set up a new LoggerFactory and make that log to the ApplicationInsights instance used by the functions project?
Using the most recent Azure Function runtime, you can now have the runtime inject your dependencies through constructors.
You can now remove the static keywords from your Azure Function and have the runtime.
Here is how you can set this up:
[assembly: WebJobsStartup(typeof(StartUp))]
public class StartUp : IWebJobsStartup
{
public void Configure(IWebJobsBuilder webJobsBuilder)
{
// Enables logging and sets the minimum level of logs.
webJobsBuilder.Services.AddLogging(loggingBuilder =>
{
loggingBuilder.SetMinimumLevel(LogLevel.Debug);
});
// Registers your services.
webJobsBuilder.Services.AddTransient<IGroupService, GroupService>();
}
}

How to filter out logging in Serilog with .NET Core?

I want to information to the log in my web app. Seems like it would fall under the Information category. The problem is that if I set the default logging level to Information, the .NET Core itself will write stuff to the log file that I don't want there.
I have the following:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Is(logLevel)
.WriteTo.RollingFile(Path.Combine(env.ContentRootPath, "{Date}.txt"))
.CreateLogger();
Is it possible to create a logger where I only write my own events to. This applies to any .net core compatible logging frameworks out there.
Or do I need to roll my own custom class for this?

NLog inject context information c#

I'm using ASP.NET WebApi and NLog.
I want to add per-request information like a correlationId to my log messages. In the best case, the user of NLog shouldn't know anything about this. The Logger itself should be able to get the information from the http request.
With Unity i can use the "PerRequestLifetimeManager" to inject those information, but it isn't recommenden. I should rather use HttpContext.Items, but i'm not happy with System.Web and HttpContext.
Is there a possibility to set the information on the server and get them in my logger every time i want to log something, based on the request scope?
NLog has the NLog.MappedDiagnosticContext that you can use to create session type of logging variables. In ASP.Net and WebAPI, using async contexts, you might need to use NLog.MappedDiagnosticsLogicalContext
You'll also need to update the Targets' layouts to include this information:
<target layout="${longdate}|${level:uppercase=true}|${logger}|[${mdc:item=SomeVariable}]${message}" >
Here's how you'd use it:
try
{
NLog.MappedDiagnosticsLogicalContext.Set("SomeVariable", Guid.NewGuid().ToString());
//do your work
Log.Info("Some message here.");
//do more work
Log.Info("Finished!");
}
finally
{
NLog.MappedDiagnosticsLogicalContext.Remove("SomeVariable");
}
Of note, I'd like to see a better way to do this utilizing the C# using statement, like log4net supported.

Categories