Monitor Aplikasi Golang Dengan Prometheus dan Grafana

Seperti yang sudah ditulis pada post sebelumnya, monitoring metrics dari server merupakan hal yang penting untuk menjaga reliability dari servicemu. Artikel ini akan menunjukkan basic-basic dalam memonitor sebuah aplikasi Golang. Tools yang akan digunakan adalah Prometheus dan Grafana.

Prometheus digunakan untuk men-scrape metrics dari aplikasi. Prometheus menyediakan client library untuk Go yang bisa kita gunakan, https://github.com/prometheus/client_golang. Setelah metrics berhasil di-scrape, kita gunakan Grafana untuk memvisualisasikannya. Ada banyak insight-insight yang bisa kita dapatkan dari metrics ini, seperti:

  • requests per second
  • error rate
  • average latency
  • dan lain-lain

Kita juga dapat membuat alert untuk memberitahu kalau ada metrics menunjukkan yang hal yang tidak diinginkan.

Pada post sebelumnya, saya sedikit menjelaskan tentang bagaimana cara kerja prometheus dan grafana. Dijelaskan juga sedikit tentang cara install dan memulai menggunakan prometheus dan grafana. Kalau kamu masih baru mengenal prometheus dan grafana, atau belum membaca post sebelumnya, coba baca dulu sebentar.

Metrics dan Labels

Data yang disimpan oleh prometheus diidentifikasikan dengan metric name. Setiap metrics memiliki key-value variable yang disebut labels. Satu contoh metrics yang akan kita buat adalah http_request_get_books_count dengan labels status untuk menyimpan status dari API. Metrics tersebut akan terlihat seperti ini ketika di-scrape:

# HELP http_request_get_books_count Number of get_books request.
# TYPE http_request_get_books_count counter
http_request_get_books_count{status="error"} 1
http_request_get_books_count{status="success"} 2

Labels sangat berguna untuk mem-filter dan meng-group data. Ini dapat kita gunakan untuk menganalisa metrics dan mengimprove system kita.

Cara Untuk Expose The Metrics

Kita perlu membuat sebuah HTTP endpoint agar prometheus bisa men-scrape metrics dari aplikasi kita. Prometheus sudah menyediakan fungsi handler nya. Kita tinggal menggunakannya di HTTP server kita.

package main

import (
	"net/http"

	"github.com/prometheus/client_golang/prometheus/promhttp"
)

func main() {

	http.Handle("/metrics", promhttp.Handler())
	
	// ...

	println("listening..")
	http.ListenAndServe(":5005", nil)
}

Coba akses ke /metrics servermu. Response yang akan didapatkan kira-kira seperti ini:

# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
go_threads 8
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 1
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0

Ini adalah metrics bawaan dari prometheus. Kita juga dapat membuat metrics kita sendiri menggunakan counter, gauge, atau metrics yang lebih komplex seperti summary atau histogram.

Cara Untuk Menggunakan Metrics Counter

Counter adalah metrics dasar yang digunakan untuk menghitung sebuah nilai. Nilai yang dihitung counter tidak bisa berkurang, hanya bertambah. Contoh penggunaan counter adalah untuk menghitung jumlah request yang masuk ke server. Berikut adalah contoh untuk mengitung metrics http_request_get_books_count dengan label status. Counter akan bertambah setiap kali endpoint kita di-hit.

// create a new counter vector
var getBookCounter = prometheus.NewCounterVec(
	prometheus.CounterOpts{
		Name: "http_request_get_books_count", // metric name
		Help: "Number of get_books request.",
	},
	[]string{"status"}, // labels
)

func init() {
    // must register counter on init
	prometheus.MustRegister(getBookCounter)
}


func bookHandler(w http.ResponseWriter, r *http.Request) {
	var status string
	defer func() {
        // increment the counter on defer func
		getBookCounter.WithLabelValues(status).Inc()
	}()

	books, err := getBooks(r.FormValue("category"))
	if err != nil {
		status = "error"
		w.Write([]byte("something's wrong: " + err.Error()))
		return
	}

	resp, err := json.Marshal(books)
	if err != nil {
		status = "error"
		w.Write([]byte("something's wrong: " + err.Error()))
		return
	}

	status = "success"
	w.Write(resp)
}

Berikut ini adalah contoh grafik yang dapat dibuat dengan grafana untuk memvisualisasikan metrics tersebut.

Request Per Second Graph

Ini adalah grafik request per second dari endpoint get_books yang di-group berdasarkan status. Query yang digunakan:

sum(rate(http_request_get_books_count{}[1m])) by (status)
Grafik Request Per Second

Grafik Request Per Second

Error Rate Graph

Ini adalah grafik error rate dari endpoint get_books. Query yang digunakan:

sum(rate(http_request_get_books_count{status="error"}[1m])) / sum(rate(http_request_get_books_count{}[1m]))
Grafik Error Rate Graph

Grafik Error Rate

Cara Menggunakan Histogram Untuk Mengukur Duration

Metrics penting lainnya yang biasa digunakan adalah API latency. Kita dapat menggunakan Histogram untuk mengukur latency dari API kita. Histogram mengukur durasi dari sebuah function dan menyimpannya dalam bucket-bucket yang bisa dikonfigurasi. Kita dapat mendapatkan quantile dari histogram dengan menggunakan fungsi histogram_quantile.

var getBookLatency = prometheus.NewHistogramVec(
	prometheus.HistogramOpts{
		Name:    "http_request_get_books_duration_seconds",
		Help:    "Latency of get_books request in second.",
		Buckets: prometheus.LinearBuckets(0.01, 0.05, 10),
	},
	[]string{"status"},
)

func init() {
	prometheus.MustRegister(getBookLatency)
}

func bookHandler(w http.ResponseWriter, r *http.Request) {
	var status string
	timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
		getBookLatency.WithLabelValues(status).Observe(v)
	}))
	defer func() {
		timer.ObserveDuration()
	}()

    // the rest of the function...
    

Gunakan histogram_quantile untuk mendapatkan quantile dari histogram.
Untuk quantile 0.95 querynya seperti ini:

histogram_quantile(0.95, rate(http_request_get_books_duration_seconds_bucket{status="success"}[1m]))

Untuk quantile 0.5 querynya seperti ini:

histogram_quantile(0.5, rate(http_request_get_books_duration_seconds_bucket{status="success"}[1m]))

Untuk mendapatkan durasi rata-rata querynya seperti ini:

rate(http_request_get_books_duration_seconds_sum{status="success"}[1m]) / rate(http_request_get_books_duration_seconds_count{status="success"}[1m])

Grafik yang dihasilkan akan seperti ini:

Grafik Histogram

Grafik Histogram

Yang menarik adalah ketika kita menggunakan histogram, prometheus juga membuat _count metrics secara otomatis. Sehingga kita tidak perlu membuat counter terpisah.

Kesimpulan

Ini adalah beberapa penggunaan metrics dasar dari prometheus yang dapat digunakan untuk memonitor aplikasi. Tapi ini pun sudah cukup untuk membuat system monitoring dan alerting yang dapat diandalkan. Ada lebih banyak metrics dan konfigurasi yang lebih komplex dari prometheus. Untuk Histogram sendiri, kamu mungkin perlu bereksperimen untuk menemukan konfigurasi bucket yang paling sesuai untuk aplikasimu.


See also