summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Fischer <martin@push-f.com>2025-04-06 22:16:04 +0200
committerMartin Fischer <martin@push-f.com>2025-04-13 23:18:01 +0200
commit35275699ade84abefbf0b1a6c82882d8d470c8ad (patch)
tree6edd7605d2caf9696485979f695c0424f451abf7
parent8d834d04be72597fa8a9627af3b471ab65baaa0d (diff)
feat: use structured logging
-rw-r--r--lex-serve/main.go40
-rw-r--r--lex-serve/main_test.go3
-rw-r--r--service.nix1
3 files changed, 31 insertions, 13 deletions
diff --git a/lex-serve/main.go b/lex-serve/main.go
index 0a1403b..416104f 100644
--- a/lex-serve/main.go
+++ b/lex-serve/main.go
@@ -6,7 +6,7 @@ import (
"encoding/json"
"html/template"
"io/ioutil"
- "log"
+ "log/slog"
"net"
"net/http"
"net/url"
@@ -18,35 +18,43 @@ import (
var countriesJSON []byte
func main() {
+ log := slog.New(slog.NewTextHandler(os.Stderr, nil))
+
socketPath := os.Getenv("SOCKET_PATH")
if socketPath == "" {
- log.Fatal("SOCKET_PATH must be set")
+ log.Error("SOCKET_PATH must be set")
+ os.Exit(1)
}
domain := os.Getenv("DOMAIN")
if domain == "" {
- log.Fatal("DOMAIN environment variable must be set")
+ log.Error("DOMAIN environment variable must be set")
+ os.Exit(1)
}
- var handler = handler{domain: domain, lawsByCC: map[string]map[string]law{}}
+ var handler = handler{logger: log, domain: domain, lawsByCC: map[string]map[string]law{}}
err := json.Unmarshal(countriesJSON, &handler.countries)
if err != nil {
- log.Fatal("countries.json ", err)
+ log.Error("failed to parse countries.json", Error(err))
+ os.Exit(1)
}
lawFiles, err := ioutil.ReadDir("laws")
if err != nil {
- log.Fatal(err)
+ log.Error("failed to read laws/ directory", Error(err))
+ os.Exit(1)
}
for _, file := range lawFiles {
text, err := ioutil.ReadFile("laws/" + file.Name())
if err != nil {
- log.Fatal(file.Name(), err)
+ log.Error("failed to read file", Error(err), "path", "laws/"+file.Name())
+ os.Exit(1)
}
var laws []law
err = json.Unmarshal([]byte(text), &laws)
if err != nil {
- log.Fatal(file.Name(), err)
+ log.Error("failed to parse file", Error(err), "path", file.Name())
+ os.Exit(1)
}
cc := strings.SplitN(file.Name(), ".", 2)[0]
handler.lawsByCC[cc] = map[string]law{}
@@ -59,13 +67,15 @@ func main() {
http.HandleFunc("/", handler.handle)
listener, err := net.Listen("unix", socketPath)
if err != nil {
- log.Fatal(err)
+ log.Error("failed to listen", Error(err))
+ os.Exit(1)
}
if err := os.Chmod(socketPath, 0666); err != nil {
- log.Fatalf("error setting socket permissions: %s", err)
+ log.Error("failed to set socket permissions", Error(err), "path", socketPath)
return
}
- log.Fatal(http.Serve(listener, nil))
+ err = http.Serve(listener, nil)
+ log.Error("failed to serve", Error(err))
}
//go:embed templates
@@ -76,6 +86,7 @@ var tpl, _ = template.New("").Funcs(template.FuncMap{
}).Option("missingkey=error").ParseFS(templates, "templates/*")
type handler struct {
+ logger *slog.Logger
domain string
countries map[string]country
lawsByCC map[string]map[string]law
@@ -94,7 +105,7 @@ func (h *handler) handle(w http.ResponseWriter, r *http.Request) {
"Domain": r.Host,
})
if err != nil {
- log.Printf("failed to execute index template: %s", err)
+ h.logger.Error("failed to execute index template", Error(err))
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
@@ -104,6 +115,7 @@ func (h *handler) handle(w http.ResponseWriter, r *http.Request) {
cc, isSubdomain := strings.CutSuffix(r.Host, "."+h.domain)
if !isSubdomain {
+ h.logger.Error("request for unknown hosts", "host", r.Host)
w.Write([]byte("unknown host"))
return
}
@@ -141,7 +153,7 @@ func (h *handler) handle(w http.ResponseWriter, r *http.Request) {
"HasJSONLaws": hasJSONLaws,
})
if err != nil {
- log.Printf("failed to execute search template: %s", err)
+ h.logger.Error("failed to execute search template", Error(err))
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
@@ -164,3 +176,5 @@ type country struct {
func (c country) HasPlaceholder() bool {
return strings.Contains(c.SearchURL, "%s")
}
+
+func Error(value error) slog.Attr { return slog.String("error", value.Error()) }
diff --git a/lex-serve/main_test.go b/lex-serve/main_test.go
index e647a2f..00cc3a3 100644
--- a/lex-serve/main_test.go
+++ b/lex-serve/main_test.go
@@ -1,7 +1,9 @@
package main
import (
+ "log/slog"
"net/http/httptest"
+ "os"
"strings"
"testing"
@@ -10,6 +12,7 @@ import (
func newHandler() handler {
return handler{
+ logger: slog.New(slog.NewTextHandler(os.Stderr, nil)),
domain: "lex.example",
countries: map[string]country{
"zu": country{
diff --git a/service.nix b/service.nix
index 6024b5e..e1ebe1c 100644
--- a/service.nix
+++ b/service.nix
@@ -53,6 +53,7 @@ in
DynamicUser = true;
RuntimeDirectory = "lex-serve";
WorkingDirectory = lex_surf;
+ LogExtraFields = "LOG_FORMAT=logfmt";
};
environment = {