Skip to content

Commit 4160b5c

Browse files
authored
Merge pull request #21 from axoflow/workaround-escaping-bug
syslog-ng-ctl: workaround invalid escaping in syslog-ng/AxoSyslog metrics
2 parents 83879ef + 1010844 commit 4160b5c

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

pkg/syslog-ng-ctl/stats_prometheus.go

+33
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,38 @@ func transformEventDelayMetric(delayMetric *io_prometheus_client.MetricFamily, d
154154
delayMetric.Type = io_prometheus_client.MetricType_GAUGE.Enum()
155155
}
156156

157+
// Workaround for a bug in older syslog-ng/AxoSyslog versions where the output of STATS PROMETHEUS was overescaped.
158+
// Escapes \ as \\ everywhere except for the allowed sequences: \\, \n, \"
159+
func sanitizeBuggyFormat(output string) string {
160+
var fixedOutput strings.Builder
161+
162+
length := len(output)
163+
for i := 0; i < length; i++ {
164+
c := output[i]
165+
166+
if c != '\\' {
167+
fixedOutput.WriteByte(c)
168+
continue
169+
}
170+
171+
if i+1 >= length {
172+
fixedOutput.WriteString(`\\`)
173+
break
174+
}
175+
176+
if next := output[i+1]; next == '\\' || next == 'n' || next == '"' {
177+
fixedOutput.WriteByte(c)
178+
fixedOutput.WriteByte(next)
179+
i++
180+
continue
181+
}
182+
183+
fixedOutput.WriteString(`\\`)
184+
}
185+
186+
return fixedOutput.String()
187+
}
188+
157189
func StatsPrometheus(ctx context.Context, cc ControlChannel, lastMetricQueryTime *time.Time) ([]*io_prometheus_client.MetricFamily, error) {
158190
rsp, err := cc.SendCommand(ctx, "STATS PROMETHEUS")
159191
if err != nil {
@@ -169,6 +201,7 @@ func StatsPrometheus(ctx context.Context, cc ControlChannel, lastMetricQueryTime
169201
return maps.Values(mfs), err
170202
}
171203

204+
rsp = sanitizeBuggyFormat(rsp)
172205
mfs, err = new(expfmt.TextParser).TextToMetricFamilies(strings.NewReader(rsp))
173206

174207
var delayMetric *io_prometheus_client.MetricFamily

pkg/syslog-ng-ctl/stats_prometheus_test.go

+39
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,34 @@ func TestStatsPrometheus(t *testing.T) {
297297
}
298298
sortMetricFamilies(expectedDelayMetrics)
299299

300+
expectedEscapeMetrics := []*io_prometheus_client.MetricFamily{
301+
{
302+
Name: amp("syslogng_classified_output_events_total"),
303+
Type: io_prometheus_client.MetricType_COUNTER.Enum(),
304+
Metric: []*io_prometheus_client.Metric{
305+
{
306+
Label: []*io_prometheus_client.LabelPair{
307+
newLabel("app", "MSWinEventLog\\t1\\tSecurity\\t921448325\\tFri"),
308+
newLabel("source", "s_critical_hosts_515"),
309+
},
310+
Counter: &io_prometheus_client.Counter{
311+
Value: amp(1.0),
312+
},
313+
},
314+
{
315+
Label: []*io_prometheus_client.LabelPair{
316+
newLabel("app", "\\a\\t\n\"\\xfa\\"),
317+
newLabel("source", "s_unescaped_bug"),
318+
},
319+
Counter: &io_prometheus_client.Counter{
320+
Value: amp(1.0),
321+
},
322+
},
323+
},
324+
},
325+
}
326+
sortMetricFamilies(expectedEscapeMetrics)
327+
300328
testCases := map[string]struct {
301329
cc ControlChannel
302330
expected []*io_prometheus_client.MetricFamily
@@ -322,6 +350,13 @@ func TestStatsPrometheus(t *testing.T) {
322350
}),
323351
expected: expectedDelayMetrics,
324352
},
353+
"syslog-ng stats prometheus label escaping": {
354+
cc: ControlChannelFunc(func(_ context.Context, cmd string) (rsp string, err error) {
355+
require.Equal(t, "STATS PROMETHEUS", cmd)
356+
return PROMETHEUS_ESCAPE_METRICS_OUTPUT, nil
357+
}),
358+
expected: expectedEscapeMetrics,
359+
},
325360
}
326361

327362
for name, testCase := range testCases {
@@ -460,6 +495,10 @@ syslogng_output_event_delay_sample_age_seconds{driver="http",url="http://localho
460495
syslogng_output_event_delay_sample_age_seconds{transport="tcp",address="localhost:5555",driver="afsocket",id="#anon-destination0#0"} 31
461496
`
462497

498+
const PROMETHEUS_ESCAPE_METRICS_OUTPUT = `syslogng_classified_output_events_total{app="MSWinEventLog\\t1\\tSecurity\\t921448325\\tFri",source="s_critical_hosts_515"} 1
499+
syslogng_classified_output_events_total{app="\a\t\n\"\xfa\\",source="s_unescaped_bug"} 1
500+
`
501+
463502
func metricFamiliesToText(mfs []*io_prometheus_client.MetricFamily) string {
464503
var buf strings.Builder
465504
for _, mf := range mfs {

0 commit comments

Comments
 (0)