From fc311a9fd6985b1c019ed7ab34b7657f6ab86e9b Mon Sep 17 00:00:00 2001 From: Ximalas Date: Fri, 1 Feb 2019 21:44:51 +0100 Subject: [PATCH 1/2] syslog logging: support setting facility in config --- config/config.go | 40 ++++++++++++++++++++++++++++++- config/config_global_test.go | 31 ++++++++++++++++++++++++ daemon/logging/build_logging.go | 1 + daemon/logging/logging_outlets.go | 3 ++- docs/configuration/logging.rst | 2 ++ 5 files changed, 75 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index 3c2131a..eb290b7 100644 --- a/config/config.go +++ b/config/config.go @@ -5,6 +5,7 @@ import ( "github.com/pkg/errors" "github.com/zrepl/yaml-config" "io/ioutil" + "log/syslog" "os" "reflect" "regexp" @@ -38,7 +39,7 @@ func (j JobEnum) Name() string { case *PullJob: name = v.Name case *SourceJob: name = v.Name default: - panic(fmt.Sprintf("unknownn job type %T", v)) + panic(fmt.Sprintf("unknown job type %T", v)) } return name } @@ -258,6 +259,7 @@ type StdoutLoggingOutlet struct { type SyslogLoggingOutlet struct { LoggingOutletCommon `yaml:",inline"` + Facility syslog.Priority `yaml:"facility,default=local0"` RetryInterval time.Duration `yaml:"retry_interval,positive,default=10s"` } @@ -284,6 +286,16 @@ type PrometheusMonitoring struct { Listen string `yaml:"listen"` } +type SyslogFacilityEnum struct { + Ret interface{} +} + +type SyslogFacilityEnumList []SyslogFacilityEnum + +type SyslogFacility struct { + Facility syslog.Priority +} + type GlobalControl struct { SockPath string `yaml:"sockpath,default=/var/run/zrepl/control"` } @@ -389,6 +401,32 @@ func (t *MonitoringEnum) UnmarshalYAML(u func(interface{}, bool) error) (err err return } +func (t *SyslogFacilityEnum) UnmarshalYAML(u func(interface{}, bool) error) (err error) { + t.Ret, err = enumUnmarshal(u, map[string]interface{}{ + "kern": &SyslogFacility{syslog.LOG_KERN}, + "user": &SyslogFacility{syslog.LOG_USER}, + "mail": &SyslogFacility{syslog.LOG_MAIL}, + "daemon": &SyslogFacility{syslog.LOG_DAEMON}, + "auth": &SyslogFacility{syslog.LOG_AUTH}, + "syslog": &SyslogFacility{syslog.LOG_SYSLOG}, + "lpr": &SyslogFacility{syslog.LOG_LPR}, + "news": &SyslogFacility{syslog.LOG_NEWS}, + "uucp": &SyslogFacility{syslog.LOG_UUCP}, + "cron": &SyslogFacility{syslog.LOG_CRON}, + "authpriv": &SyslogFacility{syslog.LOG_AUTHPRIV}, + "ftp": &SyslogFacility{syslog.LOG_FTP}, + "local0": &SyslogFacility{syslog.LOG_LOCAL0}, + "local1": &SyslogFacility{syslog.LOG_LOCAL1}, + "local2": &SyslogFacility{syslog.LOG_LOCAL2}, + "local3": &SyslogFacility{syslog.LOG_LOCAL3}, + "local4": &SyslogFacility{syslog.LOG_LOCAL4}, + "local5": &SyslogFacility{syslog.LOG_LOCAL5}, + "local6": &SyslogFacility{syslog.LOG_LOCAL6}, + "local7": &SyslogFacility{syslog.LOG_LOCAL7}, + }) + return +} + var ConfigFileDefaultLocations = []string{ "/etc/zrepl/zrepl.yml", "/usr/local/etc/zrepl/zrepl.yml", diff --git a/config/config_global_test.go b/config/config_global_test.go index e14b936..a6c4f7b 100644 --- a/config/config_global_test.go +++ b/config/config_global_test.go @@ -1,9 +1,11 @@ package config import ( + "fmt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zrepl/yaml-config" + "log/syslog" "testing" ) @@ -72,6 +74,35 @@ global: assert.Equal(t, ":9091", conf.Global.Monitoring[0].Ret.(*PrometheusMonitoring).Listen) } +func TestSyslogLoggingOutletFacility(t *testing.T) { + type SyslogFacilityPriority struct { + Facility string + Priority syslog.Priority + } + syslogFacilitiesPriorities := []SyslogFacilityPriority{ + {"kern", syslog.LOG_KERN}, {"daemon", syslog.LOG_DAEMON}, {"auth", syslog.LOG_AUTH}, + {"syslog", syslog.LOG_SYSLOG}, {"lpr", syslog.LOG_LPR}, {"news", syslog.LOG_NEWS}, + {"uucp", syslog.LOG_UUCP}, {"cron", syslog.LOG_CRON}, {"authpriv", syslog.LOG_AUTHPRIV}, + {"ftp", syslog.LOG_FTP}, {"local0", syslog.LOG_LOCAL0}, {"local1", syslog.LOG_LOCAL1}, + {"local2", syslog.LOG_LOCAL2}, {"local3", syslog.LOG_LOCAL3}, {"local4", syslog.LOG_LOCAL4}, + {"local5", syslog.LOG_LOCAL5}, {"local6", syslog.LOG_LOCAL6}, {"local7", syslog.LOG_LOCAL7}, + } + + for _, sFP := range syslogFacilitiesPriorities { + logcfg := fmt.Sprintf(` +global: + logging: + - type: syslog + level: info + format: human + facility: %s +`, sFP.Facility) + conf := testValidGlobalSection(t, logcfg) + assert.Equal(t, 1, len(*conf.Global.Logging)) + assert.Equal(t, sFP.Priority, (*conf.Global.Logging)[0].Ret.(*SyslogLoggingOutlet).Facility) + } +} + func TestLoggingOutletEnumList_SetDefaults(t *testing.T) { e := &LoggingOutletEnumList{} var i yaml.Defaulter = e diff --git a/daemon/logging/build_logging.go b/daemon/logging/build_logging.go index bcefec5..e4c2634 100644 --- a/daemon/logging/build_logging.go +++ b/daemon/logging/build_logging.go @@ -222,6 +222,7 @@ func parseSyslogOutlet(in *config.SyslogLoggingOutlet, formatter EntryFormatter) out = &SyslogOutlet{} out.Formatter = formatter out.Formatter.SetMetadataFlags(MetadataNone) + out.Facility = in.Facility out.RetryInterval = in.RetryInterval return out, nil } diff --git a/daemon/logging/logging_outlets.go b/daemon/logging/logging_outlets.go index 5a00d42..b03d008 100644 --- a/daemon/logging/logging_outlets.go +++ b/daemon/logging/logging_outlets.go @@ -124,6 +124,7 @@ func (h *TCPOutlet) WriteEntry(e logger.Entry) error { type SyslogOutlet struct { Formatter EntryFormatter RetryInterval time.Duration + Facility syslog.Priority writer *syslog.Writer lastConnectAttempt time.Time } @@ -142,7 +143,7 @@ func (o *SyslogOutlet) WriteEntry(entry logger.Entry) error { if now.Sub(o.lastConnectAttempt) < o.RetryInterval { return nil // not an error toward logger } - o.writer, err = syslog.New(syslog.LOG_LOCAL0, "zrepl") + o.writer, err = syslog.New(o.Facility, "zrepl") o.lastConnectAttempt = time.Now() if err != nil { o.writer = nil diff --git a/docs/configuration/logging.rst b/docs/configuration/logging.rst index f1a8466..a9077bb 100644 --- a/docs/configuration/logging.rst +++ b/docs/configuration/logging.rst @@ -147,6 +147,8 @@ Can only be specified once. - minimum :ref:`log level ` * - ``format`` - output :ref:`format ` + * - ``facility`` + - Which syslog facility to use (default = ``local0``) * - ``retry_interval`` - Interval between reconnection attempts to syslog (default = 0) From a0f301d7005835636d369be40e18c76357fa847e Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Fri, 15 Mar 2019 17:44:41 +0100 Subject: [PATCH 2/2] syslog logging: fix priority parsing + add test for default facility --- config/config.go | 70 ++++++++++++++++++--------------- config/config_global_test.go | 3 +- daemon/logging/build_logging.go | 3 +- 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/config/config.go b/config/config.go index eb290b7..7ff0ca9 100644 --- a/config/config.go +++ b/config/config.go @@ -259,7 +259,7 @@ type StdoutLoggingOutlet struct { type SyslogLoggingOutlet struct { LoggingOutletCommon `yaml:",inline"` - Facility syslog.Priority `yaml:"facility,default=local0"` + Facility *SyslogFacility `yaml:"facility,optional,fromdefaults"` RetryInterval time.Duration `yaml:"retry_interval,positive,default=10s"` } @@ -286,15 +286,13 @@ type PrometheusMonitoring struct { Listen string `yaml:"listen"` } -type SyslogFacilityEnum struct { - Ret interface{} +type SyslogFacility syslog.Priority + +func (f *SyslogFacility) SetDefault() { + *f = SyslogFacility(syslog.LOG_LOCAL0) } -type SyslogFacilityEnumList []SyslogFacilityEnum - -type SyslogFacility struct { - Facility syslog.Priority -} +var _ yaml.Defaulter = (*SyslogFacility)(nil) type GlobalControl struct { SockPath string `yaml:"sockpath,default=/var/run/zrepl/control"` @@ -401,30 +399,38 @@ func (t *MonitoringEnum) UnmarshalYAML(u func(interface{}, bool) error) (err err return } -func (t *SyslogFacilityEnum) UnmarshalYAML(u func(interface{}, bool) error) (err error) { - t.Ret, err = enumUnmarshal(u, map[string]interface{}{ - "kern": &SyslogFacility{syslog.LOG_KERN}, - "user": &SyslogFacility{syslog.LOG_USER}, - "mail": &SyslogFacility{syslog.LOG_MAIL}, - "daemon": &SyslogFacility{syslog.LOG_DAEMON}, - "auth": &SyslogFacility{syslog.LOG_AUTH}, - "syslog": &SyslogFacility{syslog.LOG_SYSLOG}, - "lpr": &SyslogFacility{syslog.LOG_LPR}, - "news": &SyslogFacility{syslog.LOG_NEWS}, - "uucp": &SyslogFacility{syslog.LOG_UUCP}, - "cron": &SyslogFacility{syslog.LOG_CRON}, - "authpriv": &SyslogFacility{syslog.LOG_AUTHPRIV}, - "ftp": &SyslogFacility{syslog.LOG_FTP}, - "local0": &SyslogFacility{syslog.LOG_LOCAL0}, - "local1": &SyslogFacility{syslog.LOG_LOCAL1}, - "local2": &SyslogFacility{syslog.LOG_LOCAL2}, - "local3": &SyslogFacility{syslog.LOG_LOCAL3}, - "local4": &SyslogFacility{syslog.LOG_LOCAL4}, - "local5": &SyslogFacility{syslog.LOG_LOCAL5}, - "local6": &SyslogFacility{syslog.LOG_LOCAL6}, - "local7": &SyslogFacility{syslog.LOG_LOCAL7}, - }) - return +func (t *SyslogFacility) UnmarshalYAML(u func(interface{}, bool) error) (err error) { + var s string + if err := u(&s, true); err != nil { + return err + } + var level syslog.Priority + switch s { + case "kern": level = syslog.LOG_KERN + case "user": level = syslog.LOG_USER + case "mail": level = syslog.LOG_MAIL + case "daemon": level = syslog.LOG_DAEMON + case "auth": level = syslog.LOG_AUTH + case "syslog": level = syslog.LOG_SYSLOG + case "lpr": level = syslog.LOG_LPR + case "news": level = syslog.LOG_NEWS + case "uucp": level = syslog.LOG_UUCP + case "cron": level = syslog.LOG_CRON + case "authpriv": level = syslog.LOG_AUTHPRIV + case "ftp": level = syslog.LOG_FTP + case "local0": level = syslog.LOG_LOCAL0 + case "local1": level = syslog.LOG_LOCAL1 + case "local2": level = syslog.LOG_LOCAL2 + case "local3": level = syslog.LOG_LOCAL3 + case "local4": level = syslog.LOG_LOCAL4 + case "local5": level = syslog.LOG_LOCAL5 + case "local6": level = syslog.LOG_LOCAL6 + case "local7": level = syslog.LOG_LOCAL7 + default: + return fmt.Errorf("invalid syslog level: %q", s) + } + *t = SyslogFacility(level) + return nil } var ConfigFileDefaultLocations = []string{ diff --git a/config/config_global_test.go b/config/config_global_test.go index a6c4f7b..51204b0 100644 --- a/config/config_global_test.go +++ b/config/config_global_test.go @@ -80,6 +80,7 @@ func TestSyslogLoggingOutletFacility(t *testing.T) { Priority syslog.Priority } syslogFacilitiesPriorities := []SyslogFacilityPriority{ + {"", syslog.LOG_LOCAL0}, // default {"kern", syslog.LOG_KERN}, {"daemon", syslog.LOG_DAEMON}, {"auth", syslog.LOG_AUTH}, {"syslog", syslog.LOG_SYSLOG}, {"lpr", syslog.LOG_LPR}, {"news", syslog.LOG_NEWS}, {"uucp", syslog.LOG_UUCP}, {"cron", syslog.LOG_CRON}, {"authpriv", syslog.LOG_AUTHPRIV}, @@ -99,7 +100,7 @@ global: `, sFP.Facility) conf := testValidGlobalSection(t, logcfg) assert.Equal(t, 1, len(*conf.Global.Logging)) - assert.Equal(t, sFP.Priority, (*conf.Global.Logging)[0].Ret.(*SyslogLoggingOutlet).Facility) + assert.True(t, SyslogFacility(sFP.Priority) == *(*conf.Global.Logging)[0].Ret.(*SyslogLoggingOutlet).Facility) } } diff --git a/daemon/logging/build_logging.go b/daemon/logging/build_logging.go index e4c2634..ce90d3c 100644 --- a/daemon/logging/build_logging.go +++ b/daemon/logging/build_logging.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "crypto/x509" + "log/syslog" "os" "github.com/mattn/go-isatty" @@ -222,7 +223,7 @@ func parseSyslogOutlet(in *config.SyslogLoggingOutlet, formatter EntryFormatter) out = &SyslogOutlet{} out.Formatter = formatter out.Formatter.SetMetadataFlags(MetadataNone) - out.Facility = in.Facility + out.Facility = syslog.Priority(*in.Facility) out.RetryInterval = in.RetryInterval return out, nil }