2017-09-23 18:20:22 +02:00
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/zrepl/zrepl/logger"
|
|
|
|
"io"
|
2017-09-24 02:05:41 +02:00
|
|
|
"log/syslog"
|
2017-09-23 18:20:22 +02:00
|
|
|
"net"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type WriterOutlet struct {
|
|
|
|
Formatter EntryFormatter
|
|
|
|
Writer io.Writer
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h WriterOutlet) WriteEntry(ctx context.Context, entry logger.Entry) error {
|
|
|
|
bytes, err := h.Formatter.Format(&entry)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = h.Writer.Write(bytes)
|
|
|
|
h.Writer.Write([]byte("\n"))
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
type TCPOutlet struct {
|
|
|
|
Formatter EntryFormatter
|
|
|
|
Net, Address string
|
|
|
|
Dialer net.Dialer
|
|
|
|
RetryInterval time.Duration
|
|
|
|
conn net.Conn
|
|
|
|
retry time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *TCPOutlet) WriteEntry(ctx context.Context, e logger.Entry) error {
|
|
|
|
|
|
|
|
b, err := h.Formatter.Format(&e)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if h.conn == nil {
|
|
|
|
if time.Now().Sub(h.retry) < h.RetryInterval {
|
|
|
|
return nil // this is not an error toward the logger
|
|
|
|
//return errors.New("TCP hook reconnect prohibited by retry interval")
|
|
|
|
}
|
|
|
|
h.conn, err = h.Dialer.DialContext(ctx, h.Net, h.Address)
|
|
|
|
if err != nil {
|
|
|
|
h.retry = time.Now()
|
|
|
|
return errors.Wrap(err, "cannot dial")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = h.conn.Write(b)
|
|
|
|
if err != nil {
|
|
|
|
h.conn.Close()
|
|
|
|
h.conn = nil
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2017-09-24 02:05:41 +02:00
|
|
|
|
|
|
|
type SyslogOutlet struct {
|
|
|
|
Formatter EntryFormatter
|
|
|
|
RetryInterval time.Duration
|
|
|
|
writer *syslog.Writer
|
|
|
|
lastConnectAttempt time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *SyslogOutlet) WriteEntry(ctx context.Context, entry logger.Entry) error {
|
|
|
|
|
|
|
|
bytes, err := o.Formatter.Format(&entry)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
s := string(bytes)
|
|
|
|
|
|
|
|
if o.writer == nil {
|
|
|
|
now := time.Now()
|
|
|
|
if now.Sub(o.lastConnectAttempt) < o.RetryInterval {
|
|
|
|
return nil // not an error toward logger
|
|
|
|
}
|
|
|
|
o.writer, err = syslog.New(syslog.LOG_LOCAL0, "zrepl")
|
|
|
|
o.lastConnectAttempt = time.Now()
|
|
|
|
if err != nil {
|
|
|
|
o.writer = nil
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch entry.Level {
|
|
|
|
case logger.Debug:
|
|
|
|
return o.writer.Debug(s)
|
|
|
|
case logger.Info:
|
|
|
|
return o.writer.Info(s)
|
|
|
|
case logger.Warn:
|
|
|
|
return o.writer.Warning(s)
|
|
|
|
case logger.Error:
|
|
|
|
return o.writer.Err(s)
|
|
|
|
default:
|
|
|
|
return o.writer.Err(s) // write as error as reaching this case is in fact an error
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|