Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spans for HTTP requests - UnityWebRequest and HttpMessageHandler #737

Open
1 of 6 tasks
Tracked by #736
bruno-garcia opened this issue May 9, 2022 · 3 comments
Open
1 of 6 tasks
Tracked by #736

Comments

@bruno-garcia
Copy link
Member

bruno-garcia commented May 9, 2022

When a user makes an HTTP request to their backend, we want to measure how long that took. And propagate the trace id so we can have end to end tracing.

This can be split in:

HttpMessageHandler

The .NET approach. Used in Sentry Defenses:
https://github.com/getsentry/sentry-defenses/blob/2989949f857f1cccb46814ce0a05d50f603f9222/game/Assets/Scripts/Manager/BugSpawner.cs#L37

We need to find a way add the handler automatically. At least on the one assembly created by Unity when compiling the scripts.

Steps:

  • A PoC that gets a DLL that has new HttpClient(...) and adds the middleware (as done in Sentry defenses) @SimonCropp
  • Find out which Unity hooks can we rely on to get the GameAssembly.dll @bitsandfoxes
  • With the PoC we can discuss next steps such as: Is this a .NET Global Tool? Do we have the code in Sentry.Unity.Editor?

UnityWebRequests (Unity Client)

Example HTTP client usage:

var www = new UnityWebRequest
{
url = message.RequestUri.ToString(),
method = message.Method.Method.ToUpperInvariant(),
uploadHandler = new UploadHandlerRaw(contentMemoryStream.ToArray()),
downloadHandler = new DownloadHandlerBuffer()
};

We need a way to plug Sentry in there. First 'manually' with some C# code. Then automatically, possibly with IL weaving.

  • We need a strategy to get spans/crumbs similar to SentryHttpMessageHandler @bitsandfoxes
  • PoC with IL weaving a DLL using UnityWebRequest and add the new interceptor @SimonCropp
  • With the PoC we can discuss next steps such as: Is this a .NET Global Tool? Do we have the code in Sentry.Unity.Editor?
@SimonCropp
Copy link
Contributor

i took a look into implementing the custom uploadHandler and downloadHandler and hit a wall.

The IL replacement plan is to detect usage of existing handlers and wrap them in our own. but that wrapping does not seem possible. The reason is that the the Dispose in the base classes is not virtual. So if we wrap an exiting instance, we override Dispose on our implementation so as to then call Dispose on the inner handler.

I considered re-implementing each of the DownloadHandler implementations that ship with Unity. Unfortunately they all use internal methods in the base class. This might be possible with some reflection. Note it would only work for the known subset of handlers that ship with unity

we cant inherit and override Unitys default handlers since they are all sealed

@bruno-garcia
Copy link
Member Author

bruno-garcia commented Jun 21, 2022

Our goal is to wrap that HTTP request into a span/crumb creation logic, like we do here: https://github.com/getsentry/sentry-dotnet/blob/36ccacf43b8aeedc493585ea57bc05880b285773/src/Sentry/SentryHttpMessageHandler.cs#L52-L96

Like if the HTTP request code would be here: https://github.com/getsentry/sentry-dotnet/blob/36ccacf43b8aeedc493585ea57bc05880b285773/src/Sentry/SentryHttpMessageHandler.cs#L76

So during IL weaving we would find:

var www = new UnityWebRequest 
{ 
    url = message.RequestUri.ToString(), 
    method = message.Method.Method.ToUpperInvariant(), 
    uploadHandler = new UploadHandlerRaw(contentMemoryStream.ToArray()), 
    downloadHandler = new DownloadHandlerBuffer() 
}; 

// REST OF CODE

Then move the two parameters up to an assignment, so we can easily copy its values, add span:

var myUrlValue = message.RequestUri.ToString(), 
var myMethodValue = message.Method.Method.ToUpperInvariant(), 

var span = _hub.GetSpan()?.StartChild(
                "http.client",
                // e.g. "GET https://example.com/"
                $"{requestMethod} {url}");
try
{
    var www = new UnityWebRequest 
    { 
        url = myUrlValue.
        method = myMethodValue,
        uploadHandler = new UploadHandlerRaw(contentMemoryStream.ToArray()), 
        downloadHandler = new DownloadHandlerBuffer() 
    }; 

    // REST OF CODE

    var breadcrumbData = new Dictionary<string, string>
    {
        { "url", myUrlValue },
        { "method", myMethodValue },
        { "status_code", ((int)response.StatusCode).ToString() }
    };
    _hub.AddBreadcrumb(string.Empty, "http", "http", breadcrumbData);

    // This will handle unsuccessful status codes as well
    span?.Finish(SpanStatusConverter.FromHttpStatusCode(response.StatusCode));

    return response;
}
catch (Exception ex)
{
    span?.Finish(ex);
    throw;
}

@bitsandfoxes bitsandfoxes moved this from In Progress to Backlog in Mobile & Cross Platform SDK Feb 21, 2023
@mattjohnsonpint mattjohnsonpint removed their assignment Jun 20, 2023
@bitsandfoxes bitsandfoxes added this to GDX Mar 13, 2024
@bruno-garcia bruno-garcia changed the title Spans for HTTP requests Spans for HTTP requests - UnityWebRequest and ~HttpMessageHandler~ Nov 16, 2024
@bruno-garcia
Copy link
Member Author

Came across this commit: be0388e

from this branch

@bitsandfoxes bitsandfoxes changed the title Spans for HTTP requests - UnityWebRequest and ~HttpMessageHandler~ Spans for HTTP requests - UnityWebRequest and HttpMessageHandler Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Backlog
Archived in project
Development

No branches or pull requests

4 participants