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)