question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Unhandled exceptions in generic host don't have breadcrumbs

See original GitHub issue

Package

Sentry.Serilog

.NET Flavor

.NET

.NET Version

6.0.7

OS

Linux

SDK Version

3.20.0

Self-Hosted Sentry Version

No response

Steps to Reproduce

I’m integrating Sentry into a dotnet C# console app that uses Serilog and generic host.

To reproduce:

  1. See snippet below for a simple example app
  2. Set up your DSN in code
  3. Install dependencies, run it.

Here’s relevant code that shows how app is all hooked up:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Sentry;
using Serilog;

using (var host = CreateHostBuilder().Build())
{
    await host.StartAsync();

    var lifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();

    // Start Martini CLI
    var martiniCLI = host.Services.GetRequiredService<MartiniCLI>();
    await martiniCLI.RunAsync(lifetime.ApplicationStopping);

    // Once completed, automatically stop the application
    lifetime.StopApplication();

    await host.WaitForShutdownAsync();
}

static IHostBuilder CreateHostBuilder() =>
    new HostBuilder()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseConsoleLifetime()
        .ConfigureHostConfiguration(hostConfigBuilder => hostConfigBuilder.AddEnvironmentVariables(prefix: "DOTNET_"))
        .ConfigureServices(services => services.AddTransient<MartiniCLI>())
        .ConfigureLogging((_, logging) =>
        {
            logging.AddSimpleConsole().SetMinimumLevel(LogLevel.Debug);

            // Configure sentry logger
            var sentryLogger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .WriteTo.Sentry(debug: true,
                                minimumBreadcrumbLevel: Serilog.Events.LogEventLevel.Debug,
                                environment: "Development",
                                dsn: "")
                .CreateLogger();
            logging.AddSerilog(sentryLogger);
        });

class MartiniCLI
{
    readonly ILogger<MartiniCLI> _logger;

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

    public async Task RunAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Start");
        _logger.LogDebug("Debug log");
        SentrySdk.AddBreadcrumb("Manually added breadcrumb", "info", level: BreadcrumbLevel.Debug);
        _logger.LogInformation("Delay for 5 seconds");
        await Task.Delay(5000, cancellationToken);
        _logger.LogInformation("Delay finished");
        throw new Exception("Unhandled exception!");
        // _logger.LogError("Fake error!");
    }
}

Expected Result

I would expect errors (both unhandled exceptions and _logger.LogError) to be logged in Sentry with breadcrumbs.

Actual Result

Errors logged manually using _logger.LogError are logged in Sentry with breadcrumbs. Unhandled exceptions are logged in Sentry but without breadcrumbs.

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
mattjohnsonpintcommented, Jul 26, 2022

Since there’s a viable workaround, I suggest using that for now until we can get a better fix in place.

Thanks.

0reactions
mattjohnsonpintcommented, Jul 26, 2022

Just to add a workaround, you can try/catch around the entire worker logic and manually capture the exception. If doing so, you’ll want to flag it as “unhandled” like this:

    using Sentry.Protocol;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            await DoExecuteAsync(stoppingToken);
        }
        catch (Exception ex)
        {
            ex.Data[Mechanism.HandledKey] = false;
            ex.Data[Mechanism.MechanismKey] = "Worker.UnhandledException";
            _hub.CaptureException(ex);
        }
    }
    
    private Task DoExecuteAsync(CancellationToken stoppingToken)
    {
        // ... the actual worker code
    }

Or in the originally reported code without changing anything else:

    using Sentry.Protocol;

    public async Task RunAsync(CancellationToken cancellationToken)
    {
        try
        {
            await DoRunAsync(cancellationToken);
        }
        catch (Exception ex)
        {
            ex.Data[Mechanism.HandledKey] = false;
            ex.Data[Mechanism.MechanismKey] = "Worker.UnhandledException";
            SentrySdk.CaptureException(ex);
        }
    }
    
    private async Task DoRunAsync(CancellationToken cancellationToken)
    {
        // ... the actual worker code
    }
Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - .NET Generic Host : Prevent application crash on ...
Is there a solution to protect the Generic Host, as well as the IHostedService against unhandled exceptions ?
Read more >
NET 6 breaking change: Exception handling in hosting - .NET
In previous versions, when a BackgroundService throws an unhandled exception, the exception is lost and the service appears unresponsive.
Read more >
when other than exception, and raise application error
What I'm trying to say there is - if the error is raised, caught and handled (not re-raised to the client) by PLSQL...
Read more >
Error: "Unhandled Exception has occurred in your application ...
In MYOB PDF Manager, you may receive the following error when saving a document to Document Manager from PDF Manager: "Unhandled Exception has...
Read more >
FragmentBreadCrumbs | Android Developers
Helper class for showing "bread crumbs" representing the fragment stack in an activity. This is intended to be used with ActionBar.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found