Example #1
0
        /// <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;
        }
Example #3
0
        /// <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);
        }
Example #4
0
        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;
            }
        }
Example #5
0
        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);
            }
        }
Example #6
0
        /// <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);
        }