Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
333
plugins/inputs/syslog/syslog.go
Normal file
333
plugins/inputs/syslog/syslog.go
Normal file
|
@ -0,0 +1,333 @@
|
|||
//go:generate ../../../tools/config_includer/generator
|
||||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package syslog
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/leodido/go-syslog/v4"
|
||||
"github.com/leodido/go-syslog/v4/nontransparent"
|
||||
"github.com/leodido/go-syslog/v4/octetcounting"
|
||||
"github.com/leodido/go-syslog/v4/rfc3164"
|
||||
"github.com/leodido/go-syslog/v4/rfc5424"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/common/socket"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
const readTimeoutMsg = "Read timeout set! Connections, inactive for the set duration, will be closed!"
|
||||
|
||||
type Syslog struct {
|
||||
Address string `toml:"server"`
|
||||
Framing string `toml:"framing"`
|
||||
SyslogStandard string `toml:"syslog_standard"`
|
||||
Trailer nontransparent.TrailerType `toml:"trailer"`
|
||||
BestEffort bool `toml:"best_effort"`
|
||||
Separator string `toml:"sdparam_separator"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
socket.Config
|
||||
|
||||
mu sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
|
||||
url *url.URL
|
||||
socket *socket.Socket
|
||||
}
|
||||
|
||||
func (*Syslog) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (s *Syslog) Init() error {
|
||||
// Check settings and set defaults
|
||||
switch s.Framing {
|
||||
case "":
|
||||
s.Framing = "octet-counting"
|
||||
case "octet-counting", "non-transparent":
|
||||
default:
|
||||
return fmt.Errorf("invalid 'framing' %q", s.Framing)
|
||||
}
|
||||
|
||||
switch s.SyslogStandard {
|
||||
case "":
|
||||
s.SyslogStandard = "RFC5424"
|
||||
case "RFC3164", "RFC5424":
|
||||
default:
|
||||
return fmt.Errorf("invalid 'syslog_standard' %q", s.SyslogStandard)
|
||||
}
|
||||
|
||||
if s.Separator == "" {
|
||||
s.Separator = "_"
|
||||
}
|
||||
|
||||
// Check and parse address, set default if necessary
|
||||
if s.Address == "" {
|
||||
s.Address = "tcp://127.0.0.1:6514"
|
||||
}
|
||||
|
||||
if !strings.Contains(s.Address, "://") {
|
||||
return fmt.Errorf("missing protocol within address %q", s.Address)
|
||||
}
|
||||
|
||||
u, err := url.Parse(s.Address)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing address %q failed: %w", s.Address, err)
|
||||
}
|
||||
|
||||
// Check if we do have a port and add the default one if not
|
||||
if u.Port() == "" {
|
||||
u.Host += ":6514"
|
||||
}
|
||||
s.url = u
|
||||
|
||||
switch s.url.Scheme {
|
||||
case "tcp", "tcp4", "tcp6", "unix", "unixpacket":
|
||||
if s.ReadTimeout > 0 {
|
||||
s.Log.Warn(readTimeoutMsg)
|
||||
}
|
||||
case "udp", "udp4", "udp6", "ip", "ip4", "ip6", "unixgram":
|
||||
default:
|
||||
return fmt.Errorf("unknown protocol %q in %q", u.Scheme, s.Address)
|
||||
}
|
||||
|
||||
// Create a socket
|
||||
sock, err := s.Config.NewSocket(u.String(), nil, s.Log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.socket = sock
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Syslog) Start(acc telegraf.Accumulator) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
// Setup the listener
|
||||
if err := s.socket.Setup(); err != nil {
|
||||
return err
|
||||
}
|
||||
addr := s.socket.Address()
|
||||
s.Log.Infof("Listening on %s://%s", addr.Network(), addr.String())
|
||||
|
||||
// Setup the callbacks and start listening
|
||||
onError := func(err error) {
|
||||
acc.AddError(err)
|
||||
}
|
||||
switch s.url.Scheme {
|
||||
case "tcp", "tcp4", "tcp6", "unix", "unixpacket":
|
||||
onConnection := s.createStreamDataHandler(acc)
|
||||
s.socket.ListenConnection(onConnection, onError)
|
||||
case "udp", "udp4", "udp6", "ip", "ip4", "ip6", "unixgram":
|
||||
onData := s.createDatagramDataHandler(acc)
|
||||
s.socket.Listen(onData, onError)
|
||||
default:
|
||||
return fmt.Errorf("unknown protocol %q in %q", s.url.Scheme, s.Address)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*Syslog) Gather(telegraf.Accumulator) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Syslog) Stop() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.socket.Close()
|
||||
s.wg.Wait()
|
||||
}
|
||||
|
||||
func (s *Syslog) createStreamDataHandler(acc telegraf.Accumulator) socket.CallbackConnection {
|
||||
// Create parser options
|
||||
var opts []syslog.ParserOption
|
||||
if s.BestEffort {
|
||||
opts = append(opts, syslog.WithBestEffort())
|
||||
}
|
||||
if s.Framing == "non-transparent" {
|
||||
opts = append(opts, nontransparent.WithTrailer(s.Trailer))
|
||||
}
|
||||
|
||||
return func(src net.Addr, reader io.ReadCloser) {
|
||||
// Create the parser depending on transport framing and other settings
|
||||
var parser syslog.Parser
|
||||
switch s.Framing {
|
||||
case "octet-counting":
|
||||
parser = octetcounting.NewParser(opts...)
|
||||
case "non-transparent":
|
||||
parser = nontransparent.NewParser(opts...)
|
||||
}
|
||||
|
||||
// Remove port from address
|
||||
var addr string
|
||||
if src.Network() != "unix" {
|
||||
var err error
|
||||
if addr, _, err = net.SplitHostPort(src.String()); err != nil {
|
||||
addr = src.String()
|
||||
}
|
||||
}
|
||||
|
||||
parser.WithListener(func(r *syslog.Result) {
|
||||
if r.Error != nil {
|
||||
acc.AddError(r.Error)
|
||||
}
|
||||
if r.Message == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Extract message information
|
||||
acc.AddFields("syslog", fields(r.Message, s.Separator), tags(r.Message, addr))
|
||||
})
|
||||
parser.Parse(reader)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Syslog) createDatagramDataHandler(acc telegraf.Accumulator) socket.CallbackData {
|
||||
// Create the parser depending on syslog standard and other settings
|
||||
var parser syslog.Machine
|
||||
switch s.SyslogStandard {
|
||||
case "RFC3164":
|
||||
parser = rfc3164.NewParser(rfc3164.WithYear(rfc3164.CurrentYear{}))
|
||||
case "RFC5424":
|
||||
parser = rfc5424.NewParser()
|
||||
}
|
||||
if s.BestEffort {
|
||||
parser.WithBestEffort()
|
||||
}
|
||||
|
||||
// Return the OnData function
|
||||
return func(src net.Addr, data []byte, _ time.Time) {
|
||||
message, err := parser.Parse(data)
|
||||
if err != nil {
|
||||
acc.AddError(err)
|
||||
} else if message == nil {
|
||||
acc.AddError(fmt.Errorf("unable to parse message: %s", string(data)))
|
||||
}
|
||||
if message == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Extract message information
|
||||
var addr string
|
||||
if src.Network() != "unixgram" {
|
||||
var err error
|
||||
if addr, _, err = net.SplitHostPort(src.String()); err != nil {
|
||||
addr = src.String()
|
||||
}
|
||||
}
|
||||
acc.AddFields("syslog", fields(message, s.Separator), tags(message, addr))
|
||||
}
|
||||
}
|
||||
|
||||
func tags(msg syslog.Message, src string) map[string]string {
|
||||
// Extract message information
|
||||
tags := map[string]string{
|
||||
"severity": *msg.SeverityShortLevel(),
|
||||
"facility": *msg.FacilityLevel(),
|
||||
}
|
||||
|
||||
if src != "" {
|
||||
tags["source"] = src
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case *rfc5424.SyslogMessage:
|
||||
if msg.Hostname != nil {
|
||||
tags["hostname"] = *msg.Hostname
|
||||
}
|
||||
if msg.Appname != nil {
|
||||
tags["appname"] = *msg.Appname
|
||||
}
|
||||
case *rfc3164.SyslogMessage:
|
||||
if msg.Hostname != nil {
|
||||
tags["hostname"] = *msg.Hostname
|
||||
}
|
||||
if msg.Appname != nil {
|
||||
tags["appname"] = *msg.Appname
|
||||
}
|
||||
}
|
||||
|
||||
return tags
|
||||
}
|
||||
|
||||
func fields(msg syslog.Message, separator string) map[string]interface{} {
|
||||
var fields map[string]interface{}
|
||||
switch msg := msg.(type) {
|
||||
case *rfc5424.SyslogMessage:
|
||||
fields = map[string]interface{}{
|
||||
"facility_code": int(*msg.Facility),
|
||||
"severity_code": int(*msg.Severity),
|
||||
"version": msg.Version,
|
||||
}
|
||||
if msg.Timestamp != nil {
|
||||
fields["timestamp"] = (*msg.Timestamp).UnixNano()
|
||||
}
|
||||
if msg.ProcID != nil {
|
||||
fields["procid"] = *msg.ProcID
|
||||
}
|
||||
if msg.MsgID != nil {
|
||||
fields["msgid"] = *msg.MsgID
|
||||
}
|
||||
if msg.Message != nil {
|
||||
fields["message"] = strings.TrimRightFunc(*msg.Message, func(r rune) bool {
|
||||
return unicode.IsSpace(r)
|
||||
})
|
||||
}
|
||||
if msg.StructuredData != nil {
|
||||
for sdid, sdparams := range *msg.StructuredData {
|
||||
if len(sdparams) == 0 {
|
||||
// When SD-ID does not have params we indicate its presence with a bool
|
||||
fields[sdid] = true
|
||||
continue
|
||||
}
|
||||
for k, v := range sdparams {
|
||||
fields[sdid+separator+k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case *rfc3164.SyslogMessage:
|
||||
fields = map[string]interface{}{
|
||||
"facility_code": int(*msg.Facility),
|
||||
"severity_code": int(*msg.Severity),
|
||||
}
|
||||
if msg.Timestamp != nil {
|
||||
fields["timestamp"] = (*msg.Timestamp).UnixNano()
|
||||
}
|
||||
if msg.ProcID != nil {
|
||||
fields["procid"] = *msg.ProcID
|
||||
}
|
||||
if msg.MsgID != nil {
|
||||
fields["msgid"] = *msg.MsgID
|
||||
}
|
||||
if msg.Message != nil {
|
||||
fields["message"] = strings.TrimRightFunc(*msg.Message, func(r rune) bool {
|
||||
return unicode.IsSpace(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("syslog", func() telegraf.Input {
|
||||
return &Syslog{
|
||||
Trailer: nontransparent.LF,
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue