diff --git a/main.go b/main.go index 20776cf..86d22bf 100644 --- a/main.go +++ b/main.go @@ -321,10 +321,10 @@ func (a *App) runRetry(ctx context.Context, cmd *cli.Command) error { if res == nil { fmt.Printf("Successfully retried: %s - %s\n", fr.rec.ArtistName(), fr.rec.TrackName) if err := a.storage.MarkPublished(did, fr.key); err != nil { - a.log.Error("Failed to mark record as published", sync.Error(err), slog.String("key", fr.key)) + a.log.Error("Failed to mark record as published", sync.ErrorAttr(err), slog.String("key", fr.key)) } if err := a.storage.RemoveFailed(did, fr.key); err != nil { - a.log.Error("Failed to remove record from failed list", sync.Error(err), slog.String("key", fr.key)) + a.log.Error("Failed to remove record from failed list", sync.ErrorAttr(err), slog.String("key", fr.key)) } successCount++ } else { @@ -508,7 +508,7 @@ func (a *App) runImport(ctx context.Context, cmd *cli.Command) error { return err } - a.log.Info("Starting import operation", sync.DID(handle)) + a.log.Info("Starting import operation", sync.DIDAttr(handle)) lastfmPath := cmd.String("lastfm") spotifyPath := cmd.String("spotify") @@ -521,7 +521,7 @@ func (a *App) runImport(ctx context.Context, cmd *cli.Command) error { if clearCache { if err := a.storage.ClearAll(); err != nil { - a.log.Error("Failed to clear cache", sync.Error(err)) + a.log.Error("Failed to clear cache", sync.ErrorAttr(err)) } else { a.log.Info("Cache cleared") } @@ -548,7 +548,7 @@ func (a *App) runImport(ctx context.Context, cmd *cli.Command) error { if err != nil { return fmt.Errorf("create auth client: %w", err) } - a.log.Info("Authenticated", sync.DID(authClient.DID()), slog.String("pds", authClient.PDS())) + a.log.Info("Authenticated", sync.DIDAttr(authClient.DID()), slog.String("pds", authClient.PDS())) limiter := sync.NewRateLimiter(a.storage, 0.9) repoClient := sync.NewRateClient(authClient.APIClient(), authClient.DID(), limiter) @@ -663,14 +663,14 @@ func (a *App) runSync(ctx context.Context, cmd *cli.Command) error { } fresh := cmd.Bool("fresh") - a.log.Info("Starting sync operation", sync.DID(authClient.DID()), slog.Bool("fresh", fresh)) + a.log.Info("Starting sync operation", sync.DIDAttr(authClient.DID()), slog.Bool("fresh", fresh)) limiter := sync.NewRateLimiter(a.storage, 0.85) repoClient := sync.NewRateClient(authClient.APIClient(), authClient.DID(), limiter) if fresh { if err := a.storage.Clear(authClient.DID()); err != nil { - a.log.Error("Failed to clear cache", sync.Error(err)) + a.log.Error("Failed to clear cache", sync.ErrorAttr(err)) } else { a.log.Info("Cache cleared") } @@ -696,7 +696,7 @@ func (a *App) runDedupe(ctx context.Context, cmd *cli.Command) error { fresh := cmd.Bool("fresh") yes := cmd.Bool("yes") a.log.Info("Starting dedupe operation", - sync.DID(authClient.DID()), + sync.DIDAttr(authClient.DID()), slog.Bool("dry_run", dryRun), slog.Bool("fresh", fresh)) @@ -705,7 +705,7 @@ func (a *App) runDedupe(ctx context.Context, cmd *cli.Command) error { if fresh { if err := a.storage.Clear(authClient.DID()); err != nil { - a.log.Error("Failed to clear cache", sync.Error(err)) + a.log.Error("Failed to clear cache", sync.ErrorAttr(err)) } else { a.log.Info("Cache cleared") } @@ -773,7 +773,7 @@ func (a *App) runDedupe(ctx context.Context, cmd *cli.Command) error { OnRetryScheduled(func(e failsafe.ExecutionScheduledEvent[any]) { a.log.Warn("Delete failed with transient error, retrying", slog.Duration("retryDelay", e.Delay), - sync.Error(e.LastError()), + sync.ErrorAttr(e.LastError()), slog.Int("attempt", e.Attempts()), slog.String("uri", uri)) }). @@ -784,7 +784,7 @@ func (a *App) runDedupe(ctx context.Context, cmd *cli.Command) error { }) if err != nil { - a.log.Error("Failed to delete record", sync.Error(err), slog.String("uri", uri)) + a.log.Error("Failed to delete record", sync.ErrorAttr(err), slog.String("uri", uri)) } else { a.log.Info("Deleted duplicate", slog.String("uri", uri), slog.String("track", rec.Value.TrackName)) } diff --git a/sync/logutil.go b/sync/logutil.go index 77c0fe0..ef5b333 100644 --- a/sync/logutil.go +++ b/sync/logutil.go @@ -13,19 +13,20 @@ type TrackInfo struct { PlayedAt time.Time } -func Track(name, artist string, playedAt time.Time) slog.Attr { - return slog.Group("track", - slog.String("name", name), - slog.String("artist", artist), - slog.Time("played_at", playedAt), +func trackAttr(rec PlayRecord) slog.Attr { + return slog.Group( + "track", + slog.String("name", rec.TrackName), + slog.String("artist", rec.ArtistName()), + slog.Time("played_at", rec.PlayedTime.Time), ) } -func DID(did string) slog.Attr { +func DIDAttr(did string) slog.Attr { return slog.String("did", did) } -func Error(err error) slog.Attr { +func ErrorAttr(err error) slog.Attr { if err == nil { return slog.Attr{} } diff --git a/sync/publish.go b/sync/publish.go index 70782a1..69af561 100644 --- a/sync/publish.go +++ b/sync/publish.go @@ -111,9 +111,7 @@ func Publish(ctx context.Context, client AuthClient, opts PublishOptions) Publis if opts.DryRun { for _, r := range batch { tid := syntax.NewTIDFromTime(r.PlayedTime.Time, 0) - slog.Info("would publish record (dry run)", - Track(r.TrackName, r.ArtistName(), r.PlayedTime.Time), - slog.String("rkey", string(tid))) + slog.Info("would publish record (dry run)", trackAttr(r), slog.String("rkey", string(tid))) } totalSuccess += len(batch) tracker.Increment(len(batch)) @@ -141,7 +139,7 @@ func Publish(ctx context.Context, client AuthClient, opts PublishOptions) Publis slog.Warn("batch failed with transient error, retrying", slog.Int("count", len(batch)), slog.Duration("retryDelay", e.Delay), - Error(e.LastError()), + ErrorAttr(e.LastError()), slog.Int("attempt", e.Attempts())) }). Build() @@ -151,12 +149,12 @@ func Publish(ctx context.Context, client AuthClient, opts PublishOptions) Publis }) if err != nil { slog.Error("batch failed after retries", - Error(err), + ErrorAttr(err), slog.Int("count", len(batch))) if opts.Storage != nil { if markErr := opts.Storage.MarkFailed(did, batchKeys, err.Error()); markErr != nil { - slog.Error("failed to mark records as failed", Error(markErr)) + slog.Error("failed to mark records as failed", ErrorAttr(markErr)) } } @@ -193,7 +191,7 @@ func Publish(ctx context.Context, client AuthClient, opts PublishOptions) Publis var record PlayRecord if err := json.Unmarshal(rec, &record); err != nil { - slog.Error("malformed record in storage", slog.String("key", key), Error(err)) + slog.Error("malformed record in storage", slog.String("key", key), ErrorAttr(err)) if opts.Storage != nil { _ = opts.Storage.MarkFailed(client.DID(), []string{key}, "malformed record") } @@ -219,7 +217,7 @@ func Publish(ctx context.Context, client AuthClient, opts PublishOptions) Publis cancelled := false if err != nil { - slog.Error("import interrupted", Error(err)) + slog.Error("import interrupted", ErrorAttr(err)) cancelled = true } @@ -287,7 +285,7 @@ func PublishBatch(ctx context.Context, client ATProtoClient, did string, batch [ atprotoRecords := prepareRecords(batch, clientAgent) err := client.ApplyWrites(ctx, RecordType, atprotoRecords) if err != nil { - slog.Error("batch publish failed", Error(err)) + slog.Error("batch publish failed", ErrorAttr(err)) return err } @@ -380,7 +378,7 @@ func fetchExistingLoop(ctx context.Context, client RepoClient[PlayRecord], did s OnRetryScheduled(func(e failsafe.ExecutionScheduledEvent[fetchResult]) { slog.Warn("fetch failed with transient error, retrying", slog.Duration("retryDelay", e.Delay), - Error(e.LastError()), + ErrorAttr(e.LastError()), slog.Int("attempt", e.Attempts())) }). Build() diff --git a/sync/record.go b/sync/record.go index d809d80..5fca73f 100644 --- a/sync/record.go +++ b/sync/record.go @@ -91,7 +91,7 @@ func (r PlayRecord) isLastFM() bool { return r.MusicServiceBaseDomain == MusicServiceLastFM } -func (r PlayRecord) BetterThan(other PlayRecord) bool { +func (r PlayRecord) betterThan(other PlayRecord) bool { if r.isLastFM() && !other.isLastFM() { return true } @@ -106,7 +106,7 @@ func (r PlayRecord) BetterThan(other PlayRecord) bool { } func (r PlayRecord) IsDuplicate(other PlayRecord, tolerance time.Duration) (bool, bool) { - return r.sameAs(other, tolerance), r.BetterThan(other) + return r.sameAs(other, tolerance), r.betterThan(other) } func (r PlayRecord) sameAs(other PlayRecord, tolerance time.Duration) bool { diff --git a/sync/record_test.go b/sync/record_test.go index f7b6bd5..832ddc2 100644 --- a/sync/record_test.go +++ b/sync/record_test.go @@ -170,7 +170,7 @@ func TestSelectBetterRecord(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := tt.r1.BetterThan(tt.r2) + result := tt.r1.betterThan(tt.r2) var resultService string if result { resultService = tt.r1.MusicServiceBaseDomain