I have a central Project which generates all the Loggers for the subprojects. (And does a lot of other stuff which is not nessesary for my problem)
One of the Subprojects is an ASP.NET Web API. Now I want to add the Logger which is generated by a Logger Factory (see below) to the WebApplication. The problem is that the current version of WebApplication doesn't accept ILoggers...
(I use .Net 6)
The following function generates my Logger Factory:
private ILoggerFactory CreateLoggerFactory()
{
IConfiguration configSerilog = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", false, false)
.Build();
Serilog.Core.Logger serilogLogger = new LoggerConfiguration()
.ReadFrom.Configuration(configSerilog)
.Enrich.WithProperty("ComponentShortcuts", _componentShortcuts)
.CreateLogger();
ILoggerFactory loggerFactory = new LoggerFactory()
.AddSerilog(serilogLogger);
return loggerFactory;
}
The only thing I can do at the moment is to delete the default Loggers:
var builder = WebApplication.CreateBuilder();
builder.Logging.ClearProviders();
The problem is that I don't know how to add my Logger, because there is no AddLogger() function.
(I have no idea how to convert the ILogger or if there is something else that I can generate with the Logger Factory that helps me.)
I hope you can help me :)
So I faced this same issue 2 days ago with logging in .net 6 web api. And I found a solution to it that worked for me, i-e; By using LoggerConfiguration.
Although I'm still looking for a way to do it by LoggerFactory I'll post it as soon as I figure it out. Till then I hope this helps you.
Here's my code;
Program.cs
builder.Logging.ClearProviders();
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
//.MinimumLevel.Override("Microsoft", LogEventLevel.Error)
//.MinimumLevel.Override("Microsoft.AspNetCore",LogEventLevel.Error)
//.MinimumLevel.Override("Serilog", LogEventLevel.Error)
.Enrich.FromLogContext()
.Enrich.WithClientIp("CF-Connecting-IP")
.Enrich.WithClientAgent()
.CreateLogger();
Log.Logger = logger;
builder.Logging.AddSerilog(logger);
builder.Host.UseSerilog();
Then add the middleware
app.UseSerilogRequestLogging();
appsettings.json (I'm logging to Console and Sql Server also (In case you want to do it.))
"Serilog": {
"Using": [ "Serilog.Enrichers.ClientInfo", "Serilog.Sinks.MSSqlServer" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning",
"System": "Warning",
"System.Net.Http.HttpClient": "Warning"
}
},
"Enrich": [
"FromLogContext",
"WithMachineName",
"WithClientIp",
"WithClientAgent",
{
"Name": "WithClientIp",
"Args": {
"xForwardHeaderName": "CF-Connecting-IP"
}
}
],
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "",
"sinkOptionsSection": {
"tableName": "TableName",
"autoCreateSqlTable": true
},
"restrictedToMinimumLevel": "Information",
"columnOptionsSection": {
"primaryKeyColumnName": "",
"addStandardColumns": [ "LogEvent", "SourceContext" ],
"additionalColumns": [
{
"ColumnName": "ClientIPAddress",
"PropertyName": "UserIp",
"DataType": "nvarchar"
}
]
}
}
}
]
}
Feel free to let me know if you have any doubts. And don't forget to install the relevant nuget packages.
All the best!! :)
Related
I am unable to get Serilog selflog working in my .NET Core 6.0 C# Windows Service. This is how the Main looks like :
public static void Main(string[] args)
{
Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine($"Seri-serlflog : {msg}"));
Log.Logger = new LoggerConfiguration().DefaultLoggerSetup<Program>();
var serviceName = "MyService";
var configurationBuilder = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
var appSettings = configurationBuilder.Get<AppSettings>();
try
{
Log.Information("{#serviceName} microservice starting up.", serviceName);
var built = Host.CreateDefaultBuilder(args)
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration))
.ConfigureServices((hostContext, services) =>
{
services
.AddHostedService<MyApp.Cloud.MyService.BusinessLogicLayer.MyService>()
.Configure<MySettings>(configurationBuilder.GetSection("MQSettings"))
.AddAutoMapper(typeof(ConnectorToCloudTreatment))
.AddTransi...
}).Build();
Log.Information("{#serviceName} all built.", serviceName);
built.Run();
Log.Information("{#serviceName} microservice closing down.", serviceName);
}
catch (Exception ex)
{
Log.Fatal(ex, "Unhanled exception in {#serviceName}.", serviceName);
}
finally
{
Log.Information("{#serviceName} Cleaning up.", serviceName);
Log.CloseAndFlush();
Log.Information("{#serviceName} Application Exit.", serviceName);
}
}
}
The serilog part of application.json looks like this :
"serilog": {
"Using": [ "Serilog.Sinks.MSSqlServer", "Serilog.Sinks.Email" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId" ],
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss.fff} [{Level}] {SourceContext} {Message}{NewLine}{Exception}",
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
}
},
{
"Name": "File",
"Args": {
"path": "/Logs/logs.txt",
"outputTemplate": "{Timestamp:G} {SourceContext} [{Level}] {Message}{NewLine:1}{Exception:1}",
"formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
"fileSizeLimitBytes": 1000000,
"rollOnFileSizeLimit": "true",
"shared": "true",
"flushToDiskInterval": 3
}
}
]
}
I do a lot of logging in this application and it works fine but there is a couple of problems and to find why I need to use the selflog but I do not get any information at all to the output > debug?
Edit : Seems like this may have something to do with the injection. In program.cs I use the static Log but in all other classes I use injected typed loggers. But regardless I should get a couple of $"Seri-serlflog : {msg}" rows in the output?
If you're trying to get debug level logging, you'll have to loosen your log level:
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Debug",
"System": "Debug"
}
I have a small console app. I have enabled Debug and Console logging. However, they do not seem to be honouring my config for log level. Here is my setup:
Add Config file and create logger
// global to Program
private static ILogger<Program> _logger;
private const string _configFile = "appsettings.json";
//inside Main
_config = new ConfigurationBuilder()
.AddJsonFile(_configFile, optional: false, reloadOnChange: true)
//.AddEnvironmentVariables()
.AddCommandLine(args)
.Build();
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddDebug();
builder.AddSimpleConsole();
});
_logger = loggerFactory.CreateLogger<Program>();
appconfig.json
"Logging": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Debug",
"Microsoft": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Warning",
"FleetLogix.TcaProcessor": "Trace"
}
},
"SimpleConsole": {
"IncludeScopes": "false",
"SingleLine": "false",
"TimestampFormat": "yyyy-MM-dd HH:mm:ss ",
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"FleetLogix.TcaProcessor": "Information"
}
}
},
Its currently set to log to two providers, Debug (visual studio run pane) and Console. This is working. Debug is meant to log at Trace, but is only logging at Info. Console is logging at Info, but is not prefixing the timestamp onto the messages.
Is my config setup correctly? (correct property names, correct depth, etc)
What should I change it to?
Console also has the awful line break that reading tells me you need to fork Microsoft.Extensions.Logging.Console to fix, so another day. :/
I know you've moved on to Serilog, but the answer here is that you're not connecting the config up to the LoggerFactory. You need to identify the config object and also which section to load logging settings from, using the .AddConfiguration extension method from Microsoft.Extensions.Configuration:
using Microsoft.Extensions.Configuration;
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConfiguration(_config.GetSection("Logging"));
builder.AddDebug();
builder.AddSimpleConsole();
});
This question is similar:
.NET Non-host LoggerFactory configuration
I ended up switching to Serilog as I needed a file writer anyway. The only hard part was working out the differences between the older and current version, where rollingfile sink has now been integrated into file sink
Program.cs
#region Initialise Logger
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(_config)
.CreateLogger();
Log.Information("Logger started");
#endregion
appsettings.json
"Serilog": {
"Using": [
"Serilog.Sinks.Console",
"Serilog.Sinks.File"
],
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "File",
"Args": {
"path": "c:\\scripts\\log\\myprogram.log",
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
}
],
"Properties": {
"Application": "MyProgram"
}
},
I have the following appsettings.json configuration:
{
"Serilog": {
"Using": [],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": [ "FromLogContext", "WithMachineName" ],
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "C:\\Logs\\log.json",
"formatter": "Serilog.Formatting.Elasticsearch.ElasticsearchJsonFormatter, Serilog.Formatting.Elasticsearch"
}
}
]
}
}
What I am trying to configure in the above appsettings.json file would be represented in C# as something like this:
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.WriteTo.File(new ElasticsearchJsonFormatter(inlineFields:true, renderMessageTemplate: false), #"C:\logs\log.json")
.CreateLogger();
I need to set "inlineFields" equal to true and "renderMessageTemplate" equal to false as overrides in my appsettings.json file on the ElasticsearchJsonFormatter instance. Is there a way to do that in the appsettings.json file so that I can keep my configuration out of C#?
I asked this question on GitHub: https://github.com/serilog/serilog-sinks-file/issues/138
No way :(
They added this feature in Serilog.Settings.Configuration -v 3.3.0-dev-00291.
Serilog__WriteTo__Console__Name=Console
Serilog__WriteTo__Console__Args__formatter__type="Serilog.Templates.ExpressionTemplate, Serilog.Expressions"
Serilog__WriteTo__Console__Args__formatter__template="[{#t:HH:mm:ss} {#l:u3} {Coalesce(SourceContext, '<none>')}] {#m}\n{#x}"
[22:38:40 INF My.Foo.FooClient] HELLO WORLD
links
https://www.nuget.org/packages/Serilog.Settings.Configuration/3.3.0-dev-00291
https://github.com/serilog/serilog-settings-configuration/pull/281
I'm using the following code to configure Sentry with Serilog in my .Net Core Console application:
return new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Sentry(o =>
{
o.MinimumBreadcrumbLevel = LogEventLevel.Error;
o.MinimumEventLevel = LogEventLevel.Error;
o.Dsn = new Dsn(configuration.GetValue<string>("Sentry:Dsn"));
o.Debug = false;
o.AttachStacktrace = true;
o.SendDefaultPii = true;
})
.CreateLogger();
Now I would like to move all this configuration in the appsettings.json file because I need to have a different configuration in Develop environment and Production:
Example:
"Sentry": {
"Dsn": "<dsn>",
"IncludeRequestPayload": true,
"IncludeActivityData": true,
"Debug": false,
"DiagnosticsLevel": "Debug",
"MinimumBreadcrumbLevel": "Debug",
"MinimumEventLevel": "Warning"
},
Is it possible to read the whole configuration from there?
update
I try the following configuration in my Console application:
static void Main(string[] args)
{
using (SentrySdk.Init("<dsn>"))
{
// my code
}
...
serviceCollection.AddSingleton<ILogger>(s =>
{
return new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
});
appsettings:
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.Sentry" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning",
"Sentry": "Information"
}
},
"Enrich": [ "FromLogContext" ],
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "Sentry",
"Args": {
"Dsn": "<dsn>",
"MinimumBreadcrumbLevel": "Info",
"MinimumEventLevel": "Info",
"AttachStackTrace": true,
"Debug": true,
"DiagnosticsLevel": "Info"
}
}
]
But SentrySdk.Init("<dsn>") needs a DSN and it won't read it from appsettings!
Is this the way?
Serilog is unaware of the ASP.NET Core configuration. At least in a way that would bind specific sections of the configuration object to its extensions.
If you're using ASP.NET Core, I assume you're also using Sentry.AspNetCore. It's advised you do. In which case you'd need to pass configuration to it too.
NuGetTrends which is an open source project uses Serilog with ASP.NET Core while using the appsettings.json file to configure things.
Here's the Program.cs setting up Sentry, Serilog and ASP.NET Core.
Note that the configuration as you mentioned (with Sentry as a key) will be picked up by Sentry.AspNetCore but not by Sentry.Serilog (which is decoupled from ASP.NET Core).
You can configure the latter, which is a normal Serilog sink like:
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning",
"Sentry": "Information"
}
},
"WriteTo": [
{
"Name": "Sentry",
"Args": {
"MinimumBreadcrumbLevel": "Debug",
"MinimumEventLevel": "Warning"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName" ]
}
I suggest leaving the DSN and other settings as you did, on the Sentry key, which makes the ASP.NET Core initialize the SDK, it will also leverage the Serilog integration.
I am trying to set up Serilog as my logger in a multi project solution using Asp.Net Core 2.0.1, EF 2.0.1 and MVC 6.
I have set up Serilog, mostly following the guidelines from this blog post
Set up Serilog post
There is a problem with the json in that post, which I've corrected and is shown here
appsettings.json file
{
"ApplicationConfiguration": {
"ConnectionStrings": {
"DevelopmentConnection": "Server=(localdb)\\mssqllocaldb;Database=TestingConfigurationNetCoreTwo_Development;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"ApplicationInfo": {
"VersionNumber": "1.0.0",
"Author": "Jimbo",
"ApplicationName": "CustomTemplate",
"CreatedOn": "November 20, 2017"
},
"Serilog": {
"Using": [
"Serilog.Sinks.RollingFile",
"Serilog.Sinks.Async",
"Serilog.Sinks.ApplicationInsights",
"Serilog.Sinks.Console",
"Serilog.Sinks.Seq"
],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning"
}
},
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "RollingFile",
"Args": { "pathFormat": "Logs/log-{Date}.log" }
}
]
}
}
],
"Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"],
"Properties": {
"Application": "CustomTemplate"
}
}
}
}
I have the logger configuration work in the Main method of Program.cs
public static int Main(string[] args)
{
var currentEnv = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{currentEnv}.json", optional: true)
.AddEnvironmentVariables()
.Build();
//Configure logger
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
//do this for now
//TODO:figure out how to add to Serilog config in appsettings.json
.WriteTo.Seq("http://localhost:5341")
.CreateLogger();
Log.Information("Logger created");
try
{
Log.Information("Starting web host");
BuildWebHost(args).Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Web Host terminated unexpectedly");
return 1;
}
finally
{
Log.CloseAndFlush();
}
//BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
And in my Startup method
services.AddLogging(loggingBuilder =>
loggingBuilder.AddSerilog(dispose: true));
I was assuming Serilog would create the Logs folder once I ran the application, but no Log folder or logs. I added a Logs folder to both the root of the solution, and the web app project and ran it again. No logs. The blog post author suggested looking in the machines root folder. I looked both in C and OneDrive main folders (Solution Files stored on OneDrive) but there were no logs there either.
I then noticed a stack trace warning
System.IO.FileNotFoundException occurred
HResult=0x80070002
Message=The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'C:\Users\OneDrive\TestingConfigurationAspNetCore2\TestMvcApp\bin\Debug\netcoreapp2.0\appsettings.json'.
Source=
StackTrace:
at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load(Boolean reload)
at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load()
at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
I was getting this warning before, which is why I added the set bath path method in the configuration set up, because the application was failing at the code line
.AddJsonFile("appsettings.json")
which was fairly obvious because in the bin folder the file isn't called appsettings.json, its called TestMvcApp.runtimeconfig.json.
Once I added .SetBasePath, the code ran through so I put a breakpoint after the configuration setup. The configuration object contains all the settings from my appsettings.json file, so why I am getting that stack trace error? I don't know but I'll bet a dollar it is why there are no logs (no log messages appear in the console either)
Any help on why the stack trace error or why there are no log messages being written to the log file or displayed on the console would be most appreciated.
which was fairly obvious because in the bin folder the file isn't
called appsettings.json, its called TestMvcApp.runtimeconfig.json.
TestMvcApp.runtimeconfig.json is not your appsettings.json, it's a runtime configuration file as it's clear from the file name.
I bet that your appsettings.json is just not copied to the output directory during the build. To fix that select appsettings.json in Visual Studio Solution explorer, in context menu select properties and set 'Copy to Output Directory' to 'Copy always' or 'Copy if newer':
Also your json configuration has several issues:
Serilog section should not be inside ApplicationConfiguration section. It should be on the same level, i.e top-level section.
You also has suspicious WriteTo section with one sink (RollingFile) inside another (Async). Check here sample json configuration for Serilog.
In order to use all those sinks (Serilog.Sinks.RollingFile, Serilog.Sinks.Console) you should install corresponding sink NuGets: Serilog.Sinks.RollingFile, Serilog.Sinks.Console, etc.
Here is configuration file (with RollingFile sink only) that works fine for me:
{
"ApplicationConfiguration": {
"ConnectionStrings": {
"DevelopmentConnection": "Server=(localdb)\\mssqllocaldb;Database=TestingConfigurationNetCoreTwo_Development;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"ApplicationInfo": {
"VersionNumber": "1.0.0",
"Author": "Jimbo",
"ApplicationName": "CustomTemplate",
"CreatedOn": "November 20, 2017"
}
},
"Serilog": {
"Using": [
"Serilog.Sinks.RollingFile"
],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning"
}
},
"WriteTo": [
{
"Name": "RollingFile",
"Args": { "pathFormat": "c:\\log-{Date}.log" }
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"Properties": {
"Application": "CustomTemplate"
}
}
}
The accepted answer only logged some messages for my project. I'm not sure why. Ondrej Balas's approach worked better for me.
Install these Nuget packages:
Serilog
Serilog.AspNetCore
Serilog.Settings.Configuration
Serilog.Sinks.Console
Serilog.Sinks.RollingFile
Program.cs needs .UseSerilog() added:
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
})
.UseStartup<Startup>()
.UseSerilog()
.Build();
Startup.cs needs a couple of changes
one in the constructor:
public Startup(IConfiguration configuration)
{
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger();
Configuration = configuration;
}
another in Configure():
loggerFactory.AddSerilog();
if (env.IsDevelopment())
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
}
appsettings.json needs a Serilog config entry in root:
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "RollingFile",
"Args": {
"pathFormat": "logs\\log-{Date}.log",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] [{SourceContext}] {Message}{NewLine}{Exception}"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"Properties": {
"Application": "My Application"
}
}