summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/logr/v2/targets/syslog.go
blob: fc3fcc5feed609f53b13fae7680709d487330e36 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// +build !windows,!nacl,!plan9

package targets

import (
	"crypto/tls"
	"errors"
	"fmt"

	"github.com/mattermost/logr/v2"
	syslog "github.com/wiggin77/srslog"
)

// Syslog outputs log records to local or remote syslog.
type Syslog struct {
	params *SyslogOptions
	writer *syslog.Writer
}

// SyslogOptions provides parameters for dialing a syslog daemon.
type SyslogOptions struct {
	IP       string `json:"ip,omitempty"` // deprecated
	Host     string `json:"host"`
	Port     int    `json:"port"`
	TLS      bool   `json:"tls"`
	Cert     string `json:"cert"`
	Insecure bool   `json:"insecure"`
	Tag      string `json:"tag"`
}

func (so SyslogOptions) CheckValid() error {
	if so.Host == "" && so.IP == "" {
		return errors.New("missing host")
	}
	if so.Port == 0 {
		return errors.New("missing port")
	}
	return nil
}

// NewSyslogTarget creates a target capable of outputting log records to remote or local syslog, with or without TLS.
func NewSyslogTarget(params *SyslogOptions) (*Syslog, error) {
	if params == nil {
		return nil, errors.New("params cannot be nil")
	}

	s := &Syslog{
		params: params,
	}
	return s, nil
}

// Init is called once to initialize the target.
func (s *Syslog) Init() error {
	network := "tcp"
	var config *tls.Config

	if s.params.TLS {
		network = "tcp+tls"
		config = &tls.Config{InsecureSkipVerify: s.params.Insecure}
		if s.params.Cert != "" {
			pool, err := GetCertPool(s.params.Cert)
			if err != nil {
				return err
			}
			config.RootCAs = pool
		}
	}
	raddr := fmt.Sprintf("%s:%d", s.params.IP, s.params.Port)
	if raddr == ":0" {
		// If no IP:port provided then connect to local syslog.
		raddr = ""
		network = ""
	}

	var err error
	s.writer, err = syslog.DialWithTLSConfig(network, raddr, syslog.LOG_INFO, s.params.Tag, config)
	return err
}

// Write outputs bytes to this file target.
func (s *Syslog) Write(p []byte, rec *logr.LogRec) (int, error) {
	txt := string(p)
	n := len(txt)
	var err error

	switch rec.Level() {
	case logr.Panic, logr.Fatal:
		err = s.writer.Crit(txt)
	case logr.Error:
		err = s.writer.Err(txt)
	case logr.Warn:
		err = s.writer.Warning(txt)
	case logr.Debug, logr.Trace:
		err = s.writer.Debug(txt)
	default:
		// logr.Info plus all custom levels.
		err = s.writer.Info(txt)
	}

	if err != nil {
		n = 0
		// syslog writer will try to reconnect.
	}
	return n, err
}

// Shutdown is called once to free/close any resources.
// Target queue is already drained when this is called.
func (s *Syslog) Shutdown() error {
	return s.writer.Close()
}