diff --git a/CHANGELOG.md b/CHANGELOG.md index ff1aec5e..817b37c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -1.4.0-rc1 +1.4.0 > MAJOR PATCH @@ -16,7 +16,7 @@ To counteract this, the antiraid system constantly checks the rate of users join Of course, the antiraid system can be toggled and the trigger threshold values can be managed in the web interface *(if you have the `sp.guild.config.antiraid` permission)*. ![](https://i.imgur.com/vLMgrM9.png) -### Metrics Monitoring +### Metrics Monitoring [#170] You are now able to monitor core metrics of shinpuru using Prometheus and Grafana. @@ -30,7 +30,17 @@ metrics: [Here](https://github.com/zekroTJA/shinpuru/blob/master/config/prometheus/prometheus.yml) you can find an example Prometheus configuration and [here](https://github.com/zekroTJA/shinpuru/blob/master/config/grafana/example-dashboard.json) you can find an example grafana dashboard to monitor shinpuru's metrics. *Example dashboard. Data from shinpuru Canary instance.* -![](https://i.imgur.com/Srr8CwE.png) +![](https://i.imgur.com/fEkV7fe.png) + + +## Minor Updates + +- Add aliases to `karma` command: `leaderboard`, `lb`, `sb` and `top`. [#181] +- The `karma` command now shows the karma points of a user when specified as argument. [#179] + +## Bug Fixes + +- The web frontend route `/guilds/:guildid/guildadmin` now redirects to `/guilds/:guildid/guildadmin/antiraid` instead of firing errors. [#180] ## Backstage @@ -42,5 +52,5 @@ metrics: Pull the docker image of this release: ``` -$ docker pull zekro/shinpuru:1.4.0-rc1 +$ docker pull zekro/shinpuru:1.4.0 ``` \ No newline at end of file diff --git a/bughunters.md b/bughunters.md index e83e4034..bcde67e5 100644 --- a/bughunters.md +++ b/bughunters.md @@ -7,12 +7,12 @@ A list to honor all people who found some bugs, had some great ideas or contribu | [voxain](https://github.com/voxain) | [#52](https://github.com/zekroTJA/shinpuru/issues/52), [#61](https://github.com/zekroTJA/shinpuru/issues/61), [#67](https://github.com/zekroTJA/shinpuru/issues/67), [#147](https://github.com/zekroTJA/shinpuru/issues/147), [#148](https://github.com/zekroTJA/shinpuru/issues/148), [#150](https://github.com/zekroTJA/shinpuru/issues/150), [#153](https://github.com/zekroTJA/shinpuru/issues/153), [#159](https://github.com/zekroTJA/shinpuru/issues/159), [#163](https://github.com/zekroTJA/shinpuru/issues/163), [#165](https://github.com/zekroTJA/shinpuru/issues/165) | | `10` | | [SnowLeoo](https://github.com/SnowLeoo) | [#129](https://github.com/zekroTJA/shinpuru/issues/129), [#145](https://github.com/zekroTJA/shinpuru/issues/145), [#169](https://github.com/zekroTJA/shinpuru/issues/169) | [#175](https://github.com/zekroTJA/shinpuru/pull/175), [#176](https://github.com/zekroTJA/shinpuru/pull/176), [#178](https://github.com/zekroTJA/shinpuru/pull/178) | `9` | | [error2507](https://github.com/error2507) | [#28](https://github.com/zekroTJA/shinpuru/issues/28), [#29](https://github.com/zekroTJA/shinpuru/issues/29), [#55](https://github.com/zekroTJA/shinpuru/issues/55) | [#1](https://github.com/zekroTJA/shinpuru/pull/1), [#2](https://github.com/zekroTJA/shinpuru/pull/2) | `7` | +| [Ron31](https://github.com/Ron31) | | [#32](https://github.com/zekroTJA/shinpuru/pull/32), [#181](https://github.com/zekroTJA/shinpuru/pull/181) | `4` | | [Eli-Dev](https://github.com/Eli-Dev) | [#45](https://github.com/zekroTJA/shinpuru/issues/45), [#47](https://github.com/zekroTJA/shinpuru/issues/47), [#49](https://github.com/zekroTJA/shinpuru/issues/49) | | `3` | | [Not-Nik](https://github.com/Not-Nik) | [#53](https://github.com/zekroTJA/shinpuru/issues/53) | [#56](https://github.com/zekroTJA/shinpuru/pull/56) | `3` | | [InterXellar](https://github.com/InterXellar) | [#70](https://github.com/zekroTJA/shinpuru/issues/70), [#73](https://github.com/zekroTJA/shinpuru/issues/73), [#74](https://github.com/zekroTJA/shinpuru/issues/74) | | `3` | +| [Skillkiller](https://github.com/Skillkiller) | [#180](https://github.com/zekroTJA/shinpuru/issues/180) | [#79](https://github.com/zekroTJA/shinpuru/pull/79) | `3` | | [ShowMeYourSkil](https://github.com/ShowMeYourSkil) | [#140](https://github.com/zekroTJA/shinpuru/issues/140), [#171](https://github.com/zekroTJA/shinpuru/issues/171) | | `2` | -| [Ron31](https://github.com/Ron31) | | [#32](https://github.com/zekroTJA/shinpuru/pull/32) | `2` | -| [Skillkiller](https://github.com/Skillkiller) | | [#79](https://github.com/zekroTJA/shinpuru/pull/79) | `2` | | [nanderLP](https://github.com/nanderLP) | [#41](https://github.com/zekroTJA/shinpuru/issues/41) | | `1` | | [newtox](https://github.com/newtox) | [#57](https://github.com/zekroTJA/shinpuru/issues/57) | | `1` | | [anathemamask](https://github.com/anathemamask) | [#85](https://github.com/zekroTJA/shinpuru/issues/85) | | `1` | @@ -20,6 +20,7 @@ A list to honor all people who found some bugs, had some great ideas or contribu | [pavll](https://github.com/pavll) | [#108](https://github.com/zekroTJA/shinpuru/issues/108) | | `1` | | [Zoriot](https://github.com/Zoriot) | [#128](https://github.com/zekroTJA/shinpuru/issues/128) | | `1` | | [okrplay](https://github.com/okrplay) | [#162](https://github.com/zekroTJA/shinpuru/issues/162) | | `1` | +| [cloudybyte](https://github.com/cloudybyte) | [#179](https://github.com/zekroTJA/shinpuru/issues/179) | | `1` | --- diff --git a/config/grafana/example-dashboard.json b/config/grafana/example-dashboard.json index 64c36ae5..2b8bc6d8 100644 --- a/config/grafana/example-dashboard.json +++ b/config/grafana/example-dashboard.json @@ -16,6 +16,7 @@ "gnetId": null, "graphTooltip": 0, "id": 1, + "iteration": 1603793889972, "links": [], "panels": [ { @@ -23,7 +24,7 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "Prometheus", + "datasource": null, "fieldConfig": { "defaults": { "custom": {} @@ -33,8 +34,8 @@ "fill": 1, "fillGradient": 0, "gridPos": { - "h": 14, - "w": 24, + "h": 11, + "w": 12, "x": 0, "y": 0 }, @@ -57,8 +58,8 @@ }, "percentage": false, "pluginVersion": "7.2.2", - "pointradius": 1, - "points": true, + "pointradius": 2, + "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, @@ -66,7 +67,7 @@ "steppedLine": false, "targets": [ { - "expr": "rate(discord_eventtriggers_total[1m])", + "expr": "rate(discord_eventtriggers_total{job=\"$instance\"}[$interval])", "interval": "", "legendFormat": "{{event}}", "refId": "A" @@ -76,7 +77,7 @@ "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Discord Event Rate", + "title": "Discord Events Trigger Rate", "tooltip": { "shared": true, "sort": 0, @@ -118,35 +119,20 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "Prometheus", - "description": "", + "datasource": null, "fieldConfig": { "defaults": { - "custom": {}, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } + "custom": {} }, "overrides": [] }, "fill": 1, "fillGradient": 0, "gridPos": { - "h": 9, - "w": 8, - "x": 0, - "y": 14 + "h": 11, + "w": 12, + "x": 12, + "y": 0 }, "hiddenSeries": false, "id": 4, @@ -167,8 +153,8 @@ }, "percentage": false, "pluginVersion": "7.2.2", - "pointradius": 1, - "points": true, + "pointradius": 2, + "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, @@ -176,16 +162,109 @@ "steppedLine": false, "targets": [ { - "expr": "go_goroutines", - "instant": false, + "expr": "rate(restapi_requests_total{job=\"$instance\"}[$interval])", "interval": "", - "intervalFactor": 1, + "legendFormat": "{{method}} {{endpoint}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "REST API Request Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"$instance\"}", + "interval": "$interval", "legendFormat": "# goroutines", "refId": "A" }, { - "expr": "go_threads", - "interval": "", + "expr": "go_threads{job=\"$instance\"}", + "interval": "$interval", "legendFormat": "# threads", "refId": "B" } @@ -194,7 +273,7 @@ "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "# Goroutines", + "title": "# goroutines / threads", "tooltip": { "shared": true, "sort": 0, @@ -246,13 +325,13 @@ "fill": 1, "fillGradient": 0, "gridPos": { - "h": 9, - "w": 8, - "x": 8, - "y": 14 + "h": 8, + "w": 12, + "x": 12, + "y": 11 }, "hiddenSeries": false, - "id": 6, + "id": 8, "legend": { "avg": false, "current": false, @@ -270,8 +349,8 @@ }, "percentage": false, "pluginVersion": "7.2.2", - "pointradius": 1, - "points": true, + "pointradius": 2, + "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, @@ -279,28 +358,25 @@ "steppedLine": false, "targets": [ { - "expr": "go_memstats_sys_bytes/1024/1024", - "format": "time_series", - "instant": false, - "interval": "", - "intervalFactor": 1, - "legendFormat": "MiB sys", + "expr": "go_memstats_alloc_bytes{job=\"$instance\"}/1024/1024", + "interval": "$interval", + "legendFormat": "MiB alloc", "refId": "A" }, { - "expr": "go_memstats_alloc_bytes/1024/1024", - "interval": "", - "legendFormat": "MiB alloc", + "expr": "go_memstats_sys_bytes{job=\"$instance\"}/1024/1024", + "interval": "$interval", + "legendFormat": "MiB sys", "refId": "B" }, { - "expr": "go_memstats_heap_idle_bytes/1024/1024", - "interval": "", + "expr": "go_memstats_heap_idle_bytes{job=\"$instance\"}/1024/1024", + "interval": "$interval", "legendFormat": "MiB heap idle", "refId": "C" }, { - "expr": "go_memstats_heap_inuse_bytes/1024/1024", + "expr": "go_memstats_heap_alloc_bytes{job=\"$instance\"}/1024/1024", "interval": "", "legendFormat": "MiB heap inuse", "refId": "D" @@ -310,7 +386,7 @@ "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "MB Allocated RAM", + "title": "Panel Title", "tooltip": { "shared": true, "sort": 0, @@ -362,13 +438,13 @@ "fill": 1, "fillGradient": 0, "gridPos": { - "h": 9, - "w": 8, - "x": 16, - "y": 14 + "h": 8, + "w": 12, + "x": 0, + "y": 19 }, "hiddenSeries": false, - "id": 8, + "id": 10, "legend": { "avg": false, "current": false, @@ -386,8 +462,8 @@ }, "percentage": false, "pluginVersion": "7.2.2", - "pointradius": 1, - "points": true, + "pointradius": 2, + "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, @@ -395,9 +471,9 @@ "steppedLine": false, "targets": [ { - "expr": "discord_gatewayping", - "interval": "", - "legendFormat": "", + "expr": "discord_gatewayping{job=\"$instance\"}", + "interval": "$interval", + "legendFormat": "ms", "refId": "A" } ], @@ -405,7 +481,94 @@ "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Discord Gateway RTT", + "title": "Discord Gateway Ping RTT", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 19 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Panel Title", "tooltip": { "shared": true, "sort": 0, @@ -443,12 +606,117 @@ } } ], - "refresh": "5s", + "refresh": "", "schemaVersion": 26, "style": "dark", "tags": [], "templating": { - "list": [] + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "shinpuru-latest", + "value": "shinpuru-latest" + }, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "instance", + "options": [ + { + "selected": false, + "text": "shinpuru-latest", + "value": "shinpuru-latest" + }, + { + "selected": true, + "text": "shinpuru-canary", + "value": "shinpuru-canary" + } + ], + "query": "shinpuru-latest,shinpuru-canary", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "1m", + "value": "1m" + }, + "hide": 0, + "label": null, + "name": "interval", + "options": [ + { + "selected": true, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "1m,5m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] }, "time": { "from": "now-30m", @@ -456,7 +724,7 @@ }, "timepicker": {}, "timezone": "", - "title": "shinpuru-canary", - "uid": "azCXnptGk", - "version": 13 -} + "title": "shinpuru", + "uid": "Cn05HLpGk", + "version": 4 +} \ No newline at end of file diff --git a/internal/commands/cmdkarma.go b/internal/commands/cmdkarma.go index ae8bac6e..bfd86ff1 100644 --- a/internal/commands/cmdkarma.go +++ b/internal/commands/cmdkarma.go @@ -8,6 +8,7 @@ import ( "github.com/zekroTJA/shinpuru/internal/util" "github.com/zekroTJA/shinpuru/internal/util/static" "github.com/zekroTJA/shinpuru/pkg/discordutil" + "github.com/zekroTJA/shinpuru/pkg/fetch" "github.com/zekroTJA/shireikan" ) @@ -15,7 +16,7 @@ type CmdKarma struct { } func (c *CmdKarma) GetInvokes() []string { - return []string{"karma", "scoreboard"} + return []string{"karma", "scoreboard", "leaderboard", "lb", "sb", "top"} } func (c *CmdKarma) GetDescription() string { @@ -23,7 +24,8 @@ func (c *CmdKarma) GetDescription() string { } func (c *CmdKarma) GetHelp() string { - return "`karma` - Display karma scoreboard" + return "`karma` - Display karma scoreboard\n" + + "`karma ` - Display karma count of this user\n" } func (c *CmdKarma) GetGroup() string { @@ -45,6 +47,11 @@ func (c *CmdKarma) IsExecutableInDMChannels() bool { func (c *CmdKarma) Exec(ctx shireikan.Context) error { db, _ := ctx.GetObject("db").(database.Database) + userRes := ctx.GetArgs().Get(0).AsString() + if userRes != "" { + return c.userKarma(ctx, db, userRes) + } + karma, err := db.GetKarma(ctx.GetUser().ID, ctx.GetGuild().ID) if err != nil && err != database.ErrDatabaseNotFound { return err @@ -100,3 +107,25 @@ func (c *CmdKarma) Exec(ctx shireikan.Context) error { return util.SendEmbedRaw(ctx.GetSession(), ctx.GetChannel().ID, emb).Error() } + +func (c *CmdKarma) userKarma(ctx shireikan.Context, db database.Database, userRes string) error { + memb, err := fetch.FetchMember(ctx.GetSession(), ctx.GetGuild().ID, userRes) + if err != nil { + return err + } + + guildKarma, err := db.GetKarma(memb.User.ID, ctx.GetGuild().ID) + if err != nil { + return err + } + + globalKarma, err := db.GetKarmaSum(memb.User.ID) + if err != nil { + return err + } + + return util.SendEmbed(ctx.GetSession(), ctx.GetChannel().ID, + fmt.Sprintf("Guild Karma: **`%d`**\nGlobal Karma: **`%d`**", guildKarma, globalKarma), + memb.User.String()+"'s Karma Stats", 0). + Error() +} diff --git a/internal/core/middleware/commandstats.go b/internal/core/middleware/commandstats.go index 11b41db3..e6ff68b3 100644 --- a/internal/core/middleware/commandstats.go +++ b/internal/core/middleware/commandstats.go @@ -1,7 +1,9 @@ package middleware import ( + "github.com/prometheus/client_golang/prometheus" "github.com/zekroTJA/shinpuru/internal/util" + "github.com/zekroTJA/shinpuru/internal/util/metrics" "github.com/zekroTJA/shireikan" ) @@ -12,6 +14,11 @@ type CommandStatsMiddleware struct{} func (m *CommandStatsMiddleware) Handle( cmd shireikan.Command, ctx shireikan.Context, layer shireikan.MiddlewareLayer) (next bool, err error) { + invoke := cmd.GetInvokes()[0] + metrics.DiscordCommandsProcessed. + With(prometheus.Labels{"command": invoke}). + Add(1) + util.StatsCommandsExecuted++ return true, nil diff --git a/internal/core/webserver/handlers_metrics.go b/internal/core/webserver/handlers_metrics.go new file mode 100644 index 00000000..e2102533 --- /dev/null +++ b/internal/core/webserver/handlers_metrics.go @@ -0,0 +1,37 @@ +package webserver + +import ( + "strings" + + "github.com/prometheus/client_golang/prometheus" + routing "github.com/qiangxue/fasthttp-routing" + "github.com/zekroTJA/shinpuru/internal/util/metrics" +) + +func (ws *WebServer) handleMetrics(ctx *routing.Context) error { + method := strings.ToUpper(string(ctx.Method())) + endpoint := strings.ToLower(getUnparameterizedPath(ctx)) + + metrics.RestapiRequests. + With(prometheus.Labels{"endpoint": endpoint, "method": method}). + Add(1) + + return nil +} + +var urlParameterNames = []string{"id", "hexcode", "guildid", "backupid", "memberid"} + +func getUnparameterizedPath(ctx *routing.Context) string { + path := string(ctx.Path()) + + for _, paramName := range urlParameterNames { + paramValue := ctx.Param(paramName) + if paramValue == "" { + continue + } + + path = strings.ReplaceAll(path, paramValue, ":"+paramName) + } + + return path +} diff --git a/internal/core/webserver/webserver.go b/internal/core/webserver/webserver.go index 2acbab04..3a007227 100644 --- a/internal/core/webserver/webserver.go +++ b/internal/core/webserver/webserver.go @@ -144,7 +144,9 @@ func (ws *WebServer) registerHandlers() { // -------------------------------- // AVAILABLE WITHOUT AUTH - ws.router.Use(ws.addHeaders, ws.optionsHandler, ws.handlerFiles) + ws.router.Use( + ws.addHeaders, ws.optionsHandler, + ws.handlerFiles, ws.handleMetrics) imagestore := ws.router.Group("/imagestore") imagestore. diff --git a/internal/util/metrics/metrics.go b/internal/util/metrics/metrics.go index 34174683..0d91595e 100644 --- a/internal/util/metrics/metrics.go +++ b/internal/util/metrics/metrics.go @@ -4,22 +4,30 @@ import ( "net/http" "time" - "github.com/go-ping/ping" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/zekroTJA/shinpuru/internal/util" ) var ( DiscordEventTriggers = prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "discord_eventtriggers_total", - Help: "Total number of discord events triggered.", + Help: "Total number of Discord events triggered.", }, []string{"event"}) + DiscordCommandsProcessed = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "discord_commands_prcessed_total", + Help: "Total number of chat commands processed.", + }, []string{"command"}) + DiscordGatewayPing = prometheus.NewGauge(prometheus.GaugeOpts{ Name: "discord_gatewayping", Help: "The ping time in milliseconds to the discord API gateay.", }) + + RestapiRequests = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "restapi_requests_total", + Help: "Total number of HTTP requests processed.", + }, []string{"endpoint", "method"}) ) // MetricsServer wraps a simple HTTP server serving @@ -34,21 +42,14 @@ type MetricsServer struct { func NewMetricsServer(addr string) (ms *MetricsServer, err error) { prometheus.MustRegister( DiscordEventTriggers, - DiscordGatewayPing) + DiscordGatewayPing, + DiscordCommandsProcessed, + RestapiRequests) - pw, err := NewPingWatcher(30 * time.Second) + _, err = startPingWatcher(30 * time.Second) if err != nil { return } - pw.OnElapsed = func(p *ping.Statistics, err error) { - var v float64 - if err == nil && p != nil { - v = float64(p.AvgRtt.Milliseconds()) - } else if err != nil { - util.Log.Warningf("failed getting rtt to discord API: %s", err.Error()) - } - DiscordGatewayPing.Set(v) - } ms = new(MetricsServer) diff --git a/internal/util/metrics/ping.go b/internal/util/metrics/ping.go index 7a3d3c19..01ebf80c 100644 --- a/internal/util/metrics/ping.go +++ b/internal/util/metrics/ping.go @@ -1,6 +1,7 @@ package metrics import ( + "math" "time" "github.com/go-ping/ping" @@ -8,47 +9,22 @@ import ( const discordAPIendpoint = "gateway.discord.gg" -// PingWatcher detects the average round trip time -// to the discord API gateway endpoint in the given -// interval and saves it. -type PingWatcher struct { - pinger *ping.Pinger - ticker *time.Ticker - - LastRead *ping.Statistics - OnElapsed func(*ping.Statistics, error) -} - -// NewPingWatcher intializes a new PingWatcher instance -// and starts the watch timer with the given interval. -func NewPingWatcher(interval time.Duration) (pw *PingWatcher, err error) { - pw = new(PingWatcher) - - pw.pinger, err = ping.NewPinger(discordAPIendpoint) +func startPingWatcher(interval time.Duration) (pinger *ping.Pinger, err error) { + pinger, err = ping.NewPinger(discordAPIendpoint) if err != nil { return } - pw.pinger.SetPrivileged(true) - pw.pinger.Count = 3 - - pw.ticker = time.NewTicker(interval) - go pw.tickerWorker() - - return -} + pinger.SetPrivileged(true) + pinger.RecordRtts = false + pinger.Interval = interval + pinger.Timeout = time.Duration(math.MaxInt64) -func (pw *PingWatcher) tickerWorker() { - for { - go pw.recordPing() - <-pw.ticker.C + pinger.OnRecv = func(p *ping.Packet) { + DiscordGatewayPing.Set(float64(p.Rtt.Microseconds()) / 1000) } -} -func (pw *PingWatcher) recordPing() { - err := pw.pinger.Run() - pw.LastRead = pw.pinger.Statistics() - if pw.OnElapsed != nil { - pw.OnElapsed(pw.LastRead, err) - } + go pinger.Run() + + return } diff --git a/web/src/app/app-routing.module.ts b/web/src/app/app-routing.module.ts index 81147afb..5f442c64 100644 --- a/web/src/app/app-routing.module.ts +++ b/web/src/app/app-routing.module.ts @@ -44,6 +44,11 @@ const routes: Routes = [ path: 'guilds/:guildid/guildadmin/karma', component: GuildAdminKarmaComponent, }, + { + path: 'guilds/:guildid/guildadmin', + redirectTo: 'guilds/:guildid/guildadmin/antiraid', + pathMatch: 'full', + }, { path: 'guilds/:guildid/:memberid', component: MemberRouteComponent,