Skip to content

Commit b95bf99

Browse files
authored
Merge pull request #76 from foomo/feature/helm-upgrade
Upgrade Helm Chart To API V2 And Enhance Deployment Configuration
2 parents 4aa6e3f + 5beb383 commit b95bf99

File tree

15 files changed

+568
-185
lines changed

15 files changed

+568
-185
lines changed

README.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -221,22 +221,26 @@ Check out the docker-compose folder
221221

222222
### Kubernetes/Helm
223223

224-
You can install the included [Helm](https://docs.helm.sh/install/) chart to your k8s cluster with:
224+
Deploy PageSpeed Exporter to Kubernetes using the included [Helm](https://helm.sh/) chart. First, create a secret with your API key (only required if monitoring more than 2 targets/sec):
225225

226+
```bash
227+
kubectl create secret generic pagespeed-configuration-secret \
228+
--from-literal=PAGESPEED_API_KEY=your-api-key-here
226229
```
227-
$ helm install helm/pagespeed-exporter
228-
```
229230

230-
And then, to quickly test it:
231+
Install the chart with your target URLs:
232+
233+
```bash
234+
helm install pagespeed-exporter ./helm/pagespeed-exporter \
235+
--set 'config.targets={https://www.example.com,https://www.yoursite.com}' \
236+
--set config.parallel=true
231237
```
232-
$ kubectl get pods
233-
pagespeed-exporter-riotous-dragonfly-6b99955999-hj2kw 1/1 Running 0 1m
234238

235-
$ kubectl exec -ti pagespeed-exporter-riotous-dragonfly-6b99955999-hj2kw -- sh
236-
# apk add curl
237-
# curl localhost:9271/metrics
238-
pagespeed_lighthouse_audit_score{audit="first-contentful-paint",host="https://www.google.com",path="/",strategy="mobile"} 1
239-
pagespeed_lighthouse_audit_score{audit="first-contentful-paint",host="https://www.google.com",path="/webhp",strategy="desktop"} 1
240-
pagespeed_lighthouse_audit_score{audit="first-contentful-paint",host="https://www.google.com",path="/webhp",strategy="mobile"} 1
241-
...
239+
Test the deployment:
240+
241+
```bash
242+
kubectl port-forward svc/pagespeed-exporter 9271:9271
243+
curl http://localhost:9271/metrics
242244
```
245+
246+
For detailed configuration options, installation examples, and Prometheus integration, see the [Helm Chart README](helm/pagespeed-exporter/README.md).

collector/collector.go

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -160,76 +160,12 @@ func collectLoadingExperience(prefix string, lexp *pagespeedonline.PagespeedApiL
160160
for k, v := range lexp.Metrics {
161161
name := strings.TrimSuffix(strings.ToLower(k), "_ms")
162162

163-
// Export P75 percentile (existing metric - unchanged)
164163
ch <- prometheus.MustNewConstMetric(
165164
prometheus.NewDesc(fqname(prefix, "metrics", name, "duration_seconds"), "Percentile metrics for "+strings.Replace(name, "_", " ", -1), nil, constLables),
166165
prometheus.GaugeValue,
167166
float64(v.Percentile)/1000)
168167

169-
// Export category distribution ratios (NEW)
170-
if len(v.Distributions) >= 3 {
171-
categories := []string{"fast", "average", "slow"}
172-
for i, dist := range v.Distributions {
173-
if i >= 3 {
174-
break
175-
}
176-
ch <- prometheus.MustNewConstMetric(
177-
prometheus.NewDesc(fqname(prefix, "metrics", name, "category_ratio"), "Proportion of users experiencing "+categories[i]+" performance", []string{"category"}, constLables),
178-
prometheus.GaugeValue,
179-
dist.Proportion,
180-
categories[i])
181-
}
182-
}
183-
184-
// Export Core Web Vitals thresholds (NEW)
185-
if len(v.Distributions) >= 2 {
186-
// Determine if this is CLS (uses hundredths) or time-based (uses ms)
187-
isCLS := strings.Contains(strings.ToLower(k), "cumulative_layout_shift")
188-
189-
// Extract good threshold (upper bound of FAST bucket)
190-
if v.Distributions[0].Max > 0 {
191-
goodThreshold := float64(v.Distributions[0].Max)
192-
if isCLS {
193-
goodThreshold = goodThreshold / 100.0 // Convert hundredths to decimal
194-
} else {
195-
goodThreshold = goodThreshold / 1000.0 // Convert ms to seconds
196-
}
197-
198-
metricSuffix := "duration_seconds"
199-
if isCLS {
200-
metricSuffix = "" // CLS is unitless
201-
}
202-
203-
ch <- prometheus.MustNewConstMetric(
204-
prometheus.NewDesc(fqname(prefix, "metrics", name, "threshold", metricSuffix), "Core Web Vitals threshold for "+strings.Replace(name, "_", " ", -1), []string{"threshold"}, constLables),
205-
prometheus.GaugeValue,
206-
goodThreshold,
207-
"good")
208-
}
209-
210-
// Extract poor threshold (upper bound of AVERAGE bucket)
211-
if v.Distributions[1].Max > 0 {
212-
poorThreshold := float64(v.Distributions[1].Max)
213-
if isCLS {
214-
poorThreshold = poorThreshold / 100.0
215-
} else {
216-
poorThreshold = poorThreshold / 1000.0
217-
}
218-
219-
metricSuffix := "duration_seconds"
220-
if isCLS {
221-
metricSuffix = ""
222-
}
223-
224-
ch <- prometheus.MustNewConstMetric(
225-
prometheus.NewDesc(fqname(prefix, "metrics", name, "threshold", metricSuffix), "Core Web Vitals threshold for "+strings.Replace(name, "_", " ", -1), []string{"threshold"}, constLables),
226-
prometheus.GaugeValue,
227-
poorThreshold,
228-
"poor")
229-
}
230-
}
231168
}
232-
233169
}
234170

235171
func collectLighthouseResults(prefix string, cats []string, lhr *pagespeedonline.LighthouseResultV5, constLabels prometheus.Labels, ch chan<- prometheus.Metric) {

collector/collector_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
package collector
22

33
import (
4+
"os"
5+
"path/filepath"
46
"reflect"
57
"testing"
68

9+
"github.com/joho/godotenv"
710
"github.com/prometheus/client_golang/prometheus"
11+
"google.golang.org/api/option"
812
)
913

14+
func loadTestEnv() {
15+
envPath := filepath.Join("..", ".env")
16+
_ = godotenv.Load(envPath)
17+
}
18+
1019
func Test_getConstLabels(t *testing.T) {
1120
type args struct {
1221
scrape *ScrapeResult
@@ -91,3 +100,93 @@ func Test_fqname(t *testing.T) {
91100
})
92101
}
93102
}
103+
104+
func Test_CollectorIntegration(t *testing.T) {
105+
if testing.Short() {
106+
t.Skip("skipping integration test in short mode")
107+
}
108+
109+
loadTestEnv()
110+
111+
var options []option.ClientOption
112+
113+
if apiKey := os.Getenv("PAGESPEED_API_KEY"); apiKey != "" {
114+
options = append(options, option.WithAPIKey(apiKey))
115+
}
116+
117+
if cf := os.Getenv("PAGESPEED_CREDENTIALS_FILE"); cf != "" {
118+
options = append(options, option.WithCredentialsFile(cf))
119+
}
120+
121+
if len(options) == 0 {
122+
t.Skip("skipping integration test unless PAGESPEED_API_KEY or PAGESPEED_CREDENTIALS_FILE is set")
123+
}
124+
125+
config := Config{
126+
ScrapeRequests: []ScrapeRequest{
127+
{
128+
Url: "https://www.example.com",
129+
Strategy: StrategyMobile,
130+
Categories: []string{CategoryPerformance},
131+
},
132+
},
133+
GoogleAPIKey: os.Getenv("PAGESPEED_API_KEY"),
134+
Parallel: false,
135+
}
136+
137+
if cf := os.Getenv("PAGESPEED_CREDENTIALS_FILE"); cf != "" {
138+
config.CredentialsFile = cf
139+
}
140+
141+
coll, err := newCollector(config)
142+
if err != nil {
143+
t.Fatalf("failed to create collector: %v", err)
144+
}
145+
146+
ch := make(chan prometheus.Metric, 100)
147+
done := make(chan bool)
148+
149+
var metrics []prometheus.Metric
150+
go func() {
151+
for m := range ch {
152+
metrics = append(metrics, m)
153+
}
154+
done <- true
155+
}()
156+
157+
coll.Collect(ch)
158+
close(ch)
159+
<-done
160+
161+
if len(metrics) == 0 {
162+
t.Fatal("expected at least one metric to be collected")
163+
}
164+
165+
t.Logf("Successfully collected %d metrics from https://www.example.com", len(metrics))
166+
167+
hasExpectedLabels := false
168+
for _, m := range metrics {
169+
desc := m.Desc().String()
170+
if contains(desc, "host") && contains(desc, "path") && contains(desc, "strategy") {
171+
hasExpectedLabels = true
172+
break
173+
}
174+
}
175+
176+
if !hasExpectedLabels {
177+
t.Error("expected metrics to contain host, path, and strategy labels")
178+
}
179+
}
180+
181+
func contains(s, substr string) bool {
182+
return len(s) >= len(substr) && (s == substr || len(s) > len(substr) && (s[:len(substr)] == substr || s[len(s)-len(substr):] == substr || containsSubstring(s, substr)))
183+
}
184+
185+
func containsSubstring(s, substr string) bool {
186+
for i := 0; i <= len(s)-len(substr); i++ {
187+
if s[i:i+len(substr)] == substr {
188+
return true
189+
}
190+
}
191+
return false
192+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ require (
2626
github.com/google/uuid v1.6.0 // indirect
2727
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
2828
github.com/googleapis/gax-go/v2 v2.14.0 // indirect
29+
github.com/joho/godotenv v1.5.1 // indirect
2930
github.com/klauspost/compress v1.17.11 // indirect
3031
github.com/kr/text v0.2.0 // indirect
3132
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gT
6161
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
6262
github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o=
6363
github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk=
64+
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
65+
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
6466
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
6567
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
6668
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=

helm/pagespeed-exporter/.helmignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
*.swp
1515
*.bak
1616
*.tmp
17+
*.orig
1718
*~
1819
# Various IDEs
1920
.project
2021
.idea/
2122
*.tmproj
23+
.vscode/

helm/pagespeed-exporter/Chart.yaml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1-
apiVersion: v1
2-
description: Pagespeed Exporter
1+
apiVersion: v2
32
name: pagespeed-exporter
4-
version: 2.1.6
5-
appVersion: 2.1.6
3+
description: A Helm chart for deploying PageSpeed Exporter to monitor website performance metrics
4+
type: application
5+
version: 0.1.0
6+
appVersion: "3.1.2"
7+
keywords:
8+
- monitoring
9+
- prometheus
10+
- pagespeed
11+
- metrics
12+
maintainers:
13+
- name: Infrastructure Team
14+
sources:
15+
- https://github.com/foomo/pagespeed_exporter

0 commit comments

Comments
 (0)