From 041a30c65c057acde32351a5b7ba3b8fc5f0a952 Mon Sep 17 00:00:00 2001
From: Filippo Giunchedi <filippo@wikimedia.org>
Date: Fri, 27 Aug 2021 11:38:13 +0200
Subject: [PATCH] Add omfwd support

---
 exporter.go     |  9 +++++++++
 forward.go      | 35 +++++++++++++++++++++++++++++++++
 forward_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
 utils.go        |  2 ++
 4 files changed, 98 insertions(+)
 create mode 100644 forward.go
 create mode 100644 forward_test.go

diff --git a/exporter.go b/exporter.go
index 5ee725c..c2a0630 100644
--- a/exporter.go
+++ b/exporter.go
@@ -22,6 +22,7 @@ const (
 	rsyslogDynStat
 	rsyslogDynafileCache
 	rsyslogInputIMDUP
+	rsyslogForward
 )
 
 type rsyslogExporter struct {
@@ -112,6 +113,14 @@ func (re *rsyslogExporter) handleStatLine(rawbuf []byte) error {
 		for _, p := range d.toPoints() {
 			re.set(p)
 		}
+	case rsyslogForward:
+		f, err := newForwardFromJSON(buf)
+		if err != nil {
+			return err
+		}
+		for _, p := range f.toPoints() {
+			re.set(p)
+		}
 
 	default:
 		return fmt.Errorf("unknown pstat type: %v", pstatType)
diff --git a/forward.go b/forward.go
new file mode 100644
index 0000000..557e6f3
--- /dev/null
+++ b/forward.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+)
+
+type forward struct {
+	Name      string `json:"name"`
+	BytesSent int64  `json:"bytes.sent"`
+}
+
+func newForwardFromJSON(b []byte) (*forward, error) {
+	var pstat forward
+	err := json.Unmarshal(b, &pstat)
+	if err != nil {
+		return nil, fmt.Errorf("failed to decode forward stat `%v`: %v", string(b), err)
+	}
+	return &pstat, nil
+}
+
+func (f *forward) toPoints() []*point {
+	points := make([]*point, 1)
+
+	points[0] = &point{
+		Name:        "forward_bytes_total",
+		Type:        counter,
+		Value:       f.BytesSent,
+		Description: "bytes forwarded to destination",
+		LabelName:   "destination",
+		LabelValue:  f.Name,
+	}
+
+	return points
+}
diff --git a/forward_test.go b/forward_test.go
new file mode 100644
index 0000000..e960242
--- /dev/null
+++ b/forward_test.go
@@ -0,0 +1,52 @@
+package main
+
+import "testing"
+
+var (
+	forwardLog = []byte(`{ "name": "TCP-FQDN-6514", "origin": "omfwd", "bytes.sent": 666 }`)
+)
+
+func TestNewForwardFromJSON(t *testing.T) {
+	logType := getStatType(forwardLog)
+	if logType != rsyslogForward {
+		t.Errorf("detected pstat type should be %d but is %d", rsyslogForward, logType)
+	}
+
+	pstat, err := newForwardFromJSON([]byte(forwardLog))
+	if err != nil {
+		t.Fatalf("expected parsing action not to fail, got: %v", err)
+	}
+
+	if want, got := "TCP-FQDN-6514", pstat.Name; want != got {
+		t.Errorf("wanted '%s', got '%s'", want, got)
+	}
+
+	if want, got := int64(666), pstat.BytesSent; want != got {
+		t.Errorf("wanted '%d', got '%d'", want, got)
+	}
+}
+
+func TestForwardToPoints(t *testing.T) {
+	pstat, err := newForwardFromJSON([]byte(forwardLog))
+	if err != nil {
+		t.Fatalf("expected parsing action not to fail, got: %v", err)
+	}
+	points := pstat.toPoints()
+
+	point := points[0]
+	if want, got := "forward_bytes_total", point.Name; want != got {
+		t.Errorf("wanted '%s', got '%s'", want, got)
+	}
+
+	if want, got := int64(666), point.Value; want != got {
+		t.Errorf("wanted '%d', got '%d'", want, got)
+	}
+
+	if want, got := counter, point.Type; want != got {
+		t.Errorf("wanted '%d', got '%d'", want, got)
+	}
+
+	if want, got := "TCP-FQDN-6514", point.LabelValue; want != got {
+		t.Errorf("wanted '%s', got '%s'", want, got)
+	}
+}
diff --git a/utils.go b/utils.go
index 1cd38e8..624fd28 100644
--- a/utils.go
+++ b/utils.go
@@ -18,6 +18,8 @@ func getStatType(buf []byte) rsyslogType {
 		return rsyslogDynStat
 	} else if strings.Contains(line, "dynafile cache") {
 		return rsyslogDynafileCache
+	} else if strings.Contains(line, "omfwd") {
+		return rsyslogForward
 	}
 	return rsyslogUnknown
 }
-- 
GitLab