mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 01:41:34 +00:00
Some checks failed
- Updated database models and repositories to replace uint IDs with UUIDs. - Modified test fixtures to generate and use UUIDs for authors, translations, users, and works. - Adjusted mock implementations to align with the new UUID structure. - Ensured all relevant functions and methods are updated to handle UUIDs correctly. - Added necessary imports for UUID handling in various files.
92 lines
3.0 KiB
Go
92 lines
3.0 KiB
Go
package observability
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"github.com/google/uuid"
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/propagation"
|
|
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
|
"go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
// ContextKey is the type for context keys to avoid collisions.
|
|
type ContextKey string
|
|
|
|
const (
|
|
// RequestIDKey is the key for the request ID in the context.
|
|
RequestIDKey ContextKey = "request_id"
|
|
// LoggerContextKey is the key for the logger in the context.
|
|
LoggerContextKey ContextKey = "logger"
|
|
)
|
|
|
|
// responseWriter is a wrapper around http.ResponseWriter to capture the status code.
|
|
type responseWriter struct {
|
|
http.ResponseWriter
|
|
statusCode int
|
|
}
|
|
|
|
func (rw *responseWriter) WriteHeader(code int) {
|
|
rw.statusCode = code
|
|
rw.ResponseWriter.WriteHeader(code)
|
|
}
|
|
|
|
// RequestIDMiddleware generates a unique request ID and adds it to the request context.
|
|
func RequestIDMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
requestID := uuid.New().String()
|
|
ctx := context.WithValue(r.Context(), RequestIDKey, requestID)
|
|
w.Header().Set("X-Request-ID", requestID)
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
|
|
// LoggingMiddleware creates a request-scoped logger and injects it into the context.
|
|
func LoggingMiddleware(log *Logger) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// Start with a logger that has trace and span IDs.
|
|
requestLogger := log.Ctx(r.Context())
|
|
|
|
// Add request_id to logger context.
|
|
if reqID, ok := r.Context().Value(RequestIDKey).(string); ok {
|
|
requestLogger = requestLogger.With("request_id", reqID)
|
|
}
|
|
|
|
// Add the logger to the context.
|
|
ctx := context.WithValue(r.Context(), LoggerContextKey, requestLogger)
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
}
|
|
|
|
// LoggerFromContext retrieves the request-scoped logger from the context.
|
|
// If no logger is found, it returns a default logger.
|
|
func LoggerFromContext(ctx context.Context) *Logger {
|
|
if logger, ok := ctx.Value(LoggerContextKey).(*Logger); ok {
|
|
return logger
|
|
}
|
|
// Fallback to a default logger if none is found in context.
|
|
return NewLogger("tercul-fallback", "development")
|
|
}
|
|
|
|
// TracingMiddleware creates a new OpenTelemetry span for each request.
|
|
func TracingMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
|
tracer := otel.Tracer("http-server")
|
|
ctx, span := tracer.Start(ctx, "HTTP "+r.Method+" "+r.URL.Path, trace.WithAttributes(
|
|
semconv.HTTPMethodKey.String(r.Method),
|
|
semconv.HTTPURLKey.String(r.URL.String()),
|
|
))
|
|
defer span.End()
|
|
|
|
rw := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
|
|
next.ServeHTTP(rw, r.WithContext(ctx))
|
|
|
|
span.SetAttributes(attribute.Int("http.status_code", rw.statusCode))
|
|
})
|
|
}
|