public SentryEvent Process(SentryEvent @event)
 {
     @event.Contexts["launch parameters"] = game.LaunchParameters;
     @event.SetTag("graphicsPlatform", $"{GraphicsDevice.Platform}");
     @event.SetTag("processArch", $"{RuntimeInformation.ProcessArchitecture}");
     @event.Release = GetVersion();
     return(@event);
 }
示例#2
0
        private static void ConfigureServices(IServiceCollection services)
        {
            services.AddHttpClient <ISymbolClient, SymbolClient>()
            .AddPolicyHandler((s, r) => HttpPolicyExtensions.HandleTransientHttpError()
                              .WaitAndRetryAsync(new[]
            {
                TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5),
#if RELEASE
                // TODO: Until a proper re-entrancy is built in the clients, add a last hope retry
                TimeSpan.FromSeconds(15)
#endif
            },
                                                 onRetry: async(result, span, retryAttempt, context) =>
            {
                var sentry = s.GetService <ISentryClient>();
                var evt    = new SentryEvent(result.Exception)
                {
                    Level    = SentryLevel.Warning,
                    LogEntry = new LogEntry
                    {
                        Formatted =
                            $"Waiting {span} following attempt {retryAttempt} failed HTTP request.",
                        Message =
                            "Waiting {span} following attempt {retryAttempt} failed HTTP request.",
                    }
                };
                evt.SetTag("Tag", "Polly");
                if (result.Result is { } request)
                {
                    const string traceIdKey = "TraceIdentifier";
                    if (request.Headers.TryGetValues(traceIdKey, out var traceIds))
                    {
                        evt.SetTag(traceIdKey, traceIds.FirstOrDefault() ?? "unknown");
                    }

                    evt.SetTag("StatusCode", request.StatusCode.ToString());
                    var responseBody = await request.Content.ReadAsStringAsync();
                    if (!string.IsNullOrWhiteSpace(responseBody))
                    {
                        evt.SetExtra("body", responseBody);
                    }
                }
                sentry.CaptureEvent(evt);
            }
                                                 ));

            services.AddSingleton <Client>();
            services.AddSingleton <ObjectFileParser>();
            services.AddSingleton <ClientMetrics>();
            services.AddSingleton <FatBinaryReader>();
            services.AddSingleton <ClientMetrics>();

            services.AddOptions <SymbolClientOptions>()
            .Configure <IConfiguration>((o, f) => f.Bind("SymbolClient", o))
            .Validate(o => o.BaseAddress is {}, "BaseAddress is required.");
示例#3
0
        public SentryEvent Process(SentryEvent @event)
        {
            if (serviceContext.TryGetInstance <ExplorerContext>() is ExplorerContext context)
            {
                @event.SetTag("ColumnType", context.ColumnInfo.Type.ToString());
                @event.SetExtra("ExplorationContext", context);
            }

            @event.SetTag("GitSha", ThisAssembly.Git.Sha);
            @event.SetTag("GitBranch", ThisAssembly.Git.Branch);

            return(@event);
        }
示例#4
0
        private static SentryEvent SentryBeforeSend(SentryEvent args)
        {
#if DEBUG
            return(null);
#else
            if (args.Exception?.TargetSite.Module.Assembly == Engine.ClassicAssembly)
            {
                return(null);
            }

            args.User = new User {
                Id = AssistantOptions.UserId
            };
            args.SetTag("SessionId", AssistantOptions.SessionId);
            args.SetExtra("PlayerName", Engine.Player?.Name ?? "Unknown");
            args.SetExtra("PlayerSerial", Engine.Player?.Serial ?? 0);
            args.SetExtra("Shard", Engine.CurrentShard?.Name ?? "Unknown");
            args.SetExtra("ShardFeatures", Engine.Features.ToString());
            args.SetExtra("CharacterListFlags", Engine.CharacterListFlags.ToString());
            args.SetExtra("Connected", Engine.Connected);
            args.SetExtra("ClientVersion",
                          Engine.ClientVersion == null ? "Unknown" : Engine.ClientVersion.ToString());
            args.SetExtra("KeyboardLayout", InputLanguageManager.Current?.CurrentInputLanguage?.Name ?? "Unknown");
            args.SetExtra("ClassicUO Version", Engine.ClassicAssembly?.GetName().Version.ToString() ?? "Unknown");

            return(args);
#endif
        }
示例#5
0
        private SentryEvent PrepareEvent(SentryEvent @event)
        {
            var scope = ScopeManagement.GetCurrent();

            // TODO: Consider multiple events being sent with the same scope:
            // Wherever this code will end up, it should evaluate only once
            if (scope.States != null)
            {
                foreach (var state in scope.States)
                {
                    if (state is string scopeString)
                    {
                        @event.SetTag("scope", scopeString);
                    }
                    else if (state is IEnumerable <KeyValuePair <string, string> > keyValStringString)
                    {
                        @event.SetTags(keyValStringString);
                    }
                    else if (state is IEnumerable <KeyValuePair <string, object> > keyValStringObject)
                    {
                        @event.SetTags(keyValStringObject.Select(k =>
                                                                 new KeyValuePair <string, string>(k.Key, k.Value.ToString())));
                    }
                    else
                    {
                        // TODO: possible callback invocation here
                        @event.SetExtra("State of unknown type", state.GetType().ToString());
                    }
                }
            }

            @event = _options.BeforeSend?.Invoke(@event);

            return(@event);
        }
        protected override void ProcessException(
            SpecialException exception,
            SentryEvent sentryEvent)
        {
            sentryEvent.AddBreadcrumb("Processor running on special exception.");

            sentryEvent.SetTag("IsSpecial", exception.IsSpecial.ToString());
        }
示例#7
0
 /// <summary>
 /// Applies the default tags to an event without resetting existing tags.
 /// </summary>
 /// <param name="options">The options to read the default tags from.</param>
 /// <param name="event">The event to apply the tags to.</param>
 public static void ApplyDefaultTags(this SentryLoggingOptions options, SentryEvent @event)
 {
     foreach (var defaultTag in options.DefaultTags
              .Where(t => [email protected](t.Key, out _)))
     {
         @event.SetTag(defaultTag.Key, defaultTag.Value);
     }
 }
示例#8
0
        private static SentryEvent BeforeSend(SentryEvent arg)
        {
            var assemblypath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var send         = true;

            arg.SetTag("admin", App.IsAdministrator().ToString());
            arg.SetTag("beta", (!string.IsNullOrWhiteSpace(LauncherContext.Instance.BetaVersion)).ToString());

            try
            {
                try
                {
                    if (!Directory.Exists($@"{assemblypath}\Logs\Hyddwn Launcher\Exceptions"))
                    {
                        Directory.CreateDirectory($@"{assemblypath}\Logs\Hyddwn Launcher\Exceptions");
                    }

                    File.WriteAllText(
                        $@"{assemblypath}\Logs\Hyddwn Launcher\Exceptions\Unhandled_Exception-{DateTime.Now:yyyy-MM-dd_hh-mm.fff}.log",
                        string.Format(Resources.HyddwnLauncherVersion, 1) +
                        string.Format(Resources.UnhandledExceptionFileSegmentException, arg.Exception));
                }
                catch
                {
                    Clipboard.SetText(arg.Exception.ToString());
                    MessageBox.Show(
                        string.Format(
                            Resources.UnhandledExceptionFileError,
                            arg.Exception));
                    return(arg);
                }

                Log.Exception(arg.Exception, Resources.UnhandledExceptionFatalError);
                var exceptionReporter = new ExceptionReporter(arg.Exception);
                exceptionReporter.ShowDialog();
                send = exceptionReporter.Result;
            }
            catch
            {
                return(arg);
            }

            return(send ? arg : null);
        }
示例#9
0
            public SentryEvent?Process(SentryEvent @event)
            {
                _metrics.SentryEventProcessed();
                @event.SetTag("server-endpoint", _options.BaseAddress);
                @event.Contexts["SymbolServiceOptions"] = _options;

                @event.SetTag("cores", _cores);

                // In dev, ignore statsd errors
                if (_environment.IsDevelopment())
                {
                    if (@event.Exception is SocketException ex &&
                        ex.ToString().Contains("StatsD"))
                    {
                        return(null);
                    }
                }
                return(@event);
            }
示例#10
0
        private static SentryEvent SentryEvent(SentryEvent e)
        {
            try
            {
                if (!string.IsNullOrEmpty(Settings.UserName) && Settings.UserId != 0)
                {
                    e.User = new Sentry.Protocol.User()
                    {
                        Id       = Settings.UserId.ToString(),
                        Username = Settings.UserName
                    };
                }
                e.SetTag("Locale", Settings.Locale);
                e.SetTag("URI", uri);
                e.SetTag("MD5", md5Luancher);
            }
            catch { }

            return(e);
        }
示例#11
0
        public void Log <TState>(
            LogLevel logLevel,
            EventId eventId,
            TState state,
            Exception exception,
            Func <TState, Exception, string> formatter)
        {
            if (!IsEnabled(logLevel))
            {
                return;
            }

            var message = formatter?.Invoke(state, exception);

            if (SendEvent(logLevel, eventId, exception))
            {
                var @event = new SentryEvent(exception)
                {
                    Logger  = CategoryName,
                    Message = message,
                    Level   = logLevel.ToSentryLevel()
                };

                var tuple = eventId.ToTupleOrNull();
                if (tuple.HasValue)
                {
                    @event.SetTag(tuple.Value.name, tuple.Value.value);
                }

                _hub.CaptureEvent(@event);
            }

            // Even if it was sent as event, add breadcrumb so next event includes it
            if (_options.MinimumBreadcrumbLevel != LogLevel.None &&
                logLevel >= _options.MinimumBreadcrumbLevel)
            {
                var data = eventId.ToDictionaryOrNull();
                if (exception != null && message != null)
                {
                    // Exception.Message won't be used as Breadcrumb message
                    // Avoid losing it by adding as data:
                    data = data ?? new Dictionary <string, string>();
                    data.Add("exception_message", exception.Message);
                }

                _hub.AddBreadcrumb(
                    _clock,
                    message ?? exception?.Message,
                    CategoryName,
                    type: null,
                    data,
                    logLevel.ToBreadcrumbLevel());
            }
        }
示例#12
0
 public void Process(Exception exception, SentryEvent sentryEvent)
 {
     if (exception is UnityLogException ule)
     {
         // TODO: At this point the original (Mono+.NET stack trace factories already ran)
         // Ideally this strategy would fit into the SDK hooks, even though this parse gives not only
         // a stacktrace but also the exception message and type so currently can't be hooked into StackTraceFactory
         sentryEvent.SentryExceptions = new[] { ule.ToSentryException() };
         sentryEvent.SetTag("source", "log");
     }
 }
        public static void FatalError(string message, Exception exception)
        {
            SentryEvent sentryEvent = new SentryEvent(exception)
            {
                Message = message,
                Level   = Sentry.Protocol.SentryLevel.Fatal
            };

            sentryEvent.SetTag("HRESULT", exception.HResult.ToString());

            SentrySdk.CaptureEvent(sentryEvent);
        }
        public void ApplyDefaultTags_TagInEvent_DoesNotOverrideTag()
        {
            const string key      = "key";
            const string expected = "event tag value";
            var          target   = new SentryEvent();

            target.SetTag(key, expected);
            _sut.DefaultTags[key] = "default value";

            _sut.ApplyDefaultTags(target);

            Assert.Equal(expected, target.Tags[key]);
        }
        private static SentryEvent SentryBeforeSend(SentryEvent args)
        {
            args.User = new User {
                Id = AssistantOptions.UserId
            };
            args.SetTag("SessionId", AssistantOptions.SessionId);
            args.SetExtra("PlayerName", Engine.Player?.Name ?? "Unknown");
            args.SetExtra("PlayerSerial", Engine.Player?.Serial ?? 0);
            args.SetExtra("Shard", Engine.CurrentShard?.Name ?? "Unknown");
            args.SetExtra("Connected", Engine.Connected);

            return(args);
        }
        public static void Error(string message, Exception exception, IEnumerable <KeyValuePair <string, string> > extraTags)
        {
            SentryEvent sentryEvent = new SentryEvent(exception)
            {
                Message = message,
                Level   = Sentry.Protocol.SentryLevel.Error,
            };

            if (extraTags != null)
            {
                sentryEvent.SetTags(extraTags);
            }
            sentryEvent.SetTag("HRESULT", exception.HResult.ToString());

            SentrySdk.CaptureEvent(sentryEvent);
        }
示例#17
0
        private static SentryEvent SentryBeforeSend(SentryEvent args)
        {
            args.User = new User {
                Id = AssistantOptions.UserId
            };
            args.SetTag("SessionId", AssistantOptions.SessionId);
            args.SetExtra("PlayerName", Engine.Player?.Name ?? "Unknown");
            args.SetExtra("PlayerSerial", Engine.Player?.Serial ?? 0);
            args.SetExtra("Shard", Engine.CurrentShard?.Name ?? "Unknown");
            args.SetExtra("ShardFeatures", Engine.Features.ToString());
            args.SetExtra("Connected", Engine.Connected);
            args.SetExtra("ClientVersion",
                          Engine.ClientVersion == null ? "Unknown" : Engine.ClientVersion.ToString());
            args.SetExtra("KeyboardLayout", InputLanguageManager.Current?.CurrentInputLanguage?.Name ?? "Unknown");

            return(args);
        }
        // SentryException.Extra is not supported by Sentry yet.
        // Move the extras to the Event Extra while marking
        // by index the Exception which owns it.
        private static void MoveExceptionExtrasToEvent(
            SentryEvent sentryEvent,
            IReadOnlyList <SentryException> sentryExceptions)
        {
            for (var i = 0; i < sentryExceptions.Count; i++)
            {
                var sentryException = sentryExceptions[i];

                if (sentryException.Data.Count <= 0)
                {
                    continue;
                }

                foreach (var keyValue in sentryException.Data)
                {
                    if (keyValue.Key.StartsWith("sentry:", StringComparison.OrdinalIgnoreCase) &&
                        keyValue.Value != null)
                    {
                        if (keyValue.Key.StartsWith(ExceptionDataTagKey, StringComparison.OrdinalIgnoreCase) &&
                            keyValue.Value is string tagValue &&
                            ExceptionDataTagKey.Length < keyValue.Key.Length)
                        {
                            // Set the key after the ExceptionDataTagKey string.
                            sentryEvent.SetTag(keyValue.Key.Substring(ExceptionDataTagKey.Length), tagValue);
                        }
                        else if (keyValue.Key.StartsWith(ExceptionDataContextKey, StringComparison.OrdinalIgnoreCase) &&
                                 ExceptionDataContextKey.Length < keyValue.Key.Length)
                        {
                            // Set the key after the ExceptionDataTagKey string.
                            _ = sentryEvent.Contexts[keyValue.Key.Substring(ExceptionDataContextKey.Length)] = keyValue.Value;
                        }
                        else
                        {
                            sentryEvent.SetExtra($"Exception[{i}][{keyValue.Key}]", sentryException.Data[keyValue.Key]);
                        }
                    }
示例#19
0
        public override void Handle(ExceptionHandlerContext context)
        {
            ExceptionDispatchInfo info = ExceptionDispatchInfo.Capture(context.Exception);

            // Add any contextual data you want to the event:
            var @event = new SentryEvent(info.SourceException)
            {
                Request = new Request
                {
                    Method      = context.Request.Method.ToString(),
                    Url         = context.Request.RequestUri.AbsoluteUri,
                    QueryString = context.Request.Headers.ToString()
                }
            };

            @event.SetTag("http-version", context.Request.Version.ToString());
            SentrySdk.CaptureEvent(@event);

            // Set the result:
            context.Result = new InternalServerErrorResult(context.Request);

            // Or re-throw if you want it to bubble up the middleware chain (Sentry removes duplicate captures)
            //info.Throw();
        }
示例#20
0
        public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject()
        {
            var ex        = new Exception("exception message");
            var timestamp = DateTimeOffset.MaxValue;
            var id        = Guid.Parse("4b780f4c-ec03-42a7-8ef8-a41c9d5621f8");
            var sut       = new SentryEvent(ex, timestamp, id)
            {
                User = new User {
                    Id = "user-id"
                },
                Request = new Request {
                    Method = "POST"
                },
                Contexts = new Contexts {
                    ["context_key"]    = "context_value",
                    [".NET Framework"] = new Dictionary <string, string> {
                        [".NET Framework"]        = "\"v2.0.50727\", \"v3.0\", \"v3.5\"",
                        [".NET Framework Client"] = "\"v4.8\", \"v4.0.0.0\"",
                        [".NET Framework Full"]   = "\"v4.8\""
                    }
                },
                Sdk = new SdkVersion {
                    Name = "SDK-test", Version = "1.1.1"
                },
                Environment = "environment",
                Level       = SentryLevel.Fatal,
                Logger      = "logger",
                Message     = new SentryMessage
                {
                    Message   = "message",
                    Formatted = "structured_message"
                },
                Modules          = { { "module_key", "module_value" } },
                Release          = "release",
                SentryExceptions = new[] { new SentryException {
                                               Value = "exception_value"
                                           } },
                SentryThreads = new[] { new SentryThread {
                                            Crashed = true
                                        } },
                ServerName      = "server_name",
                TransactionName = "transaction",
            };

            sut.Sdk.AddPackage(new Package("name", "version"));
            sut.AddBreadcrumb(new Breadcrumb(timestamp, "crumb"));
            sut.AddBreadcrumb(new Breadcrumb(
                                  timestamp,
                                  "message",
                                  "type",
                                  new Dictionary <string, string> {
                { "data-key", "data-value" }
            },
                                  "category",
                                  BreadcrumbLevel.Warning));

            sut.SetExtra("extra_key", "extra_value");
            sut.Fingerprint = new[] { "fingerprint" };
            sut.SetTag("tag_key", "tag_value");

            var actualString = sut.ToJsonString();

            var actual = SentryEvent.FromJson(Json.Parse(actualString));

            actual.Should().BeEquivalentTo(sut, o =>
            {
                // Due to timestamp precision
                o.Excluding(e => e.Breadcrumbs);
                o.Excluding(e => e.Exception);

                return(o);
            });

            // Expected item[0].Timestamp to be <9999-12-31 23:59:59.9999999>, but found <9999-12-31 23:59:59.999>.
            actual.Breadcrumbs.Should().BeEquivalentTo(sut.Breadcrumbs, o => o.Excluding(b => b.Timestamp));
            var counter = 0;

            foreach (var sutBreadcrumb in sut.Breadcrumbs)
            {
                sutBreadcrumb.Timestamp.Should().BeCloseTo(actual.Breadcrumbs.ElementAt(counter++).Timestamp);
            }
        }
示例#21
0
        public void Log <TState>(
            LogLevel logLevel,
            EventId eventId,
            TState state,
            Exception exception,
            Func <TState, Exception, string> formatter)
        {
            if (!IsEnabled(logLevel))
            {
                return;
            }

            var message = formatter?.Invoke(state, exception);

            if (_options.MinimumEventLevel != LogLevel.None &&
                logLevel >= _options.MinimumEventLevel)
            {
                var @event = new SentryEvent(exception)
                {
                    Logger = CategoryName,
                };

                if (message != null)
                {
                    // TODO: this will override the current message
                    // which could have been set from reading Exception.Message
                    if (@event.Message != null)
                    {
                        @event.SetExtra("original_message", @event.Message);
                    }
                    @event.Message = message;
                }

                var tuple = eventId.ToTupleOrNull();
                if (tuple.HasValue)
                {
                    @event.SetTag(tuple.Value.name, tuple.Value.value);
                }

                _sentryClient.CaptureEvent(@event);
            }

            // Even if it was sent as event, add breadcrumb so next event includes it
            if (_options.MinimumBreadcrumbLevel != LogLevel.None &&
                logLevel >= _options.MinimumBreadcrumbLevel)
            {
                var data = eventId.ToDictionaryOrNull();
                if (exception != null && message != null)
                {
                    // Exception.Message won't be used as Breadcrumb message
                    // Avoid losing it by adding as data:
                    data = data ?? new Dictionary <string, string>();
                    data.Add("exception_message", exception.Message);
                }

                _sentryClient.AddBreadcrumb(
                    _clock,
                    message ?? exception?.Message,
                    "default",
                    CategoryName,
                    data,
                    logLevel.ToBreadcrumbLevel());
            }
        }
示例#22
0
        public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject()
        {
            var ex        = new Exception("exception message");
            var timestamp = DateTimeOffset.MaxValue;
            var id        = Guid.Parse("4b780f4c-ec03-42a7-8ef8-a41c9d5621f8");
            var sut       = new SentryEvent(ex, timestamp, id)
            {
                User = new User {
                    Id = "user-id"
                },
                Request = new Request {
                    Method = "POST"
                },
                Contexts = new Contexts
                {
                    ["context_key"]    = "context_value",
                    [".NET Framework"] = new Dictionary <string, string>
                    {
                        [".NET Framework"]        = "\"v2.0.50727\", \"v3.0\", \"v3.5\"",
                        [".NET Framework Client"] = "\"v4.8\", \"v4.0.0.0\"",
                        [".NET Framework Full"]   = "\"v4.8\""
                    }
                },
                Sdk = new SdkVersion {
                    Name = "SDK-test", Version = "1.1.1"
                },
                Environment = "environment",
                Level       = SentryLevel.Fatal,
                Logger      = "logger",
                Message     = new SentryMessage
                {
                    Message   = "message",
                    Formatted = "structured_message"
                },
                Modules          = { { "module_key", "module_value" } },
                Release          = "release",
                SentryExceptions = new[] { new SentryException {
                                               Value = "exception_value"
                                           } },
                SentryThreads = new[] { new SentryThread {
                                            Crashed = true
                                        } },
                ServerName      = "server_name",
                TransactionName = "transaction",
            };

            sut.Sdk.AddPackage(new Package("name", "version"));
            sut.AddBreadcrumb(new Breadcrumb(timestamp, "crumb"));
            sut.AddBreadcrumb(new Breadcrumb(
                                  timestamp,
                                  "message",
                                  "type",
                                  new Dictionary <string, string> {
                { "data-key", "data-value" }
            },
                                  "category",
                                  BreadcrumbLevel.Warning));

            sut.SetExtra("extra_key", "extra_value");
            sut.Fingerprint = new[] { "fingerprint" };
            sut.SetTag("tag_key", "tag_value");

            var actualString = sut.ToJsonString();

            var actual = SentryEvent.FromJson(Json.Parse(actualString));

            // Assert
            actual.Should().BeEquivalentTo(sut, o =>
            {
                // Exceptions are not deserialized
                o.Excluding(x => x.Exception);

                // Timestamps lose some precision when writing to JSON
                o.Using <DateTimeOffset>(ctx =>
                                         ctx.Subject.Should().BeCloseTo(ctx.Expectation, TimeSpan.FromMilliseconds(1))
                                         ).WhenTypeIs <DateTimeOffset>();

                return(o);
            });
        }
示例#23
0
 public SentryEvent Process(SentryEvent @event)
 {
     @event.SetTag("server-endpoint", _options.BaseAddress);
     @event.Contexts["SymbolServiceOptions"] = _options;
     return(@event);
 }
示例#24
0
 protected override void ProcessException(ArgumentException exception, SentryEvent sentryEvent)
 {
     // Handle specific types of exceptions and add more data to the event
     sentryEvent.SetTag("parameter-name", exception.ParamName);
 }
示例#25
0
        public void Log <TState>(
            LogLevel logLevel,
            EventId eventId,
            TState state,
            Exception exception,
            Func <TState, Exception, string> formatter)
        {
            if (!IsEnabled(logLevel))
            {
                return;
            }

            var message = formatter?.Invoke(state, exception);

            if (ShouldCaptureEvent(logLevel, eventId, exception))
            {
                var @event = new SentryEvent(exception)
                {
                    Logger  = CategoryName,
                    Message = message,
                    Level   = logLevel.ToSentryLevel()
                };

                if (state is IEnumerable <KeyValuePair <string, object> > pairs)
                {
                    foreach (var property in pairs)
                    {
                        if (property.Key == "{OriginalFormat}" && property.Value is string template)
                        {
                            // Original format found, use Sentry logEntry interface
                            @event.Message  = null;
                            @event.LogEntry = new LogEntry
                            {
                                Formatted = message,
                                Message   = template
                            };
                            continue;
                        }

                        if (property.Value is string tagValue)
                        {
                            @event.SetTag(property.Key, tagValue);
                        }
                    }
                }

                var tuple = eventId.ToTupleOrNull();
                if (tuple.HasValue)
                {
                    @event.SetTag(tuple.Value.name, tuple.Value.value);
                }

                _hub.CaptureEvent(@event);
            }

            // Even if it was sent as event, add breadcrumb so next event includes it
            if (ShouldAddBreadcrumb(logLevel, eventId, exception))
            {
                var data = eventId.ToDictionaryOrNull();
                if (exception != null && message != null)
                {
                    // Exception.Message won't be used as Breadcrumb message
                    // Avoid losing it by adding as data:
                    data = data ?? new Dictionary <string, string>();
                    data.Add("exception_message", exception.Message);
                }

                _hub.AddBreadcrumb(
                    _clock,
                    message ?? exception?.Message,
                    CategoryName,
                    type: null,
                    data,
                    logLevel.ToBreadcrumbLevel());
            }
        }
示例#26
0
        public async Task Roundtrip_WithEvent_Success()
        {
            // Arrange
            var ex        = new Exception("exception message");
            var timestamp = DateTimeOffset.MaxValue;
            var id        = Guid.Parse("4b780f4c-ec03-42a7-8ef8-a41c9d5621f8");
            var @event    = new SentryEvent(ex, timestamp, id)
            {
                User = new User {
                    Id = "user-id"
                },
                Request = new Request {
                    Method = "POST"
                },
                Contexts = new Contexts {
                    ["context_key"] = "context_value"
                },
                Sdk = new SdkVersion {
                    Name = "SDK-test", Version = "1.0.0"
                },
                Environment = "environment",
                Level       = SentryLevel.Fatal,
                Logger      = "logger",
                Message     = new SentryMessage
                {
                    Message   = "message",
                    Formatted = "structured_message"
                },
                Modules          = { { "module_key", "module_value" } },
                Release          = "release",
                SentryExceptions = new[] { new SentryException {
                                               Value = "exception_value"
                                           } },
                SentryThreads = new[] { new SentryThread {
                                            Crashed = true
                                        } },
                ServerName      = "server_name",
                TransactionName = "transaction",
            };

            @event.SetExtra("extra_key", "extra_value");
            @event.Fingerprint = new[] { "fingerprint" };
            @event.SetTag("tag_key", "tag_value");

            using var envelope = Envelope.FromEvent(@event);

#if !NET461 && !NETCOREAPP2_1
            await
#endif
            using var stream = new MemoryStream();

            // Act
            await envelope.SerializeAsync(stream);

            stream.Seek(0, SeekOrigin.Begin);

            using var envelopeRoundtrip = await Envelope.DeserializeAsync(stream);

            // Assert

            // Can't compare the entire object graph because output envelope contains evaluated length,
            // which original envelope doesn't have.
            envelopeRoundtrip.Header.Should().BeEquivalentTo(envelope.Header);
            envelopeRoundtrip.Items.Should().ContainSingle();

            var payloadContent = (envelopeRoundtrip.Items[0].Payload as JsonSerializable)?.Source;
            payloadContent.Should().BeEquivalentTo(@event, o => o.Excluding(x => x.Exception));
        }