Hone logo
Hone
Problems

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:

  1. app_requests_total: A counter that increments every time a request is made to a specific endpoint. This metric should have a method label to distinguish between different HTTP methods (e.g., GET, POST).
  2. app_processing_time_seconds: A gauge that measures the duration of processing for requests. This metric should have a status label 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/prometheus library.
  • Define and register two custom metrics: app_requests_total (counter) and app_processing_time_seconds (gauge).
  • Implement an HTTP handler that increments the app_requests_total counter and sets/updates the app_processing_time_seconds gauge.
  • The HTTP server must listen on port 9090.
  • The /metrics endpoint 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_total counter should increase for each request, with the method label reflecting the HTTP method used.
  • The app_processing_time_seconds gauge should be updated with the processing time, with the status label indicating whether the simulated operation was successful or resulted in an error.
  • Accessing http://localhost:9090/metrics should 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.ListenAndServe is 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

  1. Run the Go application.

  2. Send a GET request to http://localhost:9090/:

    • curl http://localhost:9090/
  3. 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

  1. Run the Go application.

  2. Send a GET request to http://localhost:9090/.

  3. Send a POST request to http://localhost:9090/simulate-error.

  4. 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_golang library.
  • Performance considerations are minimal for this challenge; focus on correctness of metric implementation.

Notes

  • You'll need to import the net/http, time, and github.com/prometheus/client_golang/prometheus packages.
  • Consider using prometheus.NewCounterVec and prometheus.NewGaugeVec to handle labels efficiently.
  • The http.HandlerFunc is 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() and time.Since() are your friends.
  • To test this, you can use curl to send requests and then curl again to fetch the /metrics endpoint. You can also set up a local Prometheus instance to scrape this endpoint.
Loading editor...
go