Skip to content
This repository was archived by the owner on Apr 24, 2025. It is now read-only.

Commit 86c2a56

Browse files
authored
example: using prometheus tags in custom metrics (#246)
1 parent af57b89 commit 86c2a56

File tree

5 files changed

+79
-57
lines changed

5 files changed

+79
-57
lines changed

e2e/e2e_test.go

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -169,29 +169,44 @@ func Test_http_routing(t *testing.T) {
169169
func Test_metrics(t *testing.T) {
170170
_, kill := startEnvoy(t, 8001)
171171
defer kill()
172-
var count int
173-
require.Eventually(t, func() bool {
174-
res, err := http.Get("http://localhost:18000")
175-
if err != nil {
176-
return false
177-
}
178-
defer res.Body.Close()
179-
if res.StatusCode != http.StatusOK {
180-
return false
181-
}
182-
count++
183-
return count == 10
184-
}, 5*time.Second, time.Millisecond, "Endpoint not healthy.")
185-
require.Eventually(t, func() bool {
186-
res, err := http.Get("http://localhost:8001/stats/prometheus")
187-
if err != nil {
188-
return false
189-
}
190-
defer res.Body.Close()
191-
raw, err := io.ReadAll(res.Body)
192-
require.NoError(t, err)
193-
return checkMessage(string(raw), []string{fmt.Sprintf("proxy_wasm_go_request_counter{} %d", count)}, nil)
194-
}, 5*time.Second, time.Millisecond, "Expected stats not found")
172+
173+
const customHeaderKey = "my-custom-header"
174+
customHeaderToExpectedCounts := map[string]int{
175+
"foo": 3,
176+
"bar": 5,
177+
}
178+
for headerValue, expCount := range customHeaderToExpectedCounts {
179+
var actualCount int
180+
require.Eventually(t, func() bool {
181+
req, err := http.NewRequest("GET", "http://localhost:18000", nil)
182+
require.NoError(t, err)
183+
req.Header.Add(customHeaderKey, headerValue)
184+
res, err := http.DefaultClient.Do(req)
185+
if err != nil {
186+
return false
187+
}
188+
defer res.Body.Close()
189+
if res.StatusCode != http.StatusOK {
190+
return false
191+
}
192+
actualCount++
193+
return actualCount == expCount
194+
}, 5*time.Second, time.Millisecond, "Endpoint not healthy.")
195+
}
196+
197+
for headerValue, expCount := range customHeaderToExpectedCounts {
198+
expectedMetric := fmt.Sprintf("custom_header_value_counts{value=\"%s\",reporter=\"wasmgosdk\"} %d", headerValue, expCount)
199+
require.Eventually(t, func() bool {
200+
res, err := http.Get("http://localhost:8001/stats/prometheus")
201+
if err != nil {
202+
return false
203+
}
204+
defer res.Body.Close()
205+
raw, err := io.ReadAll(res.Body)
206+
require.NoError(t, err)
207+
return checkMessage(string(raw), []string{expectedMetric}, nil)
208+
}, 5*time.Second, time.Millisecond, "Expected stats not found")
209+
}
195210
}
196211

197212
func Test_network(t *testing.T) {

examples/metrics/README.md

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,12 @@
11

22
## metrics
33

4-
this example creates simple request counter
4+
this example creates simple request counter with prometheus tags.
55

66
```
7-
wasm log: previous value of proxy_wasm_go.request_counter: 0
8-
wasm log: incremented
9-
wasm log: previous value of proxy_wasm_go.request_counter: 1
10-
wasm log: incremented
11-
wasm log: previous value of proxy_wasm_go.request_counter: 2
12-
wasm log: incremented
13-
wasm log: previous value of proxy_wasm_go.request_counter: 3
14-
wasm log: incremented
15-
wasm log: previous value of proxy_wasm_go.request_counter: 4
16-
wasm log: incremented
17-
wasm log: previous value of proxy_wasm_go.request_counter: 5
18-
wasm log: incremented
19-
```
7+
$ curl localhost:18000 -v -H "my-custom-header: foo"
208
21-
```
229
$ curl -s 'localhost:8001/stats/prometheus'| grep proxy
23-
# TYPE proxy_wasm_go_request_counter counter
24-
proxy_wasm_go_request_counter{} 5
10+
# TYPE custom_header_value_counts counter
11+
custom_header_value_counts{value="foo",reporter="wasmgosdk"} 1
2512
```

examples/metrics/envoy.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
stats_config:
2+
stats_tags:
3+
# Envoy extracs the first matching group as a value.
4+
# This case, the part ([a-zA-Z]+) is extracted as a value for "value" tag.
5+
# See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/metrics/v3/stats.proto#config-metrics-v3-statsconfig.
6+
- tag_name: value
7+
regex: '(_value=([a-zA-Z]+))'
8+
- tag_name: reporter
9+
regex: '(_reporter=([a-zA-Z]+))'
10+
111
static_resources:
212
listeners:
313
- name: main

examples/metrics/main.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package main
1616

1717
import (
18+
"fmt"
19+
1820
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
1921
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
2022
)
@@ -31,36 +33,47 @@ type vmContext struct {
3133

3234
// Override types.DefaultVMContext.
3335
func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
34-
return &metricPluginContext{
35-
counter: proxywasm.DefineCounterMetric("proxy_wasm_go.request_counter"),
36-
}
36+
return &metricPluginContext{}
3737
}
3838

3939
type metricPluginContext struct {
4040
// Embed the default plugin context here,
4141
// so that we don't need to reimplement all the methods.
4242
types.DefaultPluginContext
43-
counter proxywasm.MetricCounter
4443
}
4544

4645
// Override types.DefaultPluginContext.
4746
func (ctx *metricPluginContext) NewHttpContext(contextID uint32) types.HttpContext {
48-
return &metricHttpContext{counter: ctx.counter}
47+
return &metricHttpContext{}
4948
}
5049

5150
type metricHttpContext struct {
5251
// Embed the default http context here,
5352
// so that we don't need to reimplement all the methods.
5453
types.DefaultHttpContext
55-
counter proxywasm.MetricCounter
5654
}
5755

56+
const (
57+
customHeaderKey = "my-custom-header"
58+
customHeaderValueTagKey = "value"
59+
)
60+
61+
var counters = map[string]proxywasm.MetricCounter{}
62+
5863
// Override types.DefaultHttpContext.
5964
func (ctx *metricHttpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
60-
prev := ctx.counter.Value()
61-
proxywasm.LogInfof("previous value of %s: %d", "proxy_wasm_go.request_counter", prev)
62-
63-
ctx.counter.Increment(1)
64-
proxywasm.LogInfo("incremented")
65+
customHeaderValue, err := proxywasm.GetHttpRequestHeader(customHeaderKey)
66+
if err == nil {
67+
counter, ok := counters[customHeaderValue]
68+
if !ok {
69+
// This metric is processed as: custom_header_value_counts{value="foo",reporter="wasmgosdk"} n.
70+
// The extraction rule is defined in envoy.yaml as a bootstrap configuration.
71+
// See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/metrics/v3/stats.proto#config-metrics-v3-statsconfig.
72+
fqn := fmt.Sprintf("custom_header_value_counts_%s=%s_reporter=wasmgosdk", customHeaderValueTagKey, customHeaderValue)
73+
counter = proxywasm.DefineCounterMetric(fqn)
74+
counters[customHeaderValue] = counter
75+
}
76+
counter.Increment(1)
77+
}
6578
return types.ActionContinue
6679
}

examples/metrics/main_test.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,17 @@ func TestMetric(t *testing.T) {
2525
require.Equal(t, types.OnVMStartStatusOK, host.StartVM())
2626

2727
// Initialize http context.
28+
headers := [][2]string{{"my-custom-header", "foo"}}
2829
contextID := host.InitializeHttpContext()
2930
exp := uint64(3)
3031
for i := uint64(0); i < exp; i++ {
3132
// Call OnRequestHeaders
32-
action := host.CallOnRequestHeaders(contextID, nil, false)
33+
action := host.CallOnRequestHeaders(contextID, headers, false)
3334
require.Equal(t, types.ActionContinue, action)
3435
}
3536

36-
// Check Envoy logs.
37-
logs := host.GetInfoLogs()
38-
require.Contains(t, logs, "incremented")
39-
4037
// Check metrics.
41-
value, err := host.GetCounterMetric("proxy_wasm_go.request_counter")
38+
value, err := host.GetCounterMetric("custom_header_value_counts_value=foo_reporter=wasmgosdk")
4239
require.NoError(t, err)
4340
require.Equal(t, uint64(3), value)
4441
}

0 commit comments

Comments
 (0)