Skip to content

refactor: migrate logging to Go slog#1552

Merged
rohilsurana merged 12 commits intomainfrom
refactor/migrate-logging-to-slog
Apr 23, 2026
Merged

refactor: migrate logging to Go slog#1552
rohilsurana merged 12 commits intomainfrom
refactor/migrate-logging-to-slog

Conversation

@ravisuhag
Copy link
Copy Markdown
Member

@ravisuhag ravisuhag commented Apr 18, 2026

Summary

  • Replace go.uber.org/zap, github.com/raystack/salt/log, and grpc-zap-middleware with Go's standard library log/slog across the entire codebase (114 files)
  • Implement idiomatic context-aware logging using a custom ContextHandler that auto-appends request-scoped attributes from context
  • Remove 3 external logging dependencies from go.mod

Architecture

pkg/logger/ — Core logging infrastructure:

  • ContextHandler wraps any slog.Handler, extracts attrs stored in context via AppendCtx, and appends them to every log record
  • AppendCtx(ctx, slog.String("key", val)) stores attributes in context (not a logger)
  • InitLogger(cfg) returns *slog.Logger with JSON or text handler, wrapped in ContextHandler
  • Fatal helper for slog.Error + os.Exit(1) (slog has no Fatal level)

Request-scoped logging flow:

Interceptor → AppendCtx(ctx, request_id, method) → ctx carries attrs
    ↓
Service/Handler → s.log.ErrorContext(ctx, "msg", "key", val)
    ↓
ContextHandler.Handle(ctx, record) → auto-appends request_id + method from ctx

Logging patterns used:

Layer Pattern
Services with struct field s.log.ErrorContext(ctx, "msg", "key", val)
API handlers (stateless) slog.ErrorContext(ctx, "msg", "key", val)
Startup/shutdown code logger.Info("msg", "key", val) (no ctx available)
Tests slog.New(slog.NewTextHandler(io.Discard, nil))

Dependencies removed:

  • go.uber.org/zap
  • github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap
  • github.com/raystack/salt/log (salt itself stays for config/cli/rql)

Test plan

  • go build ./... passes
  • go vet ./... passes
  • go mod tidy clean
  • golangci-lint run ./... — 0 issues
  • Zero remaining imports of zap, salt/log, or ctxzap
  • All *Context(ctx, ...) variants used when ctx is available
  • go test ./... (unit tests)
  • Manual smoke test: start server, make RPC call, verify request_id + method appear in logs

Replace go.uber.org/zap and github.com/raystack/salt/log with log/slog
across the entire codebase. This removes external logging dependencies
in favor of Go's built-in structured logging introduced in Go 1.21.

Key changes:
- Rewrite pkg/logger with slog-based InitLogger, ToContext, FromContext
- Replace salt log.Logger interface with *slog.Logger throughout
- Replace grpczap context propagation with custom context helpers
- Convert all zap typed fields (zap.String, zap.Error) to key-value pairs
- Update Connect RPC logger interceptor to use *slog.Logger
- Update all tests to use slog with io.Discard handler
- Remove go.uber.org/zap and grpc-zap-middleware dependencies
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Apr 22, 2026 4:34pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 18, 2026

Warning

Rate limit exceeded

@ravisuhag has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 51 minutes and 17 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 51 minutes and 17 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9d83fffa-ac95-411f-9830-94addbb5db7d

📥 Commits

Reviewing files that changed from the base of the PR and between fb2b7d4 and 8b92e5a.

📒 Files selected for processing (5)
  • cmd/serve.go
  • core/membership/service.go
  • core/membership/service_test.go
  • internal/api/v1beta1connect/project.go
  • pkg/server/server.go
📝 Walkthrough

Walkthrough

This PR migrates the codebase from Zap/salt/log/grpczap logging to Go's standard library structured logger (log/slog). It updates logger types (to *slog.Logger) on many services, repositories, handlers, interceptors, tests, and the logger infrastructure, and converts logging calls to context-aware *slog.Logger APIs and plain key/value args.

Changes

Cohort / File(s) Summary
Billing services
billing/checkout/service.go, billing/checkout/service_test.go, billing/customer/service.go, billing/customer/service_test.go, billing/invoice/service.go, billing/subscription/service.go, billing/subscription/service_test.go
Added log *slog.Logger to Service structs and updated NewService signatures to accept *slog.Logger as first arg; replaced grpczap/zap extraction and zap fields with s.log.*Context calls and slog key/value args.
Core services & auth/session
core/authenticate/..., core/domain/service.go, core/membership/..., core/userpat/..., core/invite/... (see raw list)
Migrated many core services, authenticators, session services, membership and userpat code to accept *slog.Logger, using context-aware slog calls; updated tests to supply slog loggers (TextHandler→io.Discard).
Event & webhook handlers
core/event/listener.go, core/event/service.go, core/webhook/service.go
Removed grpczap/zap context extraction; emit errors via slog.*Context(ctx, ...) with plain key/value args.
Command & server plumbing
cmd/migrate.go, cmd/serve.go, cmd/server.go
Changed command/server signatures to accept *slog.Logger, propagate logger into dependency builders, call slog.SetDefault(logger) during server start, and remove salt/zap types.
API handlers (v1beta1connect)
internal/api/v1beta1connect/*.go (~60 files)
Removed go.uber.org/zap usage; changed errorLogger logging calls to accept plain key/value args instead of zap.Field wrappers; removed context-extracted zap logger where present.
API error handler core
internal/api/v1beta1connect/error_handler.go, internal/api/v1beta1connect/v1beta1connect.go
Changed LogServiceError/LogUnexpectedError signatures to variadic ...any, implemented slog-based logging, removed request-id extraction/getRequestID and the exported ExtractLogger.
Repositories & store
internal/store/postgres/*.go (many), internal/store/spicedb/*.go, internal/store/blob/resources_repository.go
Updated repositories to use *slog.Logger; adjusted constructors and logging calls to use context-aware slog methods; updated many repository tests to construct *slog.Logger (TextHandler→io.Discard).
Logger infra & interceptors
pkg/logger/logger.go, pkg/server/connect_interceptors/logger.go, pkg/server/server.go
Replaced Zap integration with log/slog implementation: InitLogger returns *slog.Logger, added ContextHandler and AppendCtx, introduced levelForCode, updated the connect interceptor and server functions to use *slog.Logger.
E2E testbench & helpers
test/e2e/testbench/*.go
Testbench/start helpers updated to accept *slog.Logger; Stripe/SpiceDB builders and calls updated accordingly.
Misc tests & small files
multiple test files under internal/store/postgres/*_test.go, core/*_test.go, etc.
Replaced salt/log noop/zap test loggers with slog.New(slog.NewTextHandler(io.Discard, nil)) and updated imports.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • rohilsurana
  • whoAbhishekSah
  • rsbh
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coveralls
Copy link
Copy Markdown

coveralls commented Apr 18, 2026

Coverage Report for CI Build 24790311138

Coverage decreased (-0.02%) to 42.368%

Details

  • Coverage decreased (-0.02%) from the base build.
  • Patch coverage: 479 uncovered changes across 66 files (435 of 914 lines covered, 47.59%).
  • 25 coverage regressions across 15 files.

Uncovered Changes

Top 10 Files by Coverage Impact Changed Covered %
pkg/logger/logger.go 48 0 0.0%
internal/api/v1beta1connect/role.go 53 7 13.21%
internal/api/v1beta1connect/authorize.go 26 0 0.0%
pkg/server/connect_interceptors/logger.go 26 0 0.0%
internal/api/v1beta1connect/billing_customer.go 28 3 10.71%
internal/api/v1beta1connect/user.go 60 35 58.33%
internal/api/v1beta1connect/group.go 37 16 43.24%
internal/api/v1beta1connect/organization.go 44 25 56.82%
internal/api/v1beta1connect/authenticate.go 19 2 10.53%
core/authenticate/authenticators.go 17 2 11.76%

Coverage Regressions

25 previously-covered lines in 15 files lost coverage.

Top 10 Files by Coverage Loss Lines Losing Coverage Coverage
internal/api/v1beta1connect/role.go 5 25.69%
core/userpat/alert_service.go 3 77.09%
internal/api/v1beta1connect/billing_product.go 2 63.78%
internal/api/v1beta1connect/organization.go 2 58.18%
internal/api/v1beta1connect/user.go 2 59.17%
pkg/server/connect_interceptors/logger.go 2 0.0%
internal/api/v1beta1connect/authenticate.go 1 22.48%
internal/api/v1beta1connect/billing_customer.go 1 6.67%
internal/api/v1beta1connect/billing_invoice.go 1 51.2%
internal/api/v1beta1connect/billing_subscription.go 1 15.98%

Coverage Stats

Coverage Status
Relevant Lines: 37037
Covered Lines: 15692
Line Coverage: 42.37%
Coverage Strength: 11.76 hits per line

💛 - Coveralls

Fatal inside a function that returns error is redundant and prevents
callers from handling the error gracefully. Keep Fatal only in the
shutdown goroutine where returning is not possible.
Replace the zap-inherited pattern of storing/extracting a *slog.Logger
from context with the idiomatic slog approach:

- Add ContextHandler that auto-appends request-scoped attrs from context
- Add AppendCtx helper to store slog.Attr in context
- Interceptor stores request_id/method as context attrs, not a logger
- API handlers use slog.ErrorContext(ctx) with default logger
- Billing services get explicit *slog.Logger struct field
- Remove ToContext/FromContext entirely

This follows the Go slog design principle: loggers are explicit
dependencies (struct fields), request-scoped data flows through
context via a custom handler.
All s.log.Error/Warn/Debug/Info calls in functions that have a
ctx parameter now use the *Context variant (e.g., ErrorContext(ctx, ...)).
This ensures request-scoped attributes (request_id, method) from the
ContextHandler appear in every log line.

47 calls updated across core/authenticate, core/membership,
core/domain, core/userpat, internal/store/postgres, and
internal/store/blob.
Replace fmt.Sprintf("msg: %v", err) with proper slog key-value pairs
("error", err) in authenticators.go. This keeps errors as structured
fields that are queryable in log aggregation tools.
Copy the existing attrs slice before appending to avoid mutating the
parent context's backing array when multiple goroutines fork from the
same context and both call AppendCtx.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
core/webhook/service.go (1)

111-153: ⚠️ Potential issue | 🟡 Minor

Detached goroutine logs against request ctx.

The goroutine outlives the request and uses the parent ctx for slog.ErrorContext. Once the request returns and ctx is cancelled, logs still emit fine (slog doesn't check cancellation), and context values (e.g., request_id extracted by ContextHandler) remain accessible — so this is functionally OK. Just flagging to confirm this matches the intended request-scoped attribute propagation pattern described in the PR, especially since the DB call intentionally uses a detachedRepoContext. If you want request-scoped attrs on these logs, the current ctx is correct; if not, consider using detachedRepoContext consistently.

Also minor: key "errs" at line 152 serializes a []error — slog's default JSON encoder will stringify via fmt. Consider errors.Join(errs...).Error() or logging count + first error for cleaner structured output.

internal/api/v1beta1connect/session.go (1)

106-119: ⚠️ Potential issue | 🟠 Major

Redact or hash session IDs before logging.

session_id is session-control data; writing the raw value to logs increases blast radius if logs are exposed. Keep correlation by logging a deterministic hash or short redacted token instead.

🛡️ Proposed direction
 errorLogger.LogServiceError(ctx, request, "RevokeSession.GetByID", err,
-	"session_id", sessionID.String())
+	"session_id_hash", hashLogID(sessionID.String()))

Apply the same pattern to the PingUserSession, PingUserSession.GetByID, and RevokeUserSession log fields.

Also applies to: 142-153, 211-214

internal/api/v1beta1connect/user.go (1)

138-150: ⚠️ Potential issue | 🟠 Major

Sanitize emails and user names before logging.

These changed slog arguments persist raw emails/user names in error logs. Prefer user IDs already present in the log context, boolean presence flags, or hashed identifiers.

🛡️ Proposed sanitization pattern
 		errorLogger.LogServiceError(ctx, request, "CreateUser", err,
-			"email", email,
-			"name", name)
+			"email_present", email != "",
+			"name_present", name != "")
@@
 			errorLogger.LogUnexpectedError(ctx, request, "CreateUser", err,
-				"user_email", email,
-				"user_name", name)
+				"email_present", email != "",
+				"name_present", name != "")
@@
 		errorLogger.LogServiceError(ctx, request, "UpdateUser", err,
 			"user_id", id,
-			"email", email)
+			"email_present", email != "")
@@
 			errorLogger.LogUnexpectedError(ctx, request, "UpdateUser", err,
 				"user_id", id,
-				"user_email", email)
+				"email_present", email != "")
@@
 		errorLogger.LogUnexpectedError(ctx, request, "ListOrganizationsByUser", err,
 			"user_id", userID,
-			"user_email", userData.Email)
+			"user_email_present", userData.Email != "")
@@
 			errorLogger.LogUnexpectedError(ctx, request, "ListOrganizationsByCurrentUser", err,
 				"principal_id", principal.ID,
 				"principal_type", principal.Type,
-				"user_email", principal.User.Email)
+				"user_email_present", principal.User.Email != "")

Also applies to: 286-300, 747-749, 812-815

core/authenticate/service.go (1)

111-116: ⚠️ Potential issue | 🟡 Minor

Guard against nil logger injection.

Service now dereferences s.log in runtime paths; a nil constructor argument will panic. Default it once in NewService.

🛡️ Proposed nil-safe fallback
 func NewService(logger *slog.Logger, config Config, flowRepo FlowRepository,
 	mailDialer mailer.Dialer, tokenService TokenService, sessionService SessionService,
 	userService UserService, serviceUserService ServiceUserService, webAuthConfig *webauthn.WebAuthn,
 	userPATService UserPATService) *Service {
+	if logger == nil {
+		logger = slog.Default()
+	}
 	r := &Service{
 		log: logger,
core/userpat/alert_service.go (1)

81-99: ⚠️ Potential issue | 🟡 Minor

Default nil loggers at construction.

Run, sendExpiryReminders, sendExpiredNotices, and sendAlert all dereference s.logger; passing nil will panic when alerts execute.

🛡️ Proposed nil-safe fallback
 func NewAlertService(
 	repo AlertRepository,
 	userSvc AlertUserService,
 	orgSvc AlertOrgService,
@@
 	logger *slog.Logger,
 	auditRepo AlertAuditRepository,
 ) *AlertService {
+	if logger == nil {
+		logger = slog.Default()
+	}
 	return &AlertService{
pkg/server/connect_interceptors/logger.go (1)

48-75: ⚠️ Potential issue | 🟡 Minor

Use connect.CodeOf for proper error code extraction and remove duplicate request-scoped attributes.

Lines 57–60 use connect.Code(0) (an invalid code) and direct type assertion to extract error codes, which misses wrapped *connect.Error values. Additionally, lines 65 and 68 explicitly log request_id and method, duplicating the context attributes already set on lines 48–51. When using ContextHandler, these fields are automatically included from context, making them redundant.

Refactor to use connect.CodeOf for proper error code extraction (which handles wrapped errors), map non-Connect errors like context.Canceled to appropriate codes, and remove explicit method and request_id from the attrs slice.

Suggested patch
 import (
 	"context"
+	"errors"
 	"log/slog"
 	"time"
@@
-			code := connect.Code(0)
-			if connectErr, ok := err.(*connect.Error); ok {
-				code = connectErr.Code()
-			}
+			code := "ok"
+			level := slog.LevelInfo
+			if err != nil {
+				connectCode := codeForError(err)
+				code = connectCode.String()
+				level = levelForCode(connectCode)
+			}
 
 			attrs := []any{
 				"system", "connect_rpc",
 				"start_time", startTime,
-				"method", req.Spec().Procedure,
 				"time_ms", duration.Milliseconds(),
-				"code", code.String(),
-				"request_id", requestID,
+				"code", code,
 			}
 			if err != nil {
 				attrs = append(attrs, "error", err)
 			}
 
-			level := levelForCode(code, err)
 			logger.Log(ctx, level, "finished call", attrs...)
@@
-func levelForCode(code connect.Code, err error) slog.Level {
-	if err == nil {
-		return slog.LevelInfo
-	}
+func codeForError(err error) connect.Code {
+	switch {
+	case errors.Is(err, context.Canceled):
+		return connect.CodeCanceled
+	case errors.Is(err, context.DeadlineExceeded):
+		return connect.CodeDeadlineExceeded
+	default:
+		return connect.CodeOf(err)
+	}
+}
+
+func levelForCode(code connect.Code) slog.Level {
 	switch code {
 	case connect.CodeCanceled,
 		connect.CodeDeadlineExceeded,
🧹 Nitpick comments (6)
core/invitation/service.go (1)

121-121: Consider injecting *slog.Logger into the Service for consistency.

slog.SetDefault() is initialized at startup (cmd/server.go:86), so the package-level logger will have your ContextHandler. However, other services in the codebase (e.g., core/userpat/, core/membership/, core/authenticate/) wire the logger directly to improve consistency and avoid relying on global state. The logger is already available at construction time; consider adding it to the Service struct for deterministic behavior aligned with the rest of the codebase.

core/authenticate/authenticators.go (1)

41-242: Inconsistent error attribute key: "error" vs "err".

Within this file, lines 41 and 51 use "error" while lines 69, 76, 117, 125, 139, 148, 161, 192, 207, 226, 242 use "err". Other migrated files in this PR (e.g., core/webhook/service.go) standardize on "error". Pick one key project-wide so log consumers/dashboards can filter reliably — slog also has a dedicated slog.Any("error", err) convention worth adopting.

Proposed fix
-		s.log.DebugContext(ctx, "PAT validation failed", "err", err)
+		s.log.DebugContext(ctx, "PAT validation failed", "error", err)

(apply similarly to all "err" occurrences in this file)

internal/api/v1beta1connect/user_orgs.go (1)

38-44: Consider: redundant logging on the ErrBadInput path.

On Line 38 a service error is logged for postgres.ErrBadInput, which is then returned to the client as CodeInvalidArgument. Caller-induced bad-input errors typically don't warrant error-level server logs (they'll generate noise for every malformed client request). Other handlers in this PR (e.g. organization_tokens.go, organization_serviceuser.go) only log in the unexpected-error branch for the same condition. Consider dropping the log on Line 38-39 or downgrading it, for consistency.

internal/api/v1beta1connect/relation.go (1)

103-119: Avoid double-logging unexpected relation errors.

These paths call LogServiceError before the switch, then call LogUnexpectedError again in the default branch with the same attrs. Pick one log call per error path to avoid duplicate error records and noisy alerting.

♻️ Proposed shape
 if err != nil {
-	errorLogger.LogServiceError(ctx, request, "CreateRelation", err,
-		"subject", request.Msg.GetBody().GetSubject(),
-		"object", request.Msg.GetBody().GetObject(),
-		"relation", request.Msg.GetBody().GetRelation(),
-		"subject_sub_relation", request.Msg.GetBody().GetSubjectSubRelation())
-
 	switch {
 	case errors.Is(err, relation.ErrInvalidDetail):
 		return nil, connect.NewError(connect.CodeInvalidArgument, ErrBadRequest)
 	default:
 		errorLogger.LogUnexpectedError(ctx, request, "CreateRelation", err,

Apply the same pattern in GetRelation and DeleteRelation.

Also applies to: 138-150, 187-202

core/event/listener.go (1)

5-6: Keep the failure reason structured.

Line 42 stringifies the wrapped error into the log message, so downstream log queries cannot filter on a stable error field. Prefer a constant message with the original error as an attribute.

Proposed cleanup
 import (
 	"context"
-	"fmt"
 	"log/slog"
 
 	"github.com/raystack/frontier/core/audit"
 )
@@
 	case audit.OrgCreatedEvent.String():
 		if err := l.processor.EnsureDefaultPlan(ctx, log.OrgID); err != nil {
-			slog.ErrorContext(ctx, fmt.Errorf("EnsureDefaultPlan: %w", err).Error(), "event", log.Action)
+			slog.ErrorContext(ctx, "failed to ensure default plan", "error", err, "event", log.Action)
 		}
 	}
 }

Also applies to: 41-42

billing/customer/service_test.go (1)

6-6: Use a discard logger in tests instead of the process-global default.

These tests should not depend on or write through slog.Default(). A local discard logger keeps the migration behavior deterministic and avoids noisy test output.

Proposed test logger helper
 import (
 	"context"
 	"errors"
+	"io"
 	"log/slog"
 	"testing"
@@
 var sampleError = errors.New("sample error")
+
+func testLogger() *slog.Logger {
+	return slog.New(slog.NewTextHandler(io.Discard, nil))
+}
@@
-				return customer.NewService(slog.Default(), stripeClient, mockRepo, cfg, mockCredit)
+				return customer.NewService(testLogger(), stripeClient, mockRepo, cfg, mockCredit)

Apply the same testLogger() replacement to the other customer.NewService(...) calls in this file.

Also applies to: 76-76, 108-108, 172-172, 265-265, 288-288, 336-336, 391-391, 408-408, 475-475, 492-492


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a83a8978-ba79-49f0-940a-498c1b92c895

📥 Commits

Reviewing files that changed from the base of the PR and between a8a19f3 and 82c5515.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (113)
  • billing/checkout/service.go
  • billing/customer/service.go
  • billing/customer/service_test.go
  • billing/invoice/service.go
  • billing/subscription/service.go
  • billing/subscription/service_test.go
  • cmd/migrate.go
  • cmd/serve.go
  • cmd/server.go
  • core/authenticate/authenticators.go
  • core/authenticate/service.go
  • core/authenticate/service_test.go
  • core/authenticate/session/service.go
  • core/authenticate/session/service_test.go
  • core/domain/service.go
  • core/event/listener.go
  • core/event/service.go
  • core/invitation/service.go
  • core/membership/service.go
  • core/membership/service_test.go
  • core/userpat/alert_service.go
  • core/userpat/alert_service_test.go
  • core/userpat/service.go
  • core/userpat/service_test.go
  • core/userpat/validator.go
  • core/userpat/validator_test.go
  • core/webhook/service.go
  • go.mod
  • internal/api/v1beta1connect/audit_record.go
  • internal/api/v1beta1connect/authenticate.go
  • internal/api/v1beta1connect/authenticate_test.go
  • internal/api/v1beta1connect/authorize.go
  • internal/api/v1beta1connect/billing_check.go
  • internal/api/v1beta1connect/billing_checkout.go
  • internal/api/v1beta1connect/billing_customer.go
  • internal/api/v1beta1connect/billing_invoice.go
  • internal/api/v1beta1connect/billing_plan.go
  • internal/api/v1beta1connect/billing_product.go
  • internal/api/v1beta1connect/billing_subscription.go
  • internal/api/v1beta1connect/billing_usage.go
  • internal/api/v1beta1connect/billing_webhook.go
  • internal/api/v1beta1connect/deleter.go
  • internal/api/v1beta1connect/domain.go
  • internal/api/v1beta1connect/error_handler.go
  • internal/api/v1beta1connect/group.go
  • internal/api/v1beta1connect/invitations.go
  • internal/api/v1beta1connect/kyc.go
  • internal/api/v1beta1connect/metaschema.go
  • internal/api/v1beta1connect/namespace.go
  • internal/api/v1beta1connect/organization.go
  • internal/api/v1beta1connect/organization_invoices.go
  • internal/api/v1beta1connect/organization_pats.go
  • internal/api/v1beta1connect/organization_projects.go
  • internal/api/v1beta1connect/organization_serviceuser.go
  • internal/api/v1beta1connect/organization_serviceuser_credentials.go
  • internal/api/v1beta1connect/organization_tokens.go
  • internal/api/v1beta1connect/organization_users.go
  • internal/api/v1beta1connect/permission.go
  • internal/api/v1beta1connect/permission_check.go
  • internal/api/v1beta1connect/platform.go
  • internal/api/v1beta1connect/policy.go
  • internal/api/v1beta1connect/preferences.go
  • internal/api/v1beta1connect/project.go
  • internal/api/v1beta1connect/project_users.go
  • internal/api/v1beta1connect/prospect.go
  • internal/api/v1beta1connect/relation.go
  • internal/api/v1beta1connect/resource.go
  • internal/api/v1beta1connect/role.go
  • internal/api/v1beta1connect/serviceuser.go
  • internal/api/v1beta1connect/session.go
  • internal/api/v1beta1connect/user.go
  • internal/api/v1beta1connect/user_orgs.go
  • internal/api/v1beta1connect/user_pat.go
  • internal/api/v1beta1connect/user_projects.go
  • internal/api/v1beta1connect/v1beta1connect.go
  • internal/api/v1beta1connect/webhook.go
  • internal/bootstrap/service.go
  • internal/store/blob/resources_repository.go
  • internal/store/postgres/audit_record_repository_test.go
  • internal/store/postgres/billing_customer_repository_test.go
  • internal/store/postgres/billing_product_repository_test.go
  • internal/store/postgres/domain_repository.go
  • internal/store/postgres/flow_repository.go
  • internal/store/postgres/group_repository_test.go
  • internal/store/postgres/invitation_repository.go
  • internal/store/postgres/invitation_repository_test.go
  • internal/store/postgres/kyc_repository_test.go
  • internal/store/postgres/lock_test.go
  • internal/store/postgres/metaschema_repository.go
  • internal/store/postgres/namespace_repository_test.go
  • internal/store/postgres/organization_repository_test.go
  • internal/store/postgres/permission_repository_test.go
  • internal/store/postgres/policy_repository_test.go
  • internal/store/postgres/postgres_test.go
  • internal/store/postgres/preference_repository_test.go
  • internal/store/postgres/project_repository_test.go
  • internal/store/postgres/prospect_repository_test.go
  • internal/store/postgres/relation_repository_test.go
  • internal/store/postgres/resource_repository_test.go
  • internal/store/postgres/role_repository_test.go
  • internal/store/postgres/session_repository.go
  • internal/store/postgres/user_repository_test.go
  • internal/store/postgres/userpat_repository_test.go
  • internal/store/postgres/webhook_endpoint_repository_test.go
  • internal/store/spicedb/relation_repository.go
  • internal/store/spicedb/schema_repository.go
  • internal/store/spicedb/spicedb.go
  • pkg/logger/logger.go
  • pkg/server/connect_interceptors/logger.go
  • pkg/server/server.go
  • test/e2e/testbench/frontier.go
  • test/e2e/testbench/spicedb.go
  • test/e2e/testbench/stripe.go
💤 Files with no reviewable changes (1)
  • internal/api/v1beta1connect/v1beta1connect.go

Comment thread billing/customer/service.go
Comment thread billing/invoice/service.go
Comment thread cmd/server.go
Comment thread core/domain/service.go
Comment thread core/userpat/alert_service.go
Comment on lines 114 to +119
errorLogger.LogServiceError(ctx, request, "CreateProjectResource", err,
zap.String("resource_id", request.Msg.GetId()),
zap.String("project_id", request.Msg.GetProjectId()),
zap.String("resource_name", request.Msg.GetBody().GetName()),
zap.String("namespace", request.Msg.GetBody().GetNamespace()),
zap.String("principal", request.Msg.GetBody().GetPrincipal()))
"resource_id", request.Msg.GetId(),
"project_id", request.Msg.GetProjectId(),
"resource_name", request.Msg.GetBody().GetName(),
"namespace", request.Msg.GetBody().GetNamespace(),
"principal", request.Msg.GetBody().GetPrincipal())
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid logging raw principals from resource requests.

principal can contain a user identifier such as an email or subject ID. Prefer logging non-identifying context like principal_type plus presence, or a hashed value if correlation is required.

🛡️ Proposed sanitization
 			"resource_id", request.Msg.GetId(),
 			"project_id", request.Msg.GetProjectId(),
 			"resource_name", request.Msg.GetBody().GetName(),
 			"namespace", request.Msg.GetBody().GetNamespace(),
-			"principal", request.Msg.GetBody().GetPrincipal())
+			"principal_type", principalType,
+			"principal_present", request.Msg.GetBody().GetPrincipal() != "")

Apply the same replacement in both CreateProjectResource and UpdateProjectResource service/unexpected error logs.

Also applies to: 130-135, 224-229, 242-247

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rohilsurana Shall we solve PII is this PR itself or new one?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment thread internal/store/blob/resources_repository.go
Comment thread internal/store/postgres/invitation_repository.go
Comment thread pkg/logger/logger.go
Comment thread pkg/server/server.go
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates the codebase from zap/salt/log/grpc-zap middleware to Go’s standard log/slog, adding context-aware request-scoped attributes via a custom handler and updating call sites accordingly.

Changes:

  • Introduces pkg/logger slog infrastructure (ContextHandler, AppendCtx, InitLogger, Fatal) to standardize structured logging.
  • Updates ConnectRPC server/interceptors and many services/repositories/tests to accept/use *slog.Logger and slog.*Context APIs.
  • Removes direct zap logging dependencies and adjusts go.mod/go.sum to reflect the new logging stack.

Reviewed changes

Copilot reviewed 113 out of 114 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
test/e2e/testbench/stripe.go Updates testbench helpers to pass *slog.Logger into Stripe mock/client setup.
test/e2e/testbench/spicedb.go Updates SpiceDB testbench startup to use *slog.Logger.
test/e2e/testbench/frontier.go Updates E2E testbench server/migration helpers to accept *slog.Logger and use new Fatal.
pkg/server/server.go Refactors UI/Connect server startup to use *slog.Logger, new Connect logging interceptor, and improved error returns.
pkg/server/connect_interceptors/logger.go Replaces zap-based interceptor logging with slog + request-scoped context attributes.
pkg/logger/logger.go Adds slog initialization, context attribute propagation handler, and a Fatal helper.
internal/store/spicedb/spicedb.go Updates SpiceDB constructor signature to accept *slog.Logger.
internal/store/spicedb/schema_repository.go Switches schema repository logger to *slog.Logger and uses slog debug gating.
internal/store/spicedb/relation_repository.go Moves debug trace logging from grpc-zap to slog.InfoContext.
internal/store/postgres/webhook_endpoint_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/userpat_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/user_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/session_repository.go Updates repository logger field to *slog.Logger and uses DebugContext.
internal/store/postgres/role_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/resource_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/relation_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/prospect_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/project_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/preference_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/postgres_test.go Updates test DB helpers to use slog debug gating and remove logger writer dependency.
internal/store/postgres/policy_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/permission_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/organization_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/namespace_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/metaschema_repository.go Updates repository logger field to *slog.Logger and uses DebugContext.
internal/store/postgres/lock_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/kyc_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/invitation_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/invitation_repository.go Updates repository logger field to *slog.Logger and uses DebugContext.
internal/store/postgres/group_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/flow_repository.go Updates repository logger field to *slog.Logger and uses DebugContext.
internal/store/postgres/domain_repository.go Updates repository logger field to *slog.Logger and uses DebugContext.
internal/store/postgres/billing_product_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/billing_customer_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/postgres/audit_record_repository_test.go Updates tests to construct discard slog logger instead of salt/zap logger.
internal/store/blob/resources_repository.go Updates blob repository to use *slog.Logger and *Context log methods.
internal/bootstrap/service.go Switches bootstrap logging to slog.*Context.
internal/api/v1beta1connect/webhook.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/v1beta1connect.go Removes zap logger extraction helper and related context key usage.
internal/api/v1beta1connect/user_projects.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/user_pat.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/user_orgs.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/session.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/serviceuser.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/role.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/resource.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/relation.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/prospect.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/project_users.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/project.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/preferences.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/policy.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/platform.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/permission_check.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/permission.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/organization_users.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/organization_tokens.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/organization_serviceuser_credentials.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/organization_serviceuser.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/organization_projects.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/organization_pats.go Switches limit override warning to slog.WarnContext.
internal/api/v1beta1connect/organization_invoices.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/namespace.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/metaschema.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/kyc.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/invitations.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/error_handler.go Refactors centralized error logger to use slog key/value args.
internal/api/v1beta1connect/domain.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/deleter.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/billing_webhook.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/billing_usage.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/billing_subscription.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/billing_product.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/billing_plan.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/billing_invoice.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/billing_customer.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/billing_checkout.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/billing_check.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/authorize.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/authenticate_test.go Removes zap logger context dependency in tests.
internal/api/v1beta1connect/authenticate.go Replaces zap fields in error logging calls with slog key/value args.
internal/api/v1beta1connect/audit_record.go Replaces zap fields in error logging calls with slog key/value args.
go.sum Removes zap module sums consistent with dependency cleanup.
go.mod Removes direct zap dependency and reclassifies grpc-middleware v1 as indirect.
core/webhook/service.go Replaces grpc-zap logging with slog.*Context for webhook publishing errors.
core/userpat/validator_test.go Updates tests to use discard slog logger instead of salt/log noop.
core/userpat/validator.go Changes validator logger type to *slog.Logger.
core/userpat/service.go Changes service logger type to *slog.Logger and updates to *Context methods.
core/userpat/alert_service_test.go Updates tests to use discard slog logger instead of salt/log noop.
core/userpat/alert_service.go Changes alert service logger type to *slog.Logger and replaces zap fields.
core/membership/service_test.go Updates tests to use discard slog logger instead of salt/log noop.
core/membership/service.go Changes membership logger type to *slog.Logger and updates to *Context methods.
core/invitation/service.go Replaces logger.Ctx(ctx)/zap usage with slog.ErrorContext.
core/event/service.go Replaces grpc-zap logging with slog.*Context for billing webhook processing.
core/event/listener.go Replaces grpc-zap logging with slog.ErrorContext in audit event listener.
core/domain/service.go Changes domain service logger type to *slog.Logger and updates to *Context methods.
core/authenticate/session/service_test.go Updates tests to use discard slog logger instead of salt/log logrus.
core/authenticate/session/service.go Changes session service logger type to *slog.Logger and uses WarnContext.
core/authenticate/service_test.go Updates tests to use discard slog logger instead of salt/log logrus.
core/authenticate/service.go Changes authenticate service logger type to *slog.Logger and uses *Context logging.
core/authenticate/authenticators.go Replaces string-formatted debug logs with structured slog context logs.
cmd/server.go Sets slog default logger during server startup.
cmd/serve.go Propagates *slog.Logger across server setup and removes ctxzap context injection.
cmd/migrate.go Updates migrations commands to accept *slog.Logger.
billing/subscription/service_test.go Updates subscription tests to pass a slog logger into the service.
billing/subscription/service.go Adds *slog.Logger to subscription service and replaces grpc-zap logging.
billing/invoice/service.go Adds *slog.Logger to invoice service and replaces grpc-zap/zap logging.
billing/customer/service_test.go Updates customer tests to pass a slog logger into the service.
billing/customer/service.go Adds *slog.Logger to customer service and replaces grpc-zap logging.
billing/checkout/service.go Adds *slog.Logger to checkout service and replaces grpc-zap logging.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +46 to +51
// Store request-scoped attrs in context for downstream loggers
requestID := req.Header().Get(consts.RequestIDHeader)
ctx = frontierlogger.AppendCtx(ctx,
slog.String("request_id", requestID),
slog.String("method", req.Spec().Procedure),
)
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UnaryConnectLoggerInterceptor appends request_id and method into the context via AppendCtx, but the log call later also includes "method" and "request_id" in attrs. With the ContextHandler this will emit duplicate attributes/keys on the same record. Consider removing these keys from attrs (or stop appending them to ctx for this interceptor) so each field appears only once per log line.

Copilot uses AI. Check for mistakes.
Comment thread test/e2e/testbench/frontier.go
Comment on lines 28 to 31
func (r SchemaRepository) WriteSchema(ctx context.Context, schema string) error {
if r.logger.Level() == "debug" {
if r.logger.Enabled(ctx, slog.LevelDebug) {
fmt.Println(schema)
}
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In debug mode WriteSchema prints the schema using fmt.Println, which bypasses the configured logger/handler (JSON vs text), output destination, and any request-scoped context attributes. Prefer logging via r.logger.DebugContext(...) (potentially with a dedicated attribute like schema) so output is structured and consistent.

Copilot uses AI. Check for mistakes.
Comment thread core/event/listener.go
case audit.OrgCreatedEvent.String():
if err := l.processor.EnsureDefaultPlan(ctx, log.OrgID); err != nil {
stdLogger.Error(fmt.Errorf("EnsureDefaultPlan: %w", err).Error())
slog.ErrorContext(ctx, fmt.Errorf("EnsureDefaultPlan: %w", err).Error(), "event", log.Action)
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logs the error by embedding it into the message string (err.Error()), which loses the structured error field and makes log filtering harder. Prefer a stable message (e.g., "EnsureDefaultPlan failed") and add the wrapped error as an attribute (e.g., "error", err) along with event/org_id.

Copilot uses AI. Check for mistakes.
Comment thread internal/api/v1beta1connect/error_handler.go
…ures

Resolved conflicts in:
- core/domain/service.go: added membershipService with slog logger
- core/membership/service_test.go: added ProjectService/GroupService mocks with slog logger
- internal/api/v1beta1connect/domain.go: adopted main's simplified JoinOrganization flow
- internal/api/v1beta1connect/invitations.go: adopted main's simplified AcceptOrganizationInvitation flow
- internal/api/v1beta1connect/organization.go: adopted main's RemoveOrganizationMember with slog-style logging
- internal/api/v1beta1connect/user_pat.go: adopted main's mapPATError helper with slog-style logging
- Fix race condition in resources_repository.go: use local variable
  instead of repo.cached after mutex release
- Fix nil err on passkey_type type assertion failure in authenticate.go
- Add slog.SetDefault in migrate and migrate-rollback commands
- Map "fatal" log level to slog.LevelError in parseLevel
- Fix duplicate logging in SearchProjectUsers: log via LogServiceError
  only for BadInput errors, use LogUnexpectedError for the rest
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/userpat/service.go (1)

619-621: ⚠️ Potential issue | 🟡 Minor

Use ErrorContext here for consistency with the slog migration.

createPATPolicy receives ctx but logs via s.logger.Error(...) instead of ErrorContext(ctx, ...). Per the PR's ContextHandler design, context-scoped attributes (request_id, method, etc.) are only appended when the *Context variants are used, so this call will drop request-scoped fields unlike the other migrated sites in this file (Delete, Regenerate, Update, Create, validateProjectAccess, enrichWithScope).

Proposed fix
-		s.logger.Error("failed to create PAT policy",
-			"pat_id", patID, "role_id", roleID, "resource_id", resourceID,
-			"resource_type", resourceType, "grant_relation", grantRelation, "error", err)
+		s.logger.ErrorContext(ctx, "failed to create PAT policy",
+			"pat_id", patID, "role_id", roleID, "resource_id", resourceID,
+			"resource_type", resourceType, "grant_relation", grantRelation, "error", err)

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b195940e-0a52-47a3-aef9-295b6f77d90c

📥 Commits

Reviewing files that changed from the base of the PR and between 82c5515 and bfa22ab.

📒 Files selected for processing (12)
  • cmd/serve.go
  • core/domain/service.go
  • core/invitation/service.go
  • core/membership/service.go
  • core/membership/service_test.go
  • core/userpat/service.go
  • core/userpat/service_test.go
  • internal/api/v1beta1connect/authorize.go
  • internal/api/v1beta1connect/domain.go
  • internal/api/v1beta1connect/invitations.go
  • internal/api/v1beta1connect/organization.go
  • internal/api/v1beta1connect/user_pat.go
✅ Files skipped from review due to trivial changes (4)
  • internal/api/v1beta1connect/domain.go
  • internal/api/v1beta1connect/user_pat.go
  • internal/api/v1beta1connect/invitations.go
  • core/userpat/service_test.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • core/invitation/service.go
  • core/membership/service.go
  • core/domain/service.go
  • core/membership/service_test.go
  • cmd/serve.go

Tests added by main still used the old log.NewNoop() logger.
Replaced with slog.New(slog.NewTextHandler(io.Discard, nil)) to
match the slog migration.
Merged latest main which added ServiceuserService to membership.
Resolved conflicts keeping slog logger + new service parameter.
frontierlogger.Fatal calls os.Exit which bypasses deferred cleanup
when invoked inside the graceful shutdown goroutine.
@rohilsurana rohilsurana merged commit b196b3d into main Apr 23, 2026
8 checks passed
@rohilsurana rohilsurana deleted the refactor/migrate-logging-to-slog branch April 23, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants