mirror of
https://github.com/zrepl/zrepl.git
synced 2025-01-05 05:48:57 +01:00
build logger from new config
This commit is contained in:
parent
38bb78b642
commit
13dc63bd23
@ -1,30 +1,33 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/zrepl/yaml-config"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"os"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/zrepl/yaml-config"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NodeEnum struct {
|
type Config struct {
|
||||||
|
Jobs []JobEnum `yaml:"jobs"`
|
||||||
|
Global Global `yaml:"global"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JobEnum struct {
|
||||||
Ret interface{}
|
Ret interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type PushNode struct {
|
type PushJob struct {
|
||||||
Type string `yaml:"type"`
|
Type string `yaml:"type"`
|
||||||
Replication PushReplication `yaml:"replication"`
|
Replication PushReplication `yaml:"replication"`
|
||||||
Snapshotting Snapshotting `yaml:"snapshotting"`
|
Snapshotting Snapshotting `yaml:"snapshotting"`
|
||||||
Pruning Pruning `yaml:"pruning"`
|
Pruning Pruning `yaml:"pruning"`
|
||||||
Global Global `yaml:"global"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SinkNode struct {
|
type SinkJob struct {
|
||||||
Type string `yaml:"type"`
|
Type string `yaml:"type"`
|
||||||
Replication SinkReplication `yaml:"replication"`
|
Replication SinkReplication `yaml:"replication"`
|
||||||
Global Global `yaml:"global"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PushReplication struct {
|
type PushReplication struct {
|
||||||
@ -48,7 +51,7 @@ type Pruning struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Global struct {
|
type Global struct {
|
||||||
Logging []LoggingOutlet `yaml:"logging"`
|
Logging []LoggingOutletEnum `yaml:"logging"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConnectEnum struct {
|
type ConnectEnum struct {
|
||||||
@ -104,26 +107,40 @@ type PruneGrid struct {
|
|||||||
Grid string `yaml:"grid"`
|
Grid string `yaml:"grid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoggingOutlet struct {
|
|
||||||
Outlet LoggingOutletEnum `yaml:"outlet"`
|
|
||||||
Level string `yaml:"level"`
|
|
||||||
Format string `yaml:"format"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoggingOutletEnum struct {
|
type LoggingOutletEnum struct {
|
||||||
Ret interface{}
|
Ret interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type StdoutLoggingOutlet struct {
|
type LoggingOutletCommon struct {
|
||||||
Type string `yaml:"type"`
|
Type string `yaml:"type"`
|
||||||
|
Level string `yaml:"level"`
|
||||||
|
Format string `yaml:"format"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StdoutLoggingOutlet struct {
|
||||||
|
LoggingOutletCommon `yaml:",inline"`
|
||||||
Time bool `yaml:"time"`
|
Time bool `yaml:"time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SyslogLoggingOutlet struct {
|
type SyslogLoggingOutlet struct {
|
||||||
Type string `yaml:"type"`
|
LoggingOutletCommon `yaml:",inline"`
|
||||||
RetryInterval time.Duration `yaml:"retry_interval"`
|
RetryInterval time.Duration `yaml:"retry_interval"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TCPLoggingOutlet struct {
|
||||||
|
LoggingOutletCommon `yaml:",inline"`
|
||||||
|
Address string `yaml:"address"` //TODO required
|
||||||
|
Net string `yaml:"net"` //TODO default tcp
|
||||||
|
RetryInterval time.Duration `yaml:"retry_interval"`
|
||||||
|
TLS *TCPLoggingOutletTLS
|
||||||
|
}
|
||||||
|
|
||||||
|
type TCPLoggingOutletTLS struct {
|
||||||
|
CA string `yaml:"ca"`
|
||||||
|
Cert string `yaml:"cert"`
|
||||||
|
Key string `yaml:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
func enumUnmarshal(u func(interface{}, bool) error, types map[string]interface{}) (interface{}, error) {
|
func enumUnmarshal(u func(interface{}, bool) error, types map[string]interface{}) (interface{}, error) {
|
||||||
var in struct {
|
var in struct {
|
||||||
Type string
|
Type string
|
||||||
@ -145,10 +162,10 @@ func enumUnmarshal(u func(interface{}, bool) error, types map[string]interface{}
|
|||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *NodeEnum) UnmarshalYAML(u func(interface{}, bool) error) (err error) {
|
func (t *JobEnum) UnmarshalYAML(u func(interface{}, bool) error) (err error) {
|
||||||
t.Ret, err = enumUnmarshal(u, map[string]interface{}{
|
t.Ret, err = enumUnmarshal(u, map[string]interface{}{
|
||||||
"push": &PushNode{},
|
"push": &PushJob{},
|
||||||
"sink": &SinkNode{},
|
"sink": &SinkJob{},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -182,6 +199,7 @@ func (t *LoggingOutletEnum) UnmarshalYAML(u func(interface{}, bool) error) (err
|
|||||||
t.Ret, err = enumUnmarshal(u, map[string]interface{}{
|
t.Ret, err = enumUnmarshal(u, map[string]interface{}{
|
||||||
"stdout": &StdoutLoggingOutlet{},
|
"stdout": &StdoutLoggingOutlet{},
|
||||||
"syslog": &SyslogLoggingOutlet{},
|
"syslog": &SyslogLoggingOutlet{},
|
||||||
|
"tcp": &TCPLoggingOutlet{},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -191,7 +209,7 @@ var ConfigFileDefaultLocations = []string{
|
|||||||
"/usr/local/etc/zrepl/zrepl.yml",
|
"/usr/local/etc/zrepl/zrepl.yml",
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseConfig(path string) (i NodeEnum, err error) {
|
func ParseConfig(path string) (i Config, err error) {
|
||||||
|
|
||||||
if path == "" {
|
if path == "" {
|
||||||
// Try default locations
|
// Try default locations
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"github.com/kr/pretty"
|
"github.com/kr/pretty"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSampleConfigsAreParsedWithoutErrors(t *testing.T) {
|
func TestSampleConfigsAreParsedWithoutErrors(t *testing.T) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
type: push
|
jobs:
|
||||||
|
- type: push
|
||||||
replication:
|
replication:
|
||||||
connect:
|
connect:
|
||||||
type: tcp
|
type: tcp
|
||||||
@ -23,8 +24,7 @@ pruning:
|
|||||||
grid: 1x1h(keep=all) | 24x1h | 35x1d | 6x30d
|
grid: 1x1h(keep=all) | 24x1h | 35x1d | 6x30d
|
||||||
global:
|
global:
|
||||||
logging:
|
logging:
|
||||||
- outlet:
|
- type: "stdout"
|
||||||
type: "stdout"
|
|
||||||
time: true
|
time: true
|
||||||
level: "warn"
|
level: "warn"
|
||||||
format: "human"
|
format: "human"
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
type: sink
|
jobs:
|
||||||
|
- type: sink
|
||||||
replication:
|
replication:
|
||||||
root_dataset: "pool2/backup_laptops"
|
root_dataset: "pool2/backup_laptops"
|
||||||
serve:
|
serve:
|
||||||
@ -9,7 +10,11 @@ replication:
|
|||||||
key: "key.pem"
|
key: "key.pem"
|
||||||
global:
|
global:
|
||||||
logging:
|
logging:
|
||||||
- outlet:
|
- type: "tcp"
|
||||||
type: "syslog"
|
address: "123.123.123.123:1234"
|
||||||
|
tls:
|
||||||
|
ca: "ca.pem"
|
||||||
|
cert: "cert.pem"
|
||||||
|
key: "key.pem"
|
||||||
level: "warn"
|
level: "warn"
|
||||||
format: "human"
|
format: "human"
|
||||||
|
@ -4,12 +4,11 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/zrepl/zrepl/cmd/config"
|
||||||
"github.com/zrepl/zrepl/cmd/tlsconf"
|
"github.com/zrepl/zrepl/cmd/tlsconf"
|
||||||
"github.com/zrepl/zrepl/logger"
|
"github.com/zrepl/zrepl/logger"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoggingConfig struct {
|
type LoggingConfig struct {
|
||||||
@ -26,16 +25,12 @@ const (
|
|||||||
MetadataAll MetadataFlags = ^0
|
MetadataAll MetadataFlags = ^0
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseLogging(i interface{}) (c *LoggingConfig, err error) {
|
func parseLogging(in []config.LoggingOutletEnum) (c *LoggingConfig, err error) {
|
||||||
|
|
||||||
c = &LoggingConfig{}
|
c = &LoggingConfig{}
|
||||||
c.Outlets = logger.NewOutlets()
|
c.Outlets = logger.NewOutlets()
|
||||||
|
|
||||||
var asList []interface{}
|
if len(in) == 0 {
|
||||||
if err = mapstructure.Decode(i, &asList); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "mapstructure error")
|
|
||||||
}
|
|
||||||
if len(asList) == 0 {
|
|
||||||
// Default config
|
// Default config
|
||||||
out := WriterOutlet{&HumanFormatter{}, os.Stdout}
|
out := WriterOutlet{&HumanFormatter{}, os.Stdout}
|
||||||
c.Outlets.Add(out, logger.Warn)
|
c.Outlets.Add(out, logger.Warn)
|
||||||
@ -43,7 +38,7 @@ func parseLogging(i interface{}) (c *LoggingConfig, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var syslogOutlets, stdoutOutlets int
|
var syslogOutlets, stdoutOutlets int
|
||||||
for lei, le := range asList {
|
for lei, le := range in {
|
||||||
|
|
||||||
outlet, minLevel, err := parseOutlet(le)
|
outlet, minLevel, err := parseOutlet(le)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -95,56 +90,52 @@ func parseLogFormat(i interface{}) (f EntryFormatter, err error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseOutlet(i interface{}) (o logger.Outlet, level logger.Level, err error) {
|
func parseOutlet(in config.LoggingOutletEnum) (o logger.Outlet, level logger.Level, err error) {
|
||||||
|
|
||||||
var in struct {
|
parseCommon := func(common config.LoggingOutletCommon) (logger.Level, EntryFormatter, error) {
|
||||||
Outlet string
|
if common.Level == "" || common.Format == "" {
|
||||||
Level string
|
return 0, nil, errors.Errorf("must specify 'level' and 'format' field")
|
||||||
Format string
|
|
||||||
}
|
|
||||||
if err = mapstructure.Decode(i, &in); err != nil {
|
|
||||||
err = errors.Wrap(err, "mapstructure error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if in.Outlet == "" || in.Level == "" || in.Format == "" {
|
|
||||||
err = errors.Errorf("must specify 'outlet', 'level' and 'format' field")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
minLevel, err := logger.ParseLevel(in.Level)
|
minLevel, err := logger.ParseLevel(common.Level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "cannot parse 'level' field")
|
return 0, nil, errors.Wrap(err, "cannot parse 'level' field")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
formatter, err := parseLogFormat(in.Format)
|
formatter, err := parseLogFormat(common.Format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "cannot parse")
|
return 0, nil, errors.Wrap(err, "cannot parse 'formatter' field")
|
||||||
return
|
}
|
||||||
|
return minLevel, formatter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch in.Outlet {
|
var f EntryFormatter
|
||||||
case "stdout":
|
|
||||||
o, err = parseStdoutOutlet(i, formatter)
|
switch v := in.Ret.(type) {
|
||||||
case "tcp":
|
case config.StdoutLoggingOutlet:
|
||||||
o, err = parseTCPOutlet(i, formatter)
|
level, f, err = parseCommon(v.LoggingOutletCommon)
|
||||||
case "syslog":
|
if err != nil {
|
||||||
o, err = parseSyslogOutlet(i, formatter)
|
break
|
||||||
|
}
|
||||||
|
o, err = parseStdoutOutlet(v, f)
|
||||||
|
case config.TCPLoggingOutlet:
|
||||||
|
level, f, err = parseCommon(v.LoggingOutletCommon)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
o, err = parseTCPOutlet(v, f)
|
||||||
|
case config.SyslogLoggingOutlet:
|
||||||
|
level, f, err = parseCommon(v.LoggingOutletCommon)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
o, err = parseSyslogOutlet(v, f)
|
||||||
default:
|
default:
|
||||||
err = errors.Errorf("unknown outlet type '%s'", in.Outlet)
|
panic(v)
|
||||||
}
|
}
|
||||||
return o, minLevel, err
|
return o, level, err
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseStdoutOutlet(i interface{}, formatter EntryFormatter) (WriterOutlet, error) {
|
|
||||||
|
|
||||||
var in struct {
|
|
||||||
Time bool
|
|
||||||
}
|
|
||||||
if err := mapstructure.Decode(i, &in); err != nil {
|
|
||||||
return WriterOutlet{}, errors.Wrap(err, "invalid structure for stdout outlet")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseStdoutOutlet(in config.StdoutLoggingOutlet, formatter EntryFormatter) (WriterOutlet, error) {
|
||||||
flags := MetadataAll
|
flags := MetadataAll
|
||||||
writer := os.Stdout
|
writer := os.Stdout
|
||||||
if !isatty.IsTerminal(writer.Fd()) && !in.Time {
|
if !isatty.IsTerminal(writer.Fd()) && !in.Time {
|
||||||
@ -158,54 +149,22 @@ func parseStdoutOutlet(i interface{}, formatter EntryFormatter) (WriterOutlet, e
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTCPOutlet(i interface{}, formatter EntryFormatter) (out *TCPOutlet, err error) {
|
func parseTCPOutlet(in config.TCPLoggingOutlet, formatter EntryFormatter) (out *TCPOutlet, err error) {
|
||||||
|
|
||||||
var in struct {
|
|
||||||
Net string
|
|
||||||
Address string
|
|
||||||
RetryInterval string `mapstructure:"retry_interval"`
|
|
||||||
TLS map[string]interface{}
|
|
||||||
}
|
|
||||||
if err = mapstructure.Decode(i, &in); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "mapstructure error")
|
|
||||||
}
|
|
||||||
|
|
||||||
retryInterval, err := time.ParseDuration(in.RetryInterval)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "cannot parse 'retry_interval'")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(in.Net) == 0 {
|
|
||||||
return nil, errors.New("field 'net' must not be empty")
|
|
||||||
}
|
|
||||||
if len(in.Address) == 0 {
|
|
||||||
return nil, errors.New("field 'address' must not be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
var tlsConfig *tls.Config
|
var tlsConfig *tls.Config
|
||||||
if in.TLS != nil {
|
if in.TLS != nil {
|
||||||
tlsConfig, err = func(m map[string]interface{}, host string) (*tls.Config, error) {
|
tlsConfig, err = func(m *config.TCPLoggingOutletTLS, host string) (*tls.Config, error) {
|
||||||
var in struct {
|
clientCert, err := tls.LoadX509KeyPair(m.Cert, m.Key)
|
||||||
CA string
|
|
||||||
Cert string
|
|
||||||
Key string
|
|
||||||
}
|
|
||||||
if err := mapstructure.Decode(m, &in); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "mapstructure error")
|
|
||||||
}
|
|
||||||
|
|
||||||
clientCert, err := tls.LoadX509KeyPair(in.Cert, in.Key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "cannot load client cert")
|
return nil, errors.Wrap(err, "cannot load client cert")
|
||||||
}
|
}
|
||||||
|
|
||||||
var rootCAs *x509.CertPool
|
var rootCAs *x509.CertPool
|
||||||
if in.CA == "" {
|
if m.CA == "" {
|
||||||
if rootCAs, err = x509.SystemCertPool(); err != nil {
|
if rootCAs, err = x509.SystemCertPool(); err != nil {
|
||||||
return nil, errors.Wrap(err, "cannot open system cert pool")
|
return nil, errors.Wrap(err, "cannot open system cert pool")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rootCAs, err = tlsconf.ParseCAFile(in.CA)
|
rootCAs, err = tlsconf.ParseCAFile(m.CA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "cannot parse CA cert")
|
return nil, errors.Wrap(err, "cannot parse CA cert")
|
||||||
}
|
}
|
||||||
@ -222,30 +181,14 @@ func parseTCPOutlet(i interface{}, formatter EntryFormatter) (out *TCPOutlet, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatter.SetMetadataFlags(MetadataAll)
|
formatter.SetMetadataFlags(MetadataAll)
|
||||||
return NewTCPOutlet(formatter, in.Net, in.Address, tlsConfig, retryInterval), nil
|
return NewTCPOutlet(formatter, in.Net, in.Address, tlsConfig, in.RetryInterval), nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSyslogOutlet(i interface{}, formatter EntryFormatter) (out *SyslogOutlet, err error) {
|
func parseSyslogOutlet(in config.SyslogLoggingOutlet, formatter EntryFormatter) (out *SyslogOutlet, err error) {
|
||||||
|
|
||||||
var in struct {
|
|
||||||
RetryInterval string `mapstructure:"retry_interval"`
|
|
||||||
}
|
|
||||||
if err = mapstructure.Decode(i, &in); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "mapstructure error")
|
|
||||||
}
|
|
||||||
|
|
||||||
out = &SyslogOutlet{}
|
out = &SyslogOutlet{}
|
||||||
out.Formatter = formatter
|
out.Formatter = formatter
|
||||||
out.Formatter.SetMetadataFlags(MetadataNone)
|
out.Formatter.SetMetadataFlags(MetadataNone)
|
||||||
|
out.RetryInterval = in.RetryInterval
|
||||||
out.RetryInterval = 0 // default to 0 as we assume local syslog will just work
|
return out, nil
|
||||||
if in.RetryInterval != "" {
|
|
||||||
out.RetryInterval, err = time.ParseDuration(in.RetryInterval)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "cannot parse 'retry_interval'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/zrepl/zrepl/cmd/config"
|
||||||
|
"github.com/zrepl/zrepl/logger"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"github.com/zrepl/zrepl/cmd/daemon"
|
"github.com/zrepl/zrepl/cmd/daemon"
|
||||||
"github.com/zrepl/zrepl/cmd/daemon/job"
|
"github.com/zrepl/zrepl/cmd/daemon/job"
|
||||||
"github.com/zrepl/zrepl/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// daemonCmd represents the daemon command
|
// daemonCmd represents the daemon command
|
||||||
@ -75,13 +75,19 @@ func (a daemonJobAdaptor) Status() interface{} { return nil }
|
|||||||
|
|
||||||
func doDaemon(cmd *cobra.Command, args []string) {
|
func doDaemon(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
conf, err := ParseConfig(rootArgs.configFile)
|
conf, err := config.ParseConfig(rootArgs.configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "error parsing config: %s\n", err)
|
fmt.Fprintf(os.Stderr, "error parsing config: %s\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
log := logger.NewLogger(conf.Global.logging.Outlets, 1*time.Second)
|
outlets, err := parseLogging(conf.Global.Logging)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed to generate logger: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log := logger.NewLogger(outlets.Outlets, 1*time.Second)
|
||||||
|
|
||||||
ctx := WithLogger(context.Background(), log)
|
ctx := WithLogger(context.Background(), log)
|
||||||
|
|
||||||
daemonJobs := make([]job.Job, 0, len(conf.Jobs))
|
daemonJobs := make([]job.Job, 0, len(conf.Jobs))
|
||||||
|
Loading…
Reference in New Issue
Block a user