feat: add Prometheus metrics endpoint and Docker image (PLAN.md 4.2)
Add internal/metrics package with dedicated Prometheus registry exposing SSH connection, auth attempt, session, and build info metrics. Wire into SSH server (4 instrumentation points) and web server (/metrics endpoint). Add dockerImage output to flake.nix via dockerTools.buildLayeredImage. Bump version to 0.7.0. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.t-juice.club/torjus/oubliette/internal/metrics"
|
||||
"git.t-juice.club/torjus/oubliette/internal/storage"
|
||||
)
|
||||
|
||||
@@ -17,7 +18,7 @@ func newTestServer(t *testing.T) *Server {
|
||||
t.Helper()
|
||||
store := storage.NewMemoryStore()
|
||||
logger := slog.Default()
|
||||
srv, err := NewServer(store, logger)
|
||||
srv, err := NewServer(store, logger, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("creating server: %v", err)
|
||||
}
|
||||
@@ -46,7 +47,7 @@ func newSeededTestServer(t *testing.T) *Server {
|
||||
}
|
||||
|
||||
logger := slog.Default()
|
||||
srv, err := NewServer(store, logger)
|
||||
srv, err := NewServer(store, logger, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("creating server: %v", err)
|
||||
}
|
||||
@@ -154,7 +155,7 @@ func TestSessionDetailHandler(t *testing.T) {
|
||||
t.Fatalf("CreateSession: %v", err)
|
||||
}
|
||||
|
||||
srv, err := NewServer(store, slog.Default())
|
||||
srv, err := NewServer(store, slog.Default(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("NewServer: %v", err)
|
||||
}
|
||||
@@ -194,7 +195,7 @@ func TestAPISessionEvents(t *testing.T) {
|
||||
t.Fatalf("AppendSessionEvents: %v", err)
|
||||
}
|
||||
|
||||
srv, err := NewServer(store, slog.Default())
|
||||
srv, err := NewServer(store, slog.Default(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("NewServer: %v", err)
|
||||
}
|
||||
@@ -236,6 +237,47 @@ func TestAPISessionEvents(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetricsEndpoint(t *testing.T) {
|
||||
t.Run("enabled", func(t *testing.T) {
|
||||
m := metrics.New("test")
|
||||
store := storage.NewMemoryStore()
|
||||
srv, err := NewServer(store, slog.Default(), m.Handler())
|
||||
if err != nil {
|
||||
t.Fatalf("NewServer: %v", err)
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
|
||||
w := httptest.NewRecorder()
|
||||
srv.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("status = %d, want 200", w.Code)
|
||||
}
|
||||
body := w.Body.String()
|
||||
if !strings.Contains(body, `oubliette_build_info{version="test"} 1`) {
|
||||
t.Errorf("response should contain build_info metric, got:\n%s", body)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("disabled", func(t *testing.T) {
|
||||
store := storage.NewMemoryStore()
|
||||
srv, err := NewServer(store, slog.Default(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("NewServer: %v", err)
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
|
||||
w := httptest.NewRecorder()
|
||||
srv.ServeHTTP(w, req)
|
||||
|
||||
// Without a metrics handler, /metrics falls through to the dashboard.
|
||||
body := w.Body.String()
|
||||
if strings.Contains(body, "oubliette_build_info") {
|
||||
t.Error("response should not contain prometheus metrics when disabled")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestStaticAssets(t *testing.T) {
|
||||
srv := newTestServer(t)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user