From 0606416b39f508888c6de72fc807393e4776f789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Wed, 13 May 2026 12:37:35 +0400 Subject: [PATCH] Add SDK version to cookie banner logs via middleware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract X-SDK-Version from request headers in a dedicated middleware and store it in context. All ErrorCtx calls in the cookie banner handler now include the sdk_version field. Signed-off-by: Émile Ré --- pkg/server/api/cookiebanner/v1/handler.go | 32 ++++++++++++---- .../cookiebanner/v1/sdk_version_middleware.go | 37 +++++++++++++++++++ 2 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 pkg/server/api/cookiebanner/v1/sdk_version_middleware.go diff --git a/pkg/server/api/cookiebanner/v1/handler.go b/pkg/server/api/cookiebanner/v1/handler.go index a5bb6164f..51bde9a22 100644 --- a/pkg/server/api/cookiebanner/v1/handler.go +++ b/pkg/server/api/cookiebanner/v1/handler.go @@ -54,6 +54,7 @@ func NewMux( r := chi.NewMux() r.Route("/{bannerID}", func(r chi.Router) { + r.Use(newSDKVersionMiddleware()) r.Use(newCORSMiddleware(logger, cookieBannerSvc)) r.Get("/config", h.handleGetConfig) r.Get("/consents/{visitorID}", h.handleGetConsent) @@ -73,7 +74,7 @@ func (h *Handler) handleGetConfig(w http.ResponseWriter, r *http.Request) { } lang := r.URL.Query().Get("lang") - sdkVersion := r.Header.Get("X-SDK-Version") + sdkVersion := sdkVersionFromContext(r.Context()) cc := h.resolveCountryCode(r) var regulation cookiebanner.Regulation @@ -91,7 +92,7 @@ func (h *Handler) handleGetConfig(w http.ResponseWriter, r *http.Request) { jsonutil.RenderNotFound(w, fmt.Errorf("no published version")) return } - h.logger.ErrorCtx(r.Context(), "cannot get banner config", log.Error(err)) + h.logger.ErrorCtx(r.Context(), "cannot get banner config", log.Error(err), log.String("sdk_version", sdkVersion)) jsonutil.RenderInternalServerError(w) return } @@ -104,7 +105,12 @@ func (h *Handler) resolveCountryCode(r *http.Request) *coredata.CountryCode { cc, err := h.geolocSvc.LookupCountry(r.Context(), ip) if err != nil { - h.logger.ErrorCtx(r.Context(), "cannot resolve country for IP", log.Error(err)) + h.logger.ErrorCtx( + r.Context(), + "cannot resolve country for IP", + log.Error(err), + log.String("sdk_version", sdkVersionFromContext(r.Context())), + ) return nil } @@ -138,7 +144,12 @@ func (h *Handler) handleGetConsent(w http.ResponseWriter, r *http.Request) { jsonutil.RenderNotFound(w, fmt.Errorf("consent not found")) return } - h.logger.ErrorCtx(r.Context(), "cannot get visitor consent", log.Error(err)) + h.logger.ErrorCtx( + r.Context(), + "cannot get visitor consent", + log.Error(err), + log.String("sdk_version", sdkVersionFromContext(r.Context())), + ) jsonutil.RenderInternalServerError(w) return } @@ -177,7 +188,7 @@ func (h *Handler) handlePostConsent(w http.ResponseWriter, r *http.Request) { ip := clientip.Extract(r) ua := r.UserAgent() - sdkVersion := r.Header.Get("X-SDK-Version") + sdkVersion := sdkVersionFromContext(r.Context()) cc := h.resolveCountryCode(r) var ( @@ -214,7 +225,7 @@ func (h *Handler) handlePostConsent(w http.ResponseWriter, r *http.Request) { jsonutil.RenderBadRequest(w, fmt.Errorf("invalid version")) return } - h.logger.ErrorCtx(r.Context(), "cannot record consent", log.Error(err)) + h.logger.ErrorCtx(r.Context(), "cannot record consent", log.Error(err), log.String("sdk_version", sdkVersion)) jsonutil.RenderInternalServerError(w) return } @@ -338,7 +349,12 @@ func (h *Handler) handleReportDetectedCookies(w http.ResponseWriter, r *http.Req return } - h.logger.ErrorCtx(r.Context(), "cannot report detected cookies", log.Error(err)) + h.logger.ErrorCtx( + r.Context(), + "cannot report detected cookies", + log.Error(err), + log.String("sdk_version", sdkVersionFromContext(r.Context())), + ) jsonutil.RenderInternalServerError(w) return } @@ -503,7 +519,7 @@ func (h *Handler) handleReportDetectedTrackers(w http.ResponseWriter, r *http.Re return } - h.logger.ErrorCtx(r.Context(), "cannot report detected trackers", log.Error(err)) + h.logger.ErrorCtx(r.Context(), "cannot report detected trackers", log.Error(err), log.String("sdk_version", sdkVersionFromContext(r.Context()))) jsonutil.RenderInternalServerError(w) return } diff --git a/pkg/server/api/cookiebanner/v1/sdk_version_middleware.go b/pkg/server/api/cookiebanner/v1/sdk_version_middleware.go new file mode 100644 index 000000000..e877c95b2 --- /dev/null +++ b/pkg/server/api/cookiebanner/v1/sdk_version_middleware.go @@ -0,0 +1,37 @@ +// Copyright (c) 2026 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package cookiebanner_v1 + +import ( + "context" + "net/http" +) + +type sdkVersionCtxKey struct{} + +func newSDKVersionMiddleware() func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + sdkVersion := r.Header.Get("X-SDK-Version") + ctx := context.WithValue(r.Context(), sdkVersionCtxKey{}, sdkVersion) + next.ServeHTTP(w, r.WithContext(ctx)) + }) + } +} + +func sdkVersionFromContext(ctx context.Context) string { + v, _ := ctx.Value(sdkVersionCtxKey{}).(string) + return v +}