mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
bd9d14a07b
The jsonlog logger currently allows specifying envs and labels that should be propagated to the log message, however there has been no way to read that back. This adds a new API option to enable inserting these attrs back to the log reader. With timestamps, this looks like so: ``` 92016-04-08T15:28:09.835913720Z foo=bar,hello=world hello ``` The extra attrs are comma separated before the log message but after timestamps. Without timestaps it looks like so: ``` foo=bar,hello=world hello ``` Signed-off-by: Brian Goff <cpuguy83@gmail.com>
114 lines
2.9 KiB
Go
114 lines
2.9 KiB
Go
// Package logger defines interfaces that logger drivers implement to
|
|
// log messages.
|
|
//
|
|
// The other half of a logger driver is the implementation of the
|
|
// factory, which holds the contextual instance information that
|
|
// allows multiple loggers of the same type to perform different
|
|
// actions, such as logging to different locations.
|
|
package logger
|
|
|
|
import (
|
|
"errors"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/docker/docker/pkg/jsonlog"
|
|
)
|
|
|
|
// ErrReadLogsNotSupported is returned when the logger does not support reading logs.
|
|
var ErrReadLogsNotSupported = errors.New("configured logging reader does not support reading")
|
|
|
|
const (
|
|
// TimeFormat is the time format used for timestamps sent to log readers.
|
|
TimeFormat = jsonlog.RFC3339NanoFixed
|
|
logWatcherBufferSize = 4096
|
|
)
|
|
|
|
// Message is datastructure that represents record from some container.
|
|
type Message struct {
|
|
ContainerID string
|
|
Line []byte
|
|
Source string
|
|
Timestamp time.Time
|
|
Attrs LogAttributes
|
|
}
|
|
|
|
// LogAttributes is used to hold the extra attributes available in the log message
|
|
// Primarily used for converting the map type to string and sorting.
|
|
type LogAttributes map[string]string
|
|
type byKey []string
|
|
|
|
func (s byKey) Len() int { return len(s) }
|
|
func (s byKey) Less(i, j int) bool {
|
|
keyI := strings.Split(s[i], "=")
|
|
keyJ := strings.Split(s[j], "=")
|
|
return keyI[0] < keyJ[0]
|
|
}
|
|
func (s byKey) Swap(i, j int) {
|
|
s[i], s[j] = s[j], s[i]
|
|
}
|
|
|
|
func (a LogAttributes) String() string {
|
|
var ss byKey
|
|
for k, v := range a {
|
|
ss = append(ss, k+"="+v)
|
|
}
|
|
sort.Sort(ss)
|
|
return strings.Join(ss, ",")
|
|
}
|
|
|
|
// Logger is the interface for docker logging drivers.
|
|
type Logger interface {
|
|
Log(*Message) error
|
|
Name() string
|
|
Close() error
|
|
}
|
|
|
|
// ReadConfig is the configuration passed into ReadLogs.
|
|
type ReadConfig struct {
|
|
Since time.Time
|
|
Tail int
|
|
Follow bool
|
|
}
|
|
|
|
// LogReader is the interface for reading log messages for loggers that support reading.
|
|
type LogReader interface {
|
|
// Read logs from underlying logging backend
|
|
ReadLogs(ReadConfig) *LogWatcher
|
|
}
|
|
|
|
// LogWatcher is used when consuming logs read from the LogReader interface.
|
|
type LogWatcher struct {
|
|
// For sending log messages to a reader.
|
|
Msg chan *Message
|
|
// For sending error messages that occur while while reading logs.
|
|
Err chan error
|
|
closeNotifier chan struct{}
|
|
}
|
|
|
|
// NewLogWatcher returns a new LogWatcher.
|
|
func NewLogWatcher() *LogWatcher {
|
|
return &LogWatcher{
|
|
Msg: make(chan *Message, logWatcherBufferSize),
|
|
Err: make(chan error, 1),
|
|
closeNotifier: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
// Close notifies the underlying log reader to stop.
|
|
func (w *LogWatcher) Close() {
|
|
// only close if not already closed
|
|
select {
|
|
case <-w.closeNotifier:
|
|
default:
|
|
close(w.closeNotifier)
|
|
}
|
|
}
|
|
|
|
// WatchClose returns a channel receiver that receives notification
|
|
// when the watcher has been closed. This should only be called from
|
|
// one goroutine.
|
|
func (w *LogWatcher) WatchClose() <-chan struct{} {
|
|
return w.closeNotifier
|
|
}
|