github.com/zerodha/fastglue-metrics
go get github.com/zerodha/fastglue-metrics

github.com/zerodha/fastglue-metrics

Prometheus Metrics exposed for Fastglue HTTP Handlers.

by zerodha

v1.0.0 (see all)License:MIT
go get github.com/zerodha/fastglue-metrics
Readme

fastglue-metrics

grafana-screenshot

Overview Go Reference Zerodha Tech

This package provides an abstraction to collect HTTP metrics from any Golang application using the package fastglue. It uses before-after middlewares to collect metrics about the request such as:

  • Count of HTTP requests.
  • Latency of each request.
  • Response size.

The metrics collection is inspired from RED principles of application monitoring. The components of this monitoring philosophy are:

  • Rate (the number of requests per second)
  • Errors (the number of those requests that are failing)
  • Duration (the amount of time those requests take)

All the metrics are grouped by the following labels:

  • status: (HTTP Status Code)
  • path: (Request URI)
  • method: (HTTP Method)

Usage

go get github.com/zerodha/fastglue-metrics

To start collecting metrics, simply initialise the metric exporter with:

package main

import (
    fastgluemetrics "github.com/zerodha/fastglue-metrics"
)

// Initialize fastglue.
g := fastglue.NewGlue()
// Initialise fastglue-metrics exporter.
exporter := fastgluemetrics.NewMetrics(g, fastgluemetrics.Opts{
    ExposeGoMetrics:       true,
    NormalizeHTTPStatus:   false,
    ServiceName: "dummy",
    MatchedRoutePathParam: g.MatchedRoutePathParam,
})
// Expose the registered metrics at `/metrics` path.
g.GET("/metrics", exporter.HandleMetrics)

Additional Options

You can configure options to configure the behaviour of exporter using fastgluemetrics.Opts. To see a fully working example, you can check examples/main.

Exporting Custom App Metrics

In case your app needs to export custom app related metrics, you can modify the following example.

// StatsManager is a struct that will hold your custom stats.
type StatsManager struct {
    Stats       map[string]int64
    ServiceName string
    sync.RWMutex
}

// NewStats returns an instance of StatsManager.
func NewStats(serviceName string) *StatsManager {
    if serviceName == "" {
        serviceName = "myapp"
    }

    return &StatsManager{
        Stats:       map[string]int64{},
        ServiceName: serviceName,
    }
}

// PromFormatter writes the value in prometheus format with the service name.
func (s *StatsManager) PromFormatter(b *bytes.Buffer, key string, val int64) {
    fmt.Fprintf(b, `%s{service="%s"} %d`, key, s.ServiceName, val)
    fmt.Fprintln(b)
}

// HandleMetrics returns a handler which exports stats.
func (app *App) HandleMetrics(g *fastglue.Fastglue) fastglue.FastRequestHandler {
    // Initialize the fastglue exporter
    exporter := fastgluemetrics.NewMetrics(g, fastgluemetrics.Opts{
        ExposeGoMetrics:       true,
        NormalizeHTTPStatus:   true,
        ServiceName:           "veto",
        MatchedRoutePathParam: g.MatchedRoutePathParam,
    })

    return func(r *fastglue.Request) error {
        app.Stats.RLock()
        defer app.Stats.RUnlock()

        buf := new(bytes.Buffer)

        // Write the metrics to the buffer
        exporter.Metrics.WritePrometheus(buf)
        metrics.WriteProcessMetrics(buf)

        for _, k := range sortedKeys(app.Stats.Stats) {
            // Format and write to the buffer
            app.Stats.PromFormatter(buf, fmt.Sprintf("count_%s", k), app.Stats.Stats[k])
        }

        return r.SendBytes(200, "text/plain; version=0.0.4", buf.Bytes())
    }
}

Configuration

metrics.Options takes in additional configurtion to customise the behaviour of exposition.

  • ServiceName: Unique identifier for the service name.

  • NormalizeHTTPStatus: If multiple status codes like 400,404,413 are present, setting this to true will make them group under their parent category i.e. 4xx.

  • ExposeGoMetrics: Setting this to true would expose various go_* and process_* metrics.

  • MatchedRoutePathParam: If the value is set, the path variable in metric label will be the one used while registering the handler. If the value is unset, the original request path is used.

The value is exposed by fastglue as Fastglue.MatchedRoutePathParam.

Notes

Label Cardinality

If your application has dynamic endpoints, which make use of the Named Params , you must set this value in order to keep label cardinality in check. If this value is not set, then a new metric will be created for each dynamic value of the named parameter, thus impacting the performance of downstream monitoring systems.

For example, for a route /orders/:userid/fetch, you don't want a million timeseries labels to be created for each user.fasthttprouter would set the value of matched path in ctx.UserValue with a key. This setting is the value of that key, which is exposed in fastglue package with the variable name: MatchedRoutePathParam.

Metrics Collection Library

This package uses VictoriaMetrics/metrics which is an extremely lightweight alternative to the official Prometheus client library. The official library pulls a lot of external dependencies and has complex features which are not really needed for this use case.

Besides being performant, VM/metrics has several improvements and optimisations on how a Histogram metric is constructed. For more details, you can read this blog post.

LICENSE

See LICENSE.

GitHub Stars

11

LAST COMMIT

8mos ago

MAINTAINERS

0

CONTRIBUTORS

4

OPEN ISSUES

0

OPEN PRs

0
VersionTagPublished
v1.0.0
8mos ago
No alternatives found
No tutorials found
Add a tutorial