Build a Prometheus Metrics Exporter
Build a Go HTTP server that exposes custom Prometheus metrics.
Introduction
30 Second Summary
Every production application needs a way to report its health. Think of it like a car dashboard showing speed, fuel level, and engine temperature. Without those signals, you are driving blind.
In this project, you will build a custom Prometheus metrics exporter in Go. This is an HTTP server that generates application metrics (request counts, error rates, response latencies) and exposes them for monitoring tools to scrape.
What You'll Build
A Go HTTP server that simulates application traffic and exposes custom Prometheus metrics (counters, gauges, histograms) at a /metrics endpoint.
By the end of this project, you'll have:
- A working Go module with an HTTP server exposing Prometheus-compatible metrics you can curl from your terminal.
- Hands-on understanding of Go fundamentals (structs, interfaces, goroutines, HTTP handlers) you can confidently explain in an interview.
- A background goroutine simulating traffic, demonstrating Go concurrency patterns in action.
- Secret Mission: Implement a custom Collector interface to expose dynamic system metrics, the same pattern used in production CNCF exporters.
Are there any prerequisites?
You need a Linux machine with a terminal. Go may already be installed on your system. The first step includes verification and setup instructions if you need them.
Verify Go and Create the Project
Before writing any Go code, you need a properly initialized project. In Go, every project lives inside a module that tracks your code's identity and its dependencies.
In this step, you will confirm Go is ready to use, create your project folder, and pull in the Prometheus client library that powers the metrics exporter.
In this step, get ready to:
- Confirm Go is installed and ready.
- Create and initialize a Go module for the exporter.
- Add the Prometheus client library as a dependency.
Confirm Go is installed
Your exporter is written in Go, so you need the Go toolchain available in your terminal. A quick version check confirms everything is in place.
- Confirm Go is available by running this command:
go version
You should see output in the format go version go1.X.Y linux/amd64. Any version 1.22 or higher works for this project.
Command not found?
If your terminal does not recognize go, Go is not installed or not on your PATH. Download the latest release from https://go.dev/dl/ and follow the Linux instructions: download the tarball, extract to /usr/local/go, and add /usr/local/go/bin to your PATH.
After installing, open a new terminal session and run go version again to confirm.
help me install Go on my Linux machine
Create the project directory and initialize a Go module
A Go module is a collection of packages with a go.mod file at its root. The go.mod file declares your module's name and tracks every dependency your code needs.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir prom-exporter && cd prom-exporter
- Initialize a new Go module by running this command:
go mod init github.com/utkarsh/prom-exporter
What do these commands do?
- mkdir prom-exporter creates a new folder called prom-exporter on your Desktop.
- cd prom-exporter moves your terminal into that folder.
- go mod init github.com/utkarsh/prom-exporter creates a go.mod file that names your module. This path becomes the import prefix for all packages in the project.
- Confirm the go.mod file was created by running:
ls
You should see go.mod listed in the output.
Don't see go.mod?
Make sure you ran go mod init from inside the prom-exporter directory. Run pwd to check your current location. It should end with /prom-exporter.
help me figure out why go mod init did not create a go.mod file
Add the Prometheus client library
The Prometheus client library for Go provides the types and functions you need to define metrics, register them, and serve them over HTTP. It is the same library used by Prometheus itself, Thanos, and most CNCF observability tooling.
- Add the Prometheus client library to your module by running this command:
go get github.com/prometheus/client_golang@v1.23.2
What does this command do?
go get downloads a dependency and records it in your go.mod file. The @v1.23.2 suffix pins the version so everyone building this project gets the same code.
It also creates a go.sum file that stores checksums for every downloaded module. This ensures your dependencies have not been tampered with.
- Verify the dependency was recorded by running:
cat go.mod
You should see your module name on the first line and a require line referencing github.com/prometheus/client_golang v1.23.2.
Don't see the dependency in go.mod?
If go get failed with a network error, check your internet connection and try again. If you see a version mismatch error, make sure you typed the version exactly as @v1.23.2.
help me troubleshoot why go get failed to download the Prometheus client library
✔️ Awesome, I've got everything!
Great. Double check you see both go.mod and go.sum in your prom-exporter directory, then move on to the next step.
ⓧ I'd like to double check the full code
Your go.mod should look like this:
module github.com/utkarsh/prom-exporter
go 1.22
require github.com/prometheus/client_golang v1.23.2
What if my go version line is different?
The go line reflects the Go version you have installed. If yours says go 1.24 or go 1.26 instead of go 1.22, that is perfectly fine. You may also see additional require lines for indirect dependencies. That is normal.
Your project skeleton is ready. Next up, you will write the HTTP server and define your first custom Prometheus metrics.
Build the HTTP Server with Custom Metrics
Your Go module is initialized and the Prometheus client library is ready to use.
Now it's time to write the actual server code. You'll define three custom metrics, wire up HTTP routes, and handle incoming requests. By the end of this step, you'll have a compiling Go program that knows how to serve /metrics in Prometheus format.
In this step, get ready to:
- Define three Prometheus metrics (Counter, Gauge, Histogram).
- Write the main() function to register metrics and start the server.
- Write the /api handler to update metrics on each request.
Define the metrics as package-level variables
Prometheus has three core metric types, each suited for a different kind of measurement. A Counter only goes up (total requests served). A Gauge goes up and down (current active connections). A Histogram tracks the distribution of values across buckets (response latency).
- Create a file called main.go inside your prom-exporter folder by running:
touch main.go
- Confirm the file exists by running:
ls
You should see go.mod, go.sum, and main.go in the output.
- Open main.go in your text editor and paste the following code that sets up the package, imports, and metric definitions:
package main
import (
"log"
"math/rand"
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Metrics - defined as package-level variables
var (
// Counter: tracks total requests, labeled by method and status
requestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "prom_exporter_requests_total",
Help: "Total number of HTTP requests processed.",
},
[]string{"method", "status"},
)
// Gauge: tracks current active connections (can go up and down)
activeConnections = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "prom_exporter_active_connections",
Help: "Number of currently active connections.",
},
)
// Histogram: tracks request duration distribution
requestDuration = prometheus.NewHistogram(
prometheus.HistogramOpts{
Name: "prom_exporter_request_duration_seconds",
Help: "Histogram of request durations in seconds.",
Buckets: prometheus.DefBuckets,
},
)
)
What does this code do?
The import block pulls in Go's standard library packages (log, math/rand, net/http, time) plus the Prometheus client packages you installed in Step 1.
The var (...) block defines three metrics as package-level variables. prometheus.NewCounterVec() creates a Counter with labels so you can track requests by HTTP method and status code separately. prometheus.NewGauge() creates a Gauge for values that go up and down. prometheus.NewHistogram() creates a Histogram that automatically sorts values into buckets for distribution analysis.
In Go, CounterOpts, GaugeOpts, and HistogramOpts are structs. Structs are value types with named fields. You are using struct literals here to configure each metric.
- Save main.go.
You won't see a change yet. The next section adds main() which brings everything together.
Write the main function
The main() function is Go's entry point. It registers your metrics with Prometheus, sets up HTTP routes, and starts the server.
- In main.go, add the following main() function below the closing ) of your var block:
func main() {
// Register metrics with the default Prometheus registry
prometheus.MustRegister(requestsTotal)
prometheus.MustRegister(activeConnections)
prometheus.MustRegister(requestDuration)
// HTTP routes
http.HandleFunc("/api", apiHandler)
http.Handle("/metrics", promhttp.Handler())
log.Println("Starting metrics server on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
What does this code do?
prometheus.MustRegister() adds each metric to Prometheus's default registry. Once registered, Prometheus knows to include these metrics whenever /metrics is scraped.
http.HandleFunc("/api", apiHandler) routes requests hitting /api to a function you'll write next. http.Handle("/metrics", promhttp.Handler()) hooks up Prometheus's built-in handler that serializes all registered metrics into Prometheus text format.
promhttp.Handler() returns an http.Handler interface. This is Go interfaces in action: any type with a ServeHTTP(ResponseWriter, *Request) method satisfies http.Handler. Go uses implicit interface satisfaction, so you never declare that you implement an interface.
- Save main.go.
You won't see a change yet. The next section adds the apiHandler function that main() references.
Write the API handler function
The apiHandler function is what runs every time someone hits /api. It measures how long the request takes, increments the counter, and records the duration in the histogram.
- In main.go, add the following function below your main() function:
// apiHandler handles requests to /api and updates metrics
func apiHandler(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Simulate some work
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
// Update metrics
requestsTotal.WithLabelValues(r.Method, "200").Inc()
requestDuration.Observe(time.Since(start).Seconds())
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK\n"))
}
What does this code do?
The function signature func apiHandler(w http.ResponseWriter, r *http.Request) is the standard Go HTTP handler pattern. Every HTTP handler in Go receives a ResponseWriter to write back and a *Request with details about the incoming request.
time.Now() captures the start time. time.Since(start).Seconds() measures elapsed time in seconds, which the histogram records with .Observe().
requestsTotal.WithLabelValues(r.Method, "200").Inc() increments the counter for a specific label combination. If you curl the endpoint, r.Method will be GET and the status will be 200.
- Save main.go.
- Confirm the code compiles by running:
go build .
If there are no errors, the command returns silently. This means your code is syntactically correct and all dependencies resolved.
Seeing a compile error?
- Check for mismatched braces or missing commas in your struct literals. Each field inside CounterOpts{}, GaugeOpts{}, or HistogramOpts{} needs a trailing comma.
- Make sure apiHandler is spelled exactly the same in the http.HandleFunc call and in the function definition. Go is case-sensitive.
- Verify all import paths are present. If you removed an import that the code uses, the compiler will tell you exactly which package is missing.
Help me fix a Go compile error in my Prometheus exporter project.
✔️ Awesome, I've got everything!
Great. Double check you've saved main.go and you're ready to move on.
ⓧ I'd like to double check the full code
Here is the complete main.go as it should look at this point:
package main
import (
"log"
"math/rand"
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Metrics - defined as package-level variables
var (
// Counter: tracks total requests, labeled by method and status
requestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "prom_exporter_requests_total",
Help: "Total number of HTTP requests processed.",
},
[]string{"method", "status"},
)
// Gauge: tracks current active connections (can go up and down)
activeConnections = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "prom_exporter_active_connections",
Help: "Number of currently active connections.",
},
)
// Histogram: tracks request duration distribution
requestDuration = prometheus.NewHistogram(
prometheus.HistogramOpts{
Name: "prom_exporter_request_duration_seconds",
Help: "Histogram of request durations in seconds.",
Buckets: prometheus.DefBuckets,
},
)
)
func main() {
// Register metrics with the default Prometheus registry
prometheus.MustRegister(requestsTotal)
prometheus.MustRegister(activeConnections)
prometheus.MustRegister(requestDuration)
// HTTP routes
http.HandleFunc("/api", apiHandler)
http.Handle("/metrics", promhttp.Handler())
log.Println("Starting metrics server on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
// apiHandler handles requests to /api and updates metrics
func apiHandler(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Simulate some work
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
// Update metrics
requestsTotal.WithLabelValues(r.Method, "200").Inc()
requestDuration.Observe(time.Since(start).Seconds())
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK\n"))
}
Your server compiles cleanly. Next up, you'll add a background goroutine that simulates live traffic so your metrics always have data to show.
Add a Background Goroutine for Simulated Traffic
Your server compiles and has three metrics registered. Right now those metrics sit at zero because nothing is generating data.
In this step, you will write a background function that continuously simulates traffic and wire it into your server using a goroutine. When you hit /metrics afterwards, you will see live, updating values.
In this step, get ready to:
- Write a simulateTraffic() function that randomly updates metrics.
- Launch it as a goroutine in main().
- Run the server and verify metrics with curl.
Write the simulateTraffic function
Your server needs a source of fake data so the metrics have something interesting to report. The simulateTraffic function will run in an infinite loop, randomly setting the active connections gauge and observing latency values on the histogram.
- In main.go, scroll to the bottom of the file (below the apiHandler function) and add the following function:
// simulateTraffic runs in a goroutine and generates fake metric data
func simulateTraffic() {
for {
// Randomly adjust active connections
connections := rand.Float64() * 100
activeConnections.Set(connections)
// Simulate request latencies
latency := rand.Float64() * 0.5
requestDuration.Observe(latency)
// Sleep between 1-3 seconds
time.Sleep(time.Duration(1+rand.Intn(2)) * time.Second)
}
}
What does this code do?
This function runs forever inside a for {} loop. Each iteration does three things:
- activeConnections.Set(connections) picks a random number between 0 and 100 and sets the Gauge to that value. Unlike a Counter, a Gauge can go up and down.
- requestDuration.Observe(latency) feeds a random value (0 to 0.5 seconds) into the Histogram. Prometheus automatically sorts observations into buckets.
- time.Sleep(...) pauses for 1 to 3 seconds so the metrics update at a realistic pace.
You will not see a change yet. The next substep wires this function into main() so it actually runs.
Launch the goroutine in main
A goroutine is a lightweight thread managed by the Go runtime. You launch one with the go keyword. Your simulateTraffic function will run concurrently alongside the HTTP server.
- In main.go, find the three prometheus.MustRegister(...) lines inside main(). Find this line immediately after them:
// HTTP routes
- Add these two lines directly above the // HTTP routes comment, so the section now looks like this:
// Start background traffic simulation
go simulateTraffic()
// HTTP routes
http.HandleFunc("/api", apiHandler)
http.Handle("/metrics", promhttp.Handler())
What does go simulateTraffic() do?
The go keyword launches simulateTraffic() as a separate goroutine. The main goroutine continues on to start the HTTP server. Both run concurrently from this point forward.
This is how Go handles concurrency without threads or async/await. The Go scheduler multiplexes goroutines onto OS threads for you.
- Save main.go.
- Confirm the code compiles by running:
go build .
If the command returns without output, your code is valid.
Seeing a compile error?
- Check that simulateTraffic is spelled the same in both the function definition and the go simulateTraffic() call. Go is case-sensitive.
- Make sure go simulateTraffic() is inside the main() function body (between its opening and closing braces), not at the package level.
Ask for help: Why is my Go code failing to compile after adding simulateTraffic?
✔️ Awesome, I've got everything!
Great. Double check you have saved main.go before moving on.
ⓧ I'd like to double check the full code
package main
import (
"log"
"math/rand"
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Metrics - defined as package-level variables
var (
// Counter: tracks total requests, labeled by method and status
requestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "prom_exporter_requests_total",
Help: "Total number of HTTP requests processed.",
},
[]string{"method", "status"},
)
// Gauge: tracks current active connections (can go up and down)
activeConnections = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "prom_exporter_active_connections",
Help: "Number of currently active connections.",
},
)
// Histogram: tracks request duration distribution
requestDuration = prometheus.NewHistogram(
prometheus.HistogramOpts{
Name: "prom_exporter_request_duration_seconds",
Help: "Histogram of request durations in seconds.",
Buckets: prometheus.DefBuckets,
},
)
)
func main() {
// Register metrics with the default Prometheus registry
prometheus.MustRegister(requestsTotal)
prometheus.MustRegister(activeConnections)
prometheus.MustRegister(requestDuration)
// Start background traffic simulation
go simulateTraffic()
// HTTP routes
http.HandleFunc("/api", apiHandler)
http.Handle("/metrics", promhttp.Handler())
log.Println("Starting metrics server on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
// apiHandler handles requests to /api and updates metrics
func apiHandler(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Simulate some work
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
// Update metrics
requestsTotal.WithLabelValues(r.Method, "200").Inc()
requestDuration.Observe(time.Since(start).Seconds())
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK\n"))
}
// simulateTraffic runs in a goroutine and generates fake metric data
func simulateTraffic() {
for {
// Randomly adjust active connections
connections := rand.Float64() * 100
activeConnections.Set(connections)
// Simulate request latencies
latency := rand.Float64() * 0.5
requestDuration.Observe(latency)
// Sleep between 1-3 seconds
time.Sleep(time.Duration(1+rand.Intn(2)) * time.Second)
}
}
Run the server and test your metrics
Time to see it all working. You will start the server, then use curl in a second terminal to inspect the output.
- Start the server by running:
go run main.go
You should see the log message: Starting metrics server on :8080.
- Open a second terminal window. Check that the metrics endpoint is returning Prometheus-formatted text by running:
curl localhost:8080/metrics
You should see lines starting with prom_exporter_requests_total, prom_exporter_active_connections, and prom_exporter_request_duration_seconds. The active connections value will be a number between 0 and 100.
- Test the API endpoint by running:
curl localhost:8080/api
You should see OK printed in the terminal.
- Hit the /api endpoint a few more times, then check /metrics again:
curl localhost:8080/api
curl localhost:8080/api
curl localhost:8080/metrics
The prom_exporter_requests_total counter should now show a value matching the number of times you hit /api.
What should I see in the metrics output?
Prometheus metrics follow a plain-text format. Each metric has a # HELP line, a # TYPE line, and then data lines with the metric name and value.
The histogram produces multiple lines: one for each bucket (labeled with le), plus _sum and _count lines. This is how Prometheus calculates percentiles later.
Not seeing your custom metrics?
- Make sure you are running curl in a separate terminal from the one running the server. The server blocks that terminal.
- If you see Connection refused, the server may not have started. Check the first terminal for error messages.
- If metrics appear but your custom ones are missing, confirm that prometheus.MustRegister is called for all three metrics in main().
Ask for help: Why is curl not showing my custom Prometheus metrics at localhost:8080/metrics?
Your exporter is now producing live data. Next up, you will practice explaining every section of this code out loud so you can walk through it confidently in your interview.
Practice Explaining the Code
Your metrics server is running, your custom metrics are updating, and you can prove it all with curl. The code works.
But writing code is only half the interview. You need to explain every pattern in this project confidently when your interviewer says "walk me through your code." In this step, you will practice articulating the Go fundamentals and Prometheus data model embedded in your exporter.
In this step, get ready to:
- Practice explaining the three Prometheus metric types in your code.
- Practice explaining Go patterns: structs, interfaces, goroutines, and error handling.
- Rehearse a full "walk me through your project" answer.
Explain the Prometheus metric types
An interviewer will want to know why you chose specific metric types. Each one serves a distinct purpose in the Prometheus data model.
- Open main.go in your editor and scroll to the var block at the top.
- Read each metric definition out loud, then practice the explanation below it.
Start with the Counter:
// Counter: tracks total requests, labeled by method and status
requestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "prom_exporter_requests_total",
Help: "Total number of HTTP requests processed.",
},
[]string{"method", "status"},
)
Practice saying:
Counter explanation
"This creates a Counter metric. A Counter only goes up, like counting total requests. CounterVec means it has labels, so we can track requests by HTTP method and status code separately."
Next, the Gauge:
// Gauge: tracks current active connections (can go up and down)
activeConnections = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "prom_exporter_active_connections",
Help: "Number of currently active connections.",
},
)
Practice saying:
Gauge explanation
"This is a Gauge. Unlike a Counter, a Gauge can go up and down. I use it for active connections because connections come and go."
Finally, the Histogram:
// Histogram: tracks request duration distribution
requestDuration = prometheus.NewHistogram(
prometheus.HistogramOpts{
Name: "prom_exporter_request_duration_seconds",
Help: "Histogram of request durations in seconds.",
Buckets: prometheus.DefBuckets,
},
)
Practice saying:
Histogram explanation
"This is a Histogram. It automatically creates buckets to track the distribution of request durations. Prometheus uses this to calculate percentiles."
Say it out loud
Reading silently is not the same as explaining to a person. Actually speak your answers out loud. You will immediately notice spots where you stumble or get vague.
Explain the Go patterns
CloudRaft's stack is built on Go. Your interviewer will likely ask about specific Go language features in your code. Practice explaining four core patterns.
For each pattern below, find the relevant code section in main.go and practice the explanation out loud.
- Structs — find prometheus.CounterOpts{} in the var block.
Structs explanation
"In Go, I use structs like CounterOpts to configure the metric. Structs are value types with named fields. I set Name and Help fields to tell Prometheus what this metric is called and what it measures."
- Interfaces — find http.Handle("/metrics", promhttp.Handler()) in main().
Interfaces explanation
"promhttp.Handler() returns an http.Handler, which is an interface. Anything with a ServeHTTP method satisfies it. Go uses implicit interface satisfaction, so you do not declare that you implement an interface."
- Goroutines — find go simulateTraffic() in main().
Goroutines explanation
"I launch simulateTraffic as a goroutine with the go keyword. It runs concurrently. The main goroutine blocks on ListenAndServe while the simulator runs independently."
- Error handling — find log.Fatal(http.ListenAndServe(":8080", nil)) at the bottom of main().
Error handling explanation
"Go handles errors by returning them as values, not exceptions. http.ListenAndServe returns an error, and I wrap it with log.Fatal to exit if the server cannot start."
Rehearse the full project walkthrough
Interviewers often open with "tell me about a project you have built." You need a concise, confident answer that hits the key points in 30 seconds.
- Close your editor so you cannot read the code.
- Say the following answer out loud, filling in from memory:
Your walkthrough answer
"I built a custom Prometheus metrics exporter in Go. It is an HTTP server that exposes three types of metrics: a Counter for total requests, a Gauge for active connections, and a Histogram for request latency."
"The metrics are exposed at /metrics in Prometheus format, ready for scraping. I used a goroutine to simulate background traffic so the metrics always have live data."
"This is the same pattern used in production exporters like node_exporter or kube-state-metrics."
- Repeat the walkthrough 2-3 times until it flows naturally without pauses.
- If you stumble on a section, open main.go to refresh your memory, then close it and try again.
Connect to CloudRaft's stack
CloudRaft provides enterprise support for Prometheus, Thanos, Grafana, and OpenTelemetry. When you mention this project in your interview, tie it back by saying something like: "This exporter is exactly the kind of tooling I would build and maintain for your clients."
Secret mission
Implement a Custom Collector
Production exporters like node_exporter and kube-state-metrics don't use pre-built Counter/Gauge/Histogram variables. They implement the prometheus.Collector interface directly, gathering metrics on-demand when Prometheus scrapes. Can you do the same?
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally on your machine, so there are no ongoing costs. Decide whether to keep your project directory for interview reference, pause the running server, or delete everything.
Resources you used:
- The prom-exporter project directory (contains go.mod, go.sum, and main.go).
- The running Go HTTP server process on port 8080 (if still active).
Keep everything running
No action needed. Choose this if you are still actively building or want the server running for practice.
- Your prom-exporter directory stays as-is.
- Consider pushing the project to GitHub so you can reference it during your interview.
- The Go module cache (managed by Go itself) remains on your machine for future Go projects.
Pause - I'll come back to this later
Stop the running server to free up port 8080, but keep the project files for later.
- In the terminal where your server is running, press Ctrl+C to stop the process.
- Your prom-exporter directory and all files remain on disk.
- To restart later, navigate back into the directory and run go run main.go.
Delete - I don't want to use this again
Remove all project files and start fresh.
- Stop the running server by pressing Ctrl+C in the terminal where it is running.
- Navigate to the parent directory (where prom-exporter lives) and remove the project folder by running:
cd ~/Desktop
rm -rf prom-exporter
- Confirm the directory is gone by running:
ls | grep prom-exporter
You should see no output, confirming the folder has been removed.
Nice Work!
Nice Work!
Nice work! You just built a custom Prometheus metrics exporter from scratch in Go, complete with a working /metrics endpoint serving real Prometheus-compatible output.
You've learned how to:
- Build a Go HTTP server that exposes three Prometheus metric types: a Counter (monotonically increasing), a Gauge (up and down), and a Histogram (distribution buckets).
- Implement concurrent background simulation using goroutines, demonstrating Go's concurrency model alongside structs, interfaces, and HTTP handlers.
- Practice explaining every Go pattern in your code confidently, turning this into an interview-ready project that maps directly to CloudRaft's observability stack.
- Secret Mission: Implemented the prometheus.Collector interface, the same pattern used in production CNCF exporters like node_exporter and kube-state-metrics.
Ready to quiz yourself?