From 47814d118c8b0d669ba5c1383f35055a24f31015 Mon Sep 17 00:00:00 2001 From: Adetokunbo Ige Date: Mon, 28 Oct 2024 13:58:26 -0700 Subject: [PATCH] feat: created dashboard for golang runtime metrics Signed-off-by: Adetokunbo Ige --- golang/README.md | 73 ++++++++++ golang/assets/os-threads-histogram.png | Bin 0 -> 25765 bytes golang/golang-prometheus.json | 179 +++++++++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 golang/README.md create mode 100644 golang/assets/os-threads-histogram.png create mode 100644 golang/golang-prometheus.json diff --git a/golang/README.md b/golang/README.md new file mode 100644 index 0000000..a86a42e --- /dev/null +++ b/golang/README.md @@ -0,0 +1,73 @@ +# Golang Runtime Metrics Dashboard - Prometheus + + +### OS Threads Histogram Panel +1. Tracks the number of goroutines currently in use by the application. +2. Tracks CGO calls, which indicate OS-level threads involvement if CGO is used. + +The code snippet below calculates the `go_goroutines_count` and `go_cgo_calls_count` + +![OS Threads Histogram](assets/os-threads-histogram.png) + +``` +package main + +import ( + "log" + "net/http" + "runtime" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +var ( + // Gauge for OS-level goroutines count + goRoutineCount = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "go_goroutines_count", + Help: "Number of goroutines currently managed by the Go runtime.", + }) + + // Counter for CGO calls (proxy for OS thread use when working with CGO) + cgoCallCount = prometheus.NewCounterFunc( + prometheus.CounterOpts{ + Name: "go_cgo_calls_count", + Help: "Number of CGO calls made by the Go runtime.", + }, + func() float64 { + return float64(runtime.NumCgoCall()) + }, + ) +) + +func initMetrics() { + // Register the goroutine count gauge + prometheus.MustRegister(goRoutineCount) + prometheus.MustRegister(cgoCallCount) +} + +func main() { + initMetrics() + + // Goroutine to periodically update goroutine count + go func() { + for { + goRoutineCount.Set(float64(runtime.NumGoroutine())) + time.Sleep(5 * time.Second) + } + }() + + // Expose metrics on port 2112 + http.Handle("/metrics", promhttp.Handler()) + log.Println("Starting server on :2112") + if err := http.ListenAndServe(":2112", nil); err != nil { + log.Fatalf("Failed to start server: %v", err) + } +} + +``` + +### Sections + +- os-threads-histogram \ No newline at end of file diff --git a/golang/assets/os-threads-histogram.png b/golang/assets/os-threads-histogram.png new file mode 100644 index 0000000000000000000000000000000000000000..d2c0918b2fa42158e60e1fa6365f03be795d8352 GIT binary patch literal 25765 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 OEHBw!EWdCk_J06