send page titles to goatcounter
11 files changed, 62 insertions(+), 23 deletions(-)
jump to
- internal/builder/builder.go
- internal/stats/counter.go
- internal/stats/goatcounter/count.go
- internal/stats/nullcounter/nullcounter.go
- internal/storage/file.go
- internal/storage/files/writer.go
- internal/storage/interface.go
- internal/storage/sqlite/reader.go
- internal/storage/sqlite/writer.go
- internal/website/mux.go
- internal/website/website.go
M internal/builder/builder.go → internal/builder/builder.go
@@ -51,7 +51,7 @@ buf.Reset() if _, err := io.Copy(buf, sf); err != nil { return err } - if err := storage.Write("/"+rel, buf); err != nil { + if err := storage.Write("/"+rel, "", buf); err != nil { return err }@@ -102,7 +102,7 @@ buf.Reset() if err := templates.TagsPage(config, "tags", mapset.Sorted(cc.Tags), "/tags").Render(ctx, buf); err != nil { return err } - if err := storage.Write("/tags/", buf); err != nil { + if err := storage.Write("/tags/", "Tags", buf); err != nil { return err } sitemap.AddPath("/tags/", lastMod)@@ -120,14 +120,15 @@ buf.Reset() if err := templates.TagPage(config, tag, matchingPosts, url).Render(ctx, buf); err != nil { return err } - if err = storage.Write(url, buf); err != nil { + if err = storage.Write(url, tag, buf); err != nil { return err } sitemap.AddPath(url, matchingPosts[0].Date) log.Debug("rendering tags feed", "tag", tag) + title := fmt.Sprintf("%s - %s", config.Title, tag) feed, err := template.RenderFeed( - fmt.Sprintf("%s - %s", config.Title, tag), + title, config, matchingPosts, tag,@@ -139,7 +140,7 @@ buf.Reset() if _, err := feed.WriteTo(buf); err != nil { return err } - if err := storage.Write(path.Join("/tags", tag, "atom.xml"), buf); err != nil { + if err := storage.Write(path.Join("/tags", tag, "atom.xml"), title, buf); err != nil { return err } }@@ -149,7 +150,7 @@ buf.Reset() if err := templates.ListPage(config, cc.Posts, "/post").Render(ctx, buf); err != nil { return err } - if err := storage.Write("/post/", buf); err != nil { + if err := storage.Write("/post/", "Posts", buf); err != nil { return err } sitemap.AddPath("/post/", lastMod)@@ -163,7 +164,7 @@ buf.Reset() if _, err := feed.WriteTo(buf); err != nil { return err } - if err := storage.Write("/atom.xml", buf); err != nil { + if err := storage.Write("/atom.xml", config.Title, buf); err != nil { return err }@@ -173,7 +174,7 @@ log.Debug("rendering template file", "filename", filename) if err := template.CopyFile(filename, buf); err != nil { return errors.WithMessagef(err, "could not render template file %s", filename) } - if err := storage.Write("/"+filename, buf); err != nil { + if err := storage.Write("/"+filename, "", buf); err != nil { return err } }@@ -211,7 +212,7 @@ buf.Reset() if _, err := sitemap.WriteTo(buf); err != nil { return err } - if err := storage.Write("/sitemap.xml", buf); err != nil { + if err := storage.Write("/sitemap.xml", "sitemap", buf); err != nil { return err }@@ -224,7 +225,7 @@ buf.Reset() if _, err := io.Copy(buf, rob); err != nil { return err } - if err := storage.Write("/robots.txt", buf); err != nil { + if err := storage.Write("/robots.txt", "", buf); err != nil { return err }
M internal/stats/counter.go → internal/stats/counter.go
@@ -3,5 +3,5 @@ import "net/http" type Counter interface { - Count(*http.Request) + Count(*http.Request, string) }
M internal/stats/goatcounter/count.go → internal/stats/goatcounter/count.go
@@ -37,6 +37,7 @@ IP string `json:"ip"` Path string `json:"path"` Query string `json:"query"` Referrer string `json:"ref"` + Title string `json:"title"` UserAgent string `json:"user_agent"` }@@ -61,14 +62,14 @@ }, } } -func (gc *Goatcounter) Count(r *http.Request) { - err := gc.count(r) +func (gc *Goatcounter) Count(r *http.Request, title string) { + err := gc.count(r, title) if err != nil { gc.log.Warn("could not log page view", "error", err) } } -func (gc *Goatcounter) count(userReq *http.Request) error { +func (gc *Goatcounter) count(userReq *http.Request, title string) error { body, err := json.Marshal(&countBody{ NoSessions: true, Hits: []hit{@@ -76,6 +77,7 @@ { IP: userReq.RemoteAddr, Path: userReq.URL.Path, Query: userReq.URL.RawQuery, + Title: title, Referrer: userReq.Header.Get("Referer"), UserAgent: userReq.Header.Get("User-Agent"), },
A internal/stats/nullcounter/nullcounter.go
@@ -0,0 +1,25 @@ +package nullcounter + +import ( + "net/http" + + "go.alanpearce.eu/x/log" +) + +type Options struct { + Logger *log.Logger +} + +type NullCounter struct { + log *log.Logger +} + +func New(opts *Options) *NullCounter { + return &NullCounter{ + log: opts.Logger, + } +} + +func (nc *NullCounter) Count(r *http.Request, title string) { + nc.log.Debug("counting request", "path", r.URL.Path, "title", title) +}
M internal/storage/file.go → internal/storage/file.go
@@ -15,6 +15,7 @@ Path string ContentType string LastModified time.Time Etag string + Title string StyleHash string Encodings map[string]*buffer.Buffer }
M internal/storage/files/writer.go → internal/storage/files/writer.go
@@ -70,7 +70,7 @@ return nil } -func (f *Files) Write(pathname string, content *buffer.Buffer) error { +func (f *Files) Write(pathname string, _ string, content *buffer.Buffer) error { fd, err := f.write(pathname, content) if err != nil { return err@@ -88,7 +88,7 @@ } } func (f *Files) WriteFile(file *storage.File, content *buffer.Buffer) error { - return f.Write(file.Path, content) + return f.Write(file.Path, file.Title, content) } func (f *Files) write(pathname string, content *buffer.Buffer) (multifile.FileLike, error) {
M internal/storage/interface.go → internal/storage/interface.go
@@ -15,7 +15,7 @@ Mkdirp(path string) error NewFileFromPost(post *content.Post) *File - Write(pathname string, content *buffer.Buffer) error + Write(pathname string, title string, content *buffer.Buffer) error WritePost(post *content.Post, content *buffer.Buffer) error WriteFile(file *File, content *buffer.Buffer) error }
M internal/storage/sqlite/reader.go → internal/storage/sqlite/reader.go
@@ -30,6 +30,7 @@ SELECT file.content_type, file.last_modified, file.etag, + file.title, file.style_hash, content.encoding, content.body@@ -81,6 +82,7 @@ err = rows.Scan( &file.ContentType, &unixTime, &file.Etag, + &file.Title, &file.StyleHash, &encoding, &content,
M internal/storage/sqlite/writer.go → internal/storage/sqlite/writer.go
@@ -66,6 +66,7 @@ file_id INTEGER PRIMARY KEY, url_id INTEGER NOT NULL, content_type TEXT NOT NULL, last_modified INTEGER NOT NULL, + title TEXT NOT NULL, etag TEXT NOT NULL, style_hash TEXT NOT NULL, FOREIGN KEY (url_id) REFERENCES url (url_id)@@ -99,8 +100,8 @@ return nil, errors.WithMessage(err, "preparing insert URL statement") } w.queries.insertFile, err = db.Prepare(` - INSERT INTO file (url_id, content_type, last_modified, etag, style_hash) - VALUES (:url_id, :content_type, :last_modified, :etag, :style_hash) + INSERT INTO file (url_id, content_type, last_modified, etag, style_hash, title) + VALUES (:url_id, :content_type, :last_modified, :etag, :style_hash, :title) `) if err != nil { return nil, errors.WithMessage(err, "preparing insert file statement")@@ -147,6 +148,7 @@ sql.Named("content_type", file.ContentType), sql.Named("last_modified", file.LastModified.Unix()), sql.Named("etag", file.Etag), sql.Named("style_hash", file.StyleHash), + sql.Named("title", file.Title), ) if err != nil { return 0, errors.WithMessage(err, "inserting file into database")@@ -186,6 +188,7 @@ } func (s *Writer) NewFileFromPost(post *content.Post) *storage.File { file := &storage.File{ + Title: post.Title, Path: post.URL, LastModified: post.Date, Encodings: map[string]*buffer.Buffer{},@@ -200,8 +203,9 @@ return s.WriteFile(s.NewFileFromPost(post), content) } -func (s *Writer) Write(pathname string, content *buffer.Buffer) error { +func (s *Writer) Write(pathname string, title string, content *buffer.Buffer) error { file := &storage.File{ + Title: title, Path: pathname, LastModified: time.Now(), Encodings: map[string]*buffer.Buffer{},
M internal/website/mux.go → internal/website/mux.go
@@ -48,9 +48,6 @@ http.Redirect(w, r, urlPath, 302) return nil } - if website.counter != nil { - website.counter.Count(r) - } file, err := website.reader.GetFile(urlPath) if err != nil { website.log.Warn("Error reading file", "error", err)@@ -61,11 +58,14 @@ Code: http.StatusInternalServerError, } } if file == nil { + website.counter.Count(r, "404") + return &ihttp.Error{ Message: "File not found", Code: http.StatusNotFound, } } + website.counter.Count(r, file.Title) w.Header().Add("ETag", file.Etag) w.Header().Add("Vary", "Accept-Encoding") csp := *website.config.CSP
M internal/website/website.go → internal/website/website.go
@@ -15,6 +15,7 @@ ihttp "go.alanpearce.eu/homestead/internal/http" "go.alanpearce.eu/homestead/internal/server" "go.alanpearce.eu/homestead/internal/stats" "go.alanpearce.eu/homestead/internal/stats/goatcounter" + "go.alanpearce.eu/homestead/internal/stats/nullcounter" "go.alanpearce.eu/homestead/internal/storage" "go.alanpearce.eu/homestead/internal/storage/sqlite" "go.alanpearce.eu/x/log"@@ -108,6 +109,9 @@ if opts.GoatcounterToken == "" { if !opts.Development { log.Warn("in production without a goatcounter token") } + website.counter = nullcounter.New(&nullcounter.Options{ + Logger: log.Named("counter"), + }) } else { website.counter = goatcounter.New(&goatcounter.Options{ Logger: log.Named("counter"),