| // Package logentries provides the log driver for forwarding server logs |
| // to logentries endpoints. |
| package logentries |
| |
| import ( |
| "fmt" |
| "strconv" |
| |
| "github.com/bsphere/le_go" |
| "github.com/docker/docker/daemon/logger" |
| "github.com/pkg/errors" |
| "github.com/sirupsen/logrus" |
| ) |
| |
| type logentries struct { |
| tag string |
| containerID string |
| containerName string |
| writer *le_go.Logger |
| extra map[string]string |
| lineOnly bool |
| } |
| |
| const ( |
| name = "logentries" |
| token = "logentries-token" |
| lineonly = "line-only" |
| ) |
| |
| func init() { |
| if err := logger.RegisterLogDriver(name, New); err != nil { |
| logrus.Fatal(err) |
| } |
| if err := logger.RegisterLogOptValidator(name, ValidateLogOpt); err != nil { |
| logrus.Fatal(err) |
| } |
| } |
| |
| // New creates a logentries logger using the configuration passed in on |
| // the context. The supported context configuration variable is |
| // logentries-token. |
| func New(info logger.Info) (logger.Logger, error) { |
| logrus.WithField("container", info.ContainerID). |
| WithField("token", info.Config[token]). |
| WithField("line-only", info.Config[lineonly]). |
| Debug("logging driver logentries configured") |
| |
| log, err := le_go.Connect(info.Config[token]) |
| if err != nil { |
| return nil, errors.Wrap(err, "error connecting to logentries") |
| } |
| var lineOnly bool |
| if info.Config[lineonly] != "" { |
| if lineOnly, err = strconv.ParseBool(info.Config[lineonly]); err != nil { |
| return nil, errors.Wrap(err, "error parsing lineonly option") |
| } |
| } |
| return &logentries{ |
| containerID: info.ContainerID, |
| containerName: info.ContainerName, |
| writer: log, |
| lineOnly: lineOnly, |
| }, nil |
| } |
| |
| func (f *logentries) Log(msg *logger.Message) error { |
| if !f.lineOnly { |
| data := map[string]string{ |
| "container_id": f.containerID, |
| "container_name": f.containerName, |
| "source": msg.Source, |
| "log": string(msg.Line), |
| } |
| for k, v := range f.extra { |
| data[k] = v |
| } |
| ts := msg.Timestamp |
| logger.PutMessage(msg) |
| f.writer.Println(f.tag, ts, data) |
| } else { |
| line := string(msg.Line) |
| logger.PutMessage(msg) |
| f.writer.Println(line) |
| } |
| return nil |
| } |
| |
| func (f *logentries) Close() error { |
| return f.writer.Close() |
| } |
| |
| func (f *logentries) Name() string { |
| return name |
| } |
| |
| // ValidateLogOpt looks for logentries specific log option logentries-address. |
| func ValidateLogOpt(cfg map[string]string) error { |
| for key := range cfg { |
| switch key { |
| case "env": |
| case "env-regex": |
| case "labels": |
| case "tag": |
| case key: |
| default: |
| return fmt.Errorf("unknown log opt '%s' for logentries log driver", key) |
| } |
| } |
| |
| if cfg[token] == "" { |
| return fmt.Errorf("Missing logentries token") |
| } |
| |
| return nil |
| } |