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

56 lines
1.3 KiB
Go

package middleware
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
)
func Tracing(tracer trace.Tracer) gin.HandlerFunc {
return func(c *gin.Context) {
ctx := otel.GetTextMapPropagator().Extract(c.Request.Context(), propagation.HeaderCarrier(c.Request.Header))
spanName := fmt.Sprintf("%s %s", c.Request.Method, c.Request.URL.Path)
ctx, span := tracer.Start(
ctx,
spanName,
trace.WithSpanKind(trace.SpanKindServer),
trace.WithAttributes(
attribute.String("http.request.method", c.Request.Method),
),
)
defer span.End()
c.Request = c.Request.WithContext(ctx)
c.Next()
route := c.FullPath()
if route == "" {
route = "/unknown"
}
status := c.Writer.Status()
span.SetName(fmt.Sprintf("%s %s", c.Request.Method, route))
span.SetAttributes(
attribute.String("http.route", route),
attribute.Int("http.response.status_code", status),
)
if status >= http.StatusInternalServerError {
span.SetStatus(codes.Error, http.StatusText(status))
}
if len(c.Errors) > 0 {
for _, err := range c.Errors {
span.RecordError(err)
}
span.SetStatus(codes.Error, c.Errors.String())
}
}
}