93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
package telemetrymeta
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"github.com/aoagents/agent-orchestrator/backend/internal/httpd/apierr"
|
|
)
|
|
|
|
// ErrorKindAndCode extracts a telemetry-safe error category and optional code.
|
|
func ErrorKindAndCode(err error) (kind, code string) {
|
|
kind = "internal"
|
|
var apiErr *apierr.Error
|
|
if errors.As(err, &apiErr) {
|
|
return ErrorKind(apiErr.Kind), apiErr.Code
|
|
}
|
|
return kind, ""
|
|
}
|
|
|
|
// ErrorKind maps API error kinds to coarse telemetry-safe categories.
|
|
func ErrorKind(kind apierr.Kind) string {
|
|
switch kind {
|
|
case apierr.KindInvalid:
|
|
return "invalid"
|
|
case apierr.KindNotFound:
|
|
return "not_found"
|
|
case apierr.KindConflict:
|
|
return "conflict"
|
|
default:
|
|
return "internal"
|
|
}
|
|
}
|
|
|
|
// PanicKind classifies panic payloads without exporting their raw contents.
|
|
func PanicKind(rec any) string {
|
|
switch rec.(type) {
|
|
case error:
|
|
return "error"
|
|
case string:
|
|
return "string"
|
|
default:
|
|
return "other"
|
|
}
|
|
}
|
|
|
|
// StatusFamily returns a telemetry-friendly HTTP status bucket like 5xx.
|
|
func StatusFamily(status int) string {
|
|
if status < 100 || status > 999 {
|
|
return "unknown"
|
|
}
|
|
return fmt.Sprintf("%dxx", status/100)
|
|
}
|
|
|
|
// RoutePattern returns the chi route template when available, else the URL path.
|
|
func RoutePattern(r *http.Request) string {
|
|
if r == nil {
|
|
return ""
|
|
}
|
|
if rc := chi.RouteContext(r.Context()); rc != nil {
|
|
if pattern := strings.TrimSpace(rc.RoutePattern()); pattern != "" {
|
|
return pattern
|
|
}
|
|
}
|
|
if r.URL == nil {
|
|
return ""
|
|
}
|
|
return r.URL.Path
|
|
}
|
|
|
|
// Fingerprint returns a short stable digest for grouping similar failures.
|
|
func Fingerprint(parts ...string) string {
|
|
h := sha256.New()
|
|
for _, part := range parts {
|
|
part = strings.TrimSpace(part)
|
|
if part == "" {
|
|
continue
|
|
}
|
|
_, _ = h.Write([]byte(part))
|
|
_, _ = h.Write([]byte{0})
|
|
}
|
|
sum := hex.EncodeToString(h.Sum(nil))
|
|
if len(sum) > 16 {
|
|
return sum[:16]
|
|
}
|
|
return sum
|
|
}
|