docs/advanced-guide/publishing-custom-metrics/page.md
GoFr publishes some {% new-tab-link newtab=false title="default metrics" href="/docs/quick-start/observability" /%}.
GoFr can handle multiple different metrics concurrently, each uniquely identified by its name during initialization. It supports the following {% new-tab-link title="metrics" href="https://opentelemetry.io/docs/specs/otel/metrics/" /%} types in Prometheus format:
CounterUpDownCounterHistogramGaugeIf any custom metric is required, it can be created by using custom metrics as shown below:
Counter is a {% new-tab-link title="synchronous Instrument" href="https://opentelemetry.io/docs/specs/otel/metrics/api/#synchronous-instrument-api" /%} which supports non-negative increments.
package main
import (
"gofr.dev/pkg/gofr"
)
func main() {
// initialize gofr object
app := gofr.New()
app.Metrics().NewCounter("transaction_success", "used to track the count of successful transactions")
app.POST("/transaction", func(ctx *gofr.Context) (any, error) {
ctx.Metrics().IncrementCounter(ctx, "transaction_success")
return "Transaction Successful", nil
})
app.Run()
}
UpDownCounter is a {% new-tab-link title="synchronous Instrument" href="https://opentelemetry.io/docs/specs/otel/metrics/api/#synchronous-instrument-api" /%} which supports increments and decrements.
Note: If the value is monotonically increasing, use Counter instead.
package main
import (
"gofr.dev/pkg/gofr"
)
func main() {
// initialize gofr object
app := gofr.New()
app.Metrics().NewUpDownCounter("total_credit_day_sale", "used to track the total credit sales in a day")
app.POST("/sale", func(ctx *gofr.Context) (any, error) {
ctx.Metrics().DeltaUpDownCounter(ctx, "total_credit_day_sale", 1000)
return "Sale Completed", nil
})
app.Run()
}
Histogram is a {% new-tab-link title="synchronous Instrument" href="https://opentelemetry.io/docs/specs/otel/metrics/api/#synchronous-instrument-api" /%} which can be used to report arbitrary values that are likely to be statistically meaningful. It is intended for statistics such as histograms, summaries, and percentile.
package main
import (
"gofr.dev/pkg/gofr"
)
func main() {
// initialize gofr object
app := gofr.New()
app.Metrics().NewHistogram("transaction_time", "used to track the time taken by a transaction",
5, 10, 15, 20, 25, 35)
app.POST("/transaction", func(ctx *gofr.Context) (any, error) {
transactionStartTime := time.Now()
// transaction logic
tranTime := time.Now().Sub(transactionStartTime).Milliseconds()
ctx.Metrics().RecordHistogram(ctx, "transaction_time", float64(tranTime))
return "Transaction Completed", nil
})
app.Run()
}
Gauge is a {% new-tab-link title="synchronous Instrument" href="https://opentelemetry.io/docs/specs/otel/metrics/api/#synchronous-instrument-api" /%} which can be used to record non-additive value(s) when changes occur.
package main
import (
"gofr.dev/pkg/gofr"
)
func main() {
// initialize gofr object
app := gofr.New()
app.Metrics().NewGauge("product_stock", "used to track the number of products in stock")
app.POST("/sale", func(ctx *gofr.Context) (any, error) {
ctx.Metrics().SetGauge("product_stock", 10)
return "Sale Completed", nil
})
app.Run()
}
GoFr leverages metrics support by enabling labels. Labels are a key feature in metrics that allows us to categorize and filter metrics based on relevant information.
Labels are key-value pairs attached to metrics. They provide additional context about the metric data.
Common examples of labels include:
By adding labels, we can create different time series for the same metric based on the label values. This allows for more granular analysis and visualization in Grafana (or any other) dashboards.
By effectively using labels in GoFr, we can enrich your custom metrics and gain deeper insights into your application's performance and behavior.
Labels are added while populating the data for metrics, by passing them as arguments (comma separated key-value pairs)
in the GoFr's methods (namely: IncrementCounter, DeltaUpDownCounter, RecordHistogram, SetGauge).
Example: c.Metrics().IncrementCounter(c, "metric-name", "metric-value", "label-1", "value-1", "label-2", "value-2")
package main
import (
"gofr.dev/pkg/gofr"
)
func main() {
// Initialize gofr object
a := gofr.New()
// Add custom metrics
a.Metrics().NewUpDownCounter("total_credit_day_sale", "used to track the total credit sales in a day")
// Add all the routes
a.POST("/sale", SaleHandler)
a.POST("/return", ReturnHandler)
// Run the application
a.Run()
}
func SaleHandler(c *gofr.Context) (any, error) {
// logic to create sales
c.Metrics().DeltaUpDownCounter(c, "total_credit_day_sale", 10, "sale_type", "credit", "product_type", "beverage") // Here "sale_type" & "product_type" are the labels and "credit" & "beverage" are the values
return "Sale Successful", nil
}
func ReturnHandler(c *gofr.Context) (any, error) {
// logic to create a sales return
c.Metrics().DeltaUpDownCounter(c, "total_credit_day_sale", -5, "sale_type", "credit_return", "product_type", "dairy")
return "Return Successful", nil
}
Good To Know
While registering a metrics 2 key pieces of information of required:
- Name
- Description
When a registered metrics has to be used 3 key pieces of information are required:
- Name
- Value
- A set of key-value pairs called tags or labels.
A permutation of these key-value values provides the metric cardinality.
Lower the cardinality, faster the query performance and lower the monitoring resource utilization.
Check out the example on how to publish custom metrics in GoFr: Visit GitHub