-
-
Notifications
You must be signed in to change notification settings - Fork 226
feat: replace libcurl with .NET HttpClient for sentry-native #4222
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
Changes from all commits
25efbb2
68f0088
ab3f90b
c7fef87
e612efe
a1d8c13
ed1e65f
a732c8e
8c33d71
72dce34
96cee16
0d64190
b1f0407
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -139,6 +139,14 @@ public static bool Init(SentryOptions options) | |
| } | ||
| } | ||
|
|
||
| unsafe | ||
| { | ||
| var cTransport = sentry_transport_new(&nativeTransport); | ||
| sentry_transport_set_state(cTransport, GCHandle.ToIntPtr(GCHandle.Alloc(options))); | ||
| sentry_transport_set_free_func(cTransport, &nativeTransportFree); | ||
| sentry_options_set_transport(cOptions, cTransport); | ||
| } | ||
|
|
||
| options.DiagnosticLogger?.LogDebug("Initializing sentry native"); | ||
| return 0 == sentry_init(cOptions); | ||
| } | ||
|
|
@@ -364,6 +372,70 @@ internal struct sentry_value_t | |
| [DllImport("sentry-native")] | ||
| private static extern void sentry_options_set_auto_session_tracking(IntPtr options, int debug); | ||
|
|
||
| [DllImport("sentry-native")] | ||
| private static extern void sentry_options_set_transport(IntPtr options, IntPtr transport); | ||
|
|
||
| [DllImport("sentry-native")] | ||
| private static extern unsafe IntPtr sentry_transport_new(delegate* unmanaged<IntPtr, IntPtr, void> sendFunc); | ||
|
|
||
| [DllImport("sentry-native")] | ||
| private static extern void sentry_transport_set_state(IntPtr transport, IntPtr state); | ||
|
|
||
| [DllImport("sentry-native")] | ||
| private static extern unsafe void sentry_transport_set_free_func(IntPtr transport, delegate* unmanaged<IntPtr, void> freeFunc); | ||
|
|
||
| [DllImport("sentry-native")] | ||
| private static extern IntPtr sentry_envelope_serialize(IntPtr envelope, out UIntPtr sizeOut); | ||
|
|
||
| [DllImport("sentry-native")] | ||
| private static extern void sentry_envelope_free(IntPtr envelope); | ||
|
|
||
| [DllImport("sentry-native")] | ||
| internal static extern void sentry_free(IntPtr ptr); | ||
|
|
||
| [UnmanagedCallersOnly] | ||
| private static void nativeTransport(IntPtr envelope, IntPtr state) | ||
jpnurmi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| var options = GCHandle.FromIntPtr(state).Target as SentryOptions; | ||
| try | ||
| { | ||
| if (options is not null) | ||
| { | ||
| var data = sentry_envelope_serialize(envelope, out var size); | ||
| using var content = new UnmanagedHttpContent(data, (int)size, options.DiagnosticLogger); | ||
|
|
||
| using var client = options.GetHttpClient(); | ||
| using var request = options.CreateHttpRequest(content); | ||
| #if NET5_0_OR_GREATER | ||
| var response = client.Send(request); | ||
| #else | ||
| var response = client.SendAsync(request).GetAwaiter().GetResult(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Flash0ver might want to add a comment here that we only go through this native transport in crashes so we dorm care about blocking and that there's no risk of deadlock since no synchronization context
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry if I was too eager to merge this. I wanted to get rid of the libcurl installation steps for #4247. :) |
||
| #endif | ||
| response.EnsureSuccessStatusCode(); | ||
| } | ||
| } | ||
| catch (HttpRequestException e) | ||
| { | ||
| options?.DiagnosticLogger?.LogError(e, "Failed to send native envelope."); | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| // never allow an exception back to native code - it would crash the app | ||
jpnurmi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| options?.DiagnosticLogger?.LogError(e, "Exception in native transport callback. The native envelope will not be sent."); | ||
| } | ||
| finally | ||
| { | ||
| sentry_envelope_free(envelope); | ||
| } | ||
| } | ||
|
|
||
| [UnmanagedCallersOnly] | ||
| private static void nativeTransportFree(IntPtr state) | ||
| { | ||
| var handle = GCHandle.FromIntPtr(state); | ||
| handle.Free(); | ||
| } | ||
|
|
||
| [DllImport("sentry-native")] | ||
| private static extern unsafe void sentry_options_set_logger(IntPtr options, delegate* unmanaged/*[Cdecl]*/<int, IntPtr, IntPtr, IntPtr, void> logger, IntPtr userData); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| using Sentry.Extensibility; | ||
|
|
||
| namespace Sentry.Native; | ||
|
|
||
| internal sealed class UnmanagedHttpContent : SerializableHttpContent | ||
| { | ||
| private IntPtr _content; | ||
| private readonly int _length = 0; | ||
| private readonly IDiagnosticLogger? _logger; | ||
|
|
||
| public UnmanagedHttpContent(IntPtr content, int length, IDiagnosticLogger? logger) | ||
| { | ||
| _content = content; | ||
| _length = length; | ||
| _logger = logger; | ||
| } | ||
|
|
||
| ~UnmanagedHttpContent() | ||
| { | ||
| Dispose(false); | ||
| } | ||
|
|
||
| protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context) | ||
| { | ||
| ThrowIfObjectDisposed(); | ||
| try | ||
Flash0ver marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| using var unmanagedStream = CreateStream(); | ||
| await unmanagedStream.CopyToAsync(stream).ConfigureAwait(false); | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| _logger?.LogError(e, "Failed to serialize unmanaged content into the network stream"); | ||
| throw; | ||
| } | ||
| } | ||
|
|
||
| protected override void SerializeToStream(Stream stream, TransportContext? context, CancellationToken cancellationToken) | ||
| { | ||
| ThrowIfObjectDisposed(); | ||
| try | ||
| { | ||
| using var unmanagedStream = CreateStream(); | ||
| unmanagedStream.CopyTo(stream); | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| _logger?.LogError(e, "Failed to serialize unmanaged content into the network stream"); | ||
| throw; | ||
| } | ||
| } | ||
|
|
||
| protected override bool TryComputeLength(out long length) | ||
| { | ||
| length = _length; | ||
| return true; | ||
| } | ||
|
|
||
| protected override void Dispose(bool disposing) | ||
| { | ||
| IntPtr content = Interlocked.Exchange(ref _content, IntPtr.Zero); | ||
| C.sentry_free(content); | ||
| base.Dispose(disposing); | ||
| } | ||
|
|
||
| private unsafe UnmanagedMemoryStream CreateStream() | ||
| { | ||
| return new UnmanagedMemoryStream((byte*)_content.ToPointer(), _length); | ||
| } | ||
|
|
||
| private void ThrowIfObjectDisposed() | ||
| { | ||
| if (_content == IntPtr.Zero) | ||
| { | ||
| throw new ObjectDisposedException(GetType().FullName); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.