Golang engineering components: prometheus monitoring indicators of microservice toolset go-kit

In the microservice architecture, monitoring is a very important part. It can help developers discover and solve system problems in time, and improve system stability and reliability. In the go language, the go-kit framework provides prometheus monitoring indicators to facilitate users to monitor the running status of microservices.

This article will introduce how to use prometheus monitoring indicators in go-kit, and give some sample codes to help readers understand these concepts.

1. What is prometheus

prometheus is an open source monitoring system and time series database. It is widely used in the cloud-native field and can help developers collect and store various types of monitoring data, and provide rich query and visualization functions.

Prometheus uses the pull method to obtain monitoring data, that is, periodically obtains the data generated by the monitored object through HTTP requests, and stores it in the local time series database. At the same time, it also supports multiple ways to export data (such as Grafana, Alertmanager, etc.), which is convenient for developers to perform real-time analysis and early warning processing on the system.

2. Prometheus monitoring indicators in go-kit

go-kit provides the prometheus package to implement custom metrics. With this package, we can easily create various metrics (such as counters, histograms, etc.) and bind them with HTTP handlers, RPC services, etc.

Here is a sample code that demonstrates how to implement a custom counter using go-kit’s prometheus package:

// Create a measurer object.
var (
    requests = prometheus. NewCounter(
        prometheus. CounterOpts{
            Name: "example_requests_total",
            Help: "The total number of requests to the example service.",
        })
)

func main() {
    // Register the metric into the default registry.
    r := prometheus. NewRegistry()
    r. MustRegister(requests)

    // Create routes and middleware.
    r := mux. NewRouter()
    r.Use(promhttp.HandlerFor(r, promhttp.HandlerOpts{}).ServeHTTP)

    // Register service endpoint.
    svc := stringService{}
    e := endpoints. Endpoints{
        UppercaseEndpoint: endpoints. MakeUppercaseEndpoint(svc),
        CountEndpoint: endpoints. MakeCountEndpoint(svc),
    }

// Register the service endpoint with the router and update the counter value as the request is processed.
r.Path("/uppercase").Methods("GET").Handler(kithttp.NewServer(
e. UppercaseEndpoint,
decodeUppercaseRequest,
encodeResponse,
options...,
)).Before(countRequests)
r.Path("/count").Methods("POST").Handler(kithttp.NewServer(
e. CountEndpoint,
decodeCountRequest,
encodeResponse,
options...,
)).Before(countRequests)

// Start the HTTP server and expose monitoring metrics to Prometheus pull.
http.Handle("/metrics", promhttp.HandlerFor(r, promhttp.HandlerOpts{Registry: r}))
http.ListenAndServe(":8080", nil)
}

// Custom middleware for updating the counter value.
func countRequests(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        requests. Inc()
        next. ServeHTTP(w, r)
    })
}

In this example, we first create a counter object called requests . Then, we register it in the default prometheus registry and use the promhttp.HandlerFor method to expose monitoring metrics to Prometheus pulls.

Next, we create a custom middleware countRequests that updates the counter value every time a request is processed. Finally, we bind the service endpoint to the corresponding URL through the kithttp.NewServer method, and call the middleware before the request is processed.

3. prometheus metric type

In addition to counters, prometheus also provides a variety of metric types. Here are some common meter types and their brief descriptions:

  • Counter: An integer or floating point value that is incremented.
  • Histogram: Statistical data distribution, including sampling data, buckets, and cumulative values.
  • Summary: Similar to a histogram, but the summary only keeps samples with a fixed-size window.

Here is a sample code that demonstrates how to implement a custom histogram using go-kit’s prometheus package:

// Create a measurer object.
var (
    requestLatency = prometheus.NewHistogramVec(
        prometheus.HistogramOpts{
            Name: "example_request_latency_seconds",
            Help: "The latency of requests to the example service.",
            Buckets: []float64{0.1, 0.5, 1, 2.5, 5},
        },
        []string{"method", "path"},
    )
)

func main() {
    // Register the metric into the default registry.
    r := prometheus. NewRegistry()
    r.MustRegister(requestLatency)

    // Create routes and middleware.
    r := mux. NewRouter()
    r.Use(promhttp.HandlerFor(r, promhttp.HandlerOpts{}).ServeHTTP)

    // Register service endpoint.
    svc := stringService{}
    e := endpoints. Endpoints{
        UppercaseEndpoint: endpoints. MakeUppercaseEndpoint(svc),
        CountEndpoint: endpoints. MakeCountEndpoint(svc),
    }

// Register the service endpoint with the router and update the histogram data when processing the request.
r.Path("/uppercase").Methods("GET").Handler(kithttp.NewServer(
e. UppercaseEndpoint,
decodeUppercaseRequest,
encodeResponse,
options...,
)).Before(recordRequestLatency("GET", "/uppercase"))
r.Path("/count").Methods("POST").Handler(kithttp.NewServer(
e. CountEndpoint,
decodeCountRequest,
encodeResponse,
options...,
)).Before(recordRequestLatency("POST", "/count"))

// Start the HTTP server and expose monitoring metrics to Prometheus pull.
http.Handle("/metrics", promhttp.HandlerFor(r, promhttp.HandlerOpts{Registry: r}))
http.ListenAndServe(":8080", nil)
}

// Custom middleware, used to record the response time of the request.
func recordRequestLatency(method, path string) Middleware {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            start := time. Now()
            next. ServeHTTP(w, r)
            requestLatency.WithLabelValues(method, path).Observe(time.Since(start).Seconds())
        })
    }
}

In this example, we create a histogram object called requestLatency and define its bucket ranges using prometheus.HistogramOpts . Then, we register it in the default prometheus registry and use the promhttp.HandlerFor method to expose monitoring metrics to Prometheus pulls.

Next, we created a custom middleware recordRequestLatency to record the response time of the request. Finally, we bind the service endpoint to the corresponding URL through the kithttp.NewServer method, and call the middleware before the request is processed.

4. Summary

The prometheus monitoring system is a very popular solution in the cloud native field. The go-kit framework provides the prometheus package to support users to implement custom metrics, which is convenient for developers to monitor the running status of microservices. This article briefly introduces how to use prometheus to monitor indicators in go-kit, and gives sample code as a reference.