diff --git a/.gitignore b/.gitignore index 6936877..8f26fb1 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ go.work dist/ +.coverprofile pages diff --git a/internal/commands/host.go b/internal/commands/host.go index d17c639..8616cef 100644 --- a/internal/commands/host.go +++ b/internal/commands/host.go @@ -20,6 +20,7 @@ import ( "context" "mime" "net/http" + "time" "github.com/urfave/cli/v2" "go.uber.org/zap" @@ -97,6 +98,21 @@ var ( group, c := errgroup.WithContext(ctx.Context) group.Go(server.ListenAndServe) + group.Go(func() error { + timer := time.NewTimer(hostConfig.Git.SyncInterval) + defer timer.Stop() + + for { + select { + case <-c.Done(): + return nil + case <-timer.C: + _ = gitService.Sync(ctx.Context) + + timer.Reset(hostConfig.Git.SyncInterval) + } + } + }) <-c.Done() diff --git a/internal/git/service.go b/internal/git/service.go index 1d24a52..2ce7534 100644 --- a/internal/git/service.go +++ b/internal/git/service.go @@ -19,6 +19,7 @@ package git import ( "context" "os" + "time" "github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/osfs" @@ -34,11 +35,12 @@ import ( // Config encapsulates the elements that can be configured about the git service. type Config struct { - URL string `json:"url" usage:"the git url used to clone the repository"` - Branch string `json:"branch" usage:"the name of the git branch to clone"` - Tag string `json:"tag" usage:"the name of the git tag to clone"` - Username string `json:"username" usage:"the username used to authenticate with the git service"` - Password string `json:"password" usage:"the password used to authenticate with the git service"` + URL string `json:"url" usage:"the git url used to clone the repository"` + Branch string `json:"branch" usage:"the name of the git branch to clone"` + Tag string `json:"tag" usage:"the name of the git tag to clone"` + Username string `json:"username" usage:"the username used to authenticate with the git service"` + Password string `json:"password" usage:"the password used to authenticate with the git service"` + SyncInterval time.Duration `json:"sync_interval" usage:"how frequently the git repository is pulled for changes" default:"1h"` } // NewService constructs a Service that manages the underlying git repository. diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index df8a04c..bc170b8 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -25,6 +25,16 @@ var ( namespace = "pages" page = "page" + // by default, summaries give us counts and sums which we can use to compute an average (not great, but it can work) + // in addition to the default information, we report on the following quantiles: + defaultObjectives = map[float64]float64{ + 0.25: 0, // lower quartile + 0.5: 0, // median + 0.75: 0, // upper quartile + 0.90: 0, // One 9 + 0.99: 0, // Two 9s + } + // PageViewCount tracks page views by how often they're loaded. PageViewCount = promauto.NewCounterVec( prometheus.CounterOpts{ @@ -37,12 +47,13 @@ var ( ) // PageSessionDuration tracks how long someone spends on an individual page. - PageSessionDuration = promauto.NewHistogramVec( - prometheus.HistogramOpts{ - Namespace: namespace, - Subsystem: page, - Name: "session_seconds", - Help: "how long someone spent on a given page", + PageSessionDuration = promauto.NewSummaryVec( + prometheus.SummaryOpts{ + Namespace: namespace, + Subsystem: page, + Name: "session_seconds", + Help: "how long someone spent on a given page", + Objectives: defaultObjectives, }, []string{"domain", "path", "country"}, ) diff --git a/internal/session/handler.go b/internal/session/handler.go index 44fb720..aed3f95 100644 --- a/internal/session/handler.go +++ b/internal/session/handler.go @@ -19,7 +19,6 @@ package session import ( "net/http" "net/url" - "time" "github.com/gorilla/websocket" "go.uber.org/zap" @@ -27,6 +26,7 @@ import ( "code.pitz.tech/mya/pages/internal/geoip" "code.pitz.tech/mya/pages/internal/metrics" + "github.com/mjpitz/myago/clocks" "github.com/mjpitz/myago/zaputil" ) @@ -62,6 +62,7 @@ type Handle struct { func (h *Handle) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() log := zaputil.Extract(ctx) + clock := clocks.Extract(ctx) conn, err := h.upgrader.Upgrade(w, r, nil) if err != nil { @@ -91,9 +92,9 @@ func (h *Handle) ServeHTTP(w http.ResponseWriter, r *http.Request) { active.Inc() defer func() { active.Dec() }() - start := time.Now() + start := clock.Now() defer func() { - metrics.PageSessionDuration.WithLabelValues(domain, path, geoInfo.CountryCode).Observe(time.Since(start).Seconds()) + metrics.PageSessionDuration.WithLabelValues(domain, path, geoInfo.CountryCode).Observe(clock.Since(start).Seconds()) }() for {