Skip to content

Commit 638aaeb

Browse files
committed
Send Prometheus metrics
- all bot.Stats values - go runtime stats
1 parent 9d787cf commit 638aaeb

File tree

7 files changed

+147
-4
lines changed

7 files changed

+147
-4
lines changed

bot/config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ type Config struct {
3232

3333
BranchLookup VCS `mapstructure:"branch_lookup"`
3434

35+
// Metrics, like Prometheus
36+
Metrics Metrics `mapstructure:"metrics"`
37+
3538
OpenWeather OpenWeather `mapstructure:"open_weather"`
3639
PullRequest PullRequest `mapstructure:"pullrequest"`
3740
Timezone string `mapstructure:"timezone"`

bot/config/metrics.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package config
2+
3+
type Metrics struct {
4+
// e.g. use ":8082" to expose metrics on all interfaces
5+
PrometheusListener string `mapstructure:"prometheus_listener"`
6+
}

bot/listener.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func (b *Bot) startRunnables(ctx *util.ServerContext) {
2424
// Run is blocking method to handle new incoming events...from different sources
2525
func (b *Bot) Run(ctx *util.ServerContext) {
2626
b.startRunnables(ctx)
27+
initMetrics(b.config, ctx)
2728

2829
// initialize Socket Mode:
2930
// https://api.slack.com/apis/connections/socket

bot/metrics.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package bot
2+
3+
import (
4+
"github.com/innogames/slack-bot/v2/bot/config"
5+
"github.com/innogames/slack-bot/v2/bot/stats"
6+
"github.com/innogames/slack-bot/v2/bot/util"
7+
"github.com/prometheus/client_golang/prometheus"
8+
"github.com/prometheus/client_golang/prometheus/collectors"
9+
"github.com/prometheus/client_golang/prometheus/promhttp"
10+
log "github.com/sirupsen/logrus"
11+
"net/http"
12+
"strings"
13+
)
14+
15+
type statRegistry struct {
16+
}
17+
18+
// Describe returns all descriptions of the collector.
19+
func (c *statRegistry) Describe(ch chan<- *prometheus.Desc) {
20+
// unused in our simple case...
21+
}
22+
23+
// Collect returns the current state of all metrics of our slack-bot stats
24+
func (c *statRegistry) Collect(ch chan<- prometheus.Metric) {
25+
for _, key := range stats.GetKeys() {
26+
metric := prometheus.NewGauge(prometheus.GaugeOpts{
27+
Namespace: "slack_bot",
28+
Name: strings.ReplaceAll(key, "-", "_"),
29+
})
30+
value, _ := stats.Get(key)
31+
metric.Set(float64(value))
32+
metric.Collect(ch)
33+
}
34+
}
35+
36+
func initMetrics(cfg config.Config, ctx *util.ServerContext) {
37+
if cfg.Metrics.PrometheusListener == "" {
38+
return
39+
}
40+
41+
registry := prometheus.NewRegistry()
42+
registry.MustRegister(
43+
&statRegistry{},
44+
collectors.NewGoCollector(),
45+
)
46+
47+
go func() {
48+
ctx.RegisterChild()
49+
defer ctx.ChildDone()
50+
51+
log.Infof("Init prometheus handler on http://%s/metrics", cfg.Metrics.PrometheusListener)
52+
53+
server := &http.Server{Addr: cfg.Metrics.PrometheusListener}
54+
55+
http.Handle(
56+
"/metrics", promhttp.HandlerFor(
57+
registry,
58+
promhttp.HandlerOpts{},
59+
),
60+
)
61+
62+
go func() {
63+
server.ListenAndServe()
64+
}()
65+
66+
<-ctx.Done()
67+
server.Shutdown(ctx)
68+
}()
69+
}

bot/metrics_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package bot
2+
3+
import (
4+
"github.com/innogames/slack-bot/v2/bot/config"
5+
"github.com/innogames/slack-bot/v2/bot/stats"
6+
"github.com/innogames/slack-bot/v2/bot/util"
7+
8+
"github.com/stretchr/testify/assert"
9+
10+
"io"
11+
"net"
12+
"net/http"
13+
"testing"
14+
)
15+
16+
func TestMetrics(t *testing.T) {
17+
ctx := util.NewServerContext()
18+
defer ctx.StopTheWorld()
19+
20+
metricsPort := getPort()
21+
22+
cfg := config.Config{
23+
Metrics: config.Metrics{
24+
PrometheusListener: metricsPort,
25+
},
26+
}
27+
28+
stats.Set("test_value", 500)
29+
30+
initMetrics(cfg, ctx)
31+
32+
resp, err := http.Get("http://" + metricsPort + "/metrics")
33+
if err != nil {
34+
t.Fatal(err)
35+
}
36+
defer resp.Body.Close()
37+
38+
assert.Equal(t, 200, resp.StatusCode)
39+
40+
content, err := io.ReadAll(resp.Body)
41+
assert.Contains(t, string(content), "slack_bot_test_value 500")
42+
}
43+
44+
func getPort() string {
45+
l, _ := net.Listen("tcp", ":0")
46+
defer l.Close()
47+
48+
return l.Addr().String()
49+
}

go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/gookit/color v1.5.4
1414
github.com/hackebrot/turtle v0.2.0
1515
github.com/pkg/errors v0.9.1
16+
github.com/prometheus/client_golang v1.17.0
1617
github.com/redis/go-redis/v9 v9.2.1
1718
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
1819
github.com/robfig/cron/v3 v3.0.1
@@ -30,6 +31,7 @@ require (
3031

3132
require (
3233
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
34+
github.com/beorn7/perks v1.0.1 // indirect
3335
github.com/cespare/xxhash/v2 v2.2.0 // indirect
3436
github.com/davecgh/go-spew v1.1.1 // indirect
3537
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@@ -46,9 +48,13 @@ require (
4648
github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 // indirect
4749
github.com/jmespath/go-jmespath v0.4.0 // indirect
4850
github.com/magiconair/properties v1.8.7 // indirect
51+
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
4952
github.com/mitchellh/mapstructure v1.5.0 // indirect
5053
github.com/pelletier/go-toml v1.9.5 // indirect
5154
github.com/pmezard/go-difflib v1.0.0 // indirect
55+
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
56+
github.com/prometheus/common v0.44.0 // indirect
57+
github.com/prometheus/procfs v0.11.1 // indirect
5258
github.com/spf13/afero v1.10.0 // indirect
5359
github.com/spf13/cast v1.5.1 // indirect
5460
github.com/spf13/jwalterweatherman v1.1.0 // indirect
@@ -64,7 +70,6 @@ require (
6470
golang.org/x/time v0.3.0 // indirect
6571
google.golang.org/appengine v1.6.8 // indirect
6672
google.golang.org/protobuf v1.31.0 // indirect
67-
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
6873
gopkg.in/ini.v1 v1.67.0 // indirect
6974
gopkg.in/yaml.v2 v2.4.0 // indirect
7075
)

go.sum

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ github.com/aws/aws-sdk-go v1.45.26 h1:PJ2NJNY5N/yeobLYe1Y+xLdavBi67ZI8gvph6ftwVC
5656
github.com/aws/aws-sdk-go v1.45.26/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
5757
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
5858
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
59+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
60+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
5961
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
6062
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
6163
github.com/bndr/gojenkins v1.1.0 h1:TWyJI6ST1qDAfH33DQb3G4mD8KkrBfyfSUoZBHQAvPI=
@@ -255,7 +257,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
255257
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
256258
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
257259
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
258-
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
259260
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
260261
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
261262
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -272,6 +273,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
272273
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
273274
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
274275
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
276+
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
277+
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
275278
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
276279
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
277280
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -302,13 +305,21 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
302305
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
303306
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
304307
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
308+
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
309+
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
305310
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
306311
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
307312
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
313+
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
314+
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
308315
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
309316
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
317+
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
318+
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
310319
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
311320
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
321+
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
322+
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
312323
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
313324
github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg=
314325
github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
@@ -318,7 +329,7 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
318329
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
319330
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
320331
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
321-
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
332+
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
322333
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
323334
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
324335
github.com/sdomino/golang-scribble v0.0.0-20230717151034-b95d4df19aa8 h1:JRRoBVPTQF96yoE0NmIpQN4Si7Fb+Ls8Llw57BeBwwI=
@@ -737,7 +748,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
737748
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
738749
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
739750
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
740-
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
741751
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
742752
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
743753
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=

0 commit comments

Comments
 (0)