コード例 #1
0
 /// <summary>
 /// Sends a report to Sentry only (no log, no toast, etc.).
 /// Does not send to Sentry if ApplicationUpdateSupport.IsDev is true.
 /// Fails silently.
 /// </summary>
 /// <param name="message">The message to send with the report</param>
 /// <param name="fullDetailedMessage">An optional message which can be added to the Sentry report</param>
 public static void ReportSentryOnly(string message, string fullDetailedMessage = null)
 {
     if (ApplicationUpdateSupport.IsDev)
     {
         Debug.WriteLine("Developer, we though you might want to know that ReportSentryOnly() was called. Ignore if you like.");
         Debug.Indent();
         Debug.WriteLine(message);
         Debug.WriteLine(fullDetailedMessage);
         Debug.Unindent();
         return;
     }
     try
     {
         var evt = new SentryEvent {
             Message = message
         };
         if (!string.IsNullOrWhiteSpace(fullDetailedMessage))
         {
             evt.SetExtra("fullDetailedMessage", fullDetailedMessage);
         }
         evt.SetExtra("stackTrace", new StackTrace().ToString());
         SentrySdk.CaptureEvent(evt);
     }
     catch (Exception err)
     {
         // will only "do something" if we're testing reporting and have thus turned off checking for dev
         Debug.Fail(err.Message);
     }
 }
コード例 #2
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
        }
コード例 #3
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("Connected", Engine.Connected);

            return(args);
        }
コード例 #4
0
ファイル: SentryClient.cs プロジェクト: robopsi/sentry-dotnet
        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);
        }
コード例 #5
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.");
コード例 #6
0
ファイル: SentryLogger.cs プロジェクト: ssh352/runner
        /// <inheritdoc />
        public void Log <TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func <TState, Exception, string> formatter)
        {
            // Skip irrelevant logging levels
            if (!IsEnabled(logLevel))
            {
                return;
            }

            // Case in which logger.LogError("message") is used
            if (exception == null)
            {
                exception = new Exception($"No exception thrown. Message included: {state}");
            }

            // Log to sentry
            var sentryEvent = new SentryEvent(exception);

            sentryEvent.SetExtra("configuration", _serializedConfiguration);
            sentryEvent.SetExtra("algorithm_configuration", _serializedAlgorithmConfiguration);
            _sentryClient.CaptureEvent(sentryEvent);
        }
コード例 #7
0
        private static void FlattenException(Exception exception, SentryEvent sentryEvent, string key)
        {
            var properties = exception.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (var propertyInfo in properties.Where(x => x.DeclaringType != typeof(Exception)))
            {
                try
                {
                    var value = JsonConvert.SerializeObject(propertyInfo.GetValue(exception, null));
                    sentryEvent.SetExtra(key + "." + propertyInfo.Name, value);
                }
                catch (Exception ex)
                {
                    sentryEvent.SetExtra(key + "." + propertyInfo.Name, "ERROR accessing value: " + ex.Message);
                }
            }

            if (exception.InnerException != null)
            {
                FlattenException(exception.InnerException, sentryEvent, key + ".innerException");
            }
        }
コード例 #8
0
        public void Process_EventHasExtrasExceptionDoesnt_NotModified()
        {
            var evt = new SentryEvent();

            evt.SetExtra("extra", 1);
            var expected = evt.Extra;

            var ex = new Exception();

            Sut.Process(ex, evt);

            Assert.Same(expected, evt.Extra);
        }
コード例 #9
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);
        }
コード例 #10
0
        public void Log(object logMessage, LogLevel logLevel, params string[] vals)
        {
            if (logLevel == LogLevel.Critical && logMessage is Exception exception && !(exception is NonLoggableException))
            {
                var sentryEvent = new SentryEvent(exception);

                lock (_lockingObject)
                {
                    foreach (var contextKeyValue in ContextData)
                    {
                        sentryEvent.SetExtra(contextKeyValue.Key, contextKeyValue.Value);
                    }
                    SentryClient.CaptureEvent(sentryEvent);
                }
            }
        }
コード例 #11
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("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");

            return(args);
        }
コード例 #12
0
        public void Process_EventAndExceptionHaveExtra_DataCombined()
        {
            const string expectedKey   = "extra";
            const int    expectedValue = 1;

            var evt = new SentryEvent();

            evt.SetExtra(expectedKey, expectedValue);

            var ex = new Exception();

            ex.Data.Add("other extra", 2);

            Sut.Process(ex, evt);

            Assert.Equal(2, evt.Extra.Count);
            Assert.Contains(evt.Extra, p => p.Key == expectedKey && (int)p.Value == expectedValue);
        }
コード例 #13
0
        // 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 key in sentryException.Data.Keys)
                {
                    sentryEvent.SetExtra($"Exception[{i}][{key}]", sentryException.Data[key]);
                }
            }
        }
コード例 #14
0
        /// <summary>
        /// Extracts details from <see cref="DbEntityValidationException"/> into the <see cref="SentryEvent"/>.
        /// </summary>
        protected override void ProcessException(DbEntityValidationException exception, SentryEvent sentryEvent)
        {
            var errorList = new Dictionary <string, List <string> >();

            foreach (var error in exception.EntityValidationErrors.SelectMany(x => x.ValidationErrors))
            {
                if (errorList.TryGetValue(error.PropertyName, out var list))
                {
                    list.Add(error.ErrorMessage);
                }
                else
                {
                    list = new List <string> {
                        error.ErrorMessage
                    };
                    errorList.Add(error.PropertyName, list);
                }
            }

            sentryEvent.SetExtra(EntityValidationErrors, errorList);
        }
コード例 #15
0
        public void Process(Exception exception, SentryEvent sentryEvent)
        {
            if ((bool)exception.Data["TickException"])
            {
                return;
            }

            // create folder "crashes"
            var crashes = Path.Combine(AppContext.BaseDirectory, "Crashes");

            Directory.CreateDirectory(crashes);

            // open filestream to write minidump to crashes folder
            var file = new FileStream(Path.Combine(crashes, $"{Guid.NewGuid()}.dmp"), FileMode.Create);
            var info = new MINIDUMP_EXCEPTION_INFORMATION
            {
                ThreadId          = GetCurrentThreadId(),
                ExceptionPointers = Marshal.GetExceptionPointers(),
                ClientPointers    = 1
            };

            MiniDumpWriteDump(
                GetCurrentProcess(),
                GetCurrentProcessId(),
                file.SafeFileHandle.DangerousGetHandle(),
                (int)MINIDUMP_TYPE.MiniDumpWithFullMemory,
                ref info,
                IntPtr.Zero,
                IntPtr.Zero);

            file.Close();

            // inform the user a minidump has been written
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("A minidump has been written to " + file.Name + ", please send this file to the developers.");
            Console.ResetColor();

            sentryEvent.SetExtra("minidump", Path.GetFileName(file.Name));
        }
コード例 #16
0
        // 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]);
                        }
                    }
コード例 #17
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);
            });
        }
コード例 #18
0
 protected override void ProcessException(DBConcurrencyException exception, SentryEvent sentryEvent)
 {
     sentryEvent.SetExtra("Row Count", exception.RowCount);
     sentryEvent.SetExtra("Row Error", exception.Row.RowError);
 }
コード例 #19
0
        public SentryEvent?Process(SentryEvent @event)
        {
            if (@event is null)
            {
                return(null);
            }
            // Add some Unity specific context:

            var version = "0.0.1-alpha";

            // TODO Sdk shouldn't be marked as nullable
            @event.Sdk !.AddPackage("github:sentry.unity", version);
            @event.Sdk.Name    = "sentry.unity";
            @event.Sdk.Version = version;

            @event.Contexts.OperatingSystem.Name = SystemInfo.operatingSystem;

            @event.Contexts.Device.Name = SystemInfo.deviceName;
#pragma warning disable RECS0018 // Value is exact when expressing no battery level
            if (SystemInfo.batteryLevel != -1.0)
#pragma warning restore RECS0018
            {
                @event.Contexts.Device.BatteryLevel = (short?)(SystemInfo.batteryLevel * 100);
            }

            @event.Release = Application.version;

            // This is the approximate amount of system memory in megabytes.
            // This function is not supported on Windows Store Apps and will always return 0.
            @event.Contexts.Device.MemorySize = SystemInfo.systemMemorySize;

            @event.Contexts.Device.Timezone = TimeZoneInfo.Local;

            @event.Contexts.App.StartTime = DateTimeOffset.UtcNow.AddSeconds(-Time.realtimeSinceStartup);

            // TODO:  @event.Contexts["Unity"] = new UnityContext (values to be read on the main thread)
            @event.SetExtra("unity:processorCount", SystemInfo.processorCount.ToString());
            @event.SetExtra("unity:supportsVibration", SystemInfo.supportsVibration.ToString());
            @event.SetExtra("unity:installMode", Application.installMode.ToString());

            // TODO: Will move to raw_description once parsing is done in Sentry
            @event.Contexts.OperatingSystem.Name = SystemInfo.operatingSystem;

            switch (Input.deviceOrientation)
            {
            case UnityEngine.DeviceOrientation.Portrait:
            case UnityEngine.DeviceOrientation.PortraitUpsideDown:
                @event.Contexts.Device.Orientation = DeviceOrientation.Portrait;
                break;

            case UnityEngine.DeviceOrientation.LandscapeLeft:
            case UnityEngine.DeviceOrientation.LandscapeRight:
                @event.Contexts.Device.Orientation = DeviceOrientation.Landscape;
                break;

            case UnityEngine.DeviceOrientation.FaceUp:
            case UnityEngine.DeviceOrientation.FaceDown:
                // TODO: Add to protocol?
                break;
            }

            var model = SystemInfo.deviceModel;
            if (model != SystemInfo.unsupportedIdentifier
                // Returned by the editor
                && model != "System Product Name (System manufacturer)")
            {
                @event.Contexts.Device.Model = model;
            }

            //device.DeviceType = SystemInfo.deviceType.ToString();
            //device.CpuDescription = SystemInfo.processorType;
            //device.BatteryStatus = SystemInfo.batteryStatus.ToString();

            @event.SetExtra("unity:batteryStatus", SystemInfo.batteryStatus.ToString());
            @event.SetExtra("unity:deviceType", SystemInfo.deviceType.ToString());
            @event.SetExtra("unity:processorType", SystemInfo.processorType);

            // This is the approximate amount of system memory in megabytes.
            // This function is not supported on Windows Store Apps and will always return 0.
            if (SystemInfo.systemMemorySize != 0)
            {
                @event.Contexts.Device.MemorySize = SystemInfo.systemMemorySize * 1048576L; // Sentry device mem is in Bytes
            }

            @event.Contexts.Gpu.Id                     = SystemInfo.graphicsDeviceID;
            @event.Contexts.Gpu.Name                   = SystemInfo.graphicsDeviceName;
            @event.Contexts.Gpu.VendorId               = SystemInfo.graphicsDeviceVendorID.ToString();
            @event.Contexts.Gpu.VendorName             = SystemInfo.graphicsDeviceVendor;
            @event.Contexts.Gpu.MemorySize             = SystemInfo.graphicsMemorySize;
            @event.Contexts.Gpu.MultiThreadedRendering = SystemInfo.graphicsMultiThreaded;
            @event.Contexts.Gpu.NpotSupport            = SystemInfo.npotSupport.ToString();
            @event.Contexts.Gpu.Version                = SystemInfo.graphicsDeviceVersion;
            @event.Contexts.Gpu.ApiType                = SystemInfo.graphicsDeviceType.ToString();

            @event.Contexts.App.StartTime = DateTimeOffset.UtcNow
                                            // NOTE: Time API requires main thread
                                            .AddSeconds(-Time.realtimeSinceStartup);

            if (Debug.isDebugBuild)
            {
                @event.Contexts.App.BuildType = "debug";
            }
            else
            {
                @event.Contexts.App.BuildType = "release";
            }

            // TODO: 'UNITY_EDITOR' preprocessor is not known from within 'Sentry.Unity'
#if UNITY_EDITOR
            @event.Contexts.Device.Simulator = true;
#else
            @event.Contexts.Device.Simulator = false;
#endif

            return(@event);
        }
コード例 #20
0
ファイル: SentryLogger.cs プロジェクト: robopsi/sentry-dotnet
        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());
            }
        }
コード例 #21
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);
            }
        }
コード例 #22
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));
        }