/// <summary> /// Run symbol collection. /// </summary> public void Run(Context context) { var host = Host.Init(context, "https://[email protected]/5953206"); var tran = SentrySdk.StartTransaction("SymbolUpload", "symbol.upload"); var options = host.Services.GetRequiredService <SymbolClientOptions>(); options.BaseAddress = new Uri("https://symbol-collector.services.sentry.io"); SentrySdk.ConfigureScope(s => s.SetTag("server-endpoint", options.BaseAddress.AbsoluteUri)); var source = new CancellationTokenSource(); var uploader = host.Services.GetRequiredService <AndroidUploader>(); #pragma warning disable 618 var friendlyName = $"Android:{Build.Manufacturer}-{Build.CpuAbi}-{Build.Model}"; #pragma warning restore 618 StructUtsname?uname = null; try { uname = Os.Uname(); friendlyName += $"-kernel-{uname?.Release ?? "??"}"; } catch (Exception e) { SentrySdk.AddBreadcrumb("Couldn't run uname", category: "exec", data: new Dictionary <string, string> { { "exception", e.Message } }, level: BreadcrumbLevel.Error); // android.runtime.JavaProxyThrowable: System.NotSupportedException: Could not activate JNI Handle 0x7ed00025 (key_handle 0x4192edf8) of Java type 'md5eb7159ad9d3514ee216d1abd14b6d16a/MainActivity' as managed type 'SymbolCollector.Android.MainActivity'. ---> // Java.Lang.NoClassDefFoundError: android/system/Os ---> Java.Lang.ClassNotFoundException: Didn't find class "android.system.Os" on path: DexPathList[[zip file "/data/app/SymbolCollector.Android.SymbolCollector.Android-1.apk"],nativeLibraryDirectories=[/data/app-lib/SymbolCollector.Android.SymbolCollector.Android-1, /vendor/lib, /system/lib]] } SentrySdk.ConfigureScope(s => { if (uname is { }) { s.Contexts["uname"] = new { uname.Machine, uname.Nodename, uname.Release, uname.Sysname, uname.Version }; s.Contexts.OperatingSystem.KernelVersion = uname.Release; } });
protected void Application_BeginRequest() { var method = Context.Request.HttpMethod; var path = Context.Request.Path; // Start a transaction that encompasses the current request var transaction = SentrySdk.StartTransaction( $"{method} {path}", "http.server" ); // Attach the transaction to the scope so that other operations can reference it SentrySdk.ConfigureScope(scope => scope.Transaction = transaction); // Attach transaction to the request context to finish it when the request ends Context.Items["__SentryTransaction"] = transaction; }
/// <summary> /// Starts a new Sentry transaction that encompasses the currently executing HTTP request. /// </summary> public static ITransaction StartSentryTransaction(this HttpContext httpContext) { var method = httpContext.Request.HttpMethod; var path = httpContext.Request.Path; var traceHeader = TryGetTraceHeader(httpContext.Request.Headers); var transactionName = $"{method} {path}"; const string transactionOperation = "http.server"; var transactionContext = traceHeader is not null ? new TransactionContext(transactionName, transactionOperation, traceHeader) : new TransactionContext(transactionName, transactionOperation); var transaction = SentrySdk.StartTransaction(transactionContext); SentrySdk.ConfigureScope(scope => scope.Transaction = transaction); return(transaction); }
private ITransaction _startupTransaction = null !; // set on OnCreate protected override void OnCreate(Bundle?savedInstanceState) { // Can't take a screenshot otherwise: System.NullReferenceException: The current Activity can not be detected. Ensure that you have called Init in your Activity or Application class. Microsoft.Maui.ApplicationModel.ActivityStateManager.Default.Init(this, savedInstanceState); #pragma warning disable 618 _friendlyName = $"Android:{Build.Manufacturer}-{Build.CpuAbi}-{Build.Model}"; #pragma warning restore 618 _host = Host.Init(this, "https://[email protected]/5953206"); _serviceProvider = _host.Services; var tran = SentrySdk.StartTransaction("AppStart", "activity.load"); _startupTransaction = tran; AddSentryContext(); var span = _startupTransaction.StartChild("OnCreate"); try { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.activity_main); var footerText = (TextView)base.FindViewById(Resource.Id.footer) !; var versionName = Application.Context.ApplicationContext?.PackageManager? .GetPackageInfo(Application.Context.ApplicationContext?.PackageName ?? "", 0)?.VersionName; footerText.Text = $"Version: {versionName}\n" + footerText.Text; var uploader = _serviceProvider.GetRequiredService <AndroidUploader>(); var metrics = _serviceProvider.GetRequiredService <ClientMetrics>(); var uploadButton = (Button)base.FindViewById(Resource.Id.btnUpload) !; var cancelButton = (Button)base.FindViewById(Resource.Id.btnCancel) !; var url = (EditText)base.FindViewById(Resource.Id.server_url) !; var source = new CancellationTokenSource(); url.FocusChange += (sender, args) => { if (!args.HasFocus) { SentrySdk.AddBreadcrumb("Unfocus", category: "ui.event"); Unfocus(); } }; uploadButton.Click += OnUploadButtonOnClick; cancelButton.Click += OnCancelButtonOnClick; async void OnUploadButtonOnClick(object?sender, EventArgs args) { var uploadTransaction = SentrySdk.StartTransaction("BatchUpload", "batch.upload"); try { SentrySdk.AddBreadcrumb("OnUploadButtonOnClick", category: "ui.event"); var options = _serviceProvider.GetRequiredService <SymbolClientOptions>(); options.BaseAddress = new Uri(url.Text !); // TODO validate SentrySdk.ConfigureScope(s => s.SetTag("server-endpoint", options.BaseAddress.AbsoluteUri)); Unfocus(); uploadButton.Enabled = false; source = new CancellationTokenSource(); var uploadTask = uploader.StartUpload(_friendlyName, source.Token); var updateUiTask = StartUiUpdater(source.Token, metrics); await UploadAsync(uploadTask, updateUiTask, metrics, cancelButton, uploadButton, uploadTransaction, source); } catch (Exception e) { uploadTransaction.Finish(e); throw; } } void OnCancelButtonOnClick(object?sender, EventArgs args) { SentrySdk.AddBreadcrumb("OnCancelButtonOnClick", category: "ui.event"); Unfocus(); source.Cancel(); } span.Finish(SpanStatus.Ok); _startupTransaction.Finish(SpanStatus.Ok); } catch (Exception e) { span.Finish(e); _startupTransaction.Finish(e); throw; } }
public async Task StartUploadSymbols(IEnumerable <string> paths, string bundleId, BatchType?batchType, CancellationToken token) { var transaction = SentrySdk.StartTransaction("StartUploadSymbols", "symbols.upload"); SentrySdk.ConfigureScope(s => { s.Transaction = transaction; s.AddEventProcessor(@event => { var uploadMetrics = new Dictionary <string, object>(); @event.Contexts["metrics"] = uploadMetrics; _metrics.Write(uploadMetrics); return(@event); }); }); if (!IsInputRedirected && KeyAvailable) { _ = Task.Run(() => { WriteLine("Press Ctrl+C to exit or 'p' to print the status."); while (!token.IsCancellationRequested) { if (ReadKey(true).Key == ConsoleKey.P) { _metrics.Write(Out); } } }, token).ContinueWith(t => { // Avoid TaskUnobservedException if (t.IsFaulted && t.Exception is { } e) { SentrySdk.AddBreadcrumb("Failed when attempting to listen to the console to print status", level: BreadcrumbLevel.Warning, data: new Dictionary <string, string> { { "message", e.ToString() }, { "stacktrace", e.StackTrace ?? "null" } }); } }, token); } try { var type = batchType ?? DeviceBatchType(); _logger.LogInformation("Uploading bundle {bundleId} of type {type} and paths: {paths}", bundleId, type, paths); await _client.UploadAllPathsAsync(bundleId, type, paths, token); transaction.Finish(SpanStatus.Ok); } catch (Exception e) { transaction.Finish(e); throw; } finally { _metrics.Write(Out); } }
/// <summary> /// Initializes <see cref="IHost"/> with Sentry monitoring. /// </summary> public static IHost Init(Context context, string dsn) { SentrySdk.Init(context, o => { // TODO: ShouldCan be deleted once this PR is released: https://github.com/getsentry/sentry-dotnet/pull/1750/files#diff-c55d438dd1d5f3731c0d04d0f1213af4873645b1daa44c4c6e1b24192110d8f8R166-R167 // System.UnauthorizedAccessException: Access to the path '/proc/stat' is denied. o.DetectStartupTime = StartupTimeDetectionMode.Fast; #if ANDROID // TODO: Should be added OOTB o.Release = $"{AppInfo.PackageName}@{AppInfo.VersionString}+{AppInfo.BuildString}"; o.Android.AttachScreenshot = true; o.Android.ProfilingEnabled = true; o.Android.EnableAndroidSdkTracing = true; // Will double report transactions but to get profiler data #endif o.TracesSampleRate = 1.0; o.Debug = true; #if DEBUG o.Environment = "development"; #else o.DiagnosticLevel = SentryLevel.Info; #endif o.MaxBreadcrumbs = 250; o.InitCacheFlushTimeout = TimeSpan.FromSeconds(5); o.AttachStacktrace = true; o.Dsn = dsn; o.SendDefaultPii = true; // TODO: This needs to be built-in o.BeforeSend += @event => { const string traceIdKey = "TraceIdentifier"; switch (@event.Exception) { case OperationCanceledException _: return(null); case var e when e?.Data.Contains(traceIdKey) == true: @event.SetTag(traceIdKey, e.Data[traceIdKey]?.ToString() ?? "unknown"); break; } return(@event); }; // TODO: https://github.com/getsentry/sentry-dotnet/issues/1751 // o.BeforeBreadcrumb = breadcrumb // // This logger adds 3 crumbs for each HTTP request and we already have a Sentry integration for HTTP // // Which shows the right category, status code and a link // => string.Equals(breadcrumb.Category, "System.Net.Http.HttpClient.ISymbolClient.LogicalHandler") // || string.Equals(breadcrumb.Category, "System.Net.Http.HttpClient.ISymbolClient.ClientHandler") // ? null // : breadcrumb; }); var tran = SentrySdk.StartTransaction("AppStart", "activity.load"); SentrySdk.ConfigureScope(s => { s.Transaction = tran; s.AddAttachment(new ScreenshotAttachment()); }); // TODO: Where is this span? var iocSpan = tran.StartChild("container.init", "Initializing the IoC container"); var userAgent = Java.Lang.JavaSystem.GetProperty("http.agent") ?? "Android/" + typeof(Host).Assembly.GetName().Version; var host = Startup.Init(services => { var messages = new [] { // Unable to resolve host "symbol-collector.services.sentry.io": No address associated with hostname "No address associated with hostname", // Read error: ssl=0x79ea0d6988: SSL_ERROR_WANT_READ occurred. You should never see this. "You should never see this", // handshake error: ssl=0x78f5b01b48: I/O error during system call, Try again "Try again", // failed to connect to symbol-collector.services.sentry.io/35.188.18.176 (port 443) from /10.22.91.71 (port 43860) after 86400000ms: isConnected failed: ETIMEDOUT (Connection timed out) "Connection timed out", // Read error: ssl=0x77f787e308: Failure in SSL library, usually a protocol error // error:100003fc:SSL routines:OPENSSL_internal:SSLV3_ALERT_BAD_RECORD_MAC (external/boringssl/src/ssl/tls_record.cc:592 0x77f854d8c8:0x00000001) "Failure in SSL library, usually a protocol error", }; services.AddSingleton <AndroidMessageHandler>(); services.AddHttpClient <ISymbolClient, SymbolClient>() .ConfigurePrimaryHttpMessageHandler <AndroidMessageHandler>() .AddPolicyHandler((s, r) => HttpPolicyExtensions.HandleTransientHttpError() // Could be deleted if merged: https://github.com/App-vNext/Polly.Extensions.Http/pull/33 // On Android web get WebException instead of HttpResponseMessage which HandleTransientHttpError covers .Or <IOException>(e => messages.Any(m => e.Message.Contains(m))) .Or <WebException>(e => messages.Any(m => e.Message.Contains(m))) .Or <SocketTimeoutException>() .SentryPolicy(s)); services.AddSingleton <AndroidUploader>(); services.AddOptions().Configure <SymbolClientOptions>(o => { o.UserAgent = userAgent; o.BlockListedPaths.Add("/system/etc/.booking.data.aid"); o.BlockListedPaths.Add("/system/build.prop"); o.BlockListedPaths.Add("/system/vendor/bin/netstat"); o.BlockListedPaths.Add("/system/vendor/bin/swapoff"); }); services.AddOptions().Configure <ObjectFileParserOptions>(o => { o.IncludeHash = false; o.UseFallbackObjectFileParser = false; // Android only, use only ELF parser. }); }); iocSpan.Finish(); SentrySdk.ConfigureScope(s => s.SetTag("user-agent", userAgent)); return(host); }