Skip to content

Commit 743bc0d

Browse files
author
Christian Roessner
committed
Feat: Switch from Prometheus summary to histogram vectors
Replaced Prometheus summary vectors with histogram vectors for HTTP request metrics. Updated related constants, function names, and tests to reflect the change. This allows for better distribution tracking and more accurate performance analysis. Signed-off-by: Christian Roessner <[email protected]>
1 parent 1a447f1 commit 743bc0d

File tree

8 files changed

+127
-21
lines changed

8 files changed

+127
-21
lines changed

server/global/const.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -1230,8 +1230,14 @@ const (
12301230
// LuaFnCreateCounterVec represents the identifier for creating a Prometheus CounterVec.
12311231
LuaFnCreateCounterVec = "create_counter_vec"
12321232

1233-
// LuaFnStartTimer specifies the identifier for starting a Prometheus timer.
1234-
LuaFnStartTimer = "start_timer"
1233+
// LuaFnCreateHistogramVec is a constant representing the Lua function name for creating a HistogramVec in Prometheus.
1234+
LuaFnCreateHistogramVec = "create_histogram_vec"
1235+
1236+
// LuaFnStartSummaryTimer specifies the identifier for starting a Prometheus timer.
1237+
LuaFnStartSummaryTimer = "start_summary_timer"
1238+
1239+
// LuaFnStartHistogramTimer represents the function name for starting a histogram timer in Lua scripts.
1240+
LuaFnStartHistogramTimer = "start_histogram_timer"
12351241

12361242
// LuaFnStopTimer defines the identifier for stopping a Prometheus timer.
12371243
LuaFnStopTimer = "stop_timer"

server/lua-plugins.d/actions/haveibeenpwnd.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ function nauthilus_call_action(request)
8686
end
8787

8888

89-
nauthilus_prometheus.create_summary_vec(N .. "_duration_seconds", "HTTP request to the haveibeenpwnd network", {"http"})
89+
nauthilus_prometheus.create_histogram_vec(N .. "_duration_seconds", "HTTP request to the haveibeenpwnd network", {"http"})
9090

91-
local timer = nauthilus_prometheus.start_timer(N .. "_duration_seconds", {http="get"})
91+
local timer = nauthilus_prometheus.start_histogram_timer(N .. "_duration_seconds", {http="get"})
9292
local result, err = http.get("https://api.pwnedpasswords.com/range/" .. hash:sub(1, 5), {
9393
timeout = "10s",
9494
headers = {

server/lua-plugins.d/actions/telegram.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ function nauthilus_call_action(request)
151151
values.username = username
152152
values.pwnd_info = pwnd_info
153153

154-
nauthilus_prometheus.create_summary_vec(N .. "_duration_seconds", "HTTP request to the telegram network", {"bot"})
154+
nauthilus_prometheus.create_histogram_vec(N .. "_duration_seconds", "HTTP request to the telegram network", {"bot"})
155155

156-
local timer = nauthilus_prometheus.start_timer(N .. "_duration_seconds", {bot="send"})
156+
local timer = nauthilus_prometheus.start_histogram_timer(N .. "_duration_seconds", {bot="send"})
157157
local _, err_bat = bot:sendMessage({
158158
chat_id = tonumber(os.getenv("TELEGRAM_CHAT_ID")),
159159
text = headline .. mustache:render(":\n\nSESSION {{session}}\nTS {{ts}}\nIP {{client_ip}}\nHOSTNAME {{hostname}}\nPROTOCOL {{proto}}\nDISPLAY_NAME {{display_name}}\nACCOUNT {{account}}\nUNIQUE ID {{unique_user_id}}\nUSERNAME {{username}}\nPWND INFO {{pwnd_info}}", values)

server/lua-plugins.d/features/blocklist.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ function nauthilus_call_feature(request)
4747
local payload, json_encode_err = json.encode(t)
4848
nauthilus_util.if_error_raise(json_encode_err)
4949

50-
nauthilus_prometheus.create_summary_vec(N .. "_duration_seconds", "HTTP request to the blocklist service", {"http"})
50+
nauthilus_prometheus.create_histogram_vec(N .. "_duration_seconds", "HTTP request to the blocklist service", {"http"})
5151

52-
local timer = nauthilus_prometheus.start_timer(N .. "_duration_seconds", {http="post"})
52+
local timer = nauthilus_prometheus.start_histogram_timer(N .. "_duration_seconds", {http="post"})
5353
local result, request_err = http.post(os.getenv("BLOCKLIST_URL"), {
5454
timeout = "10s",
5555
headers = {

server/lua-plugins.d/filters/geoip.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ function nauthilus_call_filter(request)
7878
local payload, json_encode_err = json.encode(t)
7979
nauthilus_util.if_error_raise(json_encode_err)
8080

81-
nauthilus_prometheus.create_summary_vec(N .. "_duration_seconds", "HTTP request to the geoip-policyd service", {
81+
nauthilus_prometheus.create_histogram_vec(N .. "_duration_seconds", "HTTP request to the geoip-policyd service", {
8282
"http",
8383
})
8484

@@ -87,7 +87,7 @@ function nauthilus_call_filter(request)
8787
"status",
8888
})
8989

90-
local timer = nauthilus_prometheus.start_timer(N .. "_duration_seconds", {http="post"})
90+
local timer = nauthilus_prometheus.start_histogram_timer(N .. "_duration_seconds", {http="post"})
9191
local result, request_err = http.post(os.getenv("GEOIP_POLICY_URL"), {
9292
timeout = "10s",
9393
headers = {

server/lualib/metrics/statistics.go

+72-9
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import (
77
)
88

99
var (
10-
summaries = make(map[string]*prometheus.SummaryVec)
11-
counters = make(map[string]*prometheus.CounterVec)
10+
summaries = make(map[string]*prometheus.SummaryVec)
11+
counters = make(map[string]*prometheus.CounterVec)
12+
histograms = make(map[string]*prometheus.HistogramVec)
1213
)
1314

1415
// createSummaryVec registers a new Prometheus SummaryVec metric with the provided name, help description, and label names.
@@ -73,8 +74,39 @@ func createCounterVec(L *lua.LState) int {
7374
return 0
7475
}
7576

76-
// startTimer starts a Prometheus timer for a specified SummaryVec metric with the provided label values.
77-
func startTimer(L *lua.LState) int {
77+
// createHistogramVec registers a new Prometheus HistogramVec with the specified name, help message, and optional label names.
78+
func createHistogramVec(L *lua.LState) int {
79+
name := L.CheckString(1)
80+
help := L.CheckString(2)
81+
82+
labelNames := make([]string, 0)
83+
84+
if L.GetTop() > 2 {
85+
labelTable := L.CheckTable(3)
86+
labelTable.ForEach(func(_ lua.LValue, value lua.LValue) {
87+
labelNames = append(labelNames, value.String())
88+
})
89+
}
90+
91+
// Check if the histogram already exists
92+
if _, exists := histograms[name]; exists {
93+
return 0
94+
}
95+
96+
histogram := prometheus.NewHistogramVec(prometheus.HistogramOpts{
97+
Name: name,
98+
Help: help,
99+
}, labelNames)
100+
101+
prometheus.MustRegister(histogram)
102+
103+
histograms[name] = histogram
104+
105+
return 0
106+
}
107+
108+
// startSumaryTimer starts a Prometheus timer for a specified SummaryVec metric with the provided label values.
109+
func startSumaryTimer(L *lua.LState) int {
78110
name := L.CheckString(1)
79111
labels := L.CheckTable(2)
80112

@@ -99,6 +131,32 @@ func startTimer(L *lua.LState) int {
99131
return 1
100132
}
101133

134+
// startHistogramTimer starts a timer for a Prometheus histogram with given name and labels.
135+
func startHistogramTimer(L *lua.LState) int {
136+
name := L.CheckString(1)
137+
labels := L.CheckTable(2)
138+
139+
histogram, exists := histograms[name]
140+
if !exists {
141+
L.ArgError(1, "HistogramVec not found")
142+
143+
return 0
144+
}
145+
146+
labelValues := make(map[string]string)
147+
labels.ForEach(func(key, value lua.LValue) {
148+
labelValues[key.String()] = value.String()
149+
})
150+
151+
timer := prometheus.NewTimer(histogram.With(labelValues))
152+
ud := L.NewUserData()
153+
ud.Value = timer
154+
155+
L.Push(ud)
156+
157+
return 1
158+
}
159+
102160
// stopTimer stops a running Prometheus timer, recording its duration in the underlying metric.
103161
func stopTimer(L *lua.LState) int {
104162
ud := L.CheckUserData(1)
@@ -132,13 +190,18 @@ func incrementCounter(L *lua.LState) int {
132190
}
133191

134192
var exportsModPrometheus = map[string]lua.LGFunction{
135-
global.LuaFnCreateSummaryVec: createSummaryVec,
136-
global.LuaFnCreateCounterVec: createCounterVec,
137-
global.LuaFnStartTimer: startTimer,
138-
global.LuaFnStopTimer: stopTimer,
139-
global.LuaFnIncrementCounter: incrementCounter,
193+
global.LuaFnCreateSummaryVec: createSummaryVec,
194+
global.LuaFnCreateCounterVec: createCounterVec,
195+
global.LuaFnCreateHistogramVec: createHistogramVec,
196+
global.LuaFnStartSummaryTimer: startSumaryTimer,
197+
global.LuaFnStartHistogramTimer: startHistogramTimer,
198+
global.LuaFnStopTimer: stopTimer,
199+
global.LuaFnIncrementCounter: incrementCounter,
140200
}
141201

202+
// LoaderModPrometheus loads the Prometheus module into the given Lua state.
203+
// It sets up the module's functions and pushes the module onto the stack.
204+
// Returns 1 to indicate the number of return values for the Lua stack.
142205
func LoaderModPrometheus(L *lua.LState) int {
143206
mod := L.SetFuncs(L.NewTable(), exportsModPrometheus)
144207

server/lualib/metrics/statistics_test.go

+38-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestCreateAndUseSummaryVec(t *testing.T) {
2828
prometheus.create_summary_vec("test_summary", "Test Summary", {"label1", "label2"})
2929
3030
-- Start timer
31-
timer = prometheus.start_timer("test_summary", {label1="value1", label2="value2"})
31+
timer = prometheus.start_summary_timer("test_summary", {label1="value1", label2="value2"})
3232
3333
-- Some operation...
3434
@@ -80,3 +80,40 @@ func TestCreateAndUseCounterVec(t *testing.T) {
8080
value := testutil.ToFloat64(counter.WithLabelValues("value1", "value2"))
8181
assert.Equal(t, float64(1), value, "Counter value should be 1")
8282
}
83+
84+
func TestCreateAndUseHistogramVec(t *testing.T) {
85+
L := lua.NewState()
86+
87+
defer L.Close()
88+
89+
// Register the module
90+
L.PreloadModule("prometheus", LoaderModPrometheus)
91+
92+
err := runLuaCode(L, `
93+
local prometheus = require("prometheus")
94+
95+
-- Create a HistogramVec
96+
prometheus.create_histogram_vec("test_histogram", "Histogram test", {"label1", "label2"})
97+
98+
-- Start timer
99+
timer = prometheus.start_histogram_timer("test_histogram", {label1 = "value1", label2 = "value2"})
100+
101+
-- Some operation...
102+
103+
-- Stop timer
104+
prometheus.stop_timer(timer)
105+
`)
106+
107+
if err != nil {
108+
t.Fatalf("Lua code execution failed: %v", err)
109+
}
110+
111+
// Verify the histogram was created and contains the recorded value.
112+
histogram, exists := histograms["test_histogram"]
113+
114+
assert.True(t, exists, "HistogramVec 'test_histogram' should exist")
115+
116+
// Test whether the histogram has recorded data
117+
count := testutil.CollectAndCount(histogram)
118+
assert.NotZero(t, count, "Expected non-zero count in HistogramVec")
119+
}

server/stats/statistics.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ var (
119119
})
120120

121121
// FunctionDuration variable declaration that creates a new Prometheus SummaryVec with the specified name and help message, and with "service" and "method" labels.
122-
FunctionDuration = promauto.NewSummaryVec(prometheus.SummaryOpts{
122+
FunctionDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
123123
Name: "function_duration_seconds",
124124
Help: "Time spent in function",
125125
}, []string{"service", "task"})

0 commit comments

Comments
 (0)