Skip to content

Commit

Permalink
Add support for non-transparent framing of syslog messages (influxdat…
Browse files Browse the repository at this point in the history
  • Loading branch information
leodido authored and Max Eshleman committed Feb 13, 2019
1 parent 4438ba7 commit 1f6d7c6
Show file tree
Hide file tree
Showing 10 changed files with 598 additions and 117 deletions.
25 changes: 20 additions & 5 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@

[[constraint]]
name = "github.com/influxdata/go-syslog"
version = "1.0.1"
version = "2.0.0"

[[constraint]]
name = "github.com/influxdata/tail"
Expand Down
24 changes: 21 additions & 3 deletions plugins/inputs/syslog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

The syslog plugin listens for syslog messages transmitted over
[UDP](https://tools.ietf.org/html/rfc5426) or
[TCP](https://tools.ietf.org/html/rfc5425).
[TCP](https://tools.ietf.org/html/rfc6587) or
[TLS](https://tools.ietf.org/html/rfc5425), with or without the octet counting framing.

Syslog messages should be formatted according to
[RFC 5424](https://tools.ietf.org/html/rfc5424).
Expand Down Expand Up @@ -37,6 +38,16 @@ Syslog messages should be formatted according to
## 0 means unlimited.
# read_timeout = "5s"

## The framing technique with which it is expected that messages are transported (default = "octet-counting").
## Whether the messages come using the octect-counting (RFC5425#section-4.3.1, RFC6587#section-3.4.1),
## or the non-transparent framing technique (RFC6587#section-3.4.2).
## Must be one of "octect-counting", "non-transparent".
# framing = "octet-counting"

## The trailer to be expected in case of non-trasparent framing (default = "LF").
## Must be one of "LF", or "NUL".
# trailer = "LF"

## Whether to parse in best effort mode or not (default = false).
## By default best effort parsing is off.
# best_effort = false
Expand All @@ -49,11 +60,18 @@ Syslog messages should be formatted according to
# sdparam_separator = "_"
```

#### Best Effort
#### Message transport

The `framing` option only applies to streams. It governs the way we expect to receive messages within the stream.
Namely, with the [`"octet counting"`](https://tools.ietf.org/html/rfc5425#section-4.3) technique (default) or with the [`"non-transparent"`](https://tools.ietf.org/html/rfc6587#section-3.4.2) framing.

The `trailer` option only applies when `framing` option is `"non-transparent"`. It must have one of the following values: `"LF"` (default), or `"NUL"`.

#### Best effort

The [`best_effort`](https://github.com/influxdata/go-syslog#best-effort-mode)
option instructs the parser to extract partial but valid info from syslog
messages. If unset only full messages will be collected.
messages. If unset only full messages will be collected.

#### Rsyslog Integration

Expand Down
62 changes: 62 additions & 0 deletions plugins/inputs/syslog/commons_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package syslog

import (
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/testutil"
"time"
)

var (
pki = testutil.NewPKI("../../../testutil/pki")
)

type testCasePacket struct {
name string
data []byte
wantBestEffort *testutil.Metric
wantStrict *testutil.Metric
werr bool
}

type testCaseStream struct {
name string
data []byte
wantBestEffort []testutil.Metric
wantStrict []testutil.Metric
werr int // how many errors we expect in the strict mode?
}

func newUDPSyslogReceiver(address string, bestEffort bool) *Syslog {
return &Syslog{
Address: address,
now: func() time.Time {
return defaultTime
},
BestEffort: bestEffort,
Separator: "_",
}
}

func newTCPSyslogReceiver(address string, keepAlive *internal.Duration, maxConn int, bestEffort bool, f Framing) *Syslog {
d := &internal.Duration{
Duration: defaultReadTimeout,
}
s := &Syslog{
Address: address,
now: func() time.Time {
return defaultTime
},
Framing: f,
ReadTimeout: d,
BestEffort: bestEffort,
Separator: "_",
}
if keepAlive != nil {
s.KeepAlivePeriod = keepAlive
}
if maxConn > 0 {
s.MaxConnections = maxConn
}

return s
}
64 changes: 64 additions & 0 deletions plugins/inputs/syslog/framing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package syslog

import (
"fmt"
"strings"
)

// Framing represents the framing technique we expect the messages to come.
type Framing int

const (
// OctetCounting indicates the transparent framing technique for syslog transport.
OctetCounting Framing = iota
// NonTransparent indicates the non-transparent framing technique for syslog transport.
NonTransparent
)

func (f Framing) String() string {
switch f {
case OctetCounting:
return "OCTET-COUNTING"
case NonTransparent:
return "NON-TRANSPARENT"
}
return ""
}

// UnmarshalTOML implements ability to unmarshal framing from TOML files.
func (f *Framing) UnmarshalTOML(data []byte) (err error) {
return f.UnmarshalText(data)
}

// UnmarshalText implements encoding.TextUnmarshaler
func (f *Framing) UnmarshalText(data []byte) (err error) {
s := string(data)
switch strings.ToUpper(s) {
case `OCTET-COUNTING`:
fallthrough
case `"OCTET-COUNTING"`:
fallthrough
case `'OCTET-COUNTING'`:
*f = OctetCounting
return

case `NON-TRANSPARENT`:
fallthrough
case `"NON-TRANSPARENT"`:
fallthrough
case `'NON-TRANSPARENT'`:
*f = NonTransparent
return
}
*f = -1
return fmt.Errorf("unknown framing")
}

// MarshalText implements encoding.TextMarshaler
func (f Framing) MarshalText() ([]byte, error) {
s := f.String()
if s != "" {
return []byte(s), nil
}
return nil, fmt.Errorf("unknown framing")
}
37 changes: 37 additions & 0 deletions plugins/inputs/syslog/framing_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package syslog

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestFraming(t *testing.T) {
var f1 Framing
f1.UnmarshalTOML([]byte(`"non-transparent"`))
assert.Equal(t, NonTransparent, f1)

var f2 Framing
f2.UnmarshalTOML([]byte(`non-transparent`))
assert.Equal(t, NonTransparent, f2)

var f3 Framing
f3.UnmarshalTOML([]byte(`'non-transparent'`))
assert.Equal(t, NonTransparent, f3)

var f4 Framing
f4.UnmarshalTOML([]byte(`"octet-counting"`))
assert.Equal(t, OctetCounting, f4)

var f5 Framing
f5.UnmarshalTOML([]byte(`octet-counting`))
assert.Equal(t, OctetCounting, f5)

var f6 Framing
f6.UnmarshalTOML([]byte(`'octet-counting'`))
assert.Equal(t, OctetCounting, f6)

var f7 Framing
err := f7.UnmarshalTOML([]byte(`nope`))
assert.Equal(t, Framing(-1), f7)
assert.Error(t, err)
}
Loading

0 comments on commit 1f6d7c6

Please sign in to comment.