Add prometheus exporter on :9100
This commit is contained in:
130
cmd/collector/prom_test.go
Normal file
130
cmd/collector/prom_test.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPromStoreIngestBodyBuckets(t *testing.T) {
|
||||
ps := NewPromStore()
|
||||
// 512 bytes: > 256, ≤ 1024 → bucket[0] stays 0, buckets[1..N] get 1
|
||||
ps.Ingest(LogRecord{Website: "example.com", Method: "GET", Status: "200", BodyBytesSent: 512})
|
||||
|
||||
ps.mu.Lock()
|
||||
be := ps.body["example.com"]
|
||||
ps.mu.Unlock()
|
||||
|
||||
if be == nil {
|
||||
t.Fatal("expected body entry, got nil")
|
||||
}
|
||||
if be.buckets[0] != 0 { // le=256: 512 > 256
|
||||
t.Errorf("le=256 bucket = %d, want 0", be.buckets[0])
|
||||
}
|
||||
if be.buckets[1] != 1 { // le=1024: 512 ≤ 1024
|
||||
t.Errorf("le=1024 bucket = %d, want 1", be.buckets[1])
|
||||
}
|
||||
for i := 2; i <= promNumBodyBounds; i++ {
|
||||
if be.buckets[i] != 1 {
|
||||
t.Errorf("bucket[%d] = %d, want 1", i, be.buckets[i])
|
||||
}
|
||||
}
|
||||
if be.sum != 512 {
|
||||
t.Errorf("sum = %d, want 512", be.sum)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromStoreIngestTimeBuckets(t *testing.T) {
|
||||
ps := NewPromStore()
|
||||
// 0.075s: > 0.05, ≤ 0.1
|
||||
ps.Ingest(LogRecord{Website: "example.com", Method: "GET", Status: "200", RequestTime: 0.075})
|
||||
|
||||
ps.mu.Lock()
|
||||
te := ps.reqTime["example.com"]
|
||||
ps.mu.Unlock()
|
||||
|
||||
if te == nil {
|
||||
t.Fatal("expected time entry, got nil")
|
||||
}
|
||||
// le=0.05 (index 3): 0.075 > 0.05 → 0
|
||||
if te.buckets[3] != 0 {
|
||||
t.Errorf("le=0.05 bucket = %d, want 0", te.buckets[3])
|
||||
}
|
||||
// le=0.1 (index 4): 0.075 ≤ 0.1 → 1
|
||||
if te.buckets[4] != 1 {
|
||||
t.Errorf("le=0.1 bucket = %d, want 1", te.buckets[4])
|
||||
}
|
||||
// +Inf (last): always 1
|
||||
if te.buckets[promNumTimeBounds] != 1 {
|
||||
t.Errorf("+Inf bucket = %d, want 1", te.buckets[promNumTimeBounds])
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromStoreCounter(t *testing.T) {
|
||||
ps := NewPromStore()
|
||||
ps.Ingest(LogRecord{Website: "a.com", Method: "GET", Status: "200"})
|
||||
ps.Ingest(LogRecord{Website: "a.com", Method: "GET", Status: "200"})
|
||||
ps.Ingest(LogRecord{Website: "a.com", Method: "POST", Status: "201"})
|
||||
|
||||
ps.mu.Lock()
|
||||
c1 := ps.counters[promCounterKey{"a.com", "GET", "200"}]
|
||||
c2 := ps.counters[promCounterKey{"a.com", "POST", "201"}]
|
||||
ps.mu.Unlock()
|
||||
|
||||
if c1 != 2 {
|
||||
t.Errorf("GET/200 count = %d, want 2", c1)
|
||||
}
|
||||
if c2 != 1 {
|
||||
t.Errorf("POST/201 count = %d, want 1", c2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromStoreServeHTTP(t *testing.T) {
|
||||
ps := NewPromStore()
|
||||
ps.Ingest(LogRecord{
|
||||
Website: "example.com", Method: "GET", Status: "200",
|
||||
BodyBytesSent: 100, RequestTime: 0.042,
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/metrics", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
ps.ServeHTTP(rec, req)
|
||||
|
||||
body := rec.Body.String()
|
||||
|
||||
checks := []string{
|
||||
"# TYPE nginx_http_requests_total counter",
|
||||
`nginx_http_requests_total{host="example.com",method="GET",status="200"} 1`,
|
||||
"# TYPE nginx_http_response_body_bytes histogram",
|
||||
`nginx_http_response_body_bytes_bucket{host="example.com",le="256"} 1`, // 100 ≤ 256
|
||||
`nginx_http_response_body_bytes_count{host="example.com"} 1`,
|
||||
`nginx_http_response_body_bytes_sum{host="example.com"} 100`,
|
||||
"# TYPE nginx_http_request_duration_seconds histogram",
|
||||
`nginx_http_request_duration_seconds_bucket{host="example.com",le="0.05"} 1`, // 0.042 ≤ 0.05
|
||||
`nginx_http_request_duration_seconds_count{host="example.com"} 1`,
|
||||
}
|
||||
for _, want := range checks {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Errorf("missing %q in output:\n%s", want, body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromStoreCounterCap(t *testing.T) {
|
||||
ps := NewPromStore()
|
||||
// Fill to cap with distinct {host,method,status} combos
|
||||
for i := 0; i < promCounterCap+10; i++ {
|
||||
host := strings.Repeat("x", i%10+1) + ".com"
|
||||
status := "200"
|
||||
if i%3 == 0 {
|
||||
status = "404"
|
||||
}
|
||||
ps.Ingest(LogRecord{Website: host, Method: "GET", Status: status})
|
||||
}
|
||||
ps.mu.Lock()
|
||||
n := len(ps.counters)
|
||||
ps.mu.Unlock()
|
||||
if n > promCounterCap {
|
||||
t.Errorf("counter map size %d exceeds cap %d", n, promCounterCap)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user