It is a general question.
I literally spent a whole day to figure it out without any success. Is there an example anywhere or can it be done with Sentry or we have to change our log subscription to antoher one? I tried everything based on samples I have found on the WEB. Unfortunately there is no sample code how to use Sentry with Serilog together with generic host (hosted service) while Sentry reads its configuration from appsettings.json.
Edit: I found a solution though it is not the one I preferred. I wanted to use appsettings.json configuration:
{
"Sentry": {
"Dsn": "<dsn>",
"MinimumBreadcrumbLevel": "Debug",
"MinimumEventLevel": "Debug"
},
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Verbose",
"Override": {
"Microsoft": "Information",
"System": "Warning",
"Sentry": "Information"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"formatter": {
"type": "Serilog.Templates.ExpressionTemplate, Serilog.Expressions",
"template": "[{@t:HH:mm:ss} {@l:u3}{#if SN is not null} {SN}{#end}] {@m}\n{@x}",
"theme": "Serilog.Templates.Themes.TemplateTheme::Code, Serilog.Expressions"
}
}
},
{
"Name": "File",
"Args": {
"path": "Logs\\Service.log",
"rollOnFileSizeLimit": true,
"formatter": {
"type": "Serilog.Templates.ExpressionTemplate, Serilog.Expressions",
"template": "[{@t:HH:mm:ss} {@l:u3}{#if SN is not null} {SN}{#end}] {@m}\n{@x}"
}
}
},
{
"Name": "Sentry",
"Args": {
"MinimumBreadcrumbLevel": "Debug",
"MinimumEventLevel": "Warning"
}
}
],
"Enrich": [ "FromLogContext" ]
}
}
Logging configuration:
var builder = Host.CreateDefaultBuilder(args);
builder.UseSerilog((context, services, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(context.Configuration));
builder.UseSentry();
The UseSentry() extension method used above:
public static IHostBuilder UseSentry(this IHostBuilder builder) =>
builder.ConfigureLogging((context, logging) =>
{
var section = context.Configuration.GetRequiredSection("Sentry");
logging.Services.Configure<SentryLoggingOptions>(section);
logging.AddSentry();
});
The problem is that Sentry.Serilog does not use the Sentry configuration section that is read in the extension method.
The solution for now:
Would be better to use an independent Sentry section where the common settings could be configured for different environment appsettings but I could not figure out how to do that. Also, I have to find a way to set Sentry options e.g. ServerName, and Environment dynamically on start.
There’s a sample on the repo: https://github.com/getsentry/sentry-dotnet/blob/main/samples/Sentry.Samples.Serilog/Program.cs
but you can also look at nuget trends:
https://github.com/dotnet/nuget-trends/blob/main/src/NuGetTrends.Scheduler/Program.cs
here I setup serilog before any framework code so if there’s a crash on startup it catches that too
EDIT: based on your comment, and no needing WebHost:
If you have no WebHost then no need for Sentry.AspNetCore
since that adds two middleware, for capturing errors at the root, and for continuing a trace if a trace-id came in the request header. It also automatically adds Sentry.Extensions.Logging
but you can add that directly to you app.
Here's some example adding directly to LoggerFactory
: https://github.com/getsentry/sentry-dotnet/blob/main/samples/Sentry.Samples.ME.Logging/Program.cs
If you're adding Serilog to the app, you'll need Sentry.Serilog
too (example how to add in the original message). That's because Serilog takes over the logging backend. It might work only with the Serilog package, I haven't tried that out.
You might need to read the .NET IConfiguration
stuff and pass it to code
EDIT 2: after your last question update with a solution
The problem is that Sentry.Serilog does not use the Sentry configuration section that is read in the extension method.
Sentry can't, really. Unless you manually bind that part of the config with it. But you are using two separate packages here and they have their own config sections by default.
Sentry should be initialized once, as early as possible. This becomes an issue in your case where you have to make a choice: Init via the Serilog configuration (and hence under the Serilog config section), or via the top-level Sentry config, which Sentry.Extensions.Logging
can bind with a line or two of code, and even, calling SentrySdk.Init
before any of that, making sure that if the app crashes to even read configs or anything, Sentry would let you know. The trade off is of course being less flexible in terms of reading config from json
etc but Sentry does have built-in support for some environment variables, so you could set for example SENTRY_DSN
, SENTRY_ENVIRONMENT
, SENTRY_RELEASE
, etc.
The Serilog Section of Sentry could take only the two values you set, since that's the only thing "Serilog specific". And the DSN
can be set as a root element so Sentry.Extension.Logging so that'll initialize the SDK. It seems that's what you're doing already though.
Also, I have to find a way to set Sentry options e.g. ServerName, and Environment dynamically on start.
You can set some options via env var as I mentioned above. ServerName is read automatically from Environment.MachineName
. You can change all of that programatically with:
AddSentry(o => o.ServerName)
etc right after the host starts. Values you pick to assign can come from the .NET's built-in config system if you want to define via env var or json.
Sentry will merge the config values with the callback you passed explicitly