From 5024d204ccefce5fb81a8775594024307a405241 Mon Sep 17 00:00:00 2001 From: Mohammad Alisafaee Date: Fri, 27 Feb 2026 11:45:58 +0100 Subject: [PATCH] feat: add sentry trace id to logs --- internal/login/login_server_routes.go | 6 ++--- internal/oidc/client.go | 5 +++-- internal/redirects/redirect_store.go | 17 ++++++++++++++ internal/revproxy/auth.go | 32 +++++++++++++++++++++++++++ internal/revproxy/middlewares.go | 6 ++--- internal/revproxy/proxies.go | 2 +- internal/sessions/session_store.go | 4 ++++ internal/utils/trace_id.go | 11 +++++++++ 8 files changed, 74 insertions(+), 9 deletions(-) diff --git a/internal/login/login_server_routes.go b/internal/login/login_server_routes.go index 4f0e3193..311113da 100644 --- a/internal/login/login_server_routes.go +++ b/internal/login/login_server_routes.go @@ -85,7 +85,7 @@ func (l *LoginServer) GetCallback(c echo.Context, params GetCallbackParams) erro // Exchange the authorization code for credentials err = echo.WrapHandler(handler(tokenCallback))(c) if err != nil { - slog.Error("code exchange handler failed", "error", err, "requestID", utils.GetRequestID(c)) + slog.Error("code exchange handler failed", "error", err, "requestID", utils.GetRequestID(c), "traceID", utils.GetTraceID(c)) return err } // Continue to the next authentication step @@ -215,7 +215,7 @@ func (l *LoginServer) nextAuthStep( if url == "" { url = l.config.RenkuBaseURL.String() } - slog.Info("login completed", "requestID", utils.GetRequestID(c), "appRedirectURL", url) + slog.Info("login completed", "requestID", utils.GetRequestID(c), "traceID", utils.GetTraceID(c), "appRedirectURL", url) // Save the session: ensure we save the session before sending redirects l.sessions.Save(c) // send product metrics @@ -235,7 +235,7 @@ func (l *LoginServer) nextAuthStep( // Handle the login handler, err := l.providerStore.AuthHandler(providerID, session.LoginState) if err != nil { - slog.Error("auth handler failed", "error", err, "requestID", utils.GetRequestID(c)) + slog.Error("auth handler failed", "error", err, "requestID", utils.GetRequestID(c), "traceID", utils.GetTraceID(c)) return err } // Save the session: ensure we save the session before sending redirects diff --git a/internal/oidc/client.go b/internal/oidc/client.go index 59962061..cbe5de67 100644 --- a/internal/oidc/client.go +++ b/internal/oidc/client.go @@ -9,6 +9,7 @@ import ( "github.com/SwissDataScienceCenter/renku-gateway/internal/config" "github.com/SwissDataScienceCenter/renku-gateway/internal/models" + "github.com/SwissDataScienceCenter/renku-gateway/internal/utils" "github.com/labstack/echo/v4" "github.com/zitadel/oidc/v3/pkg/client/rp" httphelper "github.com/zitadel/oidc/v3/pkg/http" @@ -36,7 +37,7 @@ func (c *oidcClient) getCodeExchangeCallback(callback TokenSetCallback) func( ) { id, err := models.ULIDGenerator{}.ID() if err != nil { - slog.Error("generating token ID failed in token exchange", "error", err, "requestID", r.Header.Get(echo.HeaderXRequestID)) + slog.Error("generating token ID failed in token exchange", "error", err, "requestID", r.Header.Get(echo.HeaderXRequestID), "traceID", utils.GetTraceIDFromHTTPRequest(r)) http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -70,7 +71,7 @@ func (c *oidcClient) getCodeExchangeCallback(callback TokenSetCallback) func( } err = callback(tokenSet) if err != nil { - slog.Error("error when running tokens callback", "error", err, "requestID", r.Header.Get(echo.HeaderXRequestID)) + slog.Error("error when running tokens callback", "error", err, "requestID", r.Header.Get(echo.HeaderXRequestID), "traceID", utils.GetTraceIDFromHTTPRequest(r)) http.Error(w, err.Error(), http.StatusInternalServerError) return } diff --git a/internal/redirects/redirect_store.go b/internal/redirects/redirect_store.go index 789e866e..0784adaa 100644 --- a/internal/redirects/redirect_store.go +++ b/internal/redirects/redirect_store.go @@ -13,6 +13,7 @@ import ( "time" "github.com/SwissDataScienceCenter/renku-gateway/internal/config" + "github.com/SwissDataScienceCenter/renku-gateway/internal/utils" "github.com/labstack/echo/v4" ) @@ -168,6 +169,10 @@ func (rs *RedirectStore) Middleware() echo.MiddlewareFunc { redirectUrl.String(), "error", err.Error(), + "requestID", + utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return c.NoContent(http.StatusNotFound) } @@ -176,6 +181,10 @@ func (rs *RedirectStore) Middleware() echo.MiddlewareFunc { "REDIRECT_STORE MIDDLEWARE", "message", "nil redirect found for url (this should not happen), returning 404", "from", redirectUrl.String(), + "requestID", + utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return c.NoContent(http.StatusNotFound) } @@ -184,6 +193,10 @@ func (rs *RedirectStore) Middleware() echo.MiddlewareFunc { "REDIRECT_STORE MIDDLEWARE", "message", "no redirect found for url, returning 404", "from", redirectUrl.String(), + "requestID", + utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return c.NoContent(http.StatusNotFound) } @@ -192,6 +205,10 @@ func (rs *RedirectStore) Middleware() echo.MiddlewareFunc { "message", "redirecting request", "from", redirectUrl.String(), "to", entry.TargetUrl, + "requestID", + utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return c.Redirect(http.StatusMovedPermanently, entry.TargetUrl) } diff --git a/internal/revproxy/auth.go b/internal/revproxy/auth.go index bcee2cc7..87779197 100644 --- a/internal/revproxy/auth.go +++ b/internal/revproxy/auth.go @@ -35,6 +35,8 @@ func InjectInHeader(headerKey string) AuthOption { token.String(), "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return nil } @@ -48,6 +50,8 @@ func InjectInHeader(headerKey string) AuthOption { token.String(), "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) c.Request().Header.Set(headerKey, token.Value) return nil @@ -70,6 +74,8 @@ func InjectBearerToken() AuthOption { token.String(), "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return nil } @@ -85,6 +91,8 @@ func InjectBearerToken() AuthOption { token.String(), "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) c.Request().Header.Set(echo.HeaderAuthorization, fmt.Sprintf("Bearer %s", token.Value)) return nil @@ -156,6 +164,8 @@ func (a *Auth) Middleware() echo.MiddlewareFunc { a.tokenType, "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return next(c) } @@ -185,6 +195,8 @@ func (a *Auth) Middleware() echo.MiddlewareFunc { a.tokenType, "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return next(c) case gwerrors.ErrTokenExpired: @@ -200,6 +212,8 @@ func (a *Auth) Middleware() echo.MiddlewareFunc { a.tokenType, "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return next(c) default: @@ -217,6 +231,8 @@ func (a *Auth) Middleware() echo.MiddlewareFunc { a.tokenType, "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return next(c) } @@ -244,6 +260,8 @@ var notebooksGitlabAccessTokenInjector TokenInjector = func(c echo.Context, acce accessToken.String(), "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return nil } @@ -291,6 +309,8 @@ var notebooksGitlabAccessTokenInjector TokenInjector = func(c echo.Context, acce accessToken.String(), "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) c.Request().Header.Set(headerKey, headerVal) return nil @@ -310,6 +330,8 @@ var coreSvcRenkuIdTokenInjector TokenInjector = func(c echo.Context, idToken mod idToken.String(), "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return nil } @@ -333,6 +355,8 @@ var coreSvcRenkuIdTokenInjector TokenInjector = func(c echo.Context, idToken mod idToken.String(), "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) c.Request().Header.Set(headerKey, idToken.Value) slog.Debug( @@ -343,6 +367,8 @@ var coreSvcRenkuIdTokenInjector TokenInjector = func(c echo.Context, idToken mod userId, "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) c.Request().Header.Set("Renku-user-id", userId) c.Request().Header.Set("Renku-user-email", base64.StdEncoding.EncodeToString([]byte(email))) @@ -375,6 +401,8 @@ var dataServiceGitlabAccessTokenInjector TokenInjector = func(c echo.Context, ac accessToken.String(), "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return nil } @@ -391,6 +419,8 @@ var dataServiceGitlabAccessTokenInjector TokenInjector = func(c echo.Context, ac accessToken.String(), "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) c.Request().Header.Set(headerKey, accessToken.Value) if accessToken.ExpiresAt.IsZero() { @@ -407,6 +437,8 @@ var dataServiceGitlabAccessTokenInjector TokenInjector = func(c echo.Context, ac accessToken.ExpiresAt, "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) return nil } diff --git a/internal/revproxy/middlewares.go b/internal/revproxy/middlewares.go index c54a596c..f61ebe48 100644 --- a/internal/revproxy/middlewares.go +++ b/internal/revproxy/middlewares.go @@ -87,7 +87,7 @@ func UiServerPathRewrite() echo.MiddlewareFunc { } c.Request().URL = newUrl c.Request().RequestURI = newUrl.String() - slog.Debug("PATH REWRITE", "message", "matched /ui-server/auth", "originalURL", originalURL, "newUrl", newUrl.String(), "requestID", utils.GetRequestID(c)) + slog.Debug("PATH REWRITE", "message", "matched /ui-server/auth", "originalURL", originalURL, "newUrl", newUrl.String(), "requestID", utils.GetRequestID(c), "traceID", utils.GetTraceID(c)) } // For notebooks rewrite to go to the data service if strings.HasPrefix(path, "/ui-server/api/notebooks") { @@ -102,7 +102,7 @@ func UiServerPathRewrite() echo.MiddlewareFunc { } c.Request().URL = newUrl c.Request().RequestURI = newUrl.String() - slog.Debug("PATH REWRITE", "message", "matched /ui-server/api/notebooks", "originalURL", originalURL, "newUrl", newUrl.String(), "requestID", utils.GetRequestID(c)) + slog.Debug("PATH REWRITE", "message", "matched /ui-server/api/notebooks", "originalURL", originalURL, "newUrl", newUrl.String(), "requestID", utils.GetRequestID(c), "traceID", utils.GetTraceID(c)) } // For all other endpoints the gateway will fully bypass the UI server routing things directly to the proper // Renku component. @@ -116,7 +116,7 @@ func UiServerPathRewrite() echo.MiddlewareFunc { } c.Request().URL = newUrl c.Request().RequestURI = newUrl.String() - slog.Debug("PATH REWRITE", "message", "matched /ui-server/api", "originalURL", originalURL, "newUrl", newUrl.String(), "requestID", utils.GetRequestID(c)) + slog.Debug("PATH REWRITE", "message", "matched /ui-server/api", "originalURL", originalURL, "newUrl", newUrl.String(), "requestID", utils.GetRequestID(c), "traceID", utils.GetTraceID(c)) } return next(c) } diff --git a/internal/revproxy/proxies.go b/internal/revproxy/proxies.go index 69b5e9d5..695ea0d8 100644 --- a/internal/revproxy/proxies.go +++ b/internal/revproxy/proxies.go @@ -19,7 +19,7 @@ func proxyFromURL(url *url.URL) echo.MiddlewareFunc { mwConfig := middleware.ProxyConfig{ // the skipper is used to log only Skipper: func(c echo.Context) bool { - slog.Info("PROXY", "requestID", utils.GetRequestID(c), "destination", url.String()) + slog.Info("PROXY", "requestID", utils.GetRequestID(c), "traceID", utils.GetTraceID(c), "destination", url.String()) return false }, Balancer: middleware.NewRoundRobinBalancer([]*middleware.ProxyTarget{ diff --git a/internal/sessions/session_store.go b/internal/sessions/session_store.go index 89e4e254..904f475d 100644 --- a/internal/sessions/session_store.go +++ b/internal/sessions/session_store.go @@ -45,6 +45,8 @@ func (sessions *SessionStore) Middleware() echo.MiddlewareFunc { loadErr, "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) } err := next(c) @@ -64,6 +66,8 @@ func (sessions *SessionStore) Middleware() echo.MiddlewareFunc { sessionID, "requestID", utils.GetRequestID(c), + "traceID", + utils.GetTraceID(c), ) } return err diff --git a/internal/utils/trace_id.go b/internal/utils/trace_id.go index 79ceaea0..e0296ca5 100644 --- a/internal/utils/trace_id.go +++ b/internal/utils/trace_id.go @@ -1,6 +1,9 @@ package utils import ( + "net/http" + + "github.com/getsentry/sentry-go" sentryecho "github.com/getsentry/sentry-go/echo" "github.com/labstack/echo/v4" ) @@ -11,3 +14,11 @@ func GetTraceID(c echo.Context) string { } return "" } + +// GetTraceIDFromHTTPRequest extracts the trace ID from an http.Request. +func GetTraceIDFromHTTPRequest(r *http.Request) string { + if hub := sentry.GetHubFromContext(r.Context()); hub != nil { + return hub.GetTraceparent() + } + return "" +}