-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add middleware to support tracing-like functionalities
- Loading branch information
Showing
7 changed files
with
237 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
src/api/rest/server/middlewares/requestIdAndDetailsIssuer.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package middlewares | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/cloud-barista/cb-tumblebug/src/core/common" | ||
"github.com/labstack/echo/v4" | ||
) | ||
|
||
func RequestIdAndDetailsIssuer(next echo.HandlerFunc) echo.HandlerFunc { | ||
return func(c echo.Context) error { | ||
// log.Debug().Msg("Start - Request ID middleware") | ||
|
||
// Make X-Request-Id visible to all handlers | ||
c.Response().Header().Set("Access-Control-Expose-Headers", echo.HeaderXRequestID) | ||
|
||
// Get or generate Request ID | ||
reqID := c.Request().Header.Get(echo.HeaderXRequestID) | ||
if reqID == "" { | ||
reqID = fmt.Sprintf("%d", time.Now().UnixNano()) | ||
} | ||
|
||
// Set Request on the context | ||
c.Set("RequestID", reqID) | ||
|
||
//log.Trace().Msgf("(Request ID middleware) Request ID: %s", reqID) | ||
if _, ok := common.RequestMap.Load(reqID); ok { | ||
return fmt.Errorf("the X-Request-Id is already in use") | ||
} | ||
|
||
// Set "X-Request-Id" in response header | ||
c.Response().Header().Set(echo.HeaderXRequestID, reqID) | ||
|
||
details := common.RequestDetails{ | ||
StartTime: time.Now(), | ||
Status: "Handling", | ||
RequestInfo: common.ExtractRequestInfo(c.Request()), | ||
} | ||
common.RequestMap.Store(reqID, details) | ||
|
||
// log.Debug().Msg("End - Request ID middleware") | ||
|
||
return next(c) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package middlewares | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/cloud-barista/cb-tumblebug/src/core/common/logger" | ||
"github.com/labstack/echo/v4" | ||
"github.com/rs/zerolog/log" | ||
// "go.opentelemetry.io/otel" | ||
) | ||
|
||
// Define Tracing middleware | ||
func TracingMiddleware(next echo.HandlerFunc) echo.HandlerFunc { | ||
return func(c echo.Context) error { | ||
|
||
// TODO: Be able to use this code when OpenTelemetry is integrated | ||
// Start a new tracing context | ||
// tracer := otel.Tracer("example-tracer") | ||
// ctx, span := tracer.Start(c.Request().Context(), c.Path()) | ||
// defer span.End() | ||
|
||
// Store trace and span IDs in the context | ||
// traceId := span.SpanContext().TraceID().String() | ||
// spanId := span.SpanContext().SpanID().String() | ||
|
||
// Get the context | ||
ctx := c.Request().Context() | ||
|
||
// [NOTE] | ||
// For now, we will use the request ID as the trace ID | ||
// and generate a new span ID for each request | ||
traceId := c.Response().Header().Get(echo.HeaderXRequestID) | ||
spanId := fmt.Sprintf("%d", time.Now().UnixNano()) | ||
|
||
ctx = context.WithValue(ctx, logger.TraceIdKey, traceId) | ||
ctx = context.WithValue(ctx, logger.SpanIdKey, spanId) | ||
|
||
// Create a childLogger with trace_id and span_id and store it in the context | ||
childLogger := log.With().Str(string(logger.TraceIdKey), traceId).Str(string(logger.SpanIdKey), spanId).Logger() | ||
ctx = childLogger.WithContext(ctx) | ||
|
||
// Set the context in the request | ||
c.SetRequest(c.Request().WithContext(ctx)) | ||
|
||
// [Tracing log] when the request is received | ||
traceLogger := logger.GetTraceLogger() | ||
|
||
traceLogger.Trace(). | ||
Str(string(logger.TraceIdKey), traceId). | ||
Str(string(logger.SpanIdKey), spanId). | ||
Str("URI", c.Request().RequestURI). | ||
Msg("[tracing] receive request") | ||
|
||
// [Tracing log] before the response is sent | ||
// Hooks: Before Response | ||
c.Response().Before(func() { | ||
// Log the request details | ||
traceLogger.Trace(). | ||
Str(string(logger.TraceIdKey), traceId). | ||
Str(string(logger.SpanIdKey), spanId). | ||
Str("URI", c.Request().RequestURI). | ||
Msg("[tracing] send response") | ||
}) | ||
|
||
// Call the next handler | ||
return next(c) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package middlewares | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/labstack/echo/v4" | ||
"github.com/labstack/echo/v4/middleware" | ||
|
||
"github.com/rs/zerolog/log" | ||
) | ||
|
||
func Zerologger(skipPatterns [][]string) echo.MiddlewareFunc { | ||
return middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{ | ||
Skipper: func(c echo.Context) bool { | ||
path := c.Request().URL.Path | ||
query := c.Request().URL.RawQuery | ||
for _, patterns := range skipPatterns { | ||
isAllMatched := true | ||
for _, pattern := range patterns { | ||
if !strings.Contains(path+query, pattern) { | ||
isAllMatched = false | ||
break | ||
} | ||
} | ||
if isAllMatched { | ||
return true | ||
} | ||
} | ||
return false | ||
}, | ||
LogError: true, | ||
LogRequestID: true, | ||
LogRemoteIP: true, | ||
LogHost: true, | ||
LogMethod: true, | ||
LogURI: true, | ||
LogUserAgent: false, | ||
LogStatus: true, | ||
LogLatency: true, | ||
LogContentLength: true, | ||
LogResponseSize: true, | ||
// HandleError: true, // forwards error to the global error handler, so it can decide appropriate status code | ||
LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error { | ||
if v.Error == nil { | ||
log.Info(). | ||
Str("id", v.RequestID). | ||
Str("client_ip", v.RemoteIP). | ||
//Str("host", v.Host). | ||
Str("method", v.Method). | ||
Str("URI", v.URI). | ||
//Str("user_agent", v.UserAgent). | ||
Int("status", v.Status). | ||
//Int64("latency", v.Latency.Nanoseconds()). | ||
Str("latency_human", v.Latency.String()). | ||
Str("bytes_in", v.ContentLength). | ||
Int64("bytes_out", v.ResponseSize). | ||
Msg("request") | ||
} else { | ||
log.Error(). | ||
Err(v.Error). | ||
Str("id", v.RequestID). | ||
Str("client_ip", v.RemoteIP). | ||
// Str("host", v.Host). | ||
Str("method", v.Method). | ||
Str("URI", v.URI). | ||
//Str("user_agent", v.UserAgent). | ||
Int("status", v.Status). | ||
// Int64("latency", v.Latency.Nanoseconds()). | ||
Str("latency_human", v.Latency.String()). | ||
Str("bytes_in", v.ContentLength). | ||
Int64("bytes_out", v.ResponseSize). | ||
Msg("request error") | ||
} | ||
return nil | ||
}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.