From 209a6808e353f8df43dab67dda670044c9cdac6b Mon Sep 17 00:00:00 2001 From: Matías Insaurralde Date: Wed, 08 Apr 2026 01:19:56 +0000 Subject: [PATCH] appview/state: replace log package with structured slog logging Replace all log.Println/log.Printf calls across follow.go, star.go, reaction.go, gfi.go, and profile.go with s.logger.Error/Warn/Info using structured key-value pairs. Each handler opens with a child logger via s.logger.With("handler", "FuncName"). Firehose-idempotent delete failures (follow, star, reaction) use Warn; all other failures use Error. Signed-off-by: Matías Insaurralde --- appview/state/follow.go | 26 +++++++++++++------------- appview/state/gfi.go | 10 +++++----- appview/state/profile.go | 41 +++++++++++++++++++++++------------------ appview/state/reaction.go | 26 +++++++++++++------------- appview/state/star.go | 24 ++++++++++++------------ 5 file(s) changed, 66 insertion(s)(+), 61 deletion(s)(-) diff --git a/appview/state/follow.go b/appview/state/follow.go --- a/appview/state/follow.go +++ b/appview/state/follow.go @@ -1,7 +1,6 @@ package state import ( - "log" "net/http" "time" @@ -15,28 +14,29 @@ "tangled.org/core/tid" ) func (s *State) Follow(w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "Follow") currentUser := s.oauth.GetMultiAccountUser(r) subject := r.URL.Query().Get("subject") if subject == "" { - log.Println("invalid form") + l.Warn("invalid form") return } subjectIdent, err := s.idResolver.ResolveIdent(r.Context(), subject) if err != nil { - log.Println("failed to follow, invalid did") + l.Error("failed to follow, invalid did", "subject", subject, "err", err) return } if currentUser.Active.Did == subjectIdent.DID.String() { - log.Println("cant follow or unfollow yourself") + l.Warn("cant follow or unfollow yourself") return } client, err := s.oauth.AuthorizedClient(r) if err != nil { - log.Println("failed to authorize client") + l.Error("failed to authorize client", "err", err) return } @@ -55,11 +55,11 @@ CreatedAt: createdAt, }}, }) if err != nil { - log.Println("failed to create atproto record", err) + l.Error("failed to create atproto record", "err", err) return } - log.Println("created atproto record: ", resp.Uri) + l.Info("created atproto record", "uri", resp.Uri) follow := &models.Follow{ UserDid: currentUser.Active.Did, @@ -69,7 +69,7 @@ } err = db.AddFollow(s.db, follow) if err != nil { - log.Println("failed to follow", err) + l.Error("failed to follow", "err", err) return } @@ -77,7 +77,7 @@ s.notifier.NewFollow(r.Context(), follow) followStats, err := db.GetFollowerFollowingCount(s.db, subjectIdent.DID.String()) if err != nil { - log.Println("failed to get follow stats", err) + l.Error("failed to get follow stats", "err", err) } s.pages.FollowFragment(w, pages.FollowFragmentParams{ @@ -91,7 +91,7 @@ case http.MethodDelete: // find the record in the db follow, err := db.GetFollow(s.db, currentUser.Active.Did, subjectIdent.DID.String()) if err != nil { - log.Println("failed to get follow relationship") + l.Error("failed to get follow relationship", "err", err) return } @@ -102,19 +102,19 @@ Rkey: follow.Rkey, }) if err != nil { - log.Println("failed to unfollow") + l.Error("failed to unfollow", "err", err) return } err = db.DeleteFollowByRkey(s.db, currentUser.Active.Did, follow.Rkey) if err != nil { - log.Println("failed to delete follow from DB") + l.Warn("failed to delete follow from DB", "err", err) // this is not an issue, the firehose event might have already done this } followStats, err := db.GetFollowerFollowingCount(s.db, subjectIdent.DID.String()) if err != nil { - log.Println("failed to get follow stats", err) + l.Error("failed to get follow stats", "err", err) } s.pages.FollowFragment(w, pages.FollowFragmentParams{ diff --git a/appview/state/gfi.go b/appview/state/gfi.go --- a/appview/state/gfi.go +++ b/appview/state/gfi.go @@ -1,7 +1,6 @@ package state import ( - "log" "net/http" "sort" @@ -15,6 +14,7 @@ "tangled.org/core/orm" ) func (s *State) GoodFirstIssues(w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "GoodFirstIssues") user := s.oauth.GetMultiAccountUser(r) page := pagination.FromContext(r.Context()) @@ -23,14 +23,14 @@ goodFirstIssueLabel := s.config.Label.GoodFirstIssue gfiLabelDef, err := db.GetLabelDefinition(s.db, orm.FilterEq("at_uri", goodFirstIssueLabel)) if err != nil { - log.Println("failed to get gfi label def", err) + l.Error("failed to get gfi label def", "err", err) s.pages.Error500(w) return } repoLabels, err := db.GetRepoLabels(s.db, orm.FilterEq("label_at", goodFirstIssueLabel)) if err != nil { - log.Println("failed to get repo labels", err) + l.Error("failed to get repo labels", "err", err) s.pages.Error503(w) return } @@ -60,7 +60,7 @@ orm.FilterIn("repo_at", repoUris), orm.FilterEq("open", 1), ) if err != nil { - log.Println("failed to get issues", err) + l.Error("failed to get issues", "err", err) s.pages.Error503(w) return } @@ -135,7 +135,7 @@ if len(uriList) > 0 { allLabelDefs, err = db.GetLabelDefinitions(s.db, orm.FilterIn("at_uri", uriList)) if err != nil { - log.Println("failed to fetch labels", err) + l.Error("failed to fetch labels", "err", err) } } } diff --git a/appview/state/profile.go b/appview/state/profile.go --- a/appview/state/profile.go +++ b/appview/state/profile.go @@ -3,7 +3,6 @@ import ( "context" "fmt" - "log" "net/http" "slices" "strings" @@ -418,7 +417,7 @@ } followStatsMap, err := db.GetFollowerFollowingCounts(s.db, followDids) if err != nil { - log.Printf("getting follow counts for %s: %s", followDids, err) + l.Error("getting follow counts", "followDids", followDids, "err", err) } loggedInUserFollowing := make(map[string]struct{}) @@ -637,18 +636,19 @@ }, nil } func (s *State) UpdateProfileBio(w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "UpdateProfileBio") user := s.oauth.GetMultiAccountUser(r) err := r.ParseForm() if err != nil { - log.Println("invalid profile update form", err) + l.Error("invalid profile update form", "err", err) s.pages.Notice(w, "update-profile", "Invalid form.") return } profile, err := db.GetProfile(s.db, user.Active.Did) if err != nil { - log.Printf("getting profile data for %s: %s", user.Active.Did, err) + l.Error("getting profile data", "did", user.Active.Did, "err", err) } if profile == nil { profile = &models.Profile{Did: user.Active.Did} @@ -691,7 +691,7 @@ profile.Stats[0].Kind = models.ParseVanityStatKind(stat0) profile.Stats[1].Kind = models.ParseVanityStatKind(stat1) if err := db.ValidateProfile(s.db, profile); err != nil { - log.Println("invalid profile", err) + l.Error("invalid profile", "err", err) s.pages.Notice(w, "update-profile", err.Error()) return } @@ -700,18 +700,19 @@ s.updateProfile(profile, w, r) } func (s *State) UpdateProfilePins(w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "UpdateProfilePins") user := s.oauth.GetMultiAccountUser(r) err := r.ParseForm() if err != nil { - log.Println("invalid profile update form", err) + l.Error("invalid profile update form", "err", err) s.pages.Notice(w, "update-profile", "Invalid form.") return } profile, err := db.GetProfile(s.db, user.Active.Did) if err != nil { - log.Printf("getting profile data for %s: %s", user.Active.Did, err) + l.Error("getting profile data", "did", user.Active.Did, "err", err) } if profile == nil { profile = &models.Profile{Did: user.Active.Did} @@ -721,7 +722,7 @@ i := 0 var pinnedRepos [6]string for key, values := range r.Form { if i >= 6 { - log.Println("invalid pin update form", err) + l.Warn("too many pinned repos") s.pages.Notice(w, "update-profile", "Only 6 repositories can be pinned at a time.") return } @@ -736,17 +737,18 @@ s.updateProfile(profile, w, r) } func (s *State) updateProfile(profile *models.Profile, w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "updateProfile") user := s.oauth.GetMultiAccountUser(r) tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { - log.Println("failed to start transaction", err) + l.Error("failed to start transaction", "err", err) s.pages.Notice(w, "update-profile", "Failed to update profile, try again later.") return } client, err := s.oauth.AuthorizedClient(r) if err != nil { - log.Println("failed to get authorized client", err) + l.Error("failed to get authorized client", "err", err) s.pages.Notice(w, "update-profile", "Failed to update profile, try again later.") return } @@ -792,14 +794,14 @@ }}, SwapRecord: cid, }) if err != nil { - log.Println("failed to update profile", err) + l.Error("failed to update profile on PDS", "err", err) s.pages.Notice(w, "update-profile", "Failed to update PDS, try again later.") return } err = db.UpsertProfile(tx, profile) if err != nil { - log.Println("failed to update profile", err) + l.Error("failed to update profile in DB", "err", err) s.pages.Notice(w, "update-profile", "Failed to update profile, try again later.") return } @@ -810,11 +812,12 @@ s.pages.HxRedirect(w, "/"+user.Active.Did) } func (s *State) EditBioFragment(w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "EditBioFragment") user := s.oauth.GetMultiAccountUser(r) profile, err := db.GetProfile(s.db, user.Active.Did) if err != nil { - log.Printf("getting profile data for %s: %s", user.Active.Did, err) + l.Error("getting profile data", "did", user.Active.Did, "err", err) } if profile == nil { profile = &models.Profile{Did: user.Active.Did} @@ -834,11 +837,12 @@ }) } func (s *State) EditPinsFragment(w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "EditPinsFragment") user := s.oauth.GetMultiAccountUser(r) profile, err := db.GetProfile(s.db, user.Active.Did) if err != nil { - log.Printf("getting profile data for %s: %s", user.Active.Did, err) + l.Error("getting profile data", "did", user.Active.Did, "err", err) } if profile == nil { profile = &models.Profile{Did: user.Active.Did} @@ -846,12 +850,12 @@ } repos, err := db.GetRepos(s.db, orm.FilterEq("did", user.Active.Did)) if err != nil { - log.Printf("getting repos for %s: %s", user.Active.Did, err) + l.Error("getting repos", "did", user.Active.Did, "err", err) } collaboratingRepos, err := db.CollaboratingIn(s.db, user.Active.Did) if err != nil { - log.Printf("getting collaborating repos for %s: %s", user.Active.Did, err) + l.Error("getting collaborating repos", "did", user.Active.Did, "err", err) } allRepos := []pages.PinnedRepo{} @@ -1071,9 +1075,10 @@ s.pages.HxRedirect(w, r.Header.Get("Referer")) } func (s *State) UpdateProfilePunchcardSetting(w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "UpdateProfilePunchcardSetting") err := r.ParseForm() if err != nil { - log.Println("invalid profile update form", err) + l.Error("invalid profile update form", "err", err) return } user := s.oauth.GetUser(r) @@ -1090,7 +1095,7 @@ } err = db.UpsertPunchcardPreference(s.db, user.Did, hideMine, hideOthers) if err != nil { - log.Println("failed to update punchcard preferences", err) + l.Error("failed to update punchcard preferences", "err", err) return } diff --git a/appview/state/reaction.go b/appview/state/reaction.go --- a/appview/state/reaction.go +++ b/appview/state/reaction.go @@ -1,7 +1,6 @@ package state import ( - "log" "net/http" "time" @@ -17,29 +16,30 @@ "tangled.org/core/tid" ) func (s *State) React(w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "React") currentUser := s.oauth.GetMultiAccountUser(r) subject := r.URL.Query().Get("subject") if subject == "" { - log.Println("invalid form") + l.Warn("invalid form") return } subjectUri, err := syntax.ParseATURI(subject) if err != nil { - log.Println("invalid form") + l.Warn("invalid form", "subject", subject, "err", err) return } reactionKind, ok := models.ParseReactionKind(r.URL.Query().Get("kind")) if !ok { - log.Println("invalid reaction kind") + l.Warn("invalid reaction kind", "kind", r.URL.Query().Get("kind")) return } client, err := s.oauth.AuthorizedClient(r) if err != nil { - log.Println("failed to authorize client", err) + l.Error("failed to authorize client", "err", err) return } @@ -60,22 +60,22 @@ }, }, }) if err != nil { - log.Println("failed to create atproto record", err) + l.Error("failed to create atproto record", "err", err) return } err = db.AddReaction(s.db, currentUser.Active.Did, subjectUri, reactionKind, rkey) if err != nil { - log.Println("failed to react", err) + l.Error("failed to react", "err", err) return } reactionMap, err := db.GetReactionMap(s.db, 20, subjectUri) if err != nil { - log.Println("failed to get reactions for ", subjectUri) + l.Error("failed to get reactions", "subjectUri", subjectUri, "err", err) } - log.Println("created atproto record: ", resp.Uri) + l.Info("created atproto record", "uri", resp.Uri) s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{ ThreadAt: subjectUri, @@ -89,7 +89,7 @@ return case http.MethodDelete: reaction, err := db.GetReaction(s.db, currentUser.Active.Did, subjectUri, reactionKind) if err != nil { - log.Println("failed to get reaction relationship for", currentUser.Active.Did, subjectUri) + l.Error("failed to get reaction relationship", "did", currentUser.Active.Did, "subjectUri", subjectUri, "err", err) return } @@ -100,19 +100,19 @@ Rkey: reaction.Rkey, }) if err != nil { - log.Println("failed to remove reaction") + l.Error("failed to remove reaction", "err", err) return } err = db.DeleteReactionByRkey(s.db, currentUser.Active.Did, reaction.Rkey) if err != nil { - log.Println("failed to delete reaction from DB") + l.Warn("failed to delete reaction from DB", "err", err) // this is not an issue, the firehose event might have already done this } reactionMap, err := db.GetReactionMap(s.db, 20, subjectUri) if err != nil { - log.Println("failed to get reactions for ", subjectUri) + l.Error("failed to get reactions", "subjectUri", subjectUri, "err", err) return } diff --git a/appview/state/star.go b/appview/state/star.go --- a/appview/state/star.go +++ b/appview/state/star.go @@ -1,7 +1,6 @@ package state import ( - "log" "net/http" "time" @@ -17,23 +16,24 @@ "tangled.org/core/tid" ) func (s *State) Star(w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "Star") currentUser := s.oauth.GetMultiAccountUser(r) subject := r.URL.Query().Get("subject") if subject == "" { - log.Println("invalid form") + l.Warn("invalid form") return } subjectUri, err := syntax.ParseATURI(subject) if err != nil { - log.Println("invalid form") + l.Warn("invalid form", "subject", subject, "err", err) return } client, err := s.oauth.AuthorizedClient(r) if err != nil { - log.Println("failed to authorize client", err) + l.Error("failed to authorize client", "err", err) return } @@ -59,10 +59,10 @@ Rkey: rkey, Record: &lexutil.LexiconTypeDecoder{Val: starRecord}, }) if err != nil { - log.Println("failed to create atproto record", err) + l.Error("failed to create atproto record", "err", err) return } - log.Println("created atproto record: ", resp.Uri) + l.Info("created atproto record", "uri", resp.Uri) star := &models.Star{ Did: currentUser.Active.Did, @@ -72,13 +72,13 @@ } err = db.AddStar(s.db, star) if err != nil { - log.Println("failed to star", err) + l.Error("failed to star", "err", err) return } starCount, err := db.GetStarCount(s.db, subjectUri) if err != nil { - log.Println("failed to get star count for ", subjectUri) + l.Error("failed to get star count", "subjectUri", subjectUri, "err", err) } s.notifier.NewStar(r.Context(), star) @@ -94,7 +94,7 @@ case http.MethodDelete: // find the record in the db star, err := db.GetStar(s.db, currentUser.Active.Did, subjectUri) if err != nil { - log.Println("failed to get star relationship") + l.Error("failed to get star relationship", "err", err) return } @@ -105,19 +105,19 @@ Rkey: star.Rkey, }) if err != nil { - log.Println("failed to unstar") + l.Error("failed to unstar", "err", err) return } err = db.DeleteStarByRkey(s.db, currentUser.Active.Did, star.Rkey) if err != nil { - log.Println("failed to delete star from DB") + l.Warn("failed to delete star from DB", "err", err) // this is not an issue, the firehose event might have already done this } starCount, err := db.GetStarCount(s.db, subjectUri) if err != nil { - log.Println("failed to get star count for ", subjectUri) + l.Error("failed to get star count", "subjectUri", subjectUri, "err", err) return } -- tangled.sh