Skip to content

Commit 1e18c13

Browse files
j-mcfaddenwillnorris
authored andcommitted
adds some simple counter and gauge metrics
Signed-off-by: Josh <[email protected]>
1 parent b54cbbb commit 1e18c13

File tree

3 files changed

+77
-12
lines changed

3 files changed

+77
-12
lines changed

go.mod

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ go 1.24.4
55
toolchain go1.24.5
66

77
require (
8-
github.com/google/go-cmp v0.6.0
8+
github.com/google/go-cmp v0.7.0
9+
github.com/prometheus/client_golang v1.23.0
910
golang.org/x/net v0.40.0
1011
modernc.org/sqlite v1.19.4
1112
tailscale.com v1.86.2
@@ -29,6 +30,8 @@ require (
2930
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 // indirect
3031
github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 // indirect
3132
github.com/aws/smithy-go v1.22.2 // indirect
33+
github.com/beorn7/perks v1.0.1 // indirect
34+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3235
github.com/coder/websocket v1.8.12 // indirect
3336
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
3437
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
@@ -47,15 +50,19 @@ require (
4750
github.com/jmespath/go-jmespath v0.4.0 // indirect
4851
github.com/jsimonetti/rtnetlink v1.4.0 // indirect
4952
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
50-
github.com/klauspost/compress v1.17.11 // indirect
53+
github.com/klauspost/compress v1.18.0 // indirect
5154
github.com/mattn/go-isatty v0.0.20 // indirect
5255
github.com/mdlayher/genetlink v1.3.2 // indirect
5356
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect
5457
github.com/mdlayher/sdnotify v1.0.0 // indirect
5558
github.com/mdlayher/socket v0.5.0 // indirect
5659
github.com/miekg/dns v1.1.58 // indirect
5760
github.com/mitchellh/go-ps v1.0.0 // indirect
61+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
5862
github.com/prometheus-community/pro-bing v0.4.0 // indirect
63+
github.com/prometheus/client_model v0.6.2 // indirect
64+
github.com/prometheus/common v0.65.0 // indirect
65+
github.com/prometheus/procfs v0.16.1 // indirect
5966
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
6067
github.com/safchain/ethtool v0.3.0 // indirect
6168
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect
@@ -81,6 +88,7 @@ require (
8188
golang.org/x/tools v0.33.0 // indirect
8289
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
8390
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
91+
google.golang.org/protobuf v1.36.6 // indirect
8492
gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 // indirect
8593
lukechampine.com/uint128 v1.2.0 // indirect
8694
modernc.org/cc/v3 v3.40.0 // indirect

go.sum

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 h1:3LXNnmtH3TURctC23hnC0p/39Q5
4040
github.com/aws/aws-sdk-go-v2/service/sts v1.33.13/go.mod h1:7Yn+p66q/jt38qMoVfNvjbm3D89mGBnkwDcijgtih8w=
4141
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
4242
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
43+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
44+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
45+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
46+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
4347
github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
4448
github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
4549
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
@@ -81,8 +85,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l
8185
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
8286
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
8387
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
84-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
85-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
88+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
89+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
8690
github.com/google/go-tpm v0.9.4 h1:awZRf9FwOeTunQmHoDYSHJps3ie6f1UlhS1fOdPEt1I=
8791
github.com/google/go-tpm v0.9.4/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
8892
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI=
@@ -105,8 +109,8 @@ github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUF
105109
github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E=
106110
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
107111
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
108-
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
109-
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
112+
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
113+
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
110114
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ=
111115
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk=
112116
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
@@ -115,6 +119,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
115119
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
116120
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
117121
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
122+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
123+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
118124
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
119125
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
120126
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
@@ -144,17 +150,23 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
144150
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
145151
github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4=
146152
github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4=
147-
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
148-
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
149-
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
150-
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
153+
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
154+
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
155+
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
156+
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
157+
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
158+
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
159+
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
160+
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
151161
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
152162
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
153163
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
154164
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
155165
github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
156166
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
157167
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
168+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
169+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
158170
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ=
159171
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4=
160172
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4=
@@ -188,6 +200,8 @@ github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1Y
188200
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
189201
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
190202
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
203+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
204+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
191205
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek=
192206
go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
193207
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
@@ -226,12 +240,14 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu
226240
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
227241
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
228242
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
229-
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
230-
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
243+
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
244+
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
231245
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
232246
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
233247
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
234248
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
249+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
250+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
235251
gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 h1:2gap+Kh/3F47cO6hAu3idFvsJ0ue6TRcEi2IUkv/F8k=
236252
gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM=
237253
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=

golink.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import (
3030
texttemplate "text/template"
3131
"time"
3232

33+
"github.com/prometheus/client_golang/prometheus"
34+
"github.com/prometheus/client_golang/prometheus/promhttp"
3335
"golang.org/x/net/xsrftoken"
3436
"tailscale.com/client/tailscale"
3537
"tailscale.com/hostinfo"
@@ -76,6 +78,29 @@ var stats struct {
7678
dirty ClickStats
7779
}
7880

81+
var (
82+
clickCounter = prometheus.NewCounterVec(
83+
prometheus.CounterOpts{
84+
Name: "golink_clicks_total",
85+
Help: "Total number of clicks for a recognized GoLink",
86+
},
87+
[]string{"path"},
88+
)
89+
clickNotFound = prometheus.NewCounterVec(
90+
prometheus.CounterOpts{
91+
Name: "golink_not_found_total",
92+
Help: "Total number of clicks for a GoLink doesn't exist",
93+
},
94+
[]string{"path"},
95+
)
96+
totalLinkCount = prometheus.NewGauge(
97+
prometheus.GaugeOpts{
98+
Name: "golinks_total",
99+
Help: "Total number of GoLinks being served",
100+
},
101+
)
102+
)
103+
79104
// LastSnapshot is the data snapshot (as returned by the /.export handler)
80105
// that will be loaded on startup.
81106
var LastSnapshot []byte
@@ -300,6 +325,8 @@ func init() {
300325
b := make([]byte, 24)
301326
rand.Read(b)
302327
xsrfKey = base64.StdEncoding.EncodeToString(b)
328+
329+
initMetrics()
303330
}
304331

305332
var tmplFuncs = template.FuncMap{
@@ -374,6 +401,7 @@ func flushStatsLoop() {
374401

375402
// deleteLinkStats removes the link stats from memory.
376403
func deleteLinkStats(link *Link) {
404+
totalLinkCount.Dec()
377405
stats.mu.Lock()
378406
delete(stats.clicks, link.Short)
379407
delete(stats.dirty, link.Short)
@@ -416,6 +444,13 @@ func HSTS(h http.Handler) http.Handler {
416444
})
417445
}
418446

447+
// initMetrics initializes prometheus metrics.
448+
func initMetrics() {
449+
prometheus.MustRegister(clickCounter)
450+
prometheus.MustRegister(totalLinkCount)
451+
prometheus.MustRegister(clickNotFound)
452+
}
453+
419454
// serverHandler returns the main http.Handler for serving all requests.
420455
func serveHandler() http.Handler {
421456
mux := http.NewServeMux()
@@ -426,6 +461,7 @@ func serveHandler() http.Handler {
426461
mux.HandleFunc("/.opensearch", serveOpenSearch)
427462
mux.HandleFunc("/.all", serveAll)
428463
mux.HandleFunc("/.delete/", serveDelete)
464+
mux.Handle("/.metrics", promhttp.Handler())
429465
mux.Handle("/.static/", http.StripPrefix("/.", http.FileServer(http.FS(embeddedFS))))
430466

431467
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -547,16 +583,20 @@ func serveGo(w http.ResponseWriter, r *http.Request) {
547583
}
548584

549585
if errors.Is(err, fs.ErrNotExist) {
586+
clickNotFound.WithLabelValues(short).Inc()
550587
w.WriteHeader(http.StatusNotFound)
551588
serveHome(w, r, short)
552589
return
553590
}
554591
if err != nil {
592+
clickNotFound.WithLabelValues(short).Inc()
555593
log.Printf("serving %q: %v", short, err)
556594
http.Error(w, err.Error(), http.StatusInternalServerError)
557595
return
558596
}
559597

598+
clickCounter.WithLabelValues(link.Short).Inc()
599+
560600
stats.mu.Lock()
561601
if stats.clicks == nil {
562602
stats.clicks = make(ClickStats)
@@ -940,6 +980,7 @@ func serveSave(w http.ResponseWriter, r *http.Request) {
940980
w.Header().Set("Content-Type", "application/json")
941981
json.NewEncoder(w).Encode(link)
942982
}
983+
totalLinkCount.Inc()
943984
}
944985

945986
// canEditLink returns whether the specified user has permission to edit link.

0 commit comments

Comments
 (0)