From 2a86d2ecb8eaf733db090bf197f616fa2a26daae Mon Sep 17 00:00:00 2001 From: Ian Miell Date: Mon, 25 May 2026 11:33:30 +0100 Subject: [PATCH] Ignore sync errors in a consistent way --- cmd/digest.go | 5 +++-- cmd/riskdigest.go | 3 ++- cmd/run.go | 3 ++- cmd/users/create.go | 3 ++- cmd/users/update.go | 3 ++- internal/logging/sync.go | 14 ++++++++++++++ internal/logging/sync_test.go | 30 ++++++++++++++++++++++++++++++ 7 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 internal/logging/sync.go create mode 100644 internal/logging/sync_test.go diff --git a/cmd/digest.go b/cmd/digest.go index f005a8ac..8ce35033 100644 --- a/cmd/digest.go +++ b/cmd/digest.go @@ -6,6 +6,7 @@ import ( "log" "github.com/compliance-framework/api/internal/config" + "github.com/compliance-framework/api/internal/logging" "github.com/compliance-framework/api/internal/service" "github.com/compliance-framework/api/internal/service/digest" "github.com/compliance-framework/api/internal/service/email" @@ -53,7 +54,7 @@ func runDigestTest(cmd *cobra.Command, args []string) { } defer func() { - if err := sugar.Sync(); err != nil { + if err := sugar.Sync(); !logging.IgnoreSyncError(err) { log.Printf("failed to sync zap logger: %v", err) } }() @@ -144,7 +145,7 @@ func runDigestPreview(cmd *cobra.Command, args []string) { } defer func() { - if err := sugar.Sync(); err != nil { + if err := sugar.Sync(); !logging.IgnoreSyncError(err) { log.Printf("failed to sync zap logger: %v", err) } }() diff --git a/cmd/riskdigest.go b/cmd/riskdigest.go index 2e4801be..ffd13d36 100644 --- a/cmd/riskdigest.go +++ b/cmd/riskdigest.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/compliance-framework/api/internal/config" + "github.com/compliance-framework/api/internal/logging" "github.com/compliance-framework/api/internal/service" "github.com/compliance-framework/api/internal/service/email" slacksvc "github.com/compliance-framework/api/internal/service/slack" @@ -47,7 +48,7 @@ func runRiskDigestTest(cmd *cobra.Command, args []string) { } defer func() { - if err := sugar.Sync(); err != nil { + if err := sugar.Sync(); !logging.IgnoreSyncError(err) { log.Printf("failed to sync zap logger: %v", err) } }() diff --git a/cmd/run.go b/cmd/run.go index 2f57d2f2..abcfa74e 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -11,6 +11,7 @@ import ( "github.com/compliance-framework/api/internal/api/handler/auth" "github.com/compliance-framework/api/internal/api/handler/oscal" "github.com/compliance-framework/api/internal/config" + "github.com/compliance-framework/api/internal/logging" "github.com/compliance-framework/api/internal/service" "github.com/compliance-framework/api/internal/service/digest" "github.com/compliance-framework/api/internal/service/email" @@ -45,7 +46,7 @@ func RunServer(cmd *cobra.Command, args []string) { } defer func() { - if err := sugar.Sync(); err != nil { + if err := sugar.Sync(); !logging.IgnoreSyncError(err) { log.Printf("failed to sync zap logger: %v", err) } }() diff --git a/cmd/users/create.go b/cmd/users/create.go index 9a9f3e0f..ff6555e7 100644 --- a/cmd/users/create.go +++ b/cmd/users/create.go @@ -7,6 +7,7 @@ import ( "math/big" "github.com/compliance-framework/api/internal/config" + "github.com/compliance-framework/api/internal/logging" "github.com/compliance-framework/api/internal/service" "github.com/compliance-framework/api/internal/service/relational" "github.com/spf13/cobra" @@ -45,7 +46,7 @@ func addUser(cmd *cobra.Command, args []string) { cobra.CheckErr(err) defer func() { err := logger.Sync() - if err != nil { + if !logging.IgnoreSyncError(err) { println("failed to sync logger:", err.Error()) } }() diff --git a/cmd/users/update.go b/cmd/users/update.go index 0ba6ef22..5918c6ac 100644 --- a/cmd/users/update.go +++ b/cmd/users/update.go @@ -4,6 +4,7 @@ import ( "context" "github.com/compliance-framework/api/internal/config" + "github.com/compliance-framework/api/internal/logging" "github.com/compliance-framework/api/internal/service" "github.com/compliance-framework/api/internal/service/relational" "github.com/spf13/cobra" @@ -40,7 +41,7 @@ func updateUser(cmd *cobra.Command, args []string) { cobra.CheckErr(err) defer func() { err := logger.Sync() - if err != nil { + if !logging.IgnoreSyncError(err) { println("failed to sync logger:", err.Error()) } }() diff --git a/internal/logging/sync.go b/internal/logging/sync.go new file mode 100644 index 00000000..9b80bc5e --- /dev/null +++ b/internal/logging/sync.go @@ -0,0 +1,14 @@ +package logging + +import ( + "errors" + "syscall" +) + +// IgnoreSyncError filters the known benign sync errors returned when zap flushes +// stdout/stderr-backed loggers on some platforms and runtimes. +func IgnoreSyncError(err error) bool { + return err == nil || + errors.Is(err, syscall.EINVAL) || + errors.Is(err, syscall.ENOTTY) +} diff --git a/internal/logging/sync_test.go b/internal/logging/sync_test.go new file mode 100644 index 00000000..28e42aee --- /dev/null +++ b/internal/logging/sync_test.go @@ -0,0 +1,30 @@ +package logging + +import ( + "errors" + "syscall" + "testing" +) + +// Test the catching of sync errors +func TestIgnoreSyncError(t *testing.T) { + tests := []struct { + name string + err error + want bool + }{ + {name: "nil", err: nil, want: true}, + {name: "EINVAL", err: syscall.EINVAL, want: true}, + {name: "wrapped EINVAL", err: errors.New("sync: " + syscall.EINVAL.Error()), want: false}, + {name: "ENOTTY", err: syscall.ENOTTY, want: true}, + {name: "other", err: syscall.EBADF, want: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := IgnoreSyncError(tt.err); got != tt.want { + t.Fatalf("IgnoreSyncError(%v) = %v, want %v", tt.err, got, tt.want) + } + }) + } +}