package internalhttp import ( "time" authlogging "galaxy/authsession/internal/logging" "galaxy/authsession/internal/telemetry" "github.com/gin-gonic/gin" "go.opentelemetry.io/otel/attribute" "go.uber.org/zap" ) type edgeOutcome string const ( edgeOutcomeSuccess edgeOutcome = "success" edgeOutcomeRejected edgeOutcome = "rejected" edgeOutcomeFailed edgeOutcome = "failed" ) func withInternalObservability(logger *zap.Logger, metrics *telemetry.Runtime) gin.HandlerFunc { if logger == nil { logger = zap.NewNop() } return func(c *gin.Context) { start := time.Now() c.Next() statusCode := c.Writer.Status() route := c.FullPath() if route == "" { route = "unmatched" } errorCode, _ := c.Get(internalErrorCodeContextKey) errorCodeValue, _ := errorCode.(string) outcome := outcomeFromStatusCode(statusCode) duration := time.Since(start) fields := []zap.Field{ zap.String("component", "internal_http"), zap.String("transport", "http"), zap.String("route", route), zap.String("method", c.Request.Method), zap.Int("status_code", statusCode), zap.Float64("duration_ms", float64(duration.Microseconds())/1000), zap.String("edge_outcome", string(outcome)), } if errorCodeValue != "" { fields = append(fields, zap.String("error_code", errorCodeValue)) } fields = append(fields, authlogging.TraceFieldsFromContext(c.Request.Context())...) metricAttrs := []attribute.KeyValue{ attribute.String("route", route), attribute.String("method", c.Request.Method), attribute.String("edge_outcome", string(outcome)), } if errorCodeValue != "" { metricAttrs = append(metricAttrs, attribute.String("error_code", errorCodeValue)) } metrics.RecordInternalHTTPRequest(c.Request.Context(), metricAttrs, duration) switch outcome { case edgeOutcomeSuccess: logger.Info("internal request completed", fields...) case edgeOutcomeFailed: logger.Error("internal request failed", fields...) default: logger.Warn("internal request rejected", fields...) } } } func outcomeFromStatusCode(statusCode int) edgeOutcome { switch { case statusCode >= 500: return edgeOutcomeFailed case statusCode >= 400: return edgeOutcomeRejected default: return edgeOutcomeSuccess } }