Introduction
Metrics provide insights into the system's general performance and specific functionalities. They will also help monitor performance and health.
Effective system monitoring and optimization require detailed metrics. This article will teach you how to use metrics in your Rust application to enhance observability, identify and address performance bottlenecks and security issues, and optimize overall efficiency.
Some standard metrics are DB Read/Write speed, CPU, and RAM usage.
Metrics types
1. Counter
- Definition: A cumulative metric that represents a monotonically increasing value. Usually combined with other functions to give a value per X unit of time (Ex, seconds)
- Use Case: Counters help measure an event's total number of occurrences, such as the number of requests processed.
2. Gauge
- Definition: A metric representing a single numerical value that can go up or down.
- Use Case: Gauges are suitable for measuring fluctuating values, such as the current number of active connections or the available memory.
3. Histogram
- Definition: A metric that samples observations and counts them in configurable buckets.
- Use Case: Histograms help understand the distribution of values, like response times, allowing you to analyze performance across different percentiles.
Tooling for Metric Visualization: Grafana and Prometheus
While collecting metrics is crucial, visualizing and analyzing them is equally important. In the Rust ecosystem, two popular tools, Grafana and Prometheus, stand out for their robust metric visualization capabilities:
- Prometheus: A leading open-source monitoring solution, Prometheus excels at collecting, storing, and querying metric data. With its powerful query language, PromQL, and scalable architecture, Prometheus is well-suited for monitoring modern, dynamic environments.
- Grafana: Grafana complements Prometheus by providing rich visualization and dashboarding capabilities. Developers can create customizable dashboards to visualize metric data in real-time, enabling deep insights into application performance and behaviour.
By integrating Prometheus with metrics-rs and visualizing the collected data using Grafana, Rust developers can establish a comprehensive monitoring solution tailored to their specific requirements.
Libraries
OpenTelemetry metrics
This crate is the official implementation of Metrics for OpenTelemetry. It's very verbose. We have to use opentelemetry::metrics to instrument our app and then opentelemetry_otlp::metrics to export to Prometheus.
The Metrics API consists of these main components:
- MeterProvider is the API entry point. It provides access to Meters.
- Meter is the class responsible for creating Instruments.
- Instrument is accountable for reporting Measurements.
Rs-Metrics
In the Rust ecosystem, metrics-rs emerge as a powerful solution for instrumenting and collecting metrics within applications. Developed with simplicity, performance, and flexibility in mind, metrics-rs provides developers with a comprehensive toolkit for effortlessly integrating metrics into their Rust projects.
It has macros that make it very easy to use, and the documentation is very simple and straightforward.
It supports all the metrics we need, has default built-in exporters to Prometheus, and, considering it's widely used in the Rust community, there is a sea of examples and implementations from which to draw inspiration.
In this tutorial, we are going to use the metrics crate, which is easy to use and understand and doesn't require a lot of boilerplate.
Getting Started with metrics-rs
First, we need to add the metrics crate to our project. Quanta and Rand Crates are used to create a demo.
We will then create a new module called our_metrics.rs that will contain all our setup and configuration configuration. Doing it in a single place makes your code cleaner, and you can quickly know your application's metrics.
We will create a Metric struct in this module with a name and description as properties.
Using the previously created struct, we instantiate some dummy metrics we will use later in the demo.
Then, we will have three constants for each Metric type: COUNTERS, GAUGES and HISTOGRAMS, which will be an array of metrics. Think of these as buckets for each metric type.
At the end of the file, I like adding utilities that make registering the metrics accessible.
We then will have a function called init_metrics. This function should ideally be initialized as early as possible in your program. Its job is to initialize the metrics that we want to track.
This function essentially does the following:
- Initialize the Prometheus builder and configure options like the HTTP listener and the idle time out.
- We loop through each of the previously created arrays and register those metrics.
Your our_metrics.rs should look like the following after the previous steps:
Returning to our main.rs file, we import the init_metrics function in our primary function and call it to initialize the metrics.
To test that our setup works correctly, we will add some demo code that uses the previously created metrics and updates them.
Run cargo run and go to localhost:3000; you should see something like the following
Conclusion
Tracking these metrics will help to monitor the performance and health of your system and network. Using rs-metrics, we can easily capture and export these metrics to various monitoring tools.