From dfeba317849215ab7162a89e3dd0fa7fed94bb0c Mon Sep 17 00:00:00 2001 From: Gabriel Simmer Date: Sat, 18 May 2024 23:02:27 +0100 Subject: [PATCH 1/6] Basic Prometheus metrics Currently track number of paste views and total pastes in database. May expand over time. --- cmd/tclipd/main.go | 46 +++++++++++++++++++++++++++++++++++++++++++--- flake.nix | 2 +- go.mod | 7 +++++++ go.sum | 14 ++++++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/cmd/tclipd/main.go b/cmd/tclipd/main.go index e031689..eea8130 100644 --- a/cmd/tclipd/main.go +++ b/cmd/tclipd/main.go @@ -26,6 +26,9 @@ import ( _ "github.com/lib/pq" "github.com/microcosm-cc/bluemonday" "github.com/niklasfasching/go-org/org" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/russross/blackfriday" _ "modernc.org/sqlite" "tailscale.com/client/tailscale" @@ -43,6 +46,7 @@ var ( hidePasteUserInfo = flag.Bool("hide-funnel-users", hasEnv("HIDE_FUNNEL_USERS"), "if set, display the username and profile picture of the user who created the paste in funneled pastes") databaseUrl = flag.String("database-url", envOr("DATABASE_URL", ""), "optional database url if you'd rather use Postgres instead of sqlite") httpPort = flag.String("http-port", envOr("HTTP_PORT", ""), "optional http port to start an http server on, e.g for reverse proxies. will only serve funnel endpoints") + enableMetrics = flag.Bool("enable-metrics", hasEnv("ENABLE_METRICS"), "if set, enabled the /metrics endpoint on the tailnet listener") //go:embed schema.sql sqlSchema string @@ -63,6 +67,17 @@ func hasEnv(name string) bool { const formDataLimit = 64 * 1024 // 64 kilobytes (approx. 32 printed pages of text) +var ( + totalPastes = promauto.NewGauge(prometheus.GaugeOpts{ + Name: "tclip_total_pastes", + Help: "The total number of stored pastes", + }) + pasteViews = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "tclip_paste_views", + Help: "Number of times a paste has been viewed", + }, []string{"id", "origin", "type"}) +) + func dataLocation() string { if dir, ok := os.LookupEnv("DATA_DIR"); ok { return dir @@ -264,7 +279,7 @@ VALUES } log.Printf("new paste: %s", id) - + totalPastes.Inc() switch r.Header.Get("Accept") { case "text/plain": w.WriteHeader(http.StatusOK) @@ -460,7 +475,7 @@ WHERE id = $1 AND user_id = $2 s.ShowError(w, r, err, http.StatusInternalServerError) return } - + totalPastes.Dec() http.Redirect(w, r, "/", http.StatusTemporaryRedirect) } @@ -470,11 +485,12 @@ func (s *Server) ShowPost(w http.ResponseWriter, r *http.Request) { if ui != nil { up = ui.UserProfile } - + origin := "tailnet" if valAny := r.Context().Value(privacyKey); valAny != nil { if val, ok := valAny.(mixedCriticalityHandlerCtxKey); ok { if val == isFunnel { up = nil + origin = "public" } } } @@ -572,6 +588,9 @@ WHERE p.id = $1` w.WriteHeader(http.StatusOK) fmt.Fprint(w, data) + + pasteViews.With(prometheus.Labels{"id": id, "origin": origin, "type": "raw"}).Inc() + return // download file to disk (plain text view plus download hint) case "dl": @@ -581,6 +600,8 @@ WHERE p.id = $1` w.WriteHeader(http.StatusOK) fmt.Fprint(w, data) + pasteViews.With(prometheus.Labels{"id": id, "origin": origin, "type": "download"}).Inc() + return case "": // view markdown file with a fancy HTML rendering step @@ -603,6 +624,7 @@ WHERE p.id = $1` title = ogTitle } } + pasteViews.With(prometheus.Labels{"id": id, "origin": origin, "type": "fancy"}).Inc() err = s.tmpls.ExecuteTemplate(w, "fancypost.html", struct { Title string @@ -635,6 +657,8 @@ WHERE p.id = $1` remoteUserID = up.ID } + pasteViews.With(prometheus.Labels{"id": id, "origin": origin, "type": "normal"}).Inc() + err = s.tmpls.ExecuteTemplate(w, "showpaste.html", struct { UserInfo *tailcfg.UserProfile Title string @@ -693,6 +717,17 @@ func main() { } defer db.Close() + if *enableMetrics { + q := ` +SELECT count(*) +FROM pastes +` + var pastes float64 + // Execute query using 'id' and place value into 'output' + db.QueryRow(q).Scan(&pastes) + totalPastes.Set(pastes) + } + lc, err := s.LocalClient() if err != nil { log.Fatal(err) @@ -736,6 +771,11 @@ func main() { tailnetMux.HandleFunc("/", srv.TailnetIndex) tailnetMux.HandleFunc("/help", srv.TailnetHelp) + if *enableMetrics { + tailnetMux.Handle("/metrics", promhttp.Handler()) + log.Printf("metrics enabled on /metrics") + } + funnelMux := http.NewServeMux() funnelMux.Handle("/static/", http.FileServer(http.FS(staticFiles))) funnelMux.HandleFunc("/", srv.PublicIndex) diff --git a/flake.nix b/flake.nix index 9f5bd07..cdfd81a 100644 --- a/flake.nix +++ b/flake.nix @@ -24,7 +24,7 @@ go = pkgs.go; src = ./.; subPackages = "cmd/tclipd"; - vendorHash = "sha256-Ho39aNWTbygA46/9lkXRVLV6FLkWenAJKxOE3MJUb2M="; + vendorHash = "sha256-nxKlKxpr7PZhDLk/J3TBjdhLjy7EYqmMGF+y4hgRgRQ="; }; tclip = pkgs.buildGo122Module { diff --git a/go.mod b/go.mod index 6d8a5ce..9c062b1 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,8 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect github.com/aws/smithy-go v1.19.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-iptables v0.7.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect @@ -68,6 +70,10 @@ require ( github.com/mitchellh/go-ps v1.0.0 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/safchain/ethtool v0.3.0 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect @@ -98,6 +104,7 @@ require ( golang.org/x/tools v0.17.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect + google.golang.org/protobuf v1.33.0 // indirect gvisor.dev/gvisor v0.0.0-20240306221502-ee1e1f6070e3 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/libc v1.41.0 // indirect diff --git a/go.sum b/go.sum index 8f81f38..3d65b11 100644 --- a/go.sum +++ b/go.sum @@ -40,6 +40,10 @@ github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= @@ -158,6 +162,14 @@ github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= @@ -251,6 +263,8 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -- 2.46.0 From 66bfb09ab09c652fed7aa16c76be5301d9361991 Mon Sep 17 00:00:00 2001 From: Gabriel Simmer Date: Sat, 18 May 2024 23:20:14 +0100 Subject: [PATCH 2/6] Add sample Grafana dashboard --- contrib/grafana.json | 1323 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1323 insertions(+) create mode 100644 contrib/grafana.json diff --git a/contrib/grafana.json b/contrib/grafana.json new file mode 100644 index 0000000..b05b947 --- /dev/null +++ b/contrib/grafana.json @@ -0,0 +1,1323 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "VAR_JOB", + "type": "constant", + "label": "Job", + "value": "tclip", + "description": "" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.4.2" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Process status published by Go Prometheus client library, e.g. memory used, fds open, GC details", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 6671, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 10, + "title": "tclip", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 0, + "y": 1 + }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "tclip_total_pastes{}", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Total Pastes", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 19, + "x": 5, + "y": 1 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "tclip_paste_views{}", + "instant": false, + "legendFormat": "{{id}} - {{origin}} ({{type}})", + "range": true, + "refId": "A" + } + ], + "title": "Paste Views", + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 9, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "resident" + }, + "properties": [ + { + "id": "unit", + "value": "short" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 1, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "process_resident_memory_bytes{job='$job'}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}} - resident", + "metric": "process_resident_memory_bytes", + "range": true, + "refId": "A", + "step": 4 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "process_virtual_memory_bytes{job='$job'}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}} - virtual", + "metric": "process_virtual_memory_bytes", + "refId": "B", + "step": 4 + } + ], + "title": "process memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 4, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "rate(process_resident_memory_bytes{job='$job'}[$interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}} - resident", + "metric": "process_resident_memory_bytes", + "refId": "A", + "step": 4 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "deriv(process_virtual_memory_bytes{job='$job'}[$interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}} - virtual", + "metric": "process_virtual_memory_bytes", + "refId": "B", + "step": 4 + } + ], + "title": "process memory deriv", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "alloc rate" + }, + "properties": [ + { + "id": "unit", + "value": "Bps" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 2, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "go_memstats_alloc_bytes{job='$job'}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}} - bytes allocated", + "metric": "go_memstats_alloc_bytes", + "refId": "A", + "step": 4 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "rate(go_memstats_alloc_bytes_total{job='$job'}[30s])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}} - alloc rate", + "metric": "go_memstats_alloc_bytes_total", + "refId": "B", + "step": 4 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "go_memstats_stack_inuse_bytes{job='$job'}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}} - stack inuse", + "metric": "go_memstats_stack_inuse_bytes", + "refId": "C", + "step": 4 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "go_memstats_heap_inuse_bytes{job='$job'}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{pod}} - heap inuse", + "metric": "go_memstats_heap_inuse_bytes", + "refId": "D", + "step": 4 + } + ], + "title": "go memstats", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "alloc rate" + }, + "properties": [ + { + "id": "unit", + "value": "Bps" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 5, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "deriv(go_memstats_alloc_bytes{job='$job'}[$interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}} - bytes allocated", + "metric": "go_memstats_alloc_bytes", + "refId": "A", + "step": 4 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "rate(go_memstats_alloc_bytes_total{job='$job'}[$interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}} - alloc rate", + "metric": "go_memstats_alloc_bytes_total", + "refId": "B", + "step": 4 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "deriv(go_memstats_stack_inuse_bytes{job='$job'}[$interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}} - stack inuse", + "metric": "go_memstats_stack_inuse_bytes", + "refId": "C", + "step": 4 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "deriv(go_memstats_heap_inuse_bytes{job='$job'}[$interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{pod}} - heap inuse", + "metric": "go_memstats_heap_inuse_bytes", + "refId": "D", + "step": 4 + } + ], + "title": "go memstats deriv", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 25 + }, + "id": 3, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "process_open_fds{job='$job'}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}}", + "metric": "process_open_fds", + "refId": "A", + "step": 4 + } + ], + "title": "open fds", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 25 + }, + "id": 6, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "deriv(process_open_fds{job='$job'}[$interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}}", + "metric": "process_open_fds", + "refId": "A", + "step": 4 + } + ], + "title": "open fds deriv", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 32 + }, + "id": 7, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "go_goroutines{job='$job'}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}}", + "metric": "go_goroutines", + "refId": "A", + "step": 4 + } + ], + "title": "Goroutines", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 32 + }, + "id": 8, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "go_gc_duration_seconds{job='$job'}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{pod}}: {{quantile}}", + "metric": "go_gc_duration_seconds", + "refId": "A", + "step": 4 + } + ], + "title": "GC duration quantiles", + "type": "timeseries" + } + ], + "title": "Go Metrics", + "type": "row" + } + ], + "refresh": "30s", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "5m", + "value": "5m" + }, + "hide": 0, + "includeAll": false, + "label": "", + "multi": false, + "name": "interval", + "options": [ + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": true, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + } + ], + "query": "1m,5m,10m,30m,1h", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "description": "tclip", + "hide": 2, + "label": "Job", + "name": "job", + "query": "${VAR_JOB}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_JOB}", + "text": "${VAR_JOB}", + "selected": false + }, + "options": [ + { + "value": "${VAR_JOB}", + "text": "${VAR_JOB}", + "selected": false + } + ] + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "tclip", + "uid": "ypFZFgvmz", + "version": 9, + "weekStart": "" +} \ No newline at end of file -- 2.46.0 From b6a5d6332d6b745a0103cabe7b75b8dabb21771b Mon Sep 17 00:00:00 2001 From: Gabriel Simmer Date: Sat, 18 May 2024 23:23:41 +0100 Subject: [PATCH 3/6] Tweak how origin is determined --- cmd/tclipd/main.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/tclipd/main.go b/cmd/tclipd/main.go index eea8130..269f8fb 100644 --- a/cmd/tclipd/main.go +++ b/cmd/tclipd/main.go @@ -482,15 +482,16 @@ WHERE id = $1 AND user_id = $2 func (s *Server) ShowPost(w http.ResponseWriter, r *http.Request) { ui, _ := upsertUserInfo(r.Context(), s.db, s.lc, r.RemoteAddr) var up *tailcfg.UserProfile + origin := "public" if ui != nil { up = ui.UserProfile + origin = "tailnet" } - origin := "tailnet" + if valAny := r.Context().Value(privacyKey); valAny != nil { if val, ok := valAny.(mixedCriticalityHandlerCtxKey); ok { if val == isFunnel { up = nil - origin = "public" } } } -- 2.46.0 From 1271c03c78cd8b905af4088773030cb01a37face Mon Sep 17 00:00:00 2001 From: Gabriel Simmer Date: Sat, 18 May 2024 23:38:28 +0100 Subject: [PATCH 4/6] Tweak Grafana dashboard origin selection --- contrib/grafana.json | 55 +++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/contrib/grafana.json b/contrib/grafana.json index b05b947..c4ce3cd 100644 --- a/contrib/grafana.json +++ b/contrib/grafana.json @@ -59,7 +59,7 @@ } ] }, - "description": "Process status published by Go Prometheus client library, e.g. memory used, fds open, GC details", + "description": "tclipd metrics", "editable": true, "fiscalYearStartMonth": 0, "gnetId": 6671, @@ -229,9 +229,9 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "tclip_paste_views{}", + "expr": "sum(tclip_paste_views{origin=~\"$origin\"}) by (id, type)", "instant": false, - "legendFormat": "{{id}} - {{origin}} ({{type}})", + "legendFormat": "{{id}} ({{type}})", "range": true, "refId": "A" } @@ -296,8 +296,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -426,8 +425,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -541,8 +539,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -696,8 +693,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -851,8 +847,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -953,8 +948,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1055,8 +1049,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1157,8 +1150,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1217,7 +1209,7 @@ "type": "row" } ], - "refresh": "30s", + "refresh": "10s", "schemaVersion": 39, "tags": [], "templating": { @@ -1288,6 +1280,27 @@ "selected": false } ] + }, + { + "allValue": ".*", + "current": {}, + "definition": "label_values(tclip_paste_views,origin)", + "hide": 0, + "includeAll": true, + "label": "Origin", + "multi": false, + "name": "origin", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(tclip_paste_views,origin)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" } ] }, @@ -1318,6 +1331,6 @@ "timezone": "browser", "title": "tclip", "uid": "ypFZFgvmz", - "version": 9, + "version": 16, "weekStart": "" } \ No newline at end of file -- 2.46.0 From 6d762244c278723f7960612d4774acf8fc1181ff Mon Sep 17 00:00:00 2001 From: Gabriel Simmer Date: Sat, 18 May 2024 23:53:00 +0100 Subject: [PATCH 5/6] Drop "type" from paste views metric --- cmd/tclipd/main.go | 10 +++++----- contrib/grafana.json | 12 ++++++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/cmd/tclipd/main.go b/cmd/tclipd/main.go index 269f8fb..f0088ae 100644 --- a/cmd/tclipd/main.go +++ b/cmd/tclipd/main.go @@ -75,7 +75,7 @@ var ( pasteViews = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "tclip_paste_views", Help: "Number of times a paste has been viewed", - }, []string{"id", "origin", "type"}) + }, []string{"id", "origin"}) ) func dataLocation() string { @@ -590,7 +590,7 @@ WHERE p.id = $1` w.WriteHeader(http.StatusOK) fmt.Fprint(w, data) - pasteViews.With(prometheus.Labels{"id": id, "origin": origin, "type": "raw"}).Inc() + pasteViews.With(prometheus.Labels{"id": id, "origin": origin}).Inc() return // download file to disk (plain text view plus download hint) @@ -601,7 +601,7 @@ WHERE p.id = $1` w.WriteHeader(http.StatusOK) fmt.Fprint(w, data) - pasteViews.With(prometheus.Labels{"id": id, "origin": origin, "type": "download"}).Inc() + pasteViews.With(prometheus.Labels{"id": id, "origin": origin}).Inc() return case "": @@ -625,7 +625,7 @@ WHERE p.id = $1` title = ogTitle } } - pasteViews.With(prometheus.Labels{"id": id, "origin": origin, "type": "fancy"}).Inc() + pasteViews.With(prometheus.Labels{"id": id, "origin": origin}).Inc() err = s.tmpls.ExecuteTemplate(w, "fancypost.html", struct { Title string @@ -658,7 +658,7 @@ WHERE p.id = $1` remoteUserID = up.ID } - pasteViews.With(prometheus.Labels{"id": id, "origin": origin, "type": "normal"}).Inc() + pasteViews.With(prometheus.Labels{"id": id, "origin": origin}).Inc() err = s.tmpls.ExecuteTemplate(w, "showpaste.html", struct { UserInfo *tailcfg.UserProfile diff --git a/contrib/grafana.json b/contrib/grafana.json index c4ce3cd..c1bf133 100644 --- a/contrib/grafana.json +++ b/contrib/grafana.json @@ -164,7 +164,7 @@ "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", - "fillOpacity": 0, + "fillOpacity": 5, "gradientMode": "none", "hideFrom": { "legend": false, @@ -229,9 +229,9 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "sum(tclip_paste_views{origin=~\"$origin\"}) by (id, type)", + "expr": "sum(tclip_paste_views{origin=~\"$origin\"}) by (id)", "instant": false, - "legendFormat": "{{id}} ({{type}})", + "legendFormat": "{{id}}", "range": true, "refId": "A" } @@ -1284,6 +1284,10 @@ { "allValue": ".*", "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "definition": "label_values(tclip_paste_views,origin)", "hide": 0, "includeAll": true, @@ -1331,6 +1335,6 @@ "timezone": "browser", "title": "tclip", "uid": "ypFZFgvmz", - "version": 16, + "version": 17, "weekStart": "" } \ No newline at end of file -- 2.46.0 From b4248c0f288d4fb13373593c205405602ac2c0be Mon Sep 17 00:00:00 2001 From: Gabriel Simmer Date: Sun, 19 May 2024 00:05:49 +0100 Subject: [PATCH 6/6] Drop copy pasted comment --- cmd/tclipd/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/tclipd/main.go b/cmd/tclipd/main.go index f0088ae..9afea24 100644 --- a/cmd/tclipd/main.go +++ b/cmd/tclipd/main.go @@ -724,7 +724,6 @@ SELECT count(*) FROM pastes ` var pastes float64 - // Execute query using 'id' and place value into 'output' db.QueryRow(q).Scan(&pastes) totalPastes.Set(pastes) } -- 2.46.0