2024-07-23 17:46:15 +02:00
|
|
|
package unitel
|
|
|
|
|
|
|
|
import (
|
2024-07-23 18:52:10 +02:00
|
|
|
"fmt"
|
2024-07-23 17:46:15 +02:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/getsentry/sentry-go"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
2024-07-23 18:52:10 +02:00
|
|
|
"github.com/gofiber/fiber/v2/utils"
|
2024-07-23 17:46:15 +02:00
|
|
|
"github.com/rs/zerolog"
|
|
|
|
"go.opentelemetry.io/otel/trace"
|
|
|
|
)
|
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
const reqLoggerBufSize = 1000
|
2024-07-23 17:46:15 +02:00
|
|
|
|
2024-07-23 18:52:10 +02:00
|
|
|
func RequestLogger(l zerolog.Logger, requestHeaders, responseHeaders bool) fiber.Handler {
|
2024-07-23 17:46:15 +02:00
|
|
|
type request struct {
|
2024-07-31 17:06:27 +02:00
|
|
|
Method string
|
|
|
|
Path string
|
|
|
|
Start time.Time
|
|
|
|
RequestHeaders map[string][]string
|
|
|
|
OtelSpanID *trace.SpanID
|
|
|
|
SentrySpanID *sentry.SpanID
|
|
|
|
}
|
|
|
|
|
|
|
|
type response struct {
|
2024-07-23 18:52:10 +02:00
|
|
|
Status int
|
2024-07-31 17:06:27 +02:00
|
|
|
End time.Time
|
2024-07-23 18:52:10 +02:00
|
|
|
Duration time.Duration
|
|
|
|
ResponseHeaders map[string][]string
|
|
|
|
OtelSpanID *trace.SpanID
|
|
|
|
SentrySpanID *sentry.SpanID
|
2024-07-23 17:46:15 +02:00
|
|
|
}
|
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
reqCh := make(chan request, reqLoggerBufSize)
|
|
|
|
resCh := make(chan response, reqLoggerBufSize)
|
|
|
|
|
2024-07-23 17:46:15 +02:00
|
|
|
go func() {
|
|
|
|
for {
|
2024-07-31 17:06:27 +02:00
|
|
|
select {
|
|
|
|
case r := <-reqCh:
|
|
|
|
l2 := l.Trace().
|
|
|
|
Str("method", r.Method).
|
|
|
|
Str("path", r.Path).
|
|
|
|
Time("start", r.Start)
|
|
|
|
|
|
|
|
if r.OtelSpanID != nil {
|
|
|
|
l2 = l2.Str("otel_span_id", r.OtelSpanID.String())
|
|
|
|
}
|
2024-07-23 17:46:15 +02:00
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
if r.SentrySpanID != nil {
|
|
|
|
l2 = l2.Str("sentry_span_id", r.SentrySpanID.String())
|
|
|
|
}
|
2024-07-23 17:46:15 +02:00
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
if requestHeaders {
|
|
|
|
for k, v := range r.RequestHeaders {
|
|
|
|
for i, vv := range v {
|
|
|
|
attr := formatHeaderAttribute("request", k, v, i)
|
2024-07-23 17:46:15 +02:00
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
l2 = l2.Str(attr, vv)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-07-23 17:46:15 +02:00
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
l2.Msg("request")
|
2024-07-31 16:58:55 +02:00
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
case r := <-resCh:
|
|
|
|
l2 := l.Trace().
|
|
|
|
Int("status", r.Status).
|
|
|
|
Time("end", r.End).
|
|
|
|
Dur("duration", r.Duration)
|
2024-07-31 16:58:55 +02:00
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
if r.OtelSpanID != nil {
|
|
|
|
l2 = l2.Str("otel_span_id", r.OtelSpanID.String())
|
2024-07-23 18:52:10 +02:00
|
|
|
}
|
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
if r.SentrySpanID != nil {
|
|
|
|
l2 = l2.Str("sentry_span_id", r.SentrySpanID.String())
|
|
|
|
}
|
2024-07-23 18:59:02 +02:00
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
if responseHeaders {
|
|
|
|
for k, v := range r.ResponseHeaders {
|
|
|
|
for i, vv := range v {
|
|
|
|
attr := formatHeaderAttribute("response", k, v, i)
|
2024-07-23 18:59:02 +02:00
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
l2 = l2.Str(attr, vv)
|
|
|
|
}
|
2024-07-23 18:52:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
l2.Msg("response")
|
|
|
|
}
|
2024-07-23 17:46:15 +02:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
return func(c *fiber.Ctx) error {
|
|
|
|
var otelSpanId *trace.SpanID = nil
|
|
|
|
if spanId := trace.SpanContextFromContext(c.UserContext()).SpanID(); spanId.IsValid() {
|
|
|
|
otelSpanId = &spanId
|
|
|
|
}
|
|
|
|
|
|
|
|
var sentrySpanId *sentry.SpanID = nil
|
|
|
|
if span := sentry.SpanFromContext(c.UserContext()); span != nil {
|
|
|
|
sentrySpanId = &span.SpanID
|
|
|
|
}
|
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
// pushing the request to the logger, so we don't block the handling
|
|
|
|
req := request{
|
|
|
|
Method: c.Method(),
|
|
|
|
Path: c.Path(),
|
|
|
|
Start: time.Now(),
|
|
|
|
OtelSpanID: otelSpanId,
|
|
|
|
SentrySpanID: sentrySpanId,
|
|
|
|
}
|
|
|
|
|
|
|
|
if requestHeaders {
|
|
|
|
req.RequestHeaders = make(map[string][]string)
|
|
|
|
for k, v := range c.GetReqHeaders() {
|
|
|
|
for _, vv := range v {
|
|
|
|
req.RequestHeaders[k] = append(req.RequestHeaders[k], utils.CopyString(vv))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
reqCh <- req
|
|
|
|
|
2024-07-23 17:46:15 +02:00
|
|
|
start := time.Now()
|
|
|
|
err := c.Next()
|
2024-07-31 17:06:27 +02:00
|
|
|
end := time.Now()
|
2024-07-23 17:46:15 +02:00
|
|
|
|
|
|
|
status := c.Response().StatusCode()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
if e, ok := err.(*fiber.Error); ok {
|
|
|
|
status = e.Code
|
|
|
|
} else {
|
|
|
|
status = fiber.StatusInternalServerError
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
// pushing the response to the logger, so we don't block the handling
|
|
|
|
res := response{
|
2024-07-23 17:46:15 +02:00
|
|
|
Status: status,
|
2024-07-31 17:06:27 +02:00
|
|
|
End: end,
|
|
|
|
Duration: end.Sub(start),
|
2024-07-23 17:46:15 +02:00
|
|
|
OtelSpanID: otelSpanId,
|
|
|
|
SentrySpanID: sentrySpanId,
|
|
|
|
}
|
|
|
|
|
2024-07-23 18:52:10 +02:00
|
|
|
if responseHeaders {
|
2024-07-31 17:06:27 +02:00
|
|
|
res.ResponseHeaders = make(map[string][]string)
|
2024-07-23 18:52:10 +02:00
|
|
|
for k, v := range c.GetRespHeaders() {
|
|
|
|
for _, vv := range v {
|
2024-07-31 17:06:27 +02:00
|
|
|
res.ResponseHeaders[k] = append(res.ResponseHeaders[k], utils.CopyString(vv))
|
2024-07-23 18:52:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-31 17:06:27 +02:00
|
|
|
resCh <- res
|
2024-07-23 18:52:10 +02:00
|
|
|
|
2024-07-23 17:46:15 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2024-08-10 01:51:58 +02:00
|
|
|
|
|
|
|
func formatHeaderAttribute(t, k string, v []string, i int) string {
|
|
|
|
attr := fmt.Sprintf("%s.headers.%s", t, k)
|
|
|
|
|
|
|
|
if len(v) != 1 {
|
|
|
|
attr = fmt.Sprintf("%s.%d", attr, i)
|
|
|
|
}
|
|
|
|
|
|
|
|
return attr
|
|
|
|
}
|