Skip to content

Commit

Permalink
Merge pull request #21 from axoflow/workaround-escaping-bug
Browse files Browse the repository at this point in the history
syslog-ng-ctl: workaround invalid escaping in syslog-ng/AxoSyslog metrics
  • Loading branch information
MrAnno authored Jul 31, 2024
2 parents 83879ef + 1010844 commit 4160b5c
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
33 changes: 33 additions & 0 deletions pkg/syslog-ng-ctl/stats_prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,38 @@ func transformEventDelayMetric(delayMetric *io_prometheus_client.MetricFamily, d
delayMetric.Type = io_prometheus_client.MetricType_GAUGE.Enum()
}

// Workaround for a bug in older syslog-ng/AxoSyslog versions where the output of STATS PROMETHEUS was overescaped.
// Escapes \ as \\ everywhere except for the allowed sequences: \\, \n, \"
func sanitizeBuggyFormat(output string) string {
var fixedOutput strings.Builder

length := len(output)
for i := 0; i < length; i++ {
c := output[i]

if c != '\\' {
fixedOutput.WriteByte(c)
continue
}

if i+1 >= length {
fixedOutput.WriteString(`\\`)
break
}

if next := output[i+1]; next == '\\' || next == 'n' || next == '"' {
fixedOutput.WriteByte(c)
fixedOutput.WriteByte(next)
i++
continue
}

fixedOutput.WriteString(`\\`)
}

return fixedOutput.String()
}

func StatsPrometheus(ctx context.Context, cc ControlChannel, lastMetricQueryTime *time.Time) ([]*io_prometheus_client.MetricFamily, error) {
rsp, err := cc.SendCommand(ctx, "STATS PROMETHEUS")
if err != nil {
Expand All @@ -169,6 +201,7 @@ func StatsPrometheus(ctx context.Context, cc ControlChannel, lastMetricQueryTime
return maps.Values(mfs), err
}

rsp = sanitizeBuggyFormat(rsp)
mfs, err = new(expfmt.TextParser).TextToMetricFamilies(strings.NewReader(rsp))

var delayMetric *io_prometheus_client.MetricFamily
Expand Down
39 changes: 39 additions & 0 deletions pkg/syslog-ng-ctl/stats_prometheus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,34 @@ func TestStatsPrometheus(t *testing.T) {
}
sortMetricFamilies(expectedDelayMetrics)

expectedEscapeMetrics := []*io_prometheus_client.MetricFamily{
{
Name: amp("syslogng_classified_output_events_total"),
Type: io_prometheus_client.MetricType_COUNTER.Enum(),
Metric: []*io_prometheus_client.Metric{
{
Label: []*io_prometheus_client.LabelPair{
newLabel("app", "MSWinEventLog\\t1\\tSecurity\\t921448325\\tFri"),
newLabel("source", "s_critical_hosts_515"),
},
Counter: &io_prometheus_client.Counter{
Value: amp(1.0),
},
},
{
Label: []*io_prometheus_client.LabelPair{
newLabel("app", "\\a\\t\n\"\\xfa\\"),
newLabel("source", "s_unescaped_bug"),
},
Counter: &io_prometheus_client.Counter{
Value: amp(1.0),
},
},
},
},
}
sortMetricFamilies(expectedEscapeMetrics)

testCases := map[string]struct {
cc ControlChannel
expected []*io_prometheus_client.MetricFamily
Expand All @@ -322,6 +350,13 @@ func TestStatsPrometheus(t *testing.T) {
}),
expected: expectedDelayMetrics,
},
"syslog-ng stats prometheus label escaping": {
cc: ControlChannelFunc(func(_ context.Context, cmd string) (rsp string, err error) {
require.Equal(t, "STATS PROMETHEUS", cmd)
return PROMETHEUS_ESCAPE_METRICS_OUTPUT, nil
}),
expected: expectedEscapeMetrics,
},
}

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

const PROMETHEUS_ESCAPE_METRICS_OUTPUT = `syslogng_classified_output_events_total{app="MSWinEventLog\\t1\\tSecurity\\t921448325\\tFri",source="s_critical_hosts_515"} 1
syslogng_classified_output_events_total{app="\a\t\n\"\xfa\\",source="s_unescaped_bug"} 1
`

func metricFamiliesToText(mfs []*io_prometheus_client.MetricFamily) string {
var buf strings.Builder
for _, mf := range mfs {
Expand Down

0 comments on commit 4160b5c

Please sign in to comment.