Skip to content

Commit 132a29e

Browse files
authored
Merge pull request #15 from kodehat/feature/prometheus-metrics
feat: add Prometheus metrics
2 parents 53433f0 + 377ac9a commit 132a29e

17 files changed

+335
-20
lines changed

README.md

+36-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
- [Installation](#installation)
6262
- [Usage](#usage)
6363
- [Configuration](#configuration)
64+
- [Metrics](#metrics)
6465
- [Docker](#docker)
6566
- [Development](#development)
6667
- [See Also](#see-also)
@@ -122,9 +123,15 @@ logJson: false
122123
# Set the host where the application should bind to.
123124
host: localhost
124125
# Set the port where the application should bind to.
125-
port: 3000
126+
port: 1414
126127
# Set the context path (aka base-url) portkey is hosted under. Must not be specified unless you're using a reverse proxy and are hosting portkey under a directory. If that's the case then you can set this value to e.g. /portkey or whatever the directory is called. Note that the forward slash (/) in the beginning is required!
127128
contextPath: ""
129+
# Enables the HTTP server that serves metrics that can be scraped by e.g. Prometheus.
130+
enableMetrics: false
131+
# Set the host where the metrics server should bind to.
132+
metricsHost: localhost
133+
# Set the port where the metrics server should bind to.
134+
metricsPort: 1515
128135
```
129136
130137
### Styling
@@ -190,6 +197,34 @@ pages:
190197
It also supports using <strong>HTML</strong>!
191198
```
192199
200+
## Metrics
201+
202+
Metrics can be enabled with the `enableMetrics` configuration key and are served on a dedicated HTTP server. By default they are served on `http://localhost:1515/metrics`. Use this address to configure your tool of choice (e.g. [Prometheus](https://prometheus.io/)) to scrape the exported metrics.
203+
204+
Besides the default metrics provided by the [Prometheus instrumentation library for Go applications ](https://github.com/prometheus/client_golang), the following additional metrics are provided:
205+
206+
```plain
207+
# HELP portkey_page_handler_requests_total Total number of HTTP requests by page.
208+
# TYPE portkey_page_handler_requests_total counter
209+
portkey_page_handler_requests_total{path="<page_path>"} 0
210+
211+
# HELP portkey_portal_handler_requests_total Total number of HTTP requests by portal.
212+
# TYPE portkey_portal_handler_requests_total counter
213+
portkey_portal_handler_requests_total{portal="<portal_title>"} 0
214+
215+
# HELP portkey_search_requests_no_results_total Total number of HTTP requests for search with no results.
216+
# TYPE portkey_search_requests_no_results_total counter
217+
portkey_search_requests_no_results_total 0
218+
219+
# HELP portkey_search_requests_with_results_total Total number of HTTP requests for search with at least one result.
220+
# TYPE portkey_search_requests_with_results_total counter
221+
portkey_search_requests_with_results_total 0
222+
223+
# HELP portkey_version_info Version information about portkey.
224+
# TYPE portkey_version_info gauge
225+
portkey_version_info{buildTime="2024.10.09_17:29:19",commitHash="4fd1a0f",goVersion="1.23.1",version="dev"} 1
226+
```
227+
193228
## Docker
194229

195230
There are also Docker images available at Docker hub that you can use. You can start a container for instance with:

config.yml

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
host: localhost
22
port: 3000
33
contextPath: ""
4+
enableMetrics: true
5+
metricsHost: localhost
6+
metricsPort: 3030
47
title: "portkey"
58
hideTitle: false
69
headerAddition: |-
@@ -49,10 +52,6 @@ portals:
4952
emoji: 🔢
5053
link: /version
5154
external: false
52-
- title: home
53-
emoji: 🏠
54-
link: /
55-
external: false
5655
pages:
5756
- heading: "About"
5857
path: /about

fly.toml

+6-1
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@ primary_region = 'ams'
88

99
[env]
1010
HOST = '0.0.0.0'
11+
METRICSHOST = '0.0.0.0'
1112

1213
[http_service]
1314
internal_port = 3000
1415
force_https = true
15-
auto_stop_machines = true
16+
auto_stop_machines = "stop"
1617
auto_start_machines = true
1718
min_machines_running = 0
1819
processes = ['app']
1920

21+
[metrics]
22+
port = 3030
23+
path = "/metrics"
24+
2025
[[vm]]
2126
size = 'shared-cpu-1x'

go.mod

+9
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,23 @@ go 1.23
55
require (
66
github.com/a-h/templ v0.2.778
77
github.com/adrg/strutil v0.3.1
8+
github.com/prometheus/client_golang v1.20.4
89
github.com/spf13/viper v1.19.0
910
)
1011

1112
require (
13+
github.com/beorn7/perks v1.0.1 // indirect
14+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
1215
github.com/fsnotify/fsnotify v1.7.0 // indirect
1316
github.com/hashicorp/hcl v1.0.0 // indirect
17+
github.com/klauspost/compress v1.17.9 // indirect
1418
github.com/magiconair/properties v1.8.7 // indirect
1519
github.com/mitchellh/mapstructure v1.5.0 // indirect
20+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
1621
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
22+
github.com/prometheus/client_model v0.6.1 // indirect
23+
github.com/prometheus/common v0.55.0 // indirect
24+
github.com/prometheus/procfs v0.15.1 // indirect
1725
github.com/sagikazarmark/locafero v0.6.0 // indirect
1826
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
1927
github.com/sourcegraph/conc v0.3.0 // indirect
@@ -25,6 +33,7 @@ require (
2533
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
2634
golang.org/x/sys v0.25.0 // indirect
2735
golang.org/x/text v0.18.0 // indirect
36+
google.golang.org/protobuf v1.34.2 // indirect
2837
gopkg.in/ini.v1 v1.67.0 // indirect
2938
gopkg.in/yaml.v3 v3.0.1 // indirect
3039
)

go.sum

+24-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ github.com/a-h/templ v0.2.778 h1:VzhOuvWECrwOec4790lcLlZpP4Iptt5Q4K9aFxQmtaM=
22
github.com/a-h/templ v0.2.778/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w=
33
github.com/adrg/strutil v0.3.1 h1:OLvSS7CSJO8lBii4YmBt8jiK9QOtB9CzCzwl4Ic/Fz4=
44
github.com/adrg/strutil v0.3.1/go.mod h1:8h90y18QLrs11IBffcGX3NW/GFBXCMcNg4M7H6MspPA=
5+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
6+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
7+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
8+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
59
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
610
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
711
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -14,21 +18,35 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
1418
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
1519
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
1620
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
21+
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
22+
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
1723
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
1824
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
1925
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
2026
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
27+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
28+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
2129
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
2230
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
2331
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
2432
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
33+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
34+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
2535
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
2636
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
2737
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
2838
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
2939
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
30-
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
31-
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
40+
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
41+
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
42+
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
43+
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
44+
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
45+
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
46+
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
47+
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
48+
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
49+
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
3250
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
3351
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
3452
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
@@ -61,9 +79,11 @@ golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
6179
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
6280
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
6381
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
82+
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
83+
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
6484
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
65-
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
66-
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
85+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
86+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
6787
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
6888
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
6989
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/components/portal.templ

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ templ HomePortal(portal models.Portal) {
3333
target="_blank"
3434
rel="nofollow"
3535
}
36-
href={ templ.SafeURL(portal.Link) }
36+
href={ templ.SafeURL("/" + portal.TitleForUrl()) }
3737
class="mx-4 whitespace-nowrap no-underline border-b-2 border-solid border-slate-700 dark:border-slate-300 hover:text-slate-800 dark:hover:text-slate-300"
3838
>{ portal.Title }</a>
3939
</span>
@@ -49,7 +49,7 @@ templ FooterPortal(portal models.Portal) {
4949
target="_blank"
5050
rel="nofollow"
5151
}
52-
href={ templ.SafeURL(portal.Link) }
52+
href={ templ.SafeURL("/" + portal.TitleForUrl()) }
5353
class="ml-1 no-underline border-b-2 border-solid border-slate-700 dark:border-slate-300 hover:text-slate-800 dark:hover:text-slate-300"
5454
>{ portal.Title }</a>
5555
</span>

internal/config/config.go

+5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ type Config struct {
2020
Host string
2121
Port string
2222
ContextPath string
23+
EnableMetrics bool
24+
MetricsHost string
25+
MetricsPort string
2326
Title string
2427
HideTitle bool
2528
Footer string
@@ -70,6 +73,8 @@ func loadConfig(configPath string) {
7073
viper.SetDefault("host", "localhost")
7174
viper.SetDefault("port", "1414")
7275
viper.SetDefault("contextPath", "")
76+
viper.SetDefault("metricsHost", "localhost")
77+
viper.SetDefault("metricsPort", "1515")
7378
viper.SetDefault("title", "Your Portal")
7479
viper.SetDefault("footerText", "Works like a portal.")
7580
viper.SetDefault("minimumStringSimilarity", 0.75)

internal/metrics/metrics.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package metrics
2+
3+
import (
4+
"github.com/kodehat/portkey/internal/build"
5+
"github.com/prometheus/client_golang/prometheus"
6+
)
7+
8+
const NAMESPACE = "portkey"
9+
10+
type Metrics struct {
11+
PortalHitCounter *prometheus.CounterVec
12+
PageHitCounter *prometheus.CounterVec
13+
SearchWithResultsCounter prometheus.Counter
14+
SearchNoResultsCounter prometheus.Counter
15+
buildInfo prometheus.Gauge
16+
}
17+
18+
var M Metrics
19+
20+
func Load() {
21+
M = Metrics{
22+
PortalHitCounter: prometheus.NewCounterVec(prometheus.CounterOpts{
23+
Namespace: NAMESPACE,
24+
Name: "portal_handler_requests_total",
25+
Help: "Total number of HTTP requests by portal.",
26+
}, []string{"portal"}),
27+
PageHitCounter: prometheus.NewCounterVec(prometheus.CounterOpts{
28+
Namespace: NAMESPACE,
29+
Name: "page_handler_requests_total",
30+
Help: "Total number of HTTP requests by page.",
31+
}, []string{"path"}),
32+
SearchWithResultsCounter: prometheus.NewCounter(prometheus.CounterOpts{
33+
Namespace: NAMESPACE,
34+
Name: "search_requests_with_results_total",
35+
Help: "Total number of HTTP requests for search with at least one result.",
36+
}),
37+
SearchNoResultsCounter: prometheus.NewCounter(prometheus.CounterOpts{
38+
Namespace: NAMESPACE,
39+
Name: "search_requests_no_results_total",
40+
Help: "Total number of HTTP requests for search with no results.",
41+
}),
42+
buildInfo: prometheus.NewGauge(prometheus.GaugeOpts{
43+
Namespace: NAMESPACE,
44+
Name: "version_info",
45+
Help: "Version information about portkey.",
46+
ConstLabels: prometheus.Labels{
47+
"buildTime": build.B.BuildTime,
48+
"commitHash": build.B.CommitHash,
49+
"version": build.B.Version,
50+
"goVersion": build.B.GoVersion,
51+
},
52+
}),
53+
}
54+
55+
// Set build info gauge to "1" so it can be used in queries.
56+
M.buildInfo.Set(1.0)
57+
58+
prometheus.MustRegister(M.PortalHitCounter)
59+
prometheus.MustRegister(M.PageHitCounter)
60+
prometheus.MustRegister(M.SearchWithResultsCounter)
61+
prometheus.MustRegister(M.SearchNoResultsCounter)
62+
prometheus.MustRegister(M.buildInfo)
63+
}

internal/models/models.go

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package models
22

3+
import "regexp"
4+
35
// Portal struct containing information about a portal.
46
// This is used later as a link destination shown to the user.
57
type Portal struct {
@@ -21,6 +23,13 @@ type Portal struct {
2123
Keywords []string `json:"keywords"`
2224
}
2325

26+
var /* const */ alphaNumDashOnlyRegex = regexp.MustCompile("[^a-zA-Z0-9-]")
27+
28+
// TitleForUrl returns the portal's title with alpha-numerical (and dash) characters only.
29+
func (portal Portal) TitleForUrl() string {
30+
return alphaNumDashOnlyRegex.ReplaceAllString(portal.Title, "")
31+
}
32+
2433
// Page struct defines a custom page that consists of a heading, content and a path,
2534
// where the page will be available at.
2635
type Page struct {

internal/server/metrics_handler.go

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package server
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/prometheus/client_golang/prometheus/promhttp"
7+
)
8+
9+
func metricsHandler() http.HandlerFunc {
10+
return promhttp.Handler().ServeHTTP
11+
}

internal/server/page_handler.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"github.com/kodehat/portkey/internal/build"
88
"github.com/kodehat/portkey/internal/components"
99
"github.com/kodehat/portkey/internal/config"
10+
"github.com/kodehat/portkey/internal/metrics"
11+
"github.com/kodehat/portkey/internal/models"
1012
)
1113

1214
type pageHandlerInfo struct {
@@ -17,10 +19,23 @@ type pageHandlerInfo struct {
1719
func pageHandler() []pageHandlerInfo {
1820
var pageHandlerInfos = make([]pageHandlerInfo, len(config.C.Pages))
1921
for i, page := range config.C.Pages {
22+
if config.C.EnableMetrics {
23+
// Required to initialize all portal metrics to "0".
24+
metrics.M.PageHitCounter.WithLabelValues(page.Path).Add(0)
25+
}
2026
pageHandlerInfos[i] = pageHandlerInfo{
2127
pagePath: page.Path,
22-
handlerFunc: templ.Handler(components.ContentLayout(page.Heading, config.C, build.B, components.ContentPage(page.Content))).ServeHTTP,
28+
handlerFunc: pageMetricsHandler(page, templ.Handler(components.ContentLayout(page.Heading, config.C, build.B, components.ContentPage(page.Content)))).ServeHTTP,
2329
}
2430
}
2531
return pageHandlerInfos
2632
}
33+
34+
func pageMetricsHandler(p models.Page, h http.Handler) http.Handler {
35+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
36+
if config.C.EnableMetrics {
37+
metrics.M.PageHitCounter.WithLabelValues(p.Path).Inc()
38+
}
39+
h.ServeHTTP(w, r)
40+
})
41+
}

0 commit comments

Comments
 (0)