diff --git a/activityPub.go b/activityPub.go index 9059ea8..a22cd2d 100644 --- a/activityPub.go +++ b/activityPub.go @@ -13,7 +13,6 @@ import ( "errors" "fmt" "io" - "log" "net/http" "strings" "time" @@ -157,7 +156,7 @@ func (a *goBlog) apCheckMentions(p *post) { links, err := allLinksFromHTML(pr, a.fullPostURL(p)) _ = pr.CloseWithError(err) if err != nil { - log.Println("Failed to extract links from post: " + err.Error()) + a.error("ActivityPub: Failed to extract links from post", err) return } apc := a.apHttpClients[p.Blog] @@ -486,12 +485,12 @@ func (a *goBlog) apUndelete(p *post) { func (a *goBlog) apAccept(blogName string, blog *configBlog, follow *ap.Activity) { newFollower := follow.Actor.GetLink() - log.Println("New follow request from follower id:", newFollower.String()) + a.info("AcitivyPub: New follow request from follower", "id", newFollower.String()) // Get remote actor follower, err := a.apGetRemoteActor(newFollower, blogName) if err != nil || follower == nil { // Couldn't retrieve remote actor info - log.Println("Failed to retrieve remote actor info:", newFollower) + a.error("ActivityPub: Failed to retrieve remote actor info", "actor", newFollower) return } // Add or update follower @@ -529,7 +528,7 @@ func (a *goBlog) apSendProfileUpdates() { func (a *goBlog) apSendToAllFollowers(blog string, activity *ap.Activity, mentions ...string) { inboxes, err := a.db.apGetAllInboxes(blog) if err != nil { - log.Println("Failed to retrieve follower inboxes:", err.Error()) + a.error("ActivityPub: Failed to retrieve follower inboxes", "err", err) return } for _, m := range mentions { @@ -583,7 +582,7 @@ func (a *goBlog) loadActivityPubPrivateKey() error { if keyData, err := a.db.retrievePersistentCache("activitypub_key"); err == nil && keyData != nil { privateKeyDecoded, _ := pem.Decode(keyData) if privateKeyDecoded == nil { - log.Println("failed to decode cached private key") + a.error("ActivityPub: failed to decode cached private key") // continue } else { key, err := x509.ParsePKCS1PrivateKey(privateKeyDecoded.Bytes) diff --git a/activityPubSending.go b/activityPubSending.go index ea118cb..d80392e 100644 --- a/activityPubSending.go +++ b/activityPubSending.go @@ -6,7 +6,6 @@ import ( "encoding/gob" "fmt" "io" - "log" "net/http" "time" @@ -26,7 +25,7 @@ func (a *goBlog) initAPSendQueue() { a.listenOnQueue("ap", 30*time.Second, func(qi *queueItem, dequeue func(), reschedule func(time.Duration)) { var r apRequest if err := gob.NewDecoder(bytes.NewReader(qi.content)).Decode(&r); err != nil { - log.Println("activitypub queue:", err.Error()) + a.error("Activitypub queue", "err", err) dequeue() return } @@ -40,7 +39,7 @@ func (a *goBlog) initAPSendQueue() { bufferpool.Put(buf) return } - log.Println("AP request failed for the 20th time:", r.To) + a.info("AP request failed for the 20th time", "to", r.To) _ = a.db.apRemoveInbox(r.To) } dequeue() diff --git a/app.go b/app.go index 3d0386a..3353c58 100644 --- a/app.go +++ b/app.go @@ -2,6 +2,7 @@ package main import ( "crypto/rsa" + "log/slog" "net/http" "sync" @@ -66,8 +67,11 @@ type goBlog struct { inLoad sync.Once // IndieAuth ias *indieauth.Server - // Logs + // Logs (HTTP) logf *rotatelogs.RotateLogs + // Logs (Program) + logger *slog.Logger + logLevel *slog.LevelVar // Markdown md, absoluteMd, titleMd goldmark.Markdown // Media diff --git a/blogroll.go b/blogroll.go index 8afe668..0a08312 100644 --- a/blogroll.go +++ b/blogroll.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "io" - "log" "net/http" "sort" "strings" @@ -25,7 +24,7 @@ func (a *goBlog) serveBlogroll(w http.ResponseWriter, r *http.Request) { return a.getBlogrollOutlines(blog) }) if err != nil { - log.Printf("Failed to get outlines: %v", err) + a.error("Blogroll: Failed to get outlines", "err", err) a.serveError(w, r, "", http.StatusInternalServerError) return } @@ -48,7 +47,7 @@ func (a *goBlog) serveBlogrollExport(w http.ResponseWriter, r *http.Request) { return a.getBlogrollOutlines(blog) }) if err != nil { - log.Printf("Failed to get outlines: %v", err) + a.error("Blogroll: Failed to get outlines", "err", err) a.serveError(w, r, "", http.StatusInternalServerError) return } diff --git a/cache.go b/cache.go index d51a138..eff8304 100644 --- a/cache.go +++ b/cache.go @@ -2,7 +2,6 @@ package main import ( "context" - "log" "net/http" "net/url" "sort" @@ -41,7 +40,7 @@ func (a *goBlog) initCache() (err error) { ticker := time.NewTicker(15 * time.Minute) for range ticker.C { met := a.cache.c.Metrics - log.Println("\nCache:", met.String()) + a.info("Cache metrics", "metrics", met.String()) } }() return diff --git a/captcha_test.go b/captcha_test.go index 75830a0..5beff31 100644 --- a/captcha_test.go +++ b/captcha_test.go @@ -3,7 +3,6 @@ package main import ( "encoding/base64" "io" - "log" "net/http" "net/http/httptest" "net/url" @@ -104,8 +103,6 @@ func Test_captchaMiddleware(t *testing.T) { _, captchaSolved := session.Values["captcha"].(bool) assert.False(t, captchaSolved) - log.Println("Captcha ID:", captchaId) - // Check form values doc, err := goquery.NewDocumentFromReader(res.Body) _ = res.Body.Close() @@ -157,8 +154,6 @@ func Test_captchaMiddleware(t *testing.T) { _, captchaSolved = session.Values["captcha"].(bool) assert.False(t, captchaSolved) - log.Println("Captcha ID:", captchaId) - // Check form values doc, err = goquery.NewDocumentFromReader(res.Body) _ = res.Body.Close() diff --git a/check.go b/check.go index 58b37e4..a22791d 100644 --- a/check.go +++ b/check.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "log" "net/http" "strings" "sync/atomic" @@ -27,24 +26,24 @@ func (a *goBlog) checkAllExternalLinks() error { if err != nil { return err } - return a.checkLinks(log.Writer(), posts...) + return a.checkLinks(posts...) } -func (a *goBlog) checkLinks(w io.Writer, posts ...*post) error { +func (a *goBlog) checkLinks(posts ...*post) error { // Get all links allLinks, err := a.allLinksToCheck(posts...) if err != nil { return err } // Print some info - fmt.Fprintln(w, "Checking", len(allLinks), "links") + fmt.Println("Checking", len(allLinks), "links") // Cancel context cancelContext, cancelFunc := context.WithCancel(context.Background()) var done atomic.Bool a.shutdown.Add(func() { done.Store(true) cancelFunc() - fmt.Fprintln(w, "Cancelled link check") + fmt.Println("Cancelled link check") }) // Create HTTP cache cache, err := ristretto.NewCache(&ristretto.Config{ @@ -106,11 +105,12 @@ func (a *goBlog) checkLinks(w io.Writer, posts ...*post) error { continue } if r.err != nil { - fmt.Fprintf(w, "%s in %s: %s\n", r.link, r.in, r.err.Error()) + fmt.Printf("%s in %s: %s\n", r.link, r.in, r.err.Error()) } else if !successStatus(r.status) { - fmt.Fprintf(w, "%s in %s: %d (%s)\n", r.link, r.in, r.status, http.StatusText(r.status)) + fmt.Printf("%s in %s: %d (%s)\n", r.link, r.in, r.status, http.StatusText(r.status)) } } + fmt.Println("Finished link check") return nil } diff --git a/config.go b/config.go index 758fd31..898a61c 100644 --- a/config.go +++ b/config.go @@ -2,7 +2,6 @@ package main import ( "errors" - "log" "net/http" "net/url" "strconv" @@ -386,6 +385,8 @@ func (a *goBlog) initConfig(logging bool) error { if a.cfg.initialized { return nil } + // Update log level + a.updateLogLevel() // Init database if err := a.initDatabase(logging); err != nil { return err @@ -561,7 +562,7 @@ func (a *goBlog) initConfig(logging bool) error { } // Log success a.cfg.initialized = true - log.Println("Initialized configuration") + a.info("Initialized configuration") return nil } diff --git a/contact.go b/contact.go index b9008e1..fcfcadf 100644 --- a/contact.go +++ b/contact.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "log" "net/http" "time" @@ -58,7 +57,7 @@ func (a *goBlog) sendContactSubmission(w http.ResponseWriter, r *http.Request) { // Send submission go func() { if err := a.sendContactEmail(bc.Contact, message.String(), formEmail); err != nil { - log.Println(err.Error()) + a.error("Failed to send contact email", "err", err) } }() // Send notification diff --git a/database.go b/database.go index d991d0d..11acbb6 100644 --- a/database.go +++ b/database.go @@ -4,7 +4,6 @@ import ( "context" "database/sql" "errors" - "log" "os" "strings" "sync" @@ -17,6 +16,7 @@ import ( ) type database struct { + a *goBlog // Basic things db *sql.DB // database em sync.Mutex // command execution (insert, update, delete ...) @@ -35,7 +35,7 @@ func (a *goBlog) initDatabase(logging bool) (err error) { return } if logging { - log.Println("Initialize database...") + a.info("Initialize database") } // Setup db db, err := a.openDatabase(a.cfg.Db.File, logging) @@ -46,9 +46,9 @@ func (a *goBlog) initDatabase(logging bool) (err error) { a.db = db a.shutdown.Add(func() { if err := db.close(); err != nil { - log.Printf("Failed to close database: %v", err) + a.error("Failed to close database", "err", err) } else { - log.Println("Closed database") + a.info("Closed database") } }) if a.cfg.Db.DumpFile != "" { @@ -58,7 +58,7 @@ func (a *goBlog) initDatabase(logging bool) (err error) { db.dump(a.cfg.Db.DumpFile) } if logging { - log.Println("Initialized database") + a.info("Initialized database") } return nil } @@ -116,7 +116,7 @@ func (a *goBlog) openDatabase(file string, logging bool) (*database, error) { return nil, errors.New("sqlite not compiled with FTS5") } // Migrate DB - err = migrateDb(db, logging) + err = a.migrateDb(db, logging) if err != nil { return nil, err } @@ -144,6 +144,7 @@ func (a *goBlog) openDatabase(file string, logging bool) (*database, error) { return nil, err } return &database{ + a: a, db: db, debug: debug, psc: psc, @@ -163,11 +164,11 @@ func (db *database) dump(file string) { // Dump database f, err := os.Create(file) if err != nil { - log.Println("Error while dump db:", err.Error()) + db.a.error("Error while dump db", "err", err) return } if err = sqlite3dump.DumpDB(db.db, f, sqlite3dump.WithTransaction(true)); err != nil { - log.Println("Error while dump db:", err.Error()) + db.a.error("Error while dump db", "err", err) } } @@ -202,7 +203,7 @@ func (db *database) prepare(query string, args ...any) (*sql.Stmt, []any, error) }) if err != nil { if db.debug { - log.Printf(`Failed to prepare query "%s": %s`, query, err.Error()) + db.a.error("Failed to prepare query", "query", query, "err", err) } return nil, args, err } diff --git a/databaseHooks.go b/databaseHooks.go index f482841..bd6e663 100644 --- a/databaseHooks.go +++ b/databaseHooks.go @@ -4,7 +4,6 @@ import ( "context" "database/sql" "fmt" - "log" "time" "github.com/spf13/cast" @@ -25,34 +24,27 @@ func (db *database) dbAfter(ctx context.Context, query string, args ...any) { return } dur := time.Since(ctx.Value(dbHooksBegin).(time.Time)) - logBuilder := builderpool.Get() - logBuilder.WriteString("\nQuery: ") - logBuilder.WriteString(`"`) - logBuilder.WriteString(query) - logBuilder.WriteString(`"`) + argsBuilder := builderpool.Get() if len(args) > 0 { - logBuilder.WriteString("\nArgs: ") for i, arg := range args { if i > 0 { - logBuilder.WriteString(", ") + argsBuilder.WriteString(", ") } if named, ok := arg.(sql.NamedArg); ok && named.Name != "" { - logBuilder.WriteString("(") - logBuilder.WriteString(named.Name) - logBuilder.WriteString(`) "`) - logBuilder.WriteString(argToString(named.Value)) - logBuilder.WriteString(`"`) + argsBuilder.WriteString("(") + argsBuilder.WriteString(named.Name) + argsBuilder.WriteString(`) '`) + argsBuilder.WriteString(argToString(named.Value)) + argsBuilder.WriteString(`'`) } else { - logBuilder.WriteString(`"`) - logBuilder.WriteString(argToString(arg)) - logBuilder.WriteString(`"`) + argsBuilder.WriteString(`'`) + argsBuilder.WriteString(argToString(arg)) + argsBuilder.WriteString(`'`) } } } - logBuilder.WriteString("\nDuration: ") - logBuilder.WriteString(dur.String()) - log.Println(logBuilder.String()) - builderpool.Put(logBuilder) + db.a.debug("Database query", "query", query, "args", argsBuilder.String(), "duration", dur.String()) + builderpool.Put(argsBuilder) } func argToString(arg any) string { diff --git a/databaseMigrations.go b/databaseMigrations.go index 514e886..8d438d4 100644 --- a/databaseMigrations.go +++ b/databaseMigrations.go @@ -3,8 +3,8 @@ package main import ( "database/sql" "embed" + "fmt" "io/fs" - "log" "strings" "github.com/lopezator/migrator" @@ -13,7 +13,7 @@ import ( //go:embed dbmigrations/* var dbMigrations embed.FS -func migrateDb(db *sql.DB, logging bool) error { +func (a *goBlog) migrateDb(db *sql.DB, logging bool) error { var sqlMigrations []any err := fs.WalkDir(dbMigrations, "dbmigrations", func(path string, d fs.DirEntry, err error) error { if err != nil || d.Type().IsDir() { @@ -41,7 +41,7 @@ func migrateDb(db *sql.DB, logging bool) error { m, err := migrator.New( migrator.WithLogger(migrator.LoggerFunc(func(s string, i ...any) { if logging { - log.Printf(s, i) + a.info(fmt.Sprintf(s, i...)) } })), migrator.Migrations(sqlMigrations...), diff --git a/debug.go b/debug.go deleted file mode 100644 index 49c990c..0000000 --- a/debug.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import "log" - -func (a *goBlog) debug(msg ...any) { - if a.cfg.Debug { - log.Println(append([]any{"Debug:"}, msg...)...) - } -} diff --git a/geoTrack.go b/geoTrack.go index d1b0e93..8e489dd 100644 --- a/geoTrack.go +++ b/geoTrack.go @@ -3,7 +3,6 @@ package main import ( "encoding/json" "errors" - "log" "math" "github.com/tkrajina/gpxgo/gpx" @@ -51,7 +50,7 @@ func (a *goBlog) getTrack(p *post, withMapFeatures bool) (result *trackResult, e parseResult, err := trackParseGPX(gpxString) if err != nil { // Failed to parse, but just log error - log.Printf("failed to parse GPX: %v", err) + a.error("failed to parse GPX", "err", err) return nil, nil } diff --git a/hooks.go b/hooks.go index e1f1c51..cd2c880 100644 --- a/hooks.go +++ b/hooks.go @@ -2,7 +2,6 @@ package main import ( "html/template" - "log" "os/exec" "time" @@ -14,7 +13,7 @@ func (a *goBlog) preStartHooks() { cfg := a.cfg.Hooks for _, cmd := range cfg.PreStart { func(cmd string) { - executeHookCommand("pre-start", cfg.Shell, cmd) + a.executeHookCommand("pre-start", cfg.Shell, cmd) }(cmd) } } @@ -26,7 +25,7 @@ func (a *goBlog) postPostHooks(p *post) { if hc := a.cfg.Hooks; hc != nil { for _, cmdTmplString := range hc.PostPost { go func(p *post, cmdTmplString string) { - a.cfg.Hooks.executeTemplateCommand("post-post", cmdTmplString, map[string]any{ + a.executeHookTemplateCommand("post-post", cmdTmplString, map[string]any{ "URL": a.fullPostURL(p), "Post": p, }) @@ -46,7 +45,7 @@ func (a *goBlog) postUpdateHooks(p *post) { if hc := a.cfg.Hooks; hc != nil { for _, cmdTmplString := range hc.PostUpdate { go func(p *post, cmdTmplString string) { - a.cfg.Hooks.executeTemplateCommand("post-update", cmdTmplString, map[string]any{ + a.executeHookTemplateCommand("post-update", cmdTmplString, map[string]any{ "URL": a.fullPostURL(p), "Post": p, }) @@ -65,7 +64,7 @@ func (a *goBlog) postDeleteHooks(p *post) { if hc := a.cfg.Hooks; hc != nil { for _, cmdTmplString := range hc.PostDelete { go func(p *post, cmdTmplString string) { - a.cfg.Hooks.executeTemplateCommand("post-delete", cmdTmplString, map[string]any{ + a.executeHookTemplateCommand("post-delete", cmdTmplString, map[string]any{ "URL": a.fullPostURL(p), "Post": p, }) @@ -84,7 +83,7 @@ func (a *goBlog) postUndeleteHooks(p *post) { if hc := a.cfg.Hooks; hc != nil { for _, cmdTmplString := range hc.PostUndelete { go func(p *post, cmdTmplString string) { - a.cfg.Hooks.executeTemplateCommand("post-undelete", cmdTmplString, map[string]any{ + a.executeHookTemplateCommand("post-undelete", cmdTmplString, map[string]any{ "URL": a.fullPostURL(p), "Post": p, }) @@ -96,19 +95,20 @@ func (a *goBlog) postUndeleteHooks(p *post) { } } -func (cfg *configHooks) executeTemplateCommand(hookType string, tmpl string, data map[string]any) { +func (a *goBlog) executeHookTemplateCommand(hookType string, tmpl string, data map[string]any) { + cfg := a.cfg.Hooks cmdTmpl, err := template.New("cmd").Parse(tmpl) if err != nil { - log.Println("Failed to parse cmd template:", err.Error()) + a.error("Failed to parse cmd template", "err", err) return } cmdBuf := bufferpool.Get() defer bufferpool.Put(cmdBuf) if err = cmdTmpl.Execute(cmdBuf, data); err != nil { - log.Println("Failed to execute cmd template:", err.Error()) + a.error("Failed to execute cmd template", "err", err) return } - executeHookCommand(hookType, cfg.Shell, cmdBuf.String()) + a.executeHookCommand(hookType, cfg.Shell, cmdBuf.String()) } type hourlyHookFunc func() @@ -119,7 +119,7 @@ func (a *goBlog) startHourlyHooks() { for _, cmd := range cfg.Hourly { c := cmd f := func() { - executeHookCommand("hourly", cfg.Shell, c) + a.executeHookCommand("hourly", cfg.Shell, c) } a.hourlyHooks = append(a.hourlyHooks, f) } @@ -135,7 +135,7 @@ func (a *goBlog) startHourlyHooks() { ticker := time.NewTicker(1 * time.Hour) a.shutdown.Add(func() { ticker.Stop() - log.Println("Stopped hourly hooks") + a.info("Stopped hourly hooks") }) for range ticker.C { for _, f := range a.hourlyHooks { @@ -145,19 +145,19 @@ func (a *goBlog) startHourlyHooks() { }) a.shutdown.Add(func() { if tr.Stop() { - log.Println("Canceled hourly hooks") + a.info("Canceled hourly hooks") } }) } } -func executeHookCommand(hookType, shell, cmd string) { - log.Printf("Executing %v hook: %v", hookType, cmd) +func (a *goBlog) executeHookCommand(hookType, shell, cmd string) { + a.info("Executing hook", "type", hookType, "cmd", cmd) out, err := exec.Command(shell, "-c", cmd).CombinedOutput() if err != nil { - log.Println("Failed to execute command:", err.Error()) + a.error("Failed to execute command", "err", err, "cmd", cmd) } if len(out) > 0 { - log.Printf("Output:\n%v", string(out)) + a.info("Hook output", "out", string(out)) } } diff --git a/http.go b/http.go index 499cdb3..c882fb0 100644 --- a/http.go +++ b/http.go @@ -4,7 +4,6 @@ import ( "database/sql" "errors" "fmt" - "log" "net" "net/http" "sort" @@ -33,7 +32,7 @@ const ( ) func (a *goBlog) startServer() (err error) { - log.Println("Start server(s)...") + a.info("Start server(s)...") // Load router a.reloadRouter() // Set basic middlewares @@ -63,7 +62,7 @@ func (a *goBlog) startServer() (err error) { if a.cfg.Server.Tor { go func() { if err := a.startOnionService(finalHandler); err != nil { - log.Println("Tor failed:", err.Error()) + a.error("Tor failed", "err", err) } }() } @@ -82,9 +81,9 @@ func (a *goBlog) startServer() (err error) { ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, } - a.shutdown.Add(shutdownServer(httpServer, "http server")) + a.shutdown.Add(a.shutdownServer(httpServer, "http server")) if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { - log.Println("Failed to start HTTP server:", err.Error()) + a.error("Failed to start HTTP server", "err", err) } }() } @@ -94,7 +93,7 @@ func (a *goBlog) startServer() (err error) { ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, } - a.shutdown.Add(shutdownServer(s, "main server")) + a.shutdown.Add(a.shutdownServer(s, "main server")) s.Addr = ":" + strconv.Itoa(a.cfg.Server.Port) if a.cfg.Server.PublicHTTPS { s.TLSConfig = a.getAutocertManager().TLSConfig() @@ -110,14 +109,14 @@ func (a *goBlog) startServer() (err error) { return err } -func shutdownServer(s *http.Server, name string) func() { +func (a *goBlog) shutdownServer(s *http.Server, name string) func() { return func() { toc, c := context.WithTimeout(context.Background(), 5*time.Second) defer c() if err := s.Shutdown(toc); err != nil { - log.Printf("Error on server shutdown (%v): %v", name, err) + a.error("Error on server shutdown (%v): %v", name, err) } - log.Println("Stopped server:", name) + a.info("Stopped server", "name", name) } } diff --git a/indexnow.go b/indexnow.go index 52eb261..8b305d9 100644 --- a/indexnow.go +++ b/indexnow.go @@ -2,7 +2,6 @@ package main import ( "context" - "log" "net/http" "github.com/carlmjohnson/requests" @@ -50,7 +49,7 @@ func (a *goBlog) indexNow(url string) { } key := a.indexNowKey() if len(key) == 0 { - log.Println("Skipping IndexNow") + a.info("Skipping IndexNow") return } err := requests.URL("https://api.indexnow.org/indexnow"). @@ -59,10 +58,10 @@ func (a *goBlog) indexNow(url string) { Param("key", string(key)). Fetch(context.Background()) if err != nil { - log.Println("Sending IndexNow request failed:", err.Error()) + a.error("Sending IndexNow request failed", "err", err) return } else { - log.Println("IndexNow request sent for", url) + a.info("IndexNow request sent", "url", url) } } @@ -71,7 +70,7 @@ func (a *goBlog) indexNowKey() []byte { // Try to load key from database keyBytes, err := a.db.retrievePersistentCache("indexnowkey") if err != nil { - log.Println("Failed to retrieve cached IndexNow key:", err.Error()) + a.error("Failed to retrieve cached IndexNow key", "err", err) return } if keyBytes == nil { @@ -80,7 +79,7 @@ func (a *goBlog) indexNowKey() []byte { // Store key in database err = a.db.cachePersistently("indexnowkey", keyBytes) if err != nil { - log.Println("Failed to cache IndexNow key:", err.Error()) + a.error("Failed to cache IndexNow key", "err", err) return } } diff --git a/log.go b/log.go new file mode 100644 index 0000000..797ecc8 --- /dev/null +++ b/log.go @@ -0,0 +1,39 @@ +package main + +import ( + "log/slog" + "os" +) + +func (a *goBlog) initLog() { + a.logLevel = new(slog.LevelVar) + a.logger = slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ + Level: a.logLevel, + })) +} + +func (a *goBlog) updateLogLevel() { + if a.logLevel == nil { + a.initLog() + } + if a.cfg.Debug { + a.logLevel.Set(slog.LevelDebug) + } +} + +func (a *goBlog) debug(msg string, args ...any) { + a.logger.Debug(msg, args...) +} + +func (a *goBlog) info(msg string, args ...any) { + a.logger.Info(msg, args...) +} + +func (a *goBlog) error(msg string, args ...any) { + a.logger.Error(msg, args...) +} + +func (a *goBlog) fatal(msg string, args ...any) { + a.error(msg, args...) + os.Exit(1) +} diff --git a/main.go b/main.go index 2089c42..8c0d3fd 100644 --- a/main.go +++ b/main.go @@ -2,7 +2,7 @@ package main import ( "flag" - "log" + "fmt" "net" "net/http" netpprof "net/http/pprof" @@ -22,17 +22,23 @@ func main() { memprofile := flag.String("memprofile", "", "write memory profile to `file`") configfile := flag.String("config", "", "use a specific config file") + // Init app and logger + app := &goBlog{ + httpClient: newHttpClient(), + } + app.initLog() + // Init CPU and memory profiling flag.Parse() if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { - log.Fatalln("could not create CPU profile: ", err) + app.fatal("could not create CPU profile", "err", err) return } defer f.Close() if err := pprof.StartCPUProfile(f); err != nil { - log.Fatalln("could not start CPU profile: ", err) + app.fatal("could not start CPU profile", "err", err) return } defer pprof.StopCPUProfile() @@ -41,29 +47,25 @@ func main() { defer func() { f, err := os.Create(*memprofile) if err != nil { - log.Fatalln("could not create memory profile: ", err.Error()) + app.fatal("could not create memory profile", "err", err) return } defer f.Close() runtime.GC() if err := pprof.WriteHeapProfile(f); err != nil { - log.Fatalln("could not write memory profile: ", err.Error()) + app.fatal("could not write memory profile", "err", err) return } }() } - app := &goBlog{ - httpClient: newHttpClient(), - } - // Initialize config if err = app.loadConfigFile(*configfile); err != nil { - app.logErrAndQuit("Failed to load config file:", err.Error()) + app.logErrAndQuit("Failed to load config file", "err", err) return } if err = app.initConfig(false); err != nil { - app.logErrAndQuit("Failed to init config:", err.Error()) + app.logErrAndQuit("Failed to init config", "err", err) return } @@ -83,17 +85,17 @@ func main() { AccountName: app.cfg.User.Nick, }) if err != nil { - app.logErrAndQuit(err.Error()) + app.logErrAndQuit("Failed to generate TOTP secret", "err", err) return } - log.Println("TOTP-Secret:", key.Secret()) + fmt.Println("TOTP-Secret:", key.Secret()) app.shutdown.ShutdownAndWait() return } // Initialize plugins if err = app.initPlugins(); err != nil { - app.logErrAndQuit("Failed to init plugins:", err.Error()) + app.logErrAndQuit("Failed to init plugins", "err", err) return } @@ -119,13 +121,13 @@ func main() { } listener, err := net.Listen("tcp", pprofServer.Addr) if err != nil { - log.Fatalln("Failed to start pprof server:", err.Error()) + app.fatal("Failed to start pprof server", "err", err) return } - log.Println("Pprof server listening on", listener.Addr().String()) + app.info("Pprof server listening", "addr", listener.Addr().String()) // Start server if err := pprofServer.Serve(listener); err != nil { - log.Fatalln("Failed to start pprof server:", err.Error()) + app.fatal("Failed to start pprof server", "err", err) return } }() @@ -139,11 +141,11 @@ func main() { app.initMarkdown() err = app.initTemplateStrings() if err != nil { - app.logErrAndQuit("Failed to start check:", err.Error()) + app.logErrAndQuit("Failed to start check", "err", err) } err = app.checkAllExternalLinks() if err != nil { - app.logErrAndQuit("Failed to start check:", err.Error()) + app.logErrAndQuit("Failed to start check", "err", err) } app.shutdown.ShutdownAndWait() return @@ -157,7 +159,7 @@ func main() { } err = app.exportMarkdownFiles(dir) if err != nil { - app.logErrAndQuit("Failed to export markdown files:", err.Error()) + app.logErrAndQuit("Failed to export markdown files", "err", err) return } app.shutdown.ShutdownAndWait() @@ -173,7 +175,7 @@ func main() { // Start the server err = app.startServer() if err != nil { - app.logErrAndQuit("Failed to start server(s):", err.Error()) + app.logErrAndQuit("Failed to start server(s)", "err", err) return } @@ -184,31 +186,31 @@ func main() { func (app *goBlog) initComponents() { var err error - log.Println("Initialize components...") + app.info("Initialize components...") app.initMarkdown() if err = app.initTemplateAssets(); err != nil { // Needs minify - app.logErrAndQuit("Failed to init template assets:", err.Error()) + app.logErrAndQuit("Failed to init template assets", "err", err) return } if err = app.initTemplateStrings(); err != nil { - app.logErrAndQuit("Failed to init template translations:", err.Error()) + app.logErrAndQuit("Failed to init template translations", "err", err) return } if err = app.initCache(); err != nil { - app.logErrAndQuit("Failed to init HTTP cache:", err.Error()) + app.logErrAndQuit("Failed to init HTTP cache", "err", err) return } if err = app.initRegexRedirects(); err != nil { - app.logErrAndQuit("Failed to init redirects:", err.Error()) + app.logErrAndQuit("Failed to init redirects", "err", err) return } if err = app.initHTTPLog(); err != nil { - app.logErrAndQuit("Failed to init HTTP logging:", err.Error()) + app.logErrAndQuit("Failed to init HTTP logging", "err", err) return } if err = app.initActivityPub(); err != nil { - app.logErrAndQuit("Failed to init ActivityPub:", err.Error()) + app.logErrAndQuit("Failed to init ActivityPub", "err", err) return } app.initWebmention() @@ -221,11 +223,11 @@ func (app *goBlog) initComponents() { app.initPostsDeleter() app.initIndexNow() - log.Println("Initialized components") + app.info("Initialized components") } -func (a *goBlog) logErrAndQuit(v ...any) { - log.Println(v...) +func (a *goBlog) logErrAndQuit(msg string, args ...any) { + a.error(msg, args...) a.shutdown.ShutdownAndWait() os.Exit(1) } diff --git a/mediaCompression.go b/mediaCompression.go index 3d8066e..ca5ccaf 100644 --- a/mediaCompression.go +++ b/mediaCompression.go @@ -7,7 +7,6 @@ import ( "fmt" "image/png" "io" - "log" "net/http" "github.com/carlmjohnson/requests" @@ -42,17 +41,18 @@ func (a *goBlog) initMediaCompressors() { } config := a.cfg.Micropub.MediaStorage if key := config.TinifyKey; key != "" { - a.compressors = append(a.compressors, &tinify{key}) + a.compressors = append(a.compressors, &tinify{a: a, key: key}) } if config.CloudflareCompressionEnabled { a.compressors = append(a.compressors, &cloudflare{}) } if config.LocalCompressionEnabled { - a.compressors = append(a.compressors, &localMediaCompressor{}) + a.compressors = append(a.compressors, &localMediaCompressor{a: a}) } } type tinify struct { + a *goBlog key string } @@ -78,12 +78,12 @@ func (tf *tinify) compress(url string, upload mediaStorageSaveFunc, hc *http.Cli ToHeaders(headers). Fetch(context.Background()) if err != nil { - log.Println("Tinify error:", err.Error()) + tf.a.error("Tinify error", "err", err) return "", tinifyErr } compressedLocation := headers.Get("Location") if compressedLocation == "" { - log.Println("Tinify error: location header missing") + tf.a.error("Tinify error: location header missing") return "", tinifyErr } // Resize and download image @@ -134,9 +134,11 @@ func (*cloudflare) compress(url string, upload mediaStorageSaveFunc, hc *http.Cl return res, err } -type localMediaCompressor struct{} +type localMediaCompressor struct { + a *goBlog +} -func (*localMediaCompressor) compress(url string, upload mediaStorageSaveFunc, hc *http.Client) (string, error) { +func (lc *localMediaCompressor) compress(url string, upload mediaStorageSaveFunc, hc *http.Client) (string, error) { // Check url fileExtension, allowed := urlHasExt(url, "jpg", "jpeg", "png") if !allowed { @@ -150,7 +152,7 @@ func (*localMediaCompressor) compress(url string, upload mediaStorageSaveFunc, h img, err := imaging.Decode(pr, imaging.AutoOrientation(true)) _ = pr.CloseWithError(err) if err != nil { - log.Println("Local compressor error:", err.Error()) + lc.a.error("Local compressor error", "err", err) return "", errors.New("failed to compress image using local compressor") } // Resize image diff --git a/notifications.go b/notifications.go index ca86089..a8ca953 100644 --- a/notifications.go +++ b/notifications.go @@ -3,7 +3,6 @@ package main import ( "database/sql" "fmt" - "log" "net/http" "reflect" "strconv" @@ -29,7 +28,7 @@ func (a *goBlog) sendNotification(text string) { Text: text, } if err := a.db.saveNotification(n); err != nil { - log.Println("Failed to save notification:", err.Error()) + a.error("Failed to save notification", "err", err) } if cfg := a.cfg.Notifications; cfg != nil { p := pool.New().WithErrors() @@ -45,7 +44,7 @@ func (a *goBlog) sendNotification(text string) { return err }) if err := p.Wait(); err != nil { - log.Println("Failed to send notification:", err.Error()) + a.error("Failed to send notification", "err", err) } } } diff --git a/postsDeleter.go b/postsDeleter.go index aaa8274..9b032d4 100644 --- a/postsDeleter.go +++ b/postsDeleter.go @@ -1,7 +1,6 @@ package main import ( - "log" "time" "github.com/araddon/dateparse" @@ -13,21 +12,24 @@ func (a *goBlog) initPostsDeleter() { }) } +const deletedPostParam = "deleted" + func (a *goBlog) checkDeletedPosts() { // Get all posts with `deleted` parameter and a deleted status postsToDelete, err := a.getPosts(&postsRequestConfig{ status: []postStatus{statusPublishedDeleted, statusDraftDeleted, statusScheduledDeleted}, - parameter: "deleted", + parameter: deletedPostParam, }) if err != nil { - log.Println("Error getting deleted posts:", err) + a.error("Error getting deleted posts", "err", err) return } for _, post := range postsToDelete { // Check if post is deleted for more than 7 days - if deleted, err := dateparse.ParseLocal(post.firstParameter("deleted")); err == nil && deleted.Add(time.Hour*24*7).Before(time.Now()) { + if deleted, err := dateparse.ParseLocal(post.firstParameter(deletedPostParam)); err == nil && + deleted.Add(time.Hour*24*7).Before(time.Now()) { if err := a.deletePost(post.Path); err != nil { - log.Println("Error deleting post:", err) + a.error("Error deleting post", "err", err) } } } diff --git a/postsScheduler.go b/postsScheduler.go index b3685c5..1b093ef 100644 --- a/postsScheduler.go +++ b/postsScheduler.go @@ -1,7 +1,6 @@ package main import ( - "log" "time" ) @@ -21,7 +20,7 @@ func (a *goBlog) startPostsScheduler() { a.shutdown.Add(func() { ticker.Stop() done <- struct{}{} - log.Println("Posts scheduler stopped") + a.info("Posts scheduler stopped") }) } @@ -31,16 +30,16 @@ func (a *goBlog) checkScheduledPosts() { publishedBefore: time.Now(), }) if err != nil { - log.Println("Error getting scheduled posts:", err) + a.error("Error getting scheduled posts", "err", err) return } for _, post := range postsToPublish { post.Status = statusPublished err := a.replacePost(post, post.Path, statusScheduled, post.Visibility) if err != nil { - log.Println("Error publishing scheduled post:", err) + a.error("Error publishing scheduled post", "err", err) continue } - log.Println("Published scheduled post:", post.Path) + a.info("Published scheduled post", "path", post.Path) } } diff --git a/queue.go b/queue.go index 4c78b4e..f6acf56 100644 --- a/queue.go +++ b/queue.go @@ -4,7 +4,6 @@ import ( "context" "database/sql" "errors" - "log" "sync" "time" @@ -101,7 +100,7 @@ func (a *goBlog) listenOnQueue(queueName string, wait time.Duration, process que } qi, err := a.peekQueue(queueContext, queueName) if err != nil { - log.Println("queue peek error:", err.Error()) + a.error("queue peek error", "err", err) continue queueLoop } if qi == nil { @@ -117,17 +116,17 @@ func (a *goBlog) listenOnQueue(queueName string, wait time.Duration, process que qi, func() { if err := a.dequeue(qi); err != nil { - log.Println("queue dequeue error:", err.Error()) + a.error("queue dequeue error", "err", err) } }, func(dur time.Duration) { if err := a.reschedule(qi, dur); err != nil { - log.Println("queue reschedule error:", err.Error()) + a.error("queue reschedule error", "err", err) } }, ) } - log.Println("stopped queue:", queueName) + a.info("stopped queue", "name", queueName) wg.Done() }() } diff --git a/sessions.go b/sessions.go index c4f36b7..f987af8 100644 --- a/sessions.go +++ b/sessions.go @@ -4,7 +4,6 @@ import ( "bytes" "database/sql" "encoding/gob" - "log" "net/http" "strings" "time" @@ -27,7 +26,7 @@ func (a *goBlog) initSessions() { "delete from sessions where expires < @now", sql.Named("now", utcNowString()), ); err != nil { - log.Println("Failed to delete expired sessions:", err.Error()) + a.error("Failed to delete expired sessions", "err", err) } } deleteExpiredSessions() diff --git a/telegram.go b/telegram.go index e4cdc88..4d279e8 100644 --- a/telegram.go +++ b/telegram.go @@ -2,7 +2,6 @@ package main import ( "errors" - "log" "net/url" "strconv" @@ -11,10 +10,10 @@ import ( ) func (a *goBlog) initTelegram() { - a.pPostHooks = append(a.pPostHooks, a.tgPost(false)) + a.pPostHooks = append(a.pPostHooks, func(p *post) { a.tgPost(p, false) }) a.pUpdateHooks = append(a.pUpdateHooks, a.tgUpdate) a.pDeleteHooks = append(a.pDeleteHooks, a.tgDelete) - a.pUndeleteHooks = append(a.pUndeleteHooks, a.tgPost(true)) + a.pUndeleteHooks = append(a.pUndeleteHooks, func(p *post) { a.tgPost(p, true) }) } func (tg *configTelegram) enabled() bool { @@ -24,39 +23,37 @@ func (tg *configTelegram) enabled() bool { return true } -func (a *goBlog) tgPost(silent bool) func(*post) { - return func(p *post) { - if tg := a.getBlogFromPost(p).Telegram; tg.enabled() && p.isPublicPublishedSectionPost() { - tgChat := p.firstParameter("telegramchat") - tgMsg := p.firstParameter("telegrammsg") - if tgChat != "" && tgMsg != "" { - // Already posted - return - } - // Generate HTML - html := tg.generateHTML(p.RenderedTitle, a.fullPostURL(p), a.shortPostURL(p)) - if html == "" { - return - } - // Send message - chatId, msgId, err := a.sendTelegram(tg, html, tgbotapi.ModeHTML, silent) - if err != nil { - log.Printf("Failed to send post to Telegram: %v", err) - return - } - if chatId == 0 || msgId == 0 { - // Not sent - return - } - // Save chat and message id to post - err = a.db.replacePostParam(p.Path, "telegramchat", []string{strconv.FormatInt(chatId, 10)}) - if err != nil { - log.Printf("Failed to save Telegram chat id: %v", err) - } - err = a.db.replacePostParam(p.Path, "telegrammsg", []string{strconv.Itoa(msgId)}) - if err != nil { - log.Printf("Failed to save Telegram message id: %v", err) - } +func (a *goBlog) tgPost(p *post, silent bool) { + if tg := a.getBlogFromPost(p).Telegram; tg.enabled() && p.isPublicPublishedSectionPost() { + tgChat := p.firstParameter("telegramchat") + tgMsg := p.firstParameter("telegrammsg") + if tgChat != "" && tgMsg != "" { + // Already posted + return + } + // Generate HTML + html := tg.generateHTML(p.RenderedTitle, a.fullPostURL(p), a.shortPostURL(p)) + if html == "" { + return + } + // Send message + chatId, msgId, err := a.sendTelegram(tg, html, tgbotapi.ModeHTML, silent) + if err != nil { + a.error("Failed to send post to Telegram", "err", err) + return + } + if chatId == 0 || msgId == 0 { + // Not sent + return + } + // Save chat and message id to post + err = a.db.replacePostParam(p.Path, "telegramchat", []string{strconv.FormatInt(chatId, 10)}) + if err != nil { + a.error("Failed to save Telegram chat id", "err", err) + } + err = a.db.replacePostParam(p.Path, "telegrammsg", []string{strconv.Itoa(msgId)}) + if err != nil { + a.error("Failed to save Telegram message id", "err", err) } } } @@ -72,13 +69,13 @@ func (a *goBlog) tgUpdate(p *post) { // Parse tgChat to int64 chatId, err := strconv.ParseInt(tgChat, 10, 64) if err != nil { - log.Printf("Failed to parse Telegram chat ID: %v", err) + a.error("Failed to parse Telegram chat ID", "err", err) return } // Parse tgMsg to int messageId, err := strconv.Atoi(tgMsg) if err != nil { - log.Printf("Failed to parse Telegram message ID: %v", err) + a.error("Failed to parse Telegram message ID", "err", err) return } // Generate HTML @@ -89,7 +86,7 @@ func (a *goBlog) tgUpdate(p *post) { // Send update err = a.updateTelegram(tg, chatId, messageId, html, "HTML") if err != nil { - log.Printf("Failed to send update to Telegram: %v", err) + a.error("Failed to send update to Telegram", "err", err) } } } @@ -105,28 +102,28 @@ func (a *goBlog) tgDelete(p *post) { // Parse tgChat to int64 chatId, err := strconv.ParseInt(tgChat, 10, 64) if err != nil { - log.Printf("Failed to parse Telegram chat ID: %v", err) + a.error("Failed to parse Telegram chat ID", "err", err) return } // Parse tgMsg to int messageId, err := strconv.Atoi(tgMsg) if err != nil { - log.Printf("Failed to parse Telegram message ID: %v", err) + a.error("Failed to parse Telegram message ID", "err", err) return } // Delete message err = a.deleteTelegram(tg, chatId, messageId) if err != nil { - log.Printf("Failed to delete Telegram message: %v", err) + a.error("Failed to delete Telegram message", "err", err) } // Delete chat and message id from post err = a.db.replacePostParam(p.Path, "telegramchat", []string{}) if err != nil { - log.Printf("Failed to remove Telegram chat id: %v", err) + a.error("Failed to remove Telegram chat id", "err", err) } err = a.db.replacePostParam(p.Path, "telegrammsg", []string{}) if err != nil { - log.Printf("Failed to remove Telegram message id: %v", err) + a.error("Failed to remove Telegram message id", "err", err) } } } diff --git a/tor.go b/tor.go index 02f86be..c8ce637 100644 --- a/tor.go +++ b/tor.go @@ -6,7 +6,6 @@ import ( "crypto/ed25519" "crypto/x509" "encoding/pem" - "log" "net/http" "net/url" "os" @@ -34,7 +33,7 @@ func (a *goBlog) startOnionService(h http.Handler) error { return err } // Start tor - log.Println("Starting and registering onion service, please wait a couple of minutes...") + a.info("Starting and registering onion service") t, err := tor.Start(context.Background(), &tor.StartConf{ TempDataDirBase: os.TempDir(), NoAutoSocksPort: true, @@ -64,7 +63,7 @@ func (a *goBlog) startOnionService(h http.Handler) error { a.torAddress = "http://" + onion.String() torUrl, _ := url.Parse(a.torAddress) a.torHostname = torUrl.Hostname() - log.Println("Onion service published on " + a.torAddress) + a.info("Onion service published", "address", a.torAddress) // Clear cache a.cache.purge() // Serve handler @@ -74,7 +73,7 @@ func (a *goBlog) startOnionService(h http.Handler) error { ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, } - a.shutdown.Add(shutdownServer(s, "tor")) + a.shutdown.Add(a.shutdownServer(s, "tor")) if err = s.Serve(onion); err != nil && err != http.ErrServerClosed { return err } diff --git a/tts.go b/tts.go index 87504d7..af34500 100644 --- a/tts.go +++ b/tts.go @@ -8,7 +8,6 @@ import ( "fmt" "html" "io" - "log" "net/http" "net/url" "path" @@ -38,7 +37,7 @@ func (a *goBlog) initTTS() { // Create TTS audio err := a.createPostTTSAudio(p) if err != nil { - log.Printf("create post audio for %s failed: %v", p.Path, err) + a.error("create post audio failed", "path", p.Path, "err", err) } } a.pPostHooks = append(a.pPostHooks, createOrUpdate) @@ -47,7 +46,7 @@ func (a *goBlog) initTTS() { a.pDeleteHooks = append(a.pDeleteHooks, func(p *post) { // Try to delete the audio file if a.deletePostTTSAudio(p) { - log.Println("deleted tts audio for", p.Path) + a.info("deleted tts audio", "path", p.Path) } }) } @@ -131,7 +130,7 @@ func (a *goBlog) createPostTTSAudio(p *post) error { // Already has tts audio, but with different location // Try to delete the old audio file if a.deletePostTTSAudio(p) { - log.Println("deleted old tts audio for", p.Path) + a.info("deleted old tts audio", "path", p.Path) } } @@ -158,7 +157,7 @@ func (a *goBlog) deletePostTTSAudio(p *post) bool { fileUrl, err := url.Parse(audio) if err != nil { // Failed to parse audio url - log.Println("failed to parse audio url:", err) + a.error("failed to parse audio url", "err", err, "audio", audio) return false } fileName := path.Base(fileUrl.Path) @@ -169,7 +168,7 @@ func (a *goBlog) deletePostTTSAudio(p *post) bool { // Try to delete the audio file err = a.deleteMediaFile(fileName) if err != nil { - log.Println("failed to delete audio file:", err) + a.error("failed to delete audio file", "err", err, "file", fileName) return false } return true diff --git a/webmention.go b/webmention.go index b3683f7..26105c6 100644 --- a/webmention.go +++ b/webmention.go @@ -52,35 +52,35 @@ func (a *goBlog) initWebmention() { func (a *goBlog) handleWebmention(w http.ResponseWriter, r *http.Request) { m, err := a.extractMention(r) if err != nil { - a.debug("Error extracting webmention:", err.Error()) + a.debug("Error extracting webmention", "err", err) a.serveError(w, r, err.Error(), http.StatusBadRequest) return } hasShortPrefix := a.cfg.Server.ShortPublicAddress != "" && strings.HasPrefix(m.Target, a.cfg.Server.ShortPublicAddress) hasLongPrefix := strings.HasPrefix(m.Target, a.cfg.Server.PublicAddress) if !hasShortPrefix && !hasLongPrefix { - a.debug("Webmention target not allowed:", m.Target) + a.debug("Webmention target not allowed", "target", m.Target) a.serveError(w, r, "target not allowed", http.StatusBadRequest) return } if m.Target == m.Source { - a.debug("Webmention target and source are the same:", m.Target) + a.debug("Webmention target and source are the same", "target", m.Target) a.serveError(w, r, "target and source are the same", http.StatusBadRequest) return } if err = a.queueMention(m); err != nil { - a.debug("Failed to queue webmention", err.Error()) + a.debug("Failed to queue webmention", "err", err) a.serveError(w, r, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusAccepted) _, _ = fmt.Fprint(w, "Webmention accepted") - a.debug("Accepted webmention:", m.Source, m.Target) + a.debug("Accepted webmention", "source", m.Source, "target", m.Target) } func (a *goBlog) extractMention(r *http.Request) (*mention, error) { if ct := r.Header.Get(contentType); !strings.Contains(ct, contenttype.WWWForm) { - a.debug("New webmention request with wrong content type:", ct) + a.debug("New webmention request with wrong content type", "ct", ct) return nil, errors.New("unsupported Content-Type") } err := r.ParseForm() @@ -90,7 +90,7 @@ func (a *goBlog) extractMention(r *http.Request) (*mention, error) { source := r.Form.Get("source") target := r.Form.Get("target") if source == "" || target == "" || !isAbsoluteURL(source) || !isAbsoluteURL(target) { - a.debug("Invalid webmention request, source:", source, "target:", target) + a.debug("Invalid webmention request", "source", source, "target", target) return nil, errors.New("invalid request") } return &mention{ diff --git a/webmentionSending.go b/webmentionSending.go index 912a266..49b6799 100644 --- a/webmentionSending.go +++ b/webmentionSending.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "log" "net/http" "net/url" "strings" @@ -49,7 +48,7 @@ func (a *goBlog) sendWebmentions(p *post) error { if strings.HasPrefix(link, a.cfg.Server.PublicAddress) { // Save mention directly if err := a.createWebmention(a.fullPostURL(p), link); err != nil { - log.Println("Failed to create webmention:", err.Error()) + a.error("Failed to create webmention", "err", err) } continue } @@ -64,10 +63,10 @@ func (a *goBlog) sendWebmentions(p *post) error { continue } if err = a.sendWebmention(endpoint, a.fullPostURL(p), link); err != nil { - log.Println("Sending webmention to " + link + " failed") + a.error("Sending webmention failed", "link", link) continue } - log.Println("Sent webmention to " + link) + a.info("Sent webmention", "link", link) } return nil } diff --git a/webmentionVerification.go b/webmentionVerification.go index ea452c9..3d10aec 100644 --- a/webmentionVerification.go +++ b/webmentionVerification.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "io" - "log" "net/http" "strings" "time" @@ -21,12 +20,12 @@ func (a *goBlog) initWebmentionQueue() { a.listenOnQueue("wm", 30*time.Second, func(qi *queueItem, dequeue func(), reschedule func(time.Duration)) { var m mention if err := gob.NewDecoder(bytes.NewReader(qi.content)).Decode(&m); err != nil { - log.Println("webmention queue:", err.Error()) + a.error("webmention queue error", "err", err) dequeue() return } if err := a.verifyMention(&m); err != nil { - log.Printf("Failed to verify webmention from %s to %s: %s", m.Source, m.Target, err.Error()) + a.error("Failed to verify webmention", "source", m.Source, "target", m.Target, "err", err) } dequeue() }) @@ -59,9 +58,7 @@ func (a *goBlog) verifyMention(m *mention) error { _ = targetResp.Body.Close() // Check if target has a valid status code if targetResp.StatusCode != http.StatusOK { - if a.cfg.Debug { - a.debug(fmt.Sprintf("Webmention for unknown path: %s", m.Target)) - } + a.debug("Webmention for unknown path", "target", m.Target) return a.db.deleteWebmention(m) } // Check if target has a redirect @@ -94,9 +91,7 @@ func (a *goBlog) verifyMention(m *mention) error { } // Check if source has a valid status code if sourceResp.StatusCode != http.StatusOK { - if a.cfg.Debug { - a.debug(fmt.Sprintf("Delete webmention because source doesn't have valid status code: %s", m.Source)) - } + a.debug("Delete webmention because source doesn't have valid status code", "source", m.Source) return a.db.deleteWebmention(m) } // Check if source has a redirect @@ -108,17 +103,13 @@ func (a *goBlog) verifyMention(m *mention) error { // Parse response body err = a.verifyReader(m, sourceResp.Body) if err != nil { - if a.cfg.Debug { - a.debug(fmt.Sprintf("Delete webmention because verifying %s threw error: %s", m.Source, err.Error())) - } + a.debug("Delete webmention because verifying source threw error", "source", m.Source, "err", err) return a.db.deleteWebmention(m) } newStatus := webmentionStatusVerified // Update or insert webmention if a.db.webmentionExists(m) { - if a.cfg.Debug { - a.debug(fmt.Sprintf("Update webmention: %s => %s", m.Source, m.Target)) - } + a.debug("Update webmention", "source", m.Source, "target", m.Target) // Update webmention err = a.db.updateWebmention(m, newStatus) if err != nil {