getsentry / sentry-dotnet

Sentry SDK for .NET
https://docs.sentry.io/platforms/dotnet
MIT License
604 stars 206 forks source link

Capture json payloads of http requests (maybe only in case of errors) #3594

Open andrekiba opened 2 months ago

andrekiba commented 2 months ago

Problem Statement

Is there a way to capture json payloads starting from HttpRequestMessage (and eventually HttpResponseMessage)? Lets say that I have a specific handler that inherits from SentryHttpMessageHandler. Can I override the ProcessRequest and HandleResponse to set the payload as extra on the span? Is it the correct way? ProcessRequest and HandleResponse they have a synchronous signature, why not something that support async code??

I'm using the .Net Maui Sentry sdk, I have an http client registered with Refit (that uses HttpClientFactory). In this case is the SentryHttpMessageHandler already in place by default? And what if need to substitute it with something else?

What if I want to use my "specialised" handler to try to capture also the payloads?

builder.Services.AddRefitClient<IApi>(
  new RefitSettings
  {
    ContentSerializer = new NewtonsoftJsonContentSerializer(
        new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore,
            Converters = { new UserInformationDTOConverter() }
        })
  })
  .ConfigureHttpClient(client =>
  {
    client.BaseAddress = new Uri(options.BaseUrl);
    client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
  })
  .ConfigurePrimaryHttpMessageHandler(AddPrimaryMessageHandler)
  .AddHttpMessageHandler<TokenHandler>()
  .AddHttpMessageHandler<SentryHttpPayloadMessageHandler>();

Can I add my SentryHttpPayloadMessageHandler in this way?

I think it's related to #2218 and https://github.com/getsentry/team-mobile/issues/41

Solution Brainstorm

No response

jamescrosswell commented 2 months ago

@andrekiba the HttpResponseMessage is stored by the Failed Request Handler: https://github.com/getsentry/sentry-dotnet/blob/914c92da678fb299f5d1cc2bae408351978db18c/src/Sentry/SentryHttpFailedRequestHandler.cs#L40

You can see an example of how to extract this in the docs.

andrekiba commented 2 months ago

hi @jamescrosswell thank you the HttpResponseMessage inside the hint is null. So my question again: is the SentryHttpMessageHandler automatically in place? Refit uses the HttpClientFactory https://github.com/reactiveui/refit/blob/main/Refit.HttpClientFactory/HttpClientFactoryExtensions.cs and I have the options.CaptureFailedRequests = true And anyway SetBeforeSend doesn't provide support for something that returns a Task so eventually do I have to force the read the Content of the request in a sync way?

jamescrosswell commented 2 months ago

is the SentryHttpMessageHandler automatically in place?

The Sentry.Extensions.Logging integration includes this IHttpMessageHandlerBuilderFilter: https://github.com/getsentry/sentry-dotnet/blob/dcc32b22b29fe77f1129f9cb848388af6093ece5/src/Sentry.Extensions.Logging/SentryHttpMessageHandlerBuilderFilter.cs#L17-L22

... which gets hooked up when adding that integration: https://github.com/getsentry/sentry-dotnet/blob/dcc32b22b29fe77f1129f9cb848388af6093ece5/src/Sentry.Extensions.Logging/Extensions/DependencyInjection/ServiceCollectionExtensions.cs#L44

And that in turn gets called by the MAUI Builder: https://github.com/getsentry/sentry-dotnet/blob/feabf090918b551d8e7c8c24d27c752881623c37/src/Sentry.Maui/SentryMauiAppBuilderExtensions.cs#L62

So normally I think all of that works out of the box with MAUI. I'm not familiar with Refit but there may be some conflict between Sentry and Refit wrt registering message handlers.

Glancing at the source code, it looks like the Refit support configuring an "inner" handler on RefitSettings.HttpMessageHandlerFactory so you could do something like:

var sentryMessageHander = new SentryHttpMessageHandler();
// ... wherever you configure refit
refitSettings.HttpMessageHandlerFactory = () => sentryMessageHander;

Alternatively, if you're using a ServiceProvider and DI, you could register SentryHttpMessageHandler as a singleton and resolve/return this for your RefitSettings.HttpMessageHandlerFactory.