repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

commit
8e35e95
parent
a60c3d8
author
Eric Bower
date
2024-09-20 18:52:19 +0000 UTC
chore: structured logging for servier and user info
18 files changed,  +101, -82
M auth/api.go
+1, -1
1@@ -656,7 +656,7 @@ func StartApiServer() {
2 		Port:   shared.GetEnv("AUTH_WEB_PORT", "3000"),
3 	}
4 
5-	logger := shared.CreateLogger()
6+	logger := shared.CreateLogger("auth")
7 	db := postgres.NewDB(cfg.DbURL, logger)
8 	defer db.Close()
9 
M feeds/config.go
+1, -1
1@@ -30,6 +30,6 @@ func NewConfigSite() *shared.ConfigSite {
2 		Space:       "feeds",
3 		AllowedExt:  []string{".txt"},
4 		HiddenPosts: []string{"_header.txt", "_readme.txt"},
5-		Logger:      shared.CreateLogger(),
6+		Logger:      shared.CreateLogger("feeds"),
7 	}
8 }
M feeds/cron.go
+30, -27
  1@@ -6,6 +6,7 @@ import (
  2 	"fmt"
  3 	html "html/template"
  4 	"io"
  5+	"log/slog"
  6 	"net/http"
  7 	"strings"
  8 	"text/template"
  9@@ -132,15 +133,15 @@ func (f *Fetcher) Validate(lastDigest *time.Time, parsed *shared.ListParsedText)
 10 	return nil
 11 }
 12 
 13-func (f *Fetcher) RunPost(user *db.User, post *db.Post) error {
 14-	f.cfg.Logger.Info("running feed post", "user", user.Name, "filename", post.Filename)
 15+func (f *Fetcher) RunPost(logger *slog.Logger, user *db.User, post *db.Post) error {
 16+	logger.Info("running feed post", "user", user.Name, "filename", post.Filename)
 17 
 18 	parsed := shared.ListParseText(post.Text)
 19 
 20-	f.cfg.Logger.Info("last digest at", "user", user.Name, "lastDigest", post.Data.LastDigest)
 21+	logger.Info("last digest at", "user", user.Name, "lastDigest", post.Data.LastDigest)
 22 	err := f.Validate(post.Data.LastDigest, parsed)
 23 	if err != nil {
 24-		f.cfg.Logger.Info(err.Error(), "user", user.Name)
 25+		logger.Info(err.Error(), "user", user.Name)
 26 		return nil
 27 	}
 28 
 29@@ -160,13 +161,13 @@ func (f *Fetcher) RunPost(user *db.User, post *db.Post) error {
 30 		urls = append(urls, url)
 31 	}
 32 
 33-	msgBody, err := f.FetchAll(urls, parsed.InlineContent, post.ID, user.Name)
 34+	msgBody, err := f.FetchAll(logger, urls, parsed.InlineContent, post.ID, user.Name)
 35 	if err != nil {
 36 		return err
 37 	}
 38 
 39 	subject := fmt.Sprintf("%s feed digest", post.Title)
 40-	err = f.SendEmail(user.Name, parsed.Email, subject, msgBody)
 41+	err = f.SendEmail(logger, user.Name, parsed.Email, subject, msgBody)
 42 	if err != nil {
 43 		return err
 44 	}
 45@@ -178,19 +179,20 @@ func (f *Fetcher) RunPost(user *db.User, post *db.Post) error {
 46 }
 47 
 48 func (f *Fetcher) RunUser(user *db.User) error {
 49+	logger := shared.LoggerWithUser(f.cfg.Logger, user)
 50 	posts, err := f.db.FindPostsForUser(&db.Pager{Num: 1000}, user.ID, "feeds")
 51 	if err != nil {
 52 		return err
 53 	}
 54 
 55 	if len(posts.Data) > 0 {
 56-		f.cfg.Logger.Info("found feed posts", "user", user.Name, "len", len(posts.Data))
 57+		logger.Info("found feed posts", "user", user.Name, "len", len(posts.Data))
 58 	}
 59 
 60 	for _, post := range posts.Data {
 61-		err = f.RunPost(user, post)
 62+		err = f.RunPost(logger, user, post)
 63 		if err != nil {
 64-			f.cfg.Logger.Info(err.Error(), "user", user)
 65+			logger.Info(err.Error(), "user", user)
 66 		}
 67 	}
 68 
 69@@ -227,8 +229,8 @@ func (f *Fetcher) ParseURL(fp *gofeed.Parser, url string) (*gofeed.Feed, error)
 70 	return feed, nil
 71 }
 72 
 73-func (f *Fetcher) Fetch(fp *gofeed.Parser, url string, username string, feedItems []*db.FeedItem) (*Feed, error) {
 74-	f.cfg.Logger.Info("fetching feed", "user", username, "url", url)
 75+func (f *Fetcher) Fetch(logger *slog.Logger, fp *gofeed.Parser, url string, username string, feedItems []*db.FeedItem) (*Feed, error) {
 76+	logger.Info("fetching feed", "user", username, "url", url)
 77 
 78 	feed, err := f.ParseURL(fp, url)
 79 	if err != nil {
 80@@ -312,7 +314,7 @@ type MsgBody struct {
 81 	Text string
 82 }
 83 
 84-func (f *Fetcher) FetchAll(urls []string, inlineContent bool, postID string, username string) (*MsgBody, error) {
 85+func (f *Fetcher) FetchAll(logger *slog.Logger, urls []string, inlineContent bool, postID string, username string) (*MsgBody, error) {
 86 	fp := gofeed.NewParser()
 87 	feeds := &DigestFeed{Options: DigestOptions{InlineContent: inlineContent}}
 88 	feedItems, err := f.db.FindFeedItemsByPostID(postID)
 89@@ -321,12 +323,12 @@ func (f *Fetcher) FetchAll(urls []string, inlineContent bool, postID string, use
 90 	}
 91 
 92 	for _, url := range urls {
 93-		feedTmpl, err := f.Fetch(fp, url, username, feedItems)
 94+		feedTmpl, err := f.Fetch(logger, fp, url, username, feedItems)
 95 		if err != nil {
 96 			if errors.Is(err, ErrNoRecentArticles) {
 97-				f.cfg.Logger.Info(err.Error())
 98+				logger.Info(err.Error())
 99 			} else {
100-				f.cfg.Logger.Error(err.Error())
101+				logger.Error(err.Error())
102 			}
103 			continue
104 		}
105@@ -374,7 +376,7 @@ func (f *Fetcher) FetchAll(urls []string, inlineContent bool, postID string, use
106 	}, nil
107 }
108 
109-func (f *Fetcher) SendEmail(username, email string, subject string, msg *MsgBody) error {
110+func (f *Fetcher) SendEmail(logger *slog.Logger, username, email string, subject string, msg *MsgBody) error {
111 	if email == "" {
112 		return fmt.Errorf("(%s) does not have an email associated with their feed post", username)
113 	}
114@@ -382,27 +384,27 @@ func (f *Fetcher) SendEmail(username, email string, subject string, msg *MsgBody
115 	from := mail.NewEmail("team pico", shared.DefaultEmail)
116 	to := mail.NewEmail(username, email)
117 
118-	// f.cfg.Logger.Infof("message body (%s)", plainTextContent)
119+	// f.logger.Infof("message body (%s)", plainTextContent)
120 
121 	message := mail.NewSingleEmail(from, subject, to, msg.Text, msg.Html)
122 	client := sendgrid.NewSendClient(f.cfg.SendgridKey)
123 
124-	f.cfg.Logger.Info("sending email digest", "user", username)
125+	logger.Info("sending email digest", "user", username)
126 	response, err := client.Send(message)
127 	if err != nil {
128 		return err
129 	}
130 
131-	// f.cfg.Logger.Infof("(%s) email digest response: %v", username, response)
132+	// f.logger.Infof("(%s) email digest response: %v", username, response)
133 
134 	if len(response.Headers["X-Message-Id"]) > 0 {
135-		f.cfg.Logger.Info(
136+		logger.Info(
137 			"successfully sent email digest",
138 			"email", email,
139 			"x-message-id", response.Headers["X-Message-Id"][0],
140 		)
141 	} else {
142-		f.cfg.Logger.Error(
143+		logger.Error(
144 			"could not find x-message-id, which means sending an email failed",
145 			"email", email,
146 		)
147@@ -411,7 +413,7 @@ func (f *Fetcher) SendEmail(username, email string, subject string, msg *MsgBody
148 	return nil
149 }
150 
151-func (f *Fetcher) Run() error {
152+func (f *Fetcher) Run(logger *slog.Logger) error {
153 	users, err := f.db.FindUsers()
154 	if err != nil {
155 		return err
156@@ -420,7 +422,7 @@ func (f *Fetcher) Run() error {
157 	for _, user := range users {
158 		err := f.RunUser(user)
159 		if err != nil {
160-			f.cfg.Logger.Error(err.Error())
161+			logger.Error("RunUser failed", "err", err.Error())
162 			continue
163 		}
164 	}
165@@ -429,15 +431,16 @@ func (f *Fetcher) Run() error {
166 }
167 
168 func (f *Fetcher) Loop() {
169+	logger := f.cfg.Logger
170 	for {
171-		f.cfg.Logger.Info("running digest emailer")
172+		logger.Info("running digest emailer")
173 
174-		err := f.Run()
175+		err := f.Run(logger)
176 		if err != nil {
177-			f.cfg.Logger.Error(err.Error())
178+			logger.Error(err.Error())
179 		}
180 
181-		f.cfg.Logger.Info("digest emailer finished, waiting 10 mins")
182+		logger.Info("digest emailer finished, waiting 10 mins")
183 		time.Sleep(10 * time.Minute)
184 	}
185 }
M filehandlers/assets/handler.go
+8, -6
 1@@ -254,8 +254,9 @@ func (h *UploadAssetHandler) Write(s ssh.Session, entry *utils.FileEntry) (strin
 2 		entry.Filepath = strings.TrimPrefix(entry.Filepath, "/")
 3 	}
 4 
 5-	logger := h.GetLogger().With(
 6-		"user", user.Name,
 7+	logger := h.GetLogger()
 8+	logger = shared.LoggerWithUser(logger, user)
 9+	logger = logger.With(
10 		"file", entry.Filepath,
11 		"size", entry.Size,
12 	)
13@@ -413,8 +414,9 @@ func (h *UploadAssetHandler) Delete(s ssh.Session, entry *utils.FileEntry) error
14 
15 	assetFilepath := shared.GetAssetFileName(entry)
16 
17-	logger := h.GetLogger().With(
18-		"user", user.Name,
19+	logger := h.GetLogger()
20+	logger = shared.LoggerWithUser(logger, user)
21+	logger = logger.With(
22 		"file", assetFilepath,
23 	)
24 
25@@ -488,9 +490,9 @@ func (h *UploadAssetHandler) validateAsset(data *FileData) (bool, error) {
26 func (h *UploadAssetHandler) writeAsset(reader io.Reader, data *FileData) (int64, error) {
27 	assetFilepath := shared.GetAssetFileName(data.FileEntry)
28 
29-	h.Cfg.Logger.Info(
30+	logger := shared.LoggerWithUser(h.Cfg.Logger, data.User)
31+	logger.Info(
32 		"uploading file to bucket",
33-		"user", data.User.Name,
34 		"bucket", data.Bucket.Name,
35 		"filename", assetFilepath,
36 	)
M filehandlers/imgs/handler.go
+12, -9
 1@@ -87,11 +87,13 @@ func (h *UploadImgHandler) Read(s ssh.Session, entry *utils.FileEntry) (os.FileI
 2 }
 3 
 4 func (h *UploadImgHandler) Write(s ssh.Session, entry *utils.FileEntry) (string, error) {
 5+	logger := h.Cfg.Logger
 6 	user, err := util.GetUser(s.Context())
 7 	if err != nil {
 8-		h.Cfg.Logger.Error(err.Error())
 9+		logger.Error("could not get user from ctx", "err", err.Error())
10 		return "", err
11 	}
12+	logger = shared.LoggerWithUser(logger, user)
13 
14 	filename := filepath.Base(entry.Filepath)
15 
16@@ -109,13 +111,13 @@ func (h *UploadImgHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
17 		noExifBytes, err := exifremove.Remove(text)
18 		if err == nil {
19 			if len(noExifBytes) == 0 {
20-				h.Cfg.Logger.Info("file silently failed to strip exif data", "filename", filename)
21+				logger.Info("file silently failed to strip exif data", "filename", filename)
22 			} else {
23 				text = noExifBytes
24-				h.Cfg.Logger.Info("stripped exif data", "filename", filename)
25+				logger.Info("stripped exif data", "filename", filename)
26 			}
27 		} else {
28-			h.Cfg.Logger.Error(err.Error())
29+			logger.Error("could not strip exif data", "err", err.Error())
30 		}
31 	}
32 
33@@ -140,7 +142,7 @@ func (h *UploadImgHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
34 		Space,
35 	)
36 	if err != nil {
37-		h.Cfg.Logger.Info("unable to find image, continuing", "filename", nextPost.Filename, "err", err.Error())
38+		logger.Info("unable to find image, continuing", "filename", nextPost.Filename, "err", err.Error())
39 	}
40 
41 	featureFlag, err := util.GetFeatureFlag(s.Context())
42@@ -162,13 +164,13 @@ func (h *UploadImgHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
43 
44 	err = h.writeImg(s, &metadata)
45 	if err != nil {
46-		h.Cfg.Logger.Error(err.Error())
47+		logger.Error("could not write img", "err", err.Error())
48 		return "", err
49 	}
50 
51 	totalFileSize, err := h.DBPool.FindTotalSizeForUser(user.ID)
52 	if err != nil {
53-		h.Cfg.Logger.Error(err.Error())
54+		logger.Error("could not find total storage size for user", "err", err.Error())
55 		return "", err
56 	}
57 
58@@ -197,8 +199,9 @@ func (h *UploadImgHandler) Delete(s ssh.Session, entry *utils.FileEntry) error {
59 
60 	filename := filepath.Base(entry.Filepath)
61 
62-	logger := h.Cfg.Logger.With(
63-		"user", user.Name,
64+	logger := h.Cfg.Logger
65+	logger = shared.LoggerWithUser(logger, user)
66+	logger = logger.With(
67 		"filename", filename,
68 	)
69 
M filehandlers/imgs/img.go
+9, -7
 1@@ -85,9 +85,12 @@ func (h *UploadImgHandler) writeImg(s ssh.Session, data *PostMetaData) error {
 2 		return err
 3 	}
 4 
 5+	logger := h.Cfg.Logger
 6+	logger = shared.LoggerWithUser(logger, user)
 7+
 8 	err = h.metaImg(data)
 9 	if err != nil {
10-		h.Cfg.Logger.Info(err.Error())
11+		logger.Error("could not get meta for img", "err", err.Error())
12 		return err
13 	}
14 
15@@ -97,8 +100,7 @@ func (h *UploadImgHandler) writeImg(s ssh.Session, data *PostMetaData) error {
16 		modTime = time.Unix(data.Mtime, 0)
17 	}
18 
19-	logger := h.Cfg.Logger.With(
20-		"user", data.Username,
21+	logger = logger.With(
22 		"filename", data.Filename,
23 	)
24 
25@@ -123,7 +125,7 @@ func (h *UploadImgHandler) writeImg(s ssh.Session, data *PostMetaData) error {
26 		}
27 		_, err := h.DBPool.InsertPost(&insertPost)
28 		if err != nil {
29-			logger.Error(err.Error())
30+			logger.Error("post could not create", "err", err.Error())
31 			return fmt.Errorf("error for %s: %v", data.Filename, err)
32 		}
33 
34@@ -134,7 +136,7 @@ func (h *UploadImgHandler) writeImg(s ssh.Session, data *PostMetaData) error {
35 			)
36 			err = h.DBPool.ReplaceTagsForPost(data.Tags, data.Post.ID)
37 			if err != nil {
38-				logger.Error(err.Error())
39+				logger.Error("post could not replace tags", "err", err.Error())
40 				return fmt.Errorf("error for %s: %v", data.Filename, err)
41 			}
42 		}
43@@ -162,7 +164,7 @@ func (h *UploadImgHandler) writeImg(s ssh.Session, data *PostMetaData) error {
44 		}
45 		_, err = h.DBPool.UpdatePost(&updatePost)
46 		if err != nil {
47-			logger.Error(err.Error())
48+			logger.Error("post could not update", "err", err.Error())
49 			return fmt.Errorf("error for %s: %v", data.Filename, err)
50 		}
51 
52@@ -172,7 +174,7 @@ func (h *UploadImgHandler) writeImg(s ssh.Session, data *PostMetaData) error {
53 		)
54 		err = h.DBPool.ReplaceTagsForPost(data.Tags, data.Cur.ID)
55 		if err != nil {
56-			logger.Error(err.Error())
57+			logger.Error("post could not replace tags", "err", err.Error())
58 			return fmt.Errorf("error for %s: %v", data.Filename, err)
59 		}
60 	}
M filehandlers/post_handler.go
+14, -14
  1@@ -78,14 +78,14 @@ func (h *ScpUploadHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
  2 	logger := h.Cfg.Logger
  3 	user, err := util.GetUser(s.Context())
  4 	if err != nil {
  5-		logger.Error(err.Error())
  6+		logger.Error("error getting user from ctx", "err", err.Error())
  7 		return "", err
  8 	}
  9 
 10 	userID := user.ID
 11 	filename := filepath.Base(entry.Filepath)
 12+	logger = shared.LoggerWithUser(logger, user)
 13 	logger = logger.With(
 14-		"user", user.Name,
 15 		"filename", filename,
 16 	)
 17 
 18@@ -128,13 +128,13 @@ func (h *ScpUploadHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
 19 
 20 	valid, err := h.Hooks.FileValidate(s, &metadata)
 21 	if !valid {
 22-		logger.Error(err.Error())
 23+		logger.Error("file failed validation", "err", err.Error())
 24 		return "", err
 25 	}
 26 
 27 	post, err := h.DBPool.FindPostWithFilename(metadata.Filename, metadata.User.ID, h.Cfg.Space)
 28 	if err != nil {
 29-		logger.Info("unable to load post, continuing", "err", err.Error())
 30+		logger.Error("unable to load post, continuing", "err", err.Error())
 31 	}
 32 
 33 	if post != nil {
 34@@ -145,7 +145,7 @@ func (h *ScpUploadHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
 35 
 36 	err = h.Hooks.FileMeta(s, &metadata)
 37 	if err != nil {
 38-		logger.Error(err.Error())
 39+		logger.Error("file could not load meta", "err", err.Error())
 40 		return "", err
 41 	}
 42 
 43@@ -178,7 +178,7 @@ func (h *ScpUploadHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
 44 		}
 45 		post, err = h.DBPool.InsertPost(&insertPost)
 46 		if err != nil {
 47-			logger.Error(err.Error())
 48+			logger.Error("post could not be created", "err", err.Error())
 49 			return "", fmt.Errorf("error for %s: %v", filename, err)
 50 		}
 51 
 52@@ -190,7 +190,7 @@ func (h *ScpUploadHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
 53 			)
 54 			err = h.DBPool.ReplaceAliasesForPost(metadata.Aliases, post.ID)
 55 			if err != nil {
 56-				logger.Error(err.Error())
 57+				logger.Error("post could not replace aliases", "err", err.Error())
 58 				return "", fmt.Errorf("error for %s: %v", filename, err)
 59 			}
 60 		}
 61@@ -202,7 +202,7 @@ func (h *ScpUploadHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
 62 			)
 63 			err = h.DBPool.ReplaceTagsForPost(metadata.Tags, post.ID)
 64 			if err != nil {
 65-				logger.Error(err.Error())
 66+				logger.Error("post could not replace tags", "err", err.Error())
 67 				return "", fmt.Errorf("error for %s: %v", filename, err)
 68 			}
 69 		}
 70@@ -232,7 +232,7 @@ func (h *ScpUploadHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
 71 		}
 72 		_, err = h.DBPool.UpdatePost(&updatePost)
 73 		if err != nil {
 74-			logger.Error(err.Error())
 75+			logger.Error("post could not be updated", "err", err.Error())
 76 			return "", fmt.Errorf("error for %s: %v", filename, err)
 77 		}
 78 
 79@@ -242,7 +242,7 @@ func (h *ScpUploadHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
 80 		)
 81 		err = h.DBPool.ReplaceTagsForPost(metadata.Tags, post.ID)
 82 		if err != nil {
 83-			logger.Error(err.Error())
 84+			logger.Error("post could not replace tags", "err", err.Error())
 85 			return "", fmt.Errorf("error for %s: %v", filename, err)
 86 		}
 87 
 88@@ -252,7 +252,7 @@ func (h *ScpUploadHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
 89 		)
 90 		err = h.DBPool.ReplaceAliasesForPost(metadata.Aliases, post.ID)
 91 		if err != nil {
 92-			logger.Error(err.Error())
 93+			logger.Error("post could not replace aliases", "err", err.Error())
 94 			return "", fmt.Errorf("error for %s: %v", filename, err)
 95 		}
 96 	}
 97@@ -265,14 +265,14 @@ func (h *ScpUploadHandler) Delete(s ssh.Session, entry *utils.FileEntry) error {
 98 	logger := h.Cfg.Logger
 99 	user, err := util.GetUser(s.Context())
100 	if err != nil {
101-		logger.Error(err.Error())
102+		logger.Error("could not get user from ctx", "err", err.Error())
103 		return err
104 	}
105 
106 	userID := user.ID
107 	filename := filepath.Base(entry.Filepath)
108+	logger = shared.LoggerWithUser(logger, user)
109 	logger = logger.With(
110-		"user", user.Name,
111 		"filename", filename,
112 	)
113 
114@@ -288,7 +288,7 @@ func (h *ScpUploadHandler) Delete(s ssh.Session, entry *utils.FileEntry) error {
115 	err = h.DBPool.RemovePosts([]string{post.ID})
116 	logger.Info("removing record")
117 	if err != nil {
118-		logger.Error(err.Error())
119+		logger.Error("post could not remove", "err", err.Error())
120 		return fmt.Errorf("error for %s: %v", filename, err)
121 	}
122 	return nil
M imgs/config.go
+1, -1
1@@ -27,7 +27,7 @@ func NewConfigSite() *shared.ConfigSite {
2 		MinioPass:  minioPass,
3 		Space:      "imgs",
4 		AllowedExt: []string{".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".ico"},
5-		Logger:     shared.CreateLogger(),
6+		Logger:     shared.CreateLogger("imgs"),
7 	}
8 
9 	return &cfg
M imgs/ssh.go
+1, -1
1@@ -270,7 +270,7 @@ func StartSshServer() {
2 	minioUser := shared.GetEnv("MINIO_ROOT_USER", "")
3 	minioPass := shared.GetEnv("MINIO_ROOT_PASSWORD", "")
4 
5-	logger := shared.CreateLogger()
6+	logger := shared.CreateLogger("imgs")
7 	logger.Info("bootup", "registry", registryUrl, "minio", minioUrl)
8 	dbh := postgres.NewDB(dbUrl, logger)
9 	st, err := storage.NewStorageMinio(minioUrl, minioUser, minioPass)
M pastes/config.go
+1, -1
1@@ -26,6 +26,6 @@ func NewConfigSite() *shared.ConfigSite {
2 		MinioUser:  minioUser,
3 		MinioPass:  minioPass,
4 		Space:      "pastes",
5-		Logger:     shared.CreateLogger(),
6+		Logger:     shared.CreateLogger("pastes"),
7 	}
8 }
M pgs/config.go
+1, -1
1@@ -34,7 +34,7 @@ func NewConfigSite() *shared.ConfigSite {
2 		Space:        "pgs",
3 		MaxSize:      maxSize,
4 		MaxAssetSize: maxAssetSize,
5-		Logger:       shared.CreateLogger(),
6+		Logger:       shared.CreateLogger("pgs"),
7 	}
8 
9 	return &cfg
M pico/config.go
+1, -1
1@@ -10,6 +10,6 @@ func NewConfigSite() *shared.ConfigSite {
2 	return &shared.ConfigSite{
3 		DbURL:  dbURL,
4 		Space:  "pico",
5-		Logger: shared.CreateLogger(),
6+		Logger: shared.CreateLogger("pico"),
7 	}
8 }
M prose/config.go
+1, -1
1@@ -44,7 +44,7 @@ func NewConfigSite() *shared.ConfigSite {
2 			".ico",
3 		},
4 		HiddenPosts:  []string{"_readme.md", "_styles.css", "_footer.md", "_404.md"},
5-		Logger:       shared.CreateLogger(),
6+		Logger:       shared.CreateLogger("prose"),
7 		MaxSize:      maxSize,
8 		MaxAssetSize: maxImgSize,
9 	}
M pubsub/api.go
+3, -3
 1@@ -16,14 +16,14 @@ func serveFile(file string, contentType string) http.HandlerFunc {
 2 
 3 		contents, err := os.ReadFile(cfg.StaticPath(fmt.Sprintf("public/%s", file)))
 4 		if err != nil {
 5-			logger.Error(err.Error())
 6+			logger.Error("could not read statis file", "err", err.Error())
 7 			http.Error(w, "file not found", 404)
 8 		}
 9 		w.Header().Add("Content-Type", contentType)
10 
11 		_, err = w.Write(contents)
12 		if err != nil {
13-			logger.Error(err.Error())
14+			logger.Error("could not write static file", "err", err.Error())
15 			http.Error(w, "server error", 500)
16 		}
17 	}
18@@ -94,5 +94,5 @@ func StartApiServer() {
19 		"domain", cfg.Domain,
20 	)
21 
22-	logger.Error(http.ListenAndServe(portStr, router).Error())
23+	logger.Error("listen", "err", http.ListenAndServe(portStr, router).Error())
24 }
M pubsub/cli.go
+4, -2
 1@@ -88,11 +88,11 @@ type CliHandler struct {
 2 
 3 func WishMiddleware(handler *CliHandler) wish.Middleware {
 4 	dbpool := handler.DBPool
 5-	log := handler.Logger
 6 	pubsub := handler.PubSub
 7 
 8 	return func(next ssh.Handler) ssh.Handler {
 9 		return func(sesh ssh.Session) {
10+			logger := handler.Logger
11 			ctx := sesh.Context()
12 			user, err := getUser(sesh, dbpool)
13 			if err != nil {
14@@ -100,6 +100,8 @@ func WishMiddleware(handler *CliHandler) wish.Middleware {
15 				return
16 			}
17 
18+			logger = shared.LoggerWithUser(logger, user)
19+
20 			args := sesh.Command()
21 
22 			if len(args) == 0 {
23@@ -167,7 +169,7 @@ func WishMiddleware(handler *CliHandler) wish.Middleware {
24 
25 			repoName := strings.TrimSpace(args[1])
26 			cmdArgs := args[2:]
27-			log.Info(
28+			logger.Info(
29 				"imgs middleware detected command",
30 				"args", args,
31 				"cmd", cmd,
M pubsub/config.go
+1, -1
1@@ -15,7 +15,7 @@ func NewConfigSite() *shared.ConfigSite {
2 		Port:     port,
3 		Protocol: protocol,
4 		DbURL:    dbURL,
5-		Logger:   shared.CreateLogger(),
6+		Logger:   shared.CreateLogger("pubsub"),
7 		Space:    "pubsub",
8 	}
9 }
M pubsub/ssh.go
+3, -3
 1@@ -54,7 +54,7 @@ func StartSshServer() {
 2 		),
 3 	)
 4 	if err != nil {
 5-		logger.Error(err.Error())
 6+		logger.Error("wish server", "err", err.Error())
 7 		return
 8 	}
 9 
10@@ -63,7 +63,7 @@ func StartSshServer() {
11 	logger.Info("Starting SSH server", "host", host, "port", port)
12 	go func() {
13 		if err = s.ListenAndServe(); err != nil {
14-			logger.Error(err.Error())
15+			logger.Error("listen", "err", err.Error())
16 		}
17 	}()
18 
19@@ -72,6 +72,6 @@ func StartSshServer() {
20 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
21 	defer func() { cancel() }()
22 	if err := s.Shutdown(ctx); err != nil {
23-		logger.Error(err.Error())
24+		logger.Error("shutdown", "err", err.Error())
25 	}
26 }
M shared/config.go
+9, -2
 1@@ -9,6 +9,8 @@ import (
 2 	"os"
 3 	"path"
 4 	"strings"
 5+
 6+	"github.com/picosh/pico/db"
 7 )
 8 
 9 var DefaultEmail = "hello@pico.sh"
10@@ -261,11 +263,16 @@ func (c *ConfigSite) AssetURL(username, projectName, fpath string) string {
11 	)
12 }
13 
14-func CreateLogger() *slog.Logger {
15+func CreateLogger(space string) *slog.Logger {
16 	opts := &slog.HandlerOptions{
17 		AddSource: true,
18 	}
19-	return slog.New(
20+	log := slog.New(
21 		slog.NewTextHandler(os.Stdout, opts),
22 	)
23+	return log.With("service", space)
24+}
25+
26+func LoggerWithUser(logger *slog.Logger, user *db.User) *slog.Logger {
27+	return logger.With("user", user.Name, "userId", user.ID)
28 }