diff --git a/README.md b/README.md index 185d759d..8272ed0b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ Server options: Logging options: -l, --log FILE File to redirect log output -T, --logtime Timestamp log entries (default: true) + -s, --syslog Enable syslog as log method. + -r, --remote_syslog Syslog server addr (udp://localhost:514). -D, --debug Enable debugging output -V, --trace Trace the raw protocol diff --git a/gnatsd.go b/gnatsd.go index ff2f0cad..31f96fa4 100644 --- a/gnatsd.go +++ b/gnatsd.go @@ -42,7 +42,10 @@ func main() { flag.StringVar(&opts.PidFile, "pid", "", "File to store process pid.") flag.StringVar(&opts.LogFile, "l", "", "File to store logging output.") flag.StringVar(&opts.LogFile, "log", "", "File to store logging output.") - flag.BoolVar(&opts.Syslog, "syslog", false, "Enable syslog as log method.") + flag.BoolVar(&opts.Syslog, "s", false, "Enable syslog as log method.") + flag.BoolVar(&opts.Syslog, "syslog", false, "Enable syslog as log method..") + flag.StringVar(&opts.RemoteSyslog, "r", "", "Syslog server addr (udp://localhost:514).") + flag.StringVar(&opts.RemoteSyslog, "remote_syslog", "", "Syslog server addr (udp://localhost:514).") flag.BoolVar(&showVersion, "version", false, "Print version information.") flag.BoolVar(&showVersion, "v", false, "Print version information.") flag.IntVar(&opts.ProfPort, "profile", 0, "Profiling HTTP port") @@ -99,14 +102,17 @@ func main() { } func buildLogger(opts *server.Options) server.Logger { - if opts.Syslog { - return logger.NewSysLogger(opts.Debug, opts.Trace) - } - if opts.LogFile != "" { return logger.NewFileLogger(opts.LogFile, opts.Logtime, opts.Debug, opts.Trace) } - return logger.NewStdLogger(opts.Logtime, opts.Debug, opts.Trace, true) + if opts.RemoteSyslog != "" { + return logger.NewRemoteSysLogger(opts.RemoteSyslog, opts.Debug, opts.Trace) + } + if opts.Syslog { + return logger.NewSysLogger(opts.Debug, opts.Trace) + } + + return logger.NewStdLogger(opts.Logtime, opts.Debug, opts.Trace, true) } diff --git a/logger/log_test.go b/logger/log_test.go index 7eb1eed3..c497946a 100644 --- a/logger/log_test.go +++ b/logger/log_test.go @@ -17,12 +17,12 @@ func TestStdLogger(t *testing.T) { t.Fatalf("Expected %q, received %q\n", 0, flags) } - if logger.debug != false { - t.Fatalf("Expected %b, received %b\n", false, logger.debug) + if logger.debug { + t.Fatalf("Expected %t, received %t\n", false, logger.debug) } - if logger.trace != false { - t.Fatalf("Expected %b, received %b\n", false, logger.trace) + if logger.trace { + t.Fatalf("Expected %t, received %t\n", false, logger.trace) } } @@ -34,12 +34,12 @@ func TestStdLoggerWithDebugTraceAndTime(t *testing.T) { t.Fatalf("Expected %d, received %d\n", log.LstdFlags, flags) } - if logger.debug != true { - t.Fatalf("Expected %b, received %b\n", true, logger.debug) + if !logger.debug { + t.Fatalf("Expected %t, received %t\n", true, logger.debug) } - if logger.trace != true { - t.Fatalf("Expected %b, received %b\n", true, logger.trace) + if !logger.trace { + t.Fatalf("Expected %t, received %t\n", true, logger.trace) } } diff --git a/logger/syslog.go b/logger/syslog.go index 217396ed..b29365eb 100644 --- a/logger/syslog.go +++ b/logger/syslog.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "log/syslog" + "net/url" ) type SysLogger struct { @@ -16,7 +17,7 @@ type SysLogger struct { func NewSysLogger(debug, trace bool) *SysLogger { w, err := syslog.New(syslog.LOG_DAEMON|syslog.LOG_NOTICE, "gnatsd") if err != nil { - log.Fatal("error connecting to syslog: %v", err) + log.Fatalf("error connecting to syslog: %q", err.Error()) } return &SysLogger{ @@ -26,10 +27,11 @@ func NewSysLogger(debug, trace bool) *SysLogger { } } -func NewRemoteSysLogger(network, raddr string, debug, trace bool) *SysLogger { - w, err := syslog.Dial(network, raddr, syslog.LOG_DEBUG, "gnatsd") +func NewRemoteSysLogger(fqn string, debug, trace bool) *SysLogger { + network, addr := getNetworkAndAddr(fqn) + w, err := syslog.Dial(network, addr, syslog.LOG_DEBUG, "gnatsd") if err != nil { - log.Fatal("error connecting to syslog: %v", err) + log.Fatalf("error connecting to syslog: %q", err.Error()) } return &SysLogger{ @@ -39,6 +41,24 @@ func NewRemoteSysLogger(network, raddr string, debug, trace bool) *SysLogger { } } +func getNetworkAndAddr(fqn string) (network, addr string) { + u, err := url.Parse(fqn) + if err != nil { + log.Fatal(err) + } + + network = u.Scheme + if network == "udp" || network == "tcp" { + addr = u.Host + } else if network == "unix" { + addr = u.Path + } else { + log.Fatalf("error invalid network type: %q", u.Scheme) + } + + return +} + func (l *SysLogger) Log(format string, v ...interface{}) { l.writer.Notice(fmt.Sprintf(format, v...)) } diff --git a/logger/syslog_test.go b/logger/syslog_test.go index db1f1775..06d2a41d 100644 --- a/logger/syslog_test.go +++ b/logger/syslog_test.go @@ -1,6 +1,7 @@ package logger import ( + "fmt" "log" "net" "strings" @@ -8,50 +9,50 @@ import ( "time" ) -var serverAddr string +var serverFQN string func TestSysLogger(t *testing.T) { logger := NewSysLogger(false, false) - if logger.debug != false { - t.Fatalf("Expected %b, received %b\n", false, logger.debug) + if logger.debug { + t.Fatalf("Expected %t, received %t\n", false, logger.debug) } - if logger.trace != false { - t.Fatalf("Expected %b, received %b\n", false, logger.trace) + if logger.trace { + t.Fatalf("Expected %t, received %t\n", false, logger.trace) } } func TestSysLoggerWithDebugAndTrace(t *testing.T) { logger := NewSysLogger(true, true) - if logger.debug != true { - t.Fatalf("Expected %b, received %b\n", true, logger.debug) + if !logger.debug { + t.Fatalf("Expected %t, received %t\n", true, logger.debug) } - if logger.trace != true { - t.Fatalf("Expected %b, received %b\n", true, logger.trace) + if !logger.trace { + t.Fatalf("Expected %t, received %t\n", true, logger.trace) } } func TestRemoteSysLogger(t *testing.T) { done := make(chan string) startServer(done) - logger := NewRemoteSysLogger("udp", serverAddr, true, true) + logger := NewRemoteSysLogger(serverFQN, true, true) - if logger.debug != true { - t.Fatalf("Expected %b, received %b\n", true, logger.debug) + if !logger.debug { + t.Fatalf("Expected %t, received %t\n", true, logger.debug) } - if logger.trace != true { - t.Fatalf("Expected %b, received %b\n", true, logger.trace) + if !logger.trace { + t.Fatalf("Expected %t, received %t\n", true, logger.trace) } } func TestRemoteSysLoggerLog(t *testing.T) { done := make(chan string) startServer(done) - logger := NewRemoteSysLogger("udp", serverAddr, true, true) + logger := NewRemoteSysLogger(serverFQN, true, true) logger.Log("foo %s", "bar") expectSyslogOutput(t, <-done, "foo bar\n") @@ -60,7 +61,7 @@ func TestRemoteSysLoggerLog(t *testing.T) { func TestRemoteSysLoggerDebug(t *testing.T) { done := make(chan string) startServer(done) - logger := NewRemoteSysLogger("udp", serverAddr, true, true) + logger := NewRemoteSysLogger(serverFQN, true, true) logger.Debug("foo %s", "qux") expectSyslogOutput(t, <-done, "foo qux\n") @@ -69,7 +70,7 @@ func TestRemoteSysLoggerDebug(t *testing.T) { func TestRemoteSysLoggerDebugDisabled(t *testing.T) { done := make(chan string) startServer(done) - logger := NewRemoteSysLogger("udp", serverAddr, false, false) + logger := NewRemoteSysLogger(serverFQN, false, false) logger.Debug("foo %s", "qux") rcvd := <-done @@ -81,7 +82,7 @@ func TestRemoteSysLoggerDebugDisabled(t *testing.T) { func TestRemoteSysLoggerTrace(t *testing.T) { done := make(chan string) startServer(done) - logger := NewRemoteSysLogger("udp", serverAddr, true, true) + logger := NewRemoteSysLogger(serverFQN, true, true) logger.Trace("foo %s", "qux") expectSyslogOutput(t, <-done, "foo qux\n") @@ -90,7 +91,7 @@ func TestRemoteSysLoggerTrace(t *testing.T) { func TestRemoteSysLoggerTraceDisabled(t *testing.T) { done := make(chan string) startServer(done) - logger := NewRemoteSysLogger("udp", serverAddr, true, false) + logger := NewRemoteSysLogger(serverFQN, true, false) logger.Trace("foo %s", "qux") rcvd := <-done @@ -99,6 +100,41 @@ func TestRemoteSysLoggerTraceDisabled(t *testing.T) { } } +func TestGetNetworkAndAddrUDP(t *testing.T) { + n, a := getNetworkAndAddr("udp://foo.com:1000") + + if n != "udp" { + t.Fatalf("Unexpected network %s\n", n) + } + + if a != "foo.com:1000" { + t.Fatalf("Unexpected addr %s\n", a) + } +} + +func TestGetNetworkAndAddrTCP(t *testing.T) { + n, a := getNetworkAndAddr("tcp://foo.com:1000") + + if n != "tcp" { + t.Fatalf("Unexpected network %s\n", n) + } + + if a != "foo.com:1000" { + t.Fatalf("Unexpected addr %s\n", a) + } +} + +func TestGetNetworkAndAddrUnix(t *testing.T) { + n, a := getNetworkAndAddr("unix:///foo.sock") + + if n != "unix" { + t.Fatalf("Unexpected network %s\n", n) + } + + if a != "/foo.sock" { + t.Fatalf("Unexpected addr %s\n", a) + } +} func expectSyslogOutput(t *testing.T, line string, expected string) { data := strings.Split(line, "]: ") if len(data) != 2 { @@ -129,7 +165,7 @@ func startServer(done chan<- string) { log.Fatalf("net.ListenPacket failed udp :0 %v", e) } - serverAddr = c.LocalAddr().String() + serverFQN = fmt.Sprintf("udp://%s", c.LocalAddr().String()) c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) go runSyslog(c, done) } diff --git a/server/configs/test.conf b/server/configs/test.conf index 598af3d7..62e6819c 100644 --- a/server/configs/test.conf +++ b/server/configs/test.conf @@ -17,6 +17,8 @@ debug: false trace: true logtime: false log_file: "/tmp/gnatsd.log" +syslog: true +remote_syslog: "udp://foo.com:33" #pid file pid_file: "/tmp/gnatsd.pid" diff --git a/server/opts.go b/server/opts.go index e7d7438d..72b636ea 100644 --- a/server/opts.go +++ b/server/opts.go @@ -44,6 +44,7 @@ type Options struct { PidFile string `json:"-"` LogFile string `json:"-"` Syslog bool `json:"-"` + RemoteSyslog string `json:"-"` } type authorization struct { @@ -98,6 +99,10 @@ func ProcessConfigFile(configFile string) (*Options, error) { } case "logfile", "log_file": opts.LogFile = v.(string) + case "syslog": + opts.Syslog = v.(bool) + case "remote_syslog": + opts.RemoteSyslog = v.(string) case "pidfile", "pid_file": opts.PidFile = v.(string) case "prof_port": diff --git a/server/opts_test.go b/server/opts_test.go index f02df7b2..05c70212 100644 --- a/server/opts_test.go +++ b/server/opts_test.go @@ -44,18 +44,20 @@ func TestOptions_RandomPort(t *testing.T) { func TestConfigFile(t *testing.T) { golden := &Options{ - Host: "apcera.me", - Port: 4242, - Username: "derek", - Password: "bella", - AuthTimeout: 1.0, - Debug: false, - Trace: true, - Logtime: false, - HTTPPort: 8222, - LogFile: "/tmp/gnatsd.log", - PidFile: "/tmp/gnatsd.pid", - ProfPort: 6543, + Host: "apcera.me", + Port: 4242, + Username: "derek", + Password: "bella", + AuthTimeout: 1.0, + Debug: false, + Trace: true, + Logtime: false, + HTTPPort: 8222, + LogFile: "/tmp/gnatsd.log", + PidFile: "/tmp/gnatsd.pid", + ProfPort: 6543, + Syslog: true, + RemoteSyslog: "udp://foo.com:33", } opts, err := ProcessConfigFile("./configs/test.conf") @@ -71,18 +73,20 @@ func TestConfigFile(t *testing.T) { func TestMergeOverrides(t *testing.T) { golden := &Options{ - Host: "apcera.me", - Port: 2222, - Username: "derek", - Password: "spooky", - AuthTimeout: 1.0, - Debug: true, - Trace: true, - Logtime: false, - HTTPPort: DEFAULT_HTTP_PORT, - LogFile: "/tmp/gnatsd.log", - PidFile: "/tmp/gnatsd.pid", - ProfPort: 6789, + Host: "apcera.me", + Port: 2222, + Username: "derek", + Password: "spooky", + AuthTimeout: 1.0, + Debug: true, + Trace: true, + Logtime: false, + HTTPPort: DEFAULT_HTTP_PORT, + LogFile: "/tmp/gnatsd.log", + PidFile: "/tmp/gnatsd.pid", + ProfPort: 6789, + Syslog: true, + RemoteSyslog: "udp://foo.com:33", } fopts, err := ProcessConfigFile("./configs/test.conf") if err != nil { diff --git a/server/usage.go b/server/usage.go index c3ed44a7..250f689f 100644 --- a/server/usage.go +++ b/server/usage.go @@ -18,6 +18,8 @@ Server options: Logging options: -l, --log FILE File to redirect log output -T, --logtime Timestamp log entries (default: true) + -s, --syslog Enable syslog as log method. + -r, --remote_syslog Syslog server addr (udp://localhost:514). -D, --debug Enable debugging output -V, --trace Trace the raw protocol