Nik Afiq 657b6aeb22 feat: implement initial application structure with health and hello endpoints
- Add bootstrap package to initialize application components including logger, tracer, and HTTP server.
- Create config package to load runtime settings from environment variables.
- Implement observability features including logging, metrics, and tracing.
- Add health check and hello use cases with corresponding HTTP handlers.
- Introduce middleware for request ID, access logging, metrics, and recovery.
- Set up HTTP router with defined routes for health and hello endpoints.
- Include tests for health and hello endpoints to ensure proper functionality.
- Add OpenTelemetry collector configuration for trace exporting.
2026-03-05 21:22:43 +09:00

45 lines
1.1 KiB
Go

package middleware
import (
"fmt"
"io"
"log/slog"
"runtime/debug"
"github.com/gin-gonic/gin"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"switchbot-api/internal/transport/http/contextkeys"
"switchbot-api/internal/transport/http/response"
)
func Recovery(logger *slog.Logger) gin.HandlerFunc {
return gin.CustomRecoveryWithWriter(io.Discard, func(c *gin.Context, recovered any) {
ctx := c.Request.Context()
span := trace.SpanFromContext(ctx)
span.RecordError(fmt.Errorf("panic: %v", recovered))
span.SetStatus(codes.Error, "panic recovered")
spanCtx := trace.SpanContextFromContext(ctx)
traceID := ""
spanID := ""
if spanCtx.IsValid() {
traceID = spanCtx.TraceID().String()
spanID = spanCtx.SpanID().String()
}
logger.Error(
"panic recovered",
slog.Any("panic", recovered),
slog.String("request_id", contextkeys.RequestIDFromContext(ctx)),
slog.String("trace_id", traceID),
slog.String("span_id", spanID),
slog.String("stack", string(debug.Stack())),
)
response.WriteInternalError(c)
c.Abort()
})
}