private void processLogEntry(LogEntry entry) { if (entry.Level < LogLevel.Verbose) { return; } var exception = entry.Exception; if (exception != null) { if (!shouldSubmitException(exception)) { return; } // since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports. if (lastException != null && lastException.Message == exception.Message && exception.StackTrace.StartsWith(lastException.StackTrace, StringComparison.Ordinal)) { return; } lastException = exception; sentry.CaptureEvent(new SentryEvent(exception) { Message = entry.Message }, sentryScope); } else { sentryScope.AddBreadcrumb(DateTimeOffset.Now, entry.Message, entry.Target.ToString(), "navigation"); } }
// TODO: should this class take the Scope by dependency injection instead? // Would allow us to create a centralized "chain of handlers" where this class could just be registered as an entry in public void Enrich(Scope scope, DiscordClient shard, MessageCreateEventArgs evt) { scope.AddBreadcrumb(evt.Message.Content, "event.message", data: new Dictionary<string, string> { {"user", evt.Author.Id.ToString()}, {"channel", evt.Channel.Id.ToString()}, {"guild", evt.Channel.GuildId.ToString()}, {"message", evt.Message.Id.ToString()}, }); scope.SetTag("shard", shard.ShardId.ToString()); // Also report information about the bot's permissions in the channel // We get a lot of permission errors so this'll be useful for determining problems var perms = evt.Channel.BotPermissions(); scope.AddBreadcrumb(perms.ToPermissionString(), "permissions"); }
public static void AddMessageBreadcrumb(this Scope scope, SocketMessage msg) { scope.AddBreadcrumb(msg.Content, "event.message", data: new Dictionary <string, string>() { { "user", msg.Author.Id.ToString() }, { "channel", msg.Channel.Id.ToString() }, { "guild", ((msg.Channel as IGuildChannel)?.GuildId ?? 0).ToString() }, { "message", msg.Id.ToString() }, }); }
public static void AddMessageBulkDeleteBreadcrumb(this Scope scope, IReadOnlyCollection <Cacheable <IMessage, ulong> > messages, ISocketMessageChannel channel) { scope.AddBreadcrumb("", "event.messageDelete", data: new Dictionary <string, string>() { { "channel", channel.Id.ToString() }, { "guild", ((channel as IGuildChannel)?.GuildId ?? 0).ToString() }, { "messages", string.Join(",", messages.Select(m => m.Id)) }, }); }
public static void AddMessageDeleteBreadcrumb(this Scope scope, Cacheable <IMessage, ulong> message, ISocketMessageChannel channel) { scope.AddBreadcrumb("", "event.messageDelete", data: new Dictionary <string, string>() { { "channel", channel.Id.ToString() }, { "guild", ((channel as IGuildChannel)?.GuildId ?? 0).ToString() }, { "message", message.Id.ToString() }, }); }
public void Enrich(Scope scope, MessageBulkDeleteEventArgs evt) { scope.AddBreadcrumb("", "event.messageDelete", data: new Dictionary <string, string>() { { "channel", evt.Channel.Id.ToString() }, { "guild", evt.Channel.Id.ToString() }, { "messages", string.Join(",", evt.Messages.Select(m => m.Id)) }, }); scope.SetTag("shard", evt.Client.ShardId.ToString()); }
public void Enrich(Scope scope, DiscordClient shard, MessageDeleteEventArgs evt) { scope.AddBreadcrumb("", "event.messageDelete", data: new Dictionary<string, string>() { {"channel", evt.Channel.Id.ToString()}, {"guild", evt.Channel.GuildId.ToString()}, {"message", evt.Message.Id.ToString()}, }); scope.SetTag("shard", shard.ShardId.ToString()); }
public void Apply_Breadcrumbs_NotOnSource_TargetUnmodified() { var target = new Scope(); target.AddBreadcrumb("test target"); var expected = target.InternalBreadcrumbs; _sut.Apply(target); Assert.Same(expected, target.InternalBreadcrumbs); }
public void Apply_Breadcrumbs_OnTarget_MergedWithSource() { _sut.AddBreadcrumb("test sut"); var target = new Scope(); target.AddBreadcrumb("test target"); _sut.Apply(target); Assert.Equal(2, target.InternalBreadcrumbs.Count); }
public void AddBreadcrumb_WithoutOptions_NoMoreThanDefaultMaxBreadcrumbs() { var scope = new Scope(); for (var i = 0; i < Constants.DefaultMaxBreadcrumbs + 1; i++) { scope.AddBreadcrumb(i.ToString()); } Assert.Equal(Constants.DefaultMaxBreadcrumbs, scope.InternalBreadcrumbs.Count); }
public void Enrich(Scope scope, int shardId, MessageDeleteEvent evt) { scope.AddBreadcrumb("", "event.messageDelete", data: new Dictionary <string, string> { { "channel", evt.ChannelId.ToString() }, { "guild", evt.GuildId.ToString() }, { "message", evt.Id.ToString() } }); scope.SetTag("shard", shardId.ToString()); }
public void Enrich(Scope scope, int shardId, MessageUpdateEvent evt) { scope.AddBreadcrumb(evt.Content.Value ?? "<unknown>", "event.messageEdit", data: new Dictionary <string, string> { { "channel", evt.ChannelId.ToString() }, { "guild", evt.GuildId.Value.ToString() }, { "message", evt.Id.ToString() } }); scope.SetTag("shard", shardId.ToString()); }
public void Enrich(Scope scope, MessageUpdateEventArgs evt) { scope.AddBreadcrumb(evt.Message.Content ?? "<unknown>", "event.messageEdit", data: new Dictionary <string, string>() { { "channel", evt.Channel.Id.ToString() }, { "guild", evt.Channel.GuildId.ToString() }, { "message", evt.Message.Id.ToString() } }); scope.SetTag("shard", evt.Client.ShardId.ToString()); }
public void Enrich(Scope scope, Shard shard, MessageDeleteBulkEvent evt) { scope.AddBreadcrumb("", "event.messageDelete", data: new Dictionary <string, string>() { { "channel", evt.ChannelId.ToString() }, { "guild", evt.GuildId.ToString() }, { "messages", string.Join(",", evt.Ids) }, }); scope.SetTag("shard", shard.ShardInfo.ShardId.ToString()); }
public SentryLogger(OsuGame game) { if (!game.IsDeployedBuild) { return; } var options = new SentryOptions { Dsn = new Dsn("https://[email protected]/1255255"), Release = game.Version }; sentry = new SentryClient(options); sentryScope = new Scope(options); Exception lastException = null; Logger.NewEntry += entry => { if (entry.Level < LogLevel.Verbose) { return; } var exception = entry.Exception; if (exception != null) { if (!shouldSubmitException(exception)) { return; } // since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports. if (lastException != null && lastException.Message == exception.Message && exception.StackTrace.StartsWith(lastException.StackTrace, StringComparison.Ordinal)) { return; } lastException = exception; sentry.CaptureEvent(new SentryEvent(exception) { Message = entry.Message }, sentryScope); } else { sentryScope.AddBreadcrumb(DateTimeOffset.Now, entry.Message, entry.Target.ToString(), "navigation"); } }; }
public static void AddReactionAddedBreadcrumb(this Scope scope, Cacheable <IUserMessage, ulong> message, ISocketMessageChannel channel, SocketReaction reaction) { scope.AddBreadcrumb("", "event.reaction", data: new Dictionary <string, string>() { { "user", reaction.UserId.ToString() }, { "channel", channel.Id.ToString() }, { "guild", ((channel as IGuildChannel)?.GuildId ?? 0).ToString() }, { "message", message.Id.ToString() }, { "reaction", reaction.Emote.Name } }); }
public void Enrich(Scope scope, MessageReactionAddEventArgs evt) { scope.AddBreadcrumb("", "event.reaction", data: new Dictionary <string, string>() { { "user", evt.User.Id.ToString() }, { "channel", (evt.Channel?.Id ?? 0).ToString() }, { "guild", (evt.Channel?.GuildId ?? 0).ToString() }, { "message", evt.Message.Id.ToString() }, { "reaction", evt.Emoji.Name } }); scope.SetTag("shard", evt.Client.ShardId.ToString()); }
public void AddBreadcrumb_WithOptions_BoundOptionsLimit(int limit) { var options = Substitute.For <IScopeOptions>(); options.MaxBreadcrumbs.Returns(limit); var scope = new Scope(options); for (var i = 0; i < limit + 1; i++) { scope.AddBreadcrumb(i.ToString()); } Assert.Equal(limit, scope.InternalBreadcrumbs.Count); }
public SentryLogger(QsorBaseGame game) { if (DebugUtils.IsDebugBuild) { return; } var sentryOptions = new SentryOptions { Dsn = new Dsn("https://[email protected]/5193034"), Release = QsorBaseGame.Version }; _sentry = new SentryClient(sentryOptions); var sentryScope = new Scope(sentryOptions); Exception lastException = null; Logger.NewEntry += async entry => { if (entry.Level < LogLevel.Verbose) { return; } var exception = entry.Exception; if (exception != null) { if (lastException != null && // We shouldn't resubmit the same exception lastException.Message == exception.Message && exception.StackTrace?.StartsWith(lastException.StackTrace ?? string.Empty) == true) { return; } _sentry.CaptureEvent(new SentryEvent(exception) { Message = entry.Message }, sentryScope); lastException = exception; } else { sentryScope.AddBreadcrumb(DateTimeOffset.Now, entry.Message, entry.Target.ToString(), "qsor-logger"); } }; }
public void AddBreadcrumb() { const int limit = 5; var options = Substitute.For <IScopeOptions>(); options.MaxBreadcrumbs.Returns(limit); var scope = new Scope(options); for (var i = 0; i < limit + 1; i++) { scope.AddBreadcrumb(i.ToString(), "test"); } // Breadcrumb 0 is dropped Assert.Equal("1", scope.Breadcrumbs[0].Message); Assert.Equal("5", scope.Breadcrumbs[4].Message); }
// TODO: should this class take the Scope by dependency injection instead? // Would allow us to create a centralized "chain of handlers" where this class could just be registered as an entry in public void Enrich(Scope scope, int shardId, MessageCreateEvent evt) { scope.AddBreadcrumb(evt.Content, "event.message", data: new Dictionary <string, string> { { "user", evt.Author.Id.ToString() }, { "channel", evt.ChannelId.ToString() }, { "guild", evt.GuildId.ToString() }, { "message", evt.Id.ToString() } }); scope.SetTag("shard", shardId.ToString()); // Also report information about the bot's permissions in the channel // We get a lot of permission errors so this'll be useful for determining problems // todo: re-add this // var perms = _bot.PermissionsIn(evt.ChannelId); // scope.AddBreadcrumb(perms.ToPermissionString(), "permissions"); }
public void AddBreadcrumb_ValueTuple_AllArgumentsMatch() { const string expectedMessage = "original Message"; const string expectedCategory = "original Category"; const string expectedType = "original Type"; var expectedData = (key : "key", value : "value"); const BreadcrumbLevel expectedLevel = BreadcrumbLevel.Critical; _sut.AddBreadcrumb( expectedMessage, expectedCategory, expectedType, expectedData, expectedLevel); var actual = Assert.Single(_sut.InternalBreadcrumbs); Assert.Equal(expectedMessage, actual.Message); Assert.Equal(expectedCategory, actual.Category); Assert.Equal(expectedType, actual.Type); Assert.Equal(expectedData.key, actual.Data.Single().Key); Assert.Equal(expectedData.value, actual.Data.Single().Value); Assert.Equal(expectedLevel, actual.Level); }
public async Task HandleMessage(SocketMessage arg) { if (_client.GetShardFor((arg.Channel as IGuildChannel)?.Guild).ConnectionState != ConnectionState.Connected) { return; // Discard messages while the bot "catches up" to avoid unnecessary CPU pressure causing timeouts } RegisterMessageMetrics(arg); // Ignore system messages (member joined, message pinned, etc) var msg = arg as SocketUserMessage; if (msg == null) { return; } // Ignore bot messages if (msg.Author.IsBot || msg.Author.IsWebhook) { return; } // Add message info as Sentry breadcrumb _msg = msg; _sentryScope.AddBreadcrumb(msg.Content, "event.message", data: new Dictionary <string, string> { { "user", msg.Author.Id.ToString() }, { "channel", msg.Channel.Id.ToString() }, { "guild", ((msg.Channel as IGuildChannel)?.GuildId ?? 0).ToString() }, { "message", msg.Id.ToString() }, }); // We fetch information about the sending account *and* guild from the cache GuildConfig cachedGuild = default; // todo: is this default correct? if (msg.Channel is ITextChannel textChannel) { cachedGuild = await _cache.GetGuildDataCached(textChannel.GuildId); } var cachedAccount = await _cache.GetAccountDataCached(msg.Author.Id); // this ^ may be null, do remember that down the line int argPos = -1; // Check if message starts with the command prefix if (msg.Content.StartsWith("pk;", StringComparison.InvariantCultureIgnoreCase)) { argPos = 3; } else if (msg.Content.StartsWith("pk!", StringComparison.InvariantCultureIgnoreCase)) { argPos = 3; } else if (msg.Content != null && Utils.HasMentionPrefix(msg.Content, ref argPos, out var id)) // Set argPos to the proper value { if (id != _client.CurrentUser.Id) // But undo it if it's someone else's ping { argPos = -1; } } // If it does, try executing a command if (argPos > -1) { _logger.Verbose("Parsing command {Command} from message {Channel}-{Message}", msg.Content, msg.Channel.Id, msg.Id); // Essentially move the argPos pointer by however much whitespace is at the start of the post-argPos string var trimStartLengthDiff = msg.Content.Substring(argPos).Length - msg.Content.Substring(argPos).TrimStart().Length; argPos += trimStartLengthDiff; await _tree.ExecuteCommand(new Context(_services, msg, argPos, cachedAccount?.System)); } else if (cachedAccount != null) { // If not, try proxying anyway // but only if the account data we got before is present // no data = no account = no system = no proxy! try { await _proxy.HandleMessageAsync(cachedGuild, cachedAccount, msg); } catch (PKError e) { await arg.Channel.SendMessageAsync($"{Emojis.Error} {e.Message}"); } } }
public static void AddPeriodicBreadcrumb(this Scope scope) => scope.AddBreadcrumb("", "periodic");