Path: blob/main/component/loki/source/syslog/internal/syslogtarget/syslogtarget_test.go
4097 views
package syslogtarget12// This code is copied from Promtail. The syslogtarget package is used to3// configure and run the targets that can read syslog entries and forward them4// to other loki components.56import (7"crypto/tls"8"crypto/x509"9"fmt"10"io"11"net"12"os"13"testing"14"time"15"unicode/utf8"1617"github.com/grafana/agent/component/common/loki/client/fake"1819"github.com/go-kit/log"20"github.com/grafana/loki/clients/pkg/promtail/scrapeconfig"21"github.com/grafana/loki/clients/pkg/promtail/targets/syslog/syslogparser"22"github.com/influxdata/go-syslog/v3"23promconfig "github.com/prometheus/common/config"24"github.com/prometheus/common/model"25"github.com/prometheus/prometheus/model/relabel"26"github.com/stretchr/testify/require"27"gopkg.in/yaml.v2"28)2930var (31caCert = []byte(`32-----BEGIN CERTIFICATE-----33MIIFDTCCAvWgAwIBAgIRAL3YFsDcKtnEWCzE0qafwlQwDQYJKoZIhvcNAQELBQAw34IDEeMBwGA1UEAxMVUHJvbXRhaWwgVGVzdCBSb290IENBMB4XDTIyMDYyOTA4MTQy35MFoXDTQyMDYyOTA4MTQyMFowIDEeMBwGA1UEAxMVUHJvbXRhaWwgVGVzdCBSb29036IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1wHnEwW3Gc1Q3v4F37BgFL9N2rayHA7yFqViEwG8AiliaCnnN5VaAN29tpWMgr9sLpve5Ka8iCO8xnIxsM385rtlSvLlFW0SInXyJsBT6NyqHrk2GZBhscgT+Qb9ouSYjil4UFRADAAEhBZPVisO39ZQiELKPS+BxyRL15QhMB7k7u1z0GRzlrG7CcopzrYM+4JLGE+2nXnoy7MSjdNduH40w4sWwI66hD192Lpkh83HZneONXiZhJdEJOHHJ8G+rYwuZRAlnLs82y+OROIozuKV41yFhWMk+BUGgkeftmAzIiUAneKwKugqz9QExVPo1imGAsiVHdprTTPn/34ZNpsDR742MXwzitVqvu/pa3BYDha7RTpeCdVPFqDs8BPFgcAleM75QQcnPtbUD/apJHUQ5D5q438c2U/2hTtcTMZIMCscoBBpx98bSOS9ojIJSGYKCdBj6rqnAFNYasayVCN5c5pPIw44Mj7HUww4gKXVKMvNDnjaXqFBEgEjSv5cquZ993C8gVGHLiMnq/Bj5k9SeOD0gTKD45/uLuLhKiMI6sOJQrYW5W0P3tTNcYGUeS0hBZW2Mo6PM+BimfzstZhsdFQnjzMEld46I5elwqWKysEvxXIvLnGLVWXJ6s0Pyr6J0ASmxpjskQEcPgaOxkRVwNzC18eSq3Ey47zUEWoyHiDedB4CCIq6nXY01FC5MCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgKkMA8G48A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFBj1+WwOdP8rb95R7kOmWena3RfMA0G49CSqGSIb3DQEBCwUAA4ICAQDQtOpfNPrv+V8ObOb+pie//UfTReOwXtBZgTxMu1Bi50uYIiFEveQ18HGAeIhbVm8wLjtfPkoJlZKzdCcMqSmLt0LZQNs13IQ8M+YuXeu5pX51PJOu0WrbdQHW5JMnPxwKMk5T2axbrX9dYW9gvr8sh5OlnNTx88fY1vMBsnNLVZT+52kC7Daf0zT0Go6VxBk6KRtfpoVCy/aYgwbJ1u5W61eYtXC4ezrpoLINo7zVs7Tob853iIxJMQ/iEk/7BbIgVh9z8lNeexdjXCqm8952pPhkGONneCESTxJjgYqXyhlV0ict54OP+CiMHl5yf6+eklfXU78Jmkh/46XBqu7JV8lt8xbbSJ4AITWxi3csxC/Xztyu/g55H5nS2gAmpAbTjHq7lGicFScBuR3g0o3+64KN3XhVXN1KFrTlsGSOxyPE657p2xNw56tAAQs9IEBIPVqMInOGue6LbHTzCzW8hMClfu0CwPXiMY5DWKif7O9kzxnb9HdmAl57gnDn+9OzTw7oAW1UyVTSbzYy0Tw1ioYR7U77Z+Gcst2+mIuWp7BFNkaX5mPaacCT58GLnXoZk8UU0ph5/uBfZL3dNsJKeXlnCMAXACdLicnMC19g6P/dKqRZcI2w7kTPtF592GlKMYjeKDuAUc9VeGzDc6PAX4oqF8XPfP5Mie4nrtpYnL0zKV1RcUS1yX1TC24O60ig==61-----END CERTIFICATE-----62`)6364// Unused, but can be useful to (re)generate some certificates65// nolint:deadcode,unused,varcheck66caKey = []byte(`67-----BEGIN RSA PRIVATE KEY-----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117-----END RSA PRIVATE KEY-----118`)119120serverCert = []byte(`121-----BEGIN CERTIFICATE-----122MIIFWDCCA0CgAwIBAgIRAMWnlYEx52Vws2b3EzexW+UwDQYJKoZIhvcNAQELBQAw123IDEeMBwGA1UEAxMVUHJvbXRhaWwgVGVzdCBSb290IENBMB4XDTIyMDYyOTA4MTQy124NFoXDTQyMDYyOTA4MTQyNFowKzEpMCcGA1UEAxMgUHJvbXRhaWwgVGVzdCBTZXJ2125ZXIgQ2VydGlmaWNhdGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCo1268+m8sVjG2tvRqzFWD6XRwvWIV/7nOHhuL7ygdouTJ5MKjpKHSudOXOoxHw9aNA4u127zmExqlSD4RVnwb2R/nXoqO1Ae5VavkNngeDw5Uk/RacqF4WFCnmFNxh523iA4ifo128ZxmVhQoE1t3O4kMrygK2SEpSTY58PfuqLfd7ZyHDEmpu9pYfuQQCqKLOsVQS5mqY129g7gyKQQLq0D4beCsSuih09PskMiG29uh/qCdSmDDR++j42xP/fwXVGm3nsOMLjQf1301DFlZFqmQS42Da1KtnKzz+SVDSHihyRKiZ0KAyyDHYdKToFO/zYlCgFGw86o4VGu131HKbolE6oPrBnqdXyIf9cON4RdnoTrChG4E6yq4LN8XoNRloePjoGQ9huoqwGie3m132c06Pnj2eV4oCJwdLarKZqZzdJnanx+ctObAGGGjjV1ocNGFc2EMBpTFVpy20Kqd/133E7t2yeGU6wJhzMNtvyFHhcOY+7PRTuvrUzbK1McFU/6NKBn4ioW2XBU8CjPEKGNx134itIZWnxppqkt2EemZEB+L1QpNtNlFmSYLqPm+j1134os3I3s+kkawiSjBcpqgzDf135stt64LiO/ULXDfPexbzE+mggQ3GsQ+b5v2O4KTQ4A4ilI48+0Qn3YxqfaVJmusGE136+Jkpo/Fnt3OCJaYBqsSzK5dIzF9TJhsOb+f5NGBJEQIDAQABo4GBMH8wDgYDVR0P137AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB138Af8EAjAAMB8GA1UdIwQYMBaAFFBj1+WwOdP8rb95R7kOmWena3RfMB8GA1UdEQQY139MBaCFHByb210YWlsLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4ICAQApSDHl140IECz4Ix+6zZqNU0DgulYTXcHKtnXEKRJVTULbKy/mWzE5ZAgVV0rpRLHbRg0fWYh1414tjd5X/Pedf4OtnpV6ekkvBf+QCKAmDiWN9rKhjdVoTFw0+wavQv1yzz8++2HenR142rgq7wWuwg0hB9/KKOWW09ZuBynjB7aeoWHztIbD+/cugMlzqDX8hODRl3OaEAwM3143PBpYEqFSuPBNrCK5Y0tGgzZDdsxrDYcX5CjJdrgwtZ1kFOT8J2VE+2Sqc7KMCPFl144LQmmtIcwjljNABf5d2L978tISFtwRoZVxrsTODqLLF8l6B7JUQdCpmoM+549E0cS145bpTj4FVftJwEpElMFMVw/Uh5pA7hOLGAK3YYqBx6fbEGHn+WmwLA5Io7tbBSKUX/146hNlOFupAU3Q/OawqlmSPRflqKIg4b8TgSVlafJOFmvKg0WLGVuLtl65g9eNQVht9147KLlPPCPbpYKXpXya42eFazxEepOeaCkchOUB+x4tmAZ44NJTMR+UmiGLGCjdQTpU148m892bbGtLA0hGhYGrMsI546Xd8PjNI117CARrDpk57E1V+CsAO6ZTOPLgI4q976L149kWYB12V1t/BNtGyChdmfIYBqvTYAGk9hbqG80SjmcZtPu5JIEvIXCyaYXiWmEs2l150j1ieRNjgNYyG/7wJmilCsnpjbWza85/JzxE1cA==151-----END CERTIFICATE-----152`)153154serverKey = []byte(`155-----BEGIN RSA PRIVATE KEY-----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205-----END RSA PRIVATE KEY-----206`)207208clientCert = []byte(`209-----BEGIN CERTIFICATE-----210MIIFNTCCAx2gAwIBAgIQWzE3b7oUqYGe2UvYWJBnyDANBgkqhkiG9w0BAQsFADAg211MR4wHAYDVQQDExVQcm9tdGFpbCBUZXN0IFJvb3QgQ0EwHhcNMjIwNjI5MDgxNDI0212WhcNNDIwNjI5MDgxNDI0WjArMSkwJwYDVQQDEyBQcm9tdGFpbCBUZXN0IENsaWVu213dCBDZXJ0aWZpY2F0ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALcQ214KhIIL7EZLIDWPMIkT5cJdPRavs5/LO50isCVs2z+PTA4mIkj2NEk8qFqgc3+1LUh215SV/NQ3p0LikSx9M6g1oBJbqQ7W6BcCzzUOHb4QlGoa2DXXGONPdO3AJxTTDNU6Li216xT5ESTbuDe56JDw3x2V0pxOzCUSuTMa1mvHnIojVn/8qHOZB0l4o9c44oHGJDUGh217o1wAc3UXGMLsd6IEYsHzLyG6kG7ayqToFftI/rkpEK8tCWMbclewh22c0OCXejEZ218pS9mz2decoIG7NnkqrRwUj+RPNlKJgBJ2USYimbQZHmdZWNb+vP/HFXs1Eq0sin+2195HrRnzuB6yCwQlqvR7Db3buENEXG2OcglGmO/1mBfB4nW7JKFAvIqBBtHDRmBCYr220YS9htPiZte8Mfak3RncxLLccEzo1CNqtW9BLfryGH3l+6LR0yZkw+C95RZ9Wni4T221e5hy5yX8SW3z4AUb3ZYbFROW4sW/sSsh8VucZoa4OXw981OB4ZGrtJnncvc1KE5Q222BBF+bRZKdMQhzwb7pZq31kZjH0So53Ntyf4S6VHgUOTs8xorPSjnP85BKnnm7XsG223W/zP+kGCyjOCu4WIrNvSlIguF4KcVZulWbMljVCU0TwKNbxBm5SZrTXPoJeyRtE6224ai+fHPoMjJvwUaLYQUkzTpfdGg8OCV3NX/LvbCuVAgMBAAGjYDBeMA4GA1UdDwEB225/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/226BAIwADAfBgNVHSMEGDAWgBRQY9flsDnT/K2/eUe5Dplnp2t0XzANBgkqhkiG9w0B227AQsFAAOCAgEAxJvDifKqK6EQrN5VPL68IPORu1VK17HeSJ2xLScL3Hh7vulPs9Nf228HLixcOhixsYhgurFZ3M3K05tT0EKy1K7WLJzJEhPccAkbz+d2oIeghksq2l75u20229t2o1X8rgT+/7d/j+VBur/+igQdwvylo+wgGNosX8VmjyQrZBWIHvDTyzrvODFbZa230JYf3DfgLSF5tr4e/HNLhynUD9G40CmRLQh7PkojrMXMyeqqWpBPzDBlZgvH2QMK8231K9S8KUuaZhGUTLQmkR3NP/bx1V/Ks1/BtpmdIchQ42w+Uu2PM/pmuZsnX7bK0tzd232zCFjgSIxifN8BKdcKMEngo+MwYy/Fj3vzy4qXxtOCbnzB+A/ziLiJV3Tsdwm+nPO233xZFcXXfnCMoNF0ouv2/WAbUrKLTZXL712MZ14JT79TkKxWZ49AUHSiGfm1I45iky234xgcn4FVgJpsCheRqL+gecNDyq+4VdwlWuFAuqMI4UBUbWwyAntOL1iiyENGA1ygo235OVuQq9M0bh93d5U+Ct79CsL4LLaoRrvBGJ6WnO8PKTTLqfFC3T8ySCtVGZiLoSqn236fJ1uhxhK8YSYhod+81/nkpJuF1xRg1t2kXgvUxPR9jzf96QaZ/94oryEH3zr59Rb237wmOulo1MN6yRdGzWiJ8sZ8VXUuh0xBCUiwrpo++Dda2s0bF0YzJGI6E=238-----END CERTIFICATE-----239`)240clientKey = []byte(`241-----BEGIN RSA PRIVATE KEY-----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-----END RSA PRIVATE KEY-----292`)293)294295type formatFunc func(string) string296297var (298fmtOctetCounting = func(s string) string { return fmt.Sprintf("%d %s", len(s), s) }299fmtNewline = func(s string) string { return s + "\n" }300)301302func Benchmark_SyslogTarget(b *testing.B) {303for _, tt := range []struct {304name string305protocol string306formatFunc formatFunc307}{308{"tcp", protocolTCP, fmtOctetCounting},309{"udp", protocolUDP, fmtOctetCounting},310} {311tt := tt312b.Run(tt.name, func(b *testing.B) {313client := fake.NewClient(func() {})314315metrics := NewMetrics(nil)316tgt, _ := NewSyslogTarget(metrics, log.NewNopLogger(), client, []*relabel.Config{}, &scrapeconfig.SyslogTargetConfig{317ListenAddress: "127.0.0.1:0",318ListenProtocol: tt.protocol,319LabelStructuredData: true,320Labels: model.LabelSet{321"test": "syslog_target",322},323})324b.Cleanup(func() {325require.NoError(b, tgt.Stop())326})327require.Eventually(b, tgt.Ready, time.Second, 10*time.Millisecond)328329addr := tgt.ListenAddress().String()330331messages := []string{332`<165>1 2022-04-08T22:14:10.001Z host1 app - id1 [custom@32473 exkey="1"] An application event log entry...`,333`<165>1 2022-04-08T22:14:11.002Z host2 app - id2 [custom@32473 exkey="1"] An application event log entry...`,334`<165>1 2022-04-08T22:14:12.003Z host1 app - id3 [custom@32473 exkey="1"] An application event log entry...`,335`<165>1 2022-04-08T22:14:13.004Z host2 app - id4 [custom@32473 exkey="1"] An application event log entry...`,336`<165>1 2022-04-08T22:14:14.005Z host1 app - id5 [custom@32473 exkey="1"] An application event log entry...`,337`<165>1 2022-04-08T22:14:15.002Z host2 app - id6 [custom@32473 exkey="1"] An application event log entry...`,338`<165>1 2022-04-08T22:14:16.003Z host1 app - id7 [custom@32473 exkey="1"] An application event log entry...`,339`<165>1 2022-04-08T22:14:17.004Z host2 app - id8 [custom@32473 exkey="1"] An application event log entry...`,340`<165>1 2022-04-08T22:14:18.005Z host1 app - id9 [custom@32473 exkey="1"] An application event log entry...`,341`<165>1 2022-04-08T22:14:19.001Z host2 app - id10 [custom@32473 exkey="1"] An application event log entry...`,342}343344b.ReportAllocs()345b.ResetTimer()346347c, _ := net.Dial(tt.protocol, addr)348for n := 0; n < b.N; n++ {349_ = writeMessagesToStream(c, messages, tt.formatFunc)350}351c.Close()352353require.Eventuallyf(b, func() bool {354return len(client.Received()) == len(messages)*b.N355}, 15*time.Second, time.Second, "expected: %d got:%d", len(messages)*b.N, len(client.Received()))356})357}358}359360func TestSyslogTarget(t *testing.T) {361for _, tt := range []struct {362name string363protocol string364fmtFunc formatFunc365}{366{"tpc newline separated", protocolTCP, fmtNewline},367{"tpc octetcounting", protocolTCP, fmtOctetCounting},368{"udp newline separated", protocolUDP, fmtNewline},369{"udp octetcounting", protocolUDP, fmtOctetCounting},370} {371tt := tt372t.Run(tt.name, func(t *testing.T) {373w := log.NewSyncWriter(os.Stderr)374logger := log.NewLogfmtLogger(w)375client := fake.NewClient(func() {})376377metrics := NewMetrics(nil)378tgt, err := NewSyslogTarget(metrics, logger, client, relabelConfig(t), &scrapeconfig.SyslogTargetConfig{379MaxMessageLength: 1 << 12, // explicitly not use default value380ListenAddress: "127.0.0.1:0",381ListenProtocol: tt.protocol,382LabelStructuredData: true,383Labels: model.LabelSet{384"test": "syslog_target",385},386})387require.NoError(t, err)388389require.Eventually(t, tgt.Ready, time.Second, 10*time.Millisecond)390391addr := tgt.ListenAddress().String()392c, err := net.Dial(tt.protocol, addr)393require.NoError(t, err)394395messages := []string{396`<165>1 2018-10-11T22:14:15.003Z host5 e - id1 [custom@32473 exkey="1"] An application event log entry...`,397`<165>1 2018-10-11T22:14:15.005Z host5 e - id2 [custom@32473 exkey="2"] An application event log entry...`,398`<165>1 2018-10-11T22:14:15.007Z host5 e - id3 [custom@32473 exkey="3"] An application event log entry...`,399}400401err = writeMessagesToStream(c, messages, tt.fmtFunc)402require.NoError(t, err)403require.NoError(t, c.Close())404405if tt.protocol == protocolUDP {406time.Sleep(time.Second)407require.NoError(t, tgt.Stop())408} else {409defer func() {410require.NoError(t, tgt.Stop())411}()412}413414require.Eventuallyf(t, func() bool {415return len(client.Received()) == len(messages)416}, time.Second, 10*time.Millisecond, "Expected to receive %d messages.", len(messages))417418labels := make([]model.LabelSet, 0, len(messages))419for _, entry := range client.Received() {420labels = append(labels, entry.Labels)421}422// we only check if one of the received entries contain the wanted label set423// because UDP does not guarantee the order of the messages424require.Contains(t, labels, model.LabelSet{425"test": "syslog_target",426427"severity": "notice",428"facility": "local4",429"hostname": "host5",430"app_name": "e",431"msg_id": "id1",432433"sd_custom_exkey": "1",434})435require.Equal(t, "An application event log entry...", client.Received()[0].Line)436437require.NotZero(t, client.Received()[0].Timestamp)438})439}440}441442func relabelConfig(t *testing.T) []*relabel.Config {443relabelCfg := `444- source_labels: ['__syslog_message_severity']445target_label: 'severity'446- source_labels: ['__syslog_message_facility']447target_label: 'facility'448- source_labels: ['__syslog_message_hostname']449target_label: 'hostname'450- source_labels: ['__syslog_message_app_name']451target_label: 'app_name'452- source_labels: ['__syslog_message_proc_id']453target_label: 'proc_id'454- source_labels: ['__syslog_message_msg_id']455target_label: 'msg_id'456- source_labels: ['__syslog_message_sd_custom_32473_exkey']457target_label: 'sd_custom_exkey'458`459460var relabels []*relabel.Config461err := yaml.Unmarshal([]byte(relabelCfg), &relabels)462require.NoError(t, err)463464return relabels465}466467func writeMessagesToStream(w io.Writer, messages []string, formatter formatFunc) error {468for _, msg := range messages {469_, err := fmt.Fprint(w, formatter(msg))470if err != nil {471return err472}473}474return nil475}476477func TestSyslogTarget_RFC5424Messages(t *testing.T) {478for _, tt := range []struct {479name string480protocol string481fmtFunc formatFunc482}{483{"tpc newline separated", protocolTCP, fmtNewline},484{"tpc octetcounting", protocolTCP, fmtOctetCounting},485} {486tt := tt487t.Run(tt.name, func(t *testing.T) {488w := log.NewSyncWriter(os.Stderr)489logger := log.NewLogfmtLogger(w)490client := fake.NewClient(func() {})491492metrics := NewMetrics(nil)493tgt, err := NewSyslogTarget(metrics, logger, client, []*relabel.Config{}, &scrapeconfig.SyslogTargetConfig{494ListenAddress: "127.0.0.1:0",495ListenProtocol: tt.protocol,496LabelStructuredData: true,497Labels: model.LabelSet{498"test": "syslog_target",499},500UseRFC5424Message: true,501})502require.NoError(t, err)503require.Eventually(t, tgt.Ready, time.Second, 10*time.Millisecond)504defer func() {505require.NoError(t, tgt.Stop())506}()507508addr := tgt.ListenAddress().String()509c, err := net.Dial(tt.protocol, addr)510require.NoError(t, err)511512messages := []string{513`<165>1 2018-10-11T22:14:15.003Z host5 e - id1 [custom@32473 exkey="1"] An application event log entry...`,514`<165>1 2018-10-11T22:14:15.005Z host5 e - id2 [custom@32473 exkey="2"] An application event log entry...`,515`<165>1 2018-10-11T22:14:15.007Z host5 e - id3 [custom@32473 exkey="3"] An application event log entry...`,516}517518err = writeMessagesToStream(c, messages, tt.fmtFunc)519require.NoError(t, err)520require.NoError(t, c.Close())521522require.Eventuallyf(t, func() bool {523return len(client.Received()) == len(messages)524}, time.Second, time.Millisecond, "Expected to receive %d messages, got %d.", len(messages), len(client.Received()))525526for i := range messages {527require.Equal(t, model.LabelSet{528"test": "syslog_target",529}, client.Received()[i].Labels)530require.Contains(t, messages, client.Received()[i].Line)531require.NotZero(t, client.Received()[i].Timestamp)532}533})534}535}536537func TestSyslogTarget_TLSConfigWithoutServerCertificate(t *testing.T) {538w := log.NewSyncWriter(os.Stderr)539logger := log.NewLogfmtLogger(w)540client := fake.NewClient(func() {})541542metrics := NewMetrics(nil)543_, err := NewSyslogTarget(metrics, logger, client, relabelConfig(t), &scrapeconfig.SyslogTargetConfig{544ListenAddress: "127.0.0.1:0",545TLSConfig: promconfig.TLSConfig{546KeyFile: "foo",547},548})549require.Error(t, err, "error setting up syslog target: certificate and key files are required")550}551552func TestSyslogTarget_TLSConfigWithoutServerKey(t *testing.T) {553w := log.NewSyncWriter(os.Stderr)554logger := log.NewLogfmtLogger(w)555client := fake.NewClient(func() {})556557metrics := NewMetrics(nil)558_, err := NewSyslogTarget(metrics, logger, client, relabelConfig(t), &scrapeconfig.SyslogTargetConfig{559ListenAddress: "127.0.0.1:0",560TLSConfig: promconfig.TLSConfig{561CertFile: "foo",562},563})564require.Error(t, err, "error setting up syslog target: certificate and key files are required")565}566567func TestSyslogTarget_TLSConfig(t *testing.T) {568t.Run("NewlineSeparatedMessages", func(t *testing.T) {569testSyslogTargetWithTLS(t, fmtNewline)570})571t.Run("OctetCounting", func(t *testing.T) {572testSyslogTargetWithTLS(t, fmtOctetCounting)573})574}575576func testSyslogTargetWithTLS(t *testing.T, fmtFunc formatFunc) {577caCertPool := x509.NewCertPool()578caCertPool.AppendCertsFromPEM(caCert)579580serverCertFile, err := createTempFile(serverCert)581if err != nil {582t.Fatalf("Unable to create server certificate temporary file: %s", err)583}584defer os.Remove(serverCertFile.Name())585586serverKeyFile, err := createTempFile(serverKey)587if err != nil {588t.Fatalf("Unable to create server key temporary file: %s", err)589}590defer os.Remove(serverKeyFile.Name())591592w := log.NewSyncWriter(os.Stderr)593logger := log.NewLogfmtLogger(w)594client := fake.NewClient(func() {})595596metrics := NewMetrics(nil)597tgt, err := NewSyslogTarget(metrics, logger, client, relabelConfig(t), &scrapeconfig.SyslogTargetConfig{598ListenAddress: "127.0.0.1:0",599LabelStructuredData: true,600Labels: model.LabelSet{601"test": "syslog_target",602},603TLSConfig: promconfig.TLSConfig{604CertFile: serverCertFile.Name(),605KeyFile: serverKeyFile.Name(),606},607})608require.NoError(t, err)609defer func() {610require.NoError(t, tgt.Stop())611}()612613tlsConfig := tls.Config{614RootCAs: caCertPool,615ServerName: "promtail.example.com",616}617618addr := tgt.ListenAddress().String()619c, err := tls.Dial("tcp", addr, &tlsConfig)620require.NoError(t, err)621622validMessages := []string{623`<165>1 2018-10-11T22:14:15.003Z host5 e - id1 [custom@32473 exkey="1"] An application event log entry...`,624`<165>1 2018-10-11T22:14:15.005Z host5 e - id2 [custom@32473 exkey="2"] An application event log entry...`,625`<165>1 2018-10-11T22:14:15.007Z host5 e - id3 [custom@32473 exkey="3"] An application event log entry...`,626}627// Messages that are malformed but still valid.628// This causes error messages being written, but the parser does not stop and close the connection.629malformeddMessages := []string{630`<165>1 - An application event log entry...`,631`<165>1 2018-10-11T22:14:15.007Z host5 e - An application event log entry...`,632}633messages := append(malformeddMessages, validMessages...)634635err = writeMessagesToStream(c, messages, fmtFunc)636require.NoError(t, err)637require.NoError(t, c.Close())638639require.Eventuallyf(t, func() bool {640return len(client.Received()) == len(validMessages)641}, time.Second, time.Millisecond, "Expected to receive %d messages, got %d.", len(validMessages), len(client.Received()))642643require.Equal(t, model.LabelSet{644"test": "syslog_target",645646"severity": "notice",647"facility": "local4",648"hostname": "host5",649"app_name": "e",650"msg_id": "id1",651652"sd_custom_exkey": "1",653}, client.Received()[0].Labels)654require.Equal(t, "An application event log entry...", client.Received()[0].Line)655656require.NotZero(t, client.Received()[0].Timestamp)657}658659func createTempFile(data []byte) (*os.File, error) {660tmpFile, err := os.CreateTemp("", "")661if err != nil {662return nil, fmt.Errorf("failed to create temporary file: %s", err)663}664665if _, err := tmpFile.Write(data); err != nil {666return nil, fmt.Errorf("failed to write data to temporary file: %s", err)667}668669if err := tmpFile.Close(); err != nil {670return nil, err671}672673return tmpFile, nil674}675676func TestSyslogTarget_TLSConfigVerifyClientCertificate(t *testing.T) {677t.Run("NewlineSeparatedMessages", func(t *testing.T) {678testSyslogTargetWithTLSVerifyClientCertificate(t, fmtNewline)679})680t.Run("OctetCounting", func(t *testing.T) {681testSyslogTargetWithTLSVerifyClientCertificate(t, fmtOctetCounting)682})683}684685func testSyslogTargetWithTLSVerifyClientCertificate(t *testing.T, fmtFunc formatFunc) {686caCertFile, err := createTempFile(caCert)687if err != nil {688t.Fatalf("Unable to create CA certificate temporary file: %s", err)689}690defer os.Remove(caCertFile.Name())691692caCertPool := x509.NewCertPool()693caCertPool.AppendCertsFromPEM(caCert)694695serverCertFile, err := createTempFile(serverCert)696if err != nil {697t.Fatalf("Unable to create server certificate temporary file: %s", err)698}699defer os.Remove(serverCertFile.Name())700701serverKeyFile, err := createTempFile(serverKey)702if err != nil {703t.Fatalf("Unable to create server key temporary file: %s", err)704}705defer os.Remove(serverKeyFile.Name())706707clientCertFile, err := createTempFile(clientCert)708if err != nil {709t.Fatalf("Unable to create client certificate temporary file: %s", err)710}711defer os.Remove(clientCertFile.Name())712713clientKeyFile, err := createTempFile(clientKey)714if err != nil {715t.Fatalf("Unable to create client key temporary file: %s", err)716}717defer os.Remove(clientKeyFile.Name())718719clientCerts, err := tls.LoadX509KeyPair(clientCertFile.Name(), clientKeyFile.Name())720if err != nil {721t.Fatalf("Unable to load client certificate or key: %s", err)722}723724w := log.NewSyncWriter(os.Stderr)725logger := log.NewLogfmtLogger(w)726client := fake.NewClient(func() {})727728metrics := NewMetrics(nil)729tgt, err := NewSyslogTarget(metrics, logger, client, relabelConfig(t), &scrapeconfig.SyslogTargetConfig{730ListenAddress: "127.0.0.1:0",731LabelStructuredData: true,732Labels: model.LabelSet{733"test": "syslog_target",734},735TLSConfig: promconfig.TLSConfig{736CAFile: caCertFile.Name(),737CertFile: serverCertFile.Name(),738KeyFile: serverKeyFile.Name(),739},740})741require.NoError(t, err)742defer func() {743require.NoError(t, tgt.Stop())744}()745746tlsConfig := tls.Config{747RootCAs: caCertPool,748ServerName: "promtail.example.com",749}750751addr := tgt.ListenAddress().String()752753t.Run("WithoutClientCertificate", func(t *testing.T) {754c, err := tls.Dial("tcp", addr, &tlsConfig)755require.NoError(t, err)756757err = c.SetDeadline(time.Now().Add(time.Second))758require.NoError(t, err)759760buf := make([]byte, 1)761_, err = c.Read(buf)762require.EqualError(t, err, "remote error: tls: bad certificate")763})764765t.Run("WithClientCertificate", func(t *testing.T) {766tlsConfig.Certificates = []tls.Certificate{clientCerts}767c, err := tls.Dial("tcp", addr, &tlsConfig)768require.NoError(t, err)769770messages := []string{771`<165>1 2018-10-11T22:14:15.003Z host5 e - id1 [custom@32473 exkey="1"] An application event log entry...`,772`<165>1 2018-10-11T22:14:15.005Z host5 e - id2 [custom@32473 exkey="2"] An application event log entry...`,773`<165>1 2018-10-11T22:14:15.007Z host5 e - id3 [custom@32473 exkey="3"] An application event log entry...`,774}775776err = writeMessagesToStream(c, messages, fmtFunc)777require.NoError(t, err)778require.NoError(t, c.Close())779780require.Eventuallyf(t, func() bool {781return len(client.Received()) == len(messages)782}, time.Second, time.Millisecond, "Expected to receive %d messages, got %d.", len(messages), len(client.Received()))783784require.Equal(t, model.LabelSet{785"test": "syslog_target",786787"severity": "notice",788"facility": "local4",789"hostname": "host5",790"app_name": "e",791"msg_id": "id1",792793"sd_custom_exkey": "1",794}, client.Received()[0].Labels)795require.Equal(t, "An application event log entry...", client.Received()[0].Line)796797require.NotZero(t, client.Received()[0].Timestamp)798})799}800801func TestSyslogTarget_InvalidData(t *testing.T) {802w := log.NewSyncWriter(os.Stderr)803logger := log.NewLogfmtLogger(w)804client := fake.NewClient(func() {})805metrics := NewMetrics(nil)806807tgt, err := NewSyslogTarget(metrics, logger, client, relabelConfig(t), &scrapeconfig.SyslogTargetConfig{808ListenAddress: "127.0.0.1:0",809})810require.NoError(t, err)811defer func() {812require.NoError(t, tgt.Stop())813}()814815addr := tgt.ListenAddress().String()816c, err := net.Dial("tcp", addr)817require.NoError(t, err)818defer c.Close()819820_, err = fmt.Fprint(c, "xxx")821require.NoError(t, err)822823// syslog target should immediately close the connection if sent invalid data824err = c.SetDeadline(time.Now().Add(time.Second))825require.NoError(t, err)826827buf := make([]byte, 1)828_, err = c.Read(buf)829require.EqualError(t, err, "EOF")830}831832func TestSyslogTarget_NonUTF8Message(t *testing.T) {833w := log.NewSyncWriter(os.Stderr)834logger := log.NewLogfmtLogger(w)835client := fake.NewClient(func() {})836metrics := NewMetrics(nil)837838tgt, err := NewSyslogTarget(metrics, logger, client, relabelConfig(t), &scrapeconfig.SyslogTargetConfig{839ListenAddress: "127.0.0.1:0",840})841require.NoError(t, err)842defer func() {843require.NoError(t, tgt.Stop())844}()845846addr := tgt.ListenAddress().String()847c, err := net.Dial("tcp", addr)848require.NoError(t, err)849850msg1 := "Some non utf8 \xF8\xF7\xE3\xE4 characters"851require.False(t, utf8.ValidString(msg1), "msg must no be valid utf8")852msg2 := "\xF8 other \xF7\xE3\xE4 characters \xE3"853require.False(t, utf8.ValidString(msg2), "msg must no be valid utf8")854855err = writeMessagesToStream(c, []string{856"<165>1 - - - - - - " + msg1,857"<123>1 - - - - - - " + msg2,858}, fmtOctetCounting)859require.NoError(t, err)860require.NoError(t, c.Close())861862require.Eventuallyf(t, func() bool {863return len(client.Received()) == 2864}, time.Second, time.Millisecond, "Expected to receive 2 messages, got %d.", len(client.Received()))865866require.Equal(t, msg1, client.Received()[0].Line)867require.Equal(t, msg2, client.Received()[1].Line)868}869870func TestSyslogTarget_IdleTimeout(t *testing.T) {871w := log.NewSyncWriter(os.Stderr)872logger := log.NewLogfmtLogger(w)873client := fake.NewClient(func() {})874metrics := NewMetrics(nil)875876tgt, err := NewSyslogTarget(metrics, logger, client, relabelConfig(t), &scrapeconfig.SyslogTargetConfig{877ListenAddress: "127.0.0.1:0",878IdleTimeout: time.Millisecond,879})880require.NoError(t, err)881defer func() {882require.NoError(t, tgt.Stop())883}()884885addr := tgt.ListenAddress().String()886c, err := net.Dial("tcp", addr)887require.NoError(t, err)888defer c.Close()889890// connection should be closed before the higher timeout891// from SetDeadline fires892err = c.SetDeadline(time.Now().Add(time.Second))893require.NoError(t, err)894895buf := make([]byte, 1)896_, err = c.Read(buf)897require.EqualError(t, err, "EOF")898}899900func TestParseStream_WithAsyncPipe(t *testing.T) {901lines := [3]string{902"<165>1 2018-10-11T22:14:15.003Z host5 e - id1 [custom@32473 exkey=\"1\"] An application event log entry...\n",903"<165>1 2018-10-11T22:14:15.005Z host5 e - id2 [custom@32473 exkey=\"2\"] An application event log entry...\n",904"<165>1 2018-10-11T22:14:15.007Z host5 e - id3 [custom@32473 exkey=\"3\"] An application event log entry...\n",905}906907addr := &net.UDPAddr{IP: net.IP{127, 0, 0, 1}, Port: 1514}908pipe := NewConnPipe(addr)909go func() {910for _, line := range lines {911_, _ = pipe.Write([]byte(line))912}913pipe.Close()914}()915916results := make([]*syslog.Result, 0)917cb := func(res *syslog.Result) {918results = append(results, res)919}920921err := syslogparser.ParseStream(pipe, cb, DefaultMaxMessageLength)922require.NoError(t, err)923require.Equal(t, 3, len(results))924}925926927