Go Prometheus Metrics Exporter
This challenge will guide you through creating a simple Go application that exposes custom Prometheus metrics. Understanding how to instrument your Go applications with metrics is crucial for monitoring their performance, health, and behavior in production environments.
Problem Description
You are tasked with building a basic Go web server that serves two custom Prometheus metrics:
app_requests_total: A counter that increments every time a request is made to a specific endpoint. This metric should have amethodlabel to distinguish between different HTTP methods (e.g., GET, POST).app_processing_time_seconds: A gauge that measures the duration of processing for requests. This metric should have astatuslabel to indicate success or failure (e.g., "success", "error").
The application should start an HTTP server on port 9090 that exposes these metrics at the /metrics endpoint, which is the standard for Prometheus exposition.
Key Requirements
- Use the
github.com/prometheus/client_golang/prometheuslibrary. - Define and register two custom metrics:
app_requests_total(counter) andapp_processing_time_seconds(gauge). - Implement an HTTP handler that increments the
app_requests_totalcounter and sets/updates theapp_processing_time_secondsgauge. - The HTTP server must listen on port
9090. - The
/metricsendpoint should be accessible to scrape by Prometheus. - Handle basic HTTP requests and simulate different processing outcomes (success/error) for the processing time metric.
Expected Behavior
When you run the application and send requests to the root path (/), the following should occur:
- The
app_requests_totalcounter should increase for each request, with themethodlabel reflecting the HTTP method used. - The
app_processing_time_secondsgauge should be updated with the processing time, with thestatuslabel indicating whether the simulated operation was successful or resulted in an error. - Accessing
http://localhost:9090/metricsshould display the current values of these metrics in Prometheus exposition format.
Edge Cases to Consider
- Graceful Shutdown: While not strictly required for this basic challenge, in a real-world scenario, you'd consider how to gracefully shut down the server and unregister metrics. For this problem, a simple
http.ListenAndServeis sufficient. - Error Handling: The application should ideally handle potential errors during server startup or request processing.
Examples
For this challenge, we'll focus on the metrics exposition, not complex request/response bodies.
Example 1: Basic Request
-
Run the Go application.
-
Send a GET request to
http://localhost:9090/:curl http://localhost:9090/
-
View the metrics at
http://localhost:9090/metrics:# HELP app_requests_total Total number of requests received. # TYPE app_requests_total counter app_requests_total{method="GET"} 1 # HELP app_processing_time_seconds Processing time for requests in seconds. # TYPE app_processing_time_seconds gauge app_processing_time_seconds{status="success"} 0.0123456789 # (Actual value will vary)
Explanation:
A GET request was made, incrementing app_requests_total{method="GET"} to 1. The processing time was recorded, and since it was a successful operation, app_processing_time_seconds{status="success"} was set to the measured duration.
Example 2: Multiple Requests and Simulated Error
-
Run the Go application.
-
Send a GET request to
http://localhost:9090/. -
Send a POST request to
http://localhost:9090/simulate-error. -
View the metrics at
http://localhost:9090/metrics:# HELP app_requests_total Total number of requests received. # TYPE app_requests_total counter app_requests_total{method="GET"} 1 app_requests_total{method="POST"} 1 # HELP app_processing_time_seconds Processing time for requests in seconds. # TYPE app_processing_time_seconds gauge app_processing_time_seconds{status="success"} 0.0123456789 # (Actual value from GET) app_processing_time_seconds{status="error"} 0.0567890123 # (Actual value will vary, associated with POST)
Explanation:
The initial GET request incremented its counter and set a success gauge. The POST request to /simulate-error incremented the POST counter and updated the error status gauge with its processing time. Note that the gauge for "success" might still hold its previous value until another successful request updates it, or it could be overwritten by a new successful request if the gauge has multiple labels and "success" is one of them. For this challenge, we'll assume the gauge for "success" remains until explicitly updated.
Constraints
- The application must run and expose metrics on port
9090. - The application should be implemented in Go.
- Use the
prometheus/client_golanglibrary. - Performance considerations are minimal for this challenge; focus on correctness of metric implementation.
Notes
- You'll need to import the
net/http,time, andgithub.com/prometheus/client_golang/prometheuspackages. - Consider using
prometheus.NewCounterVecandprometheus.NewGaugeVecto handle labels efficiently. - The
http.HandlerFuncis a good starting point for your request handler. - Remember to register your collectors with the default Prometheus registry (
prometheus.MustRegister). - For simulating processing time,
time.Now()andtime.Since()are your friends. - To test this, you can use
curlto send requests and thencurlagain to fetch the/metricsendpoint. You can also set up a local Prometheus instance to scrape this endpoint.