mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #34174 from aaronlehmann/logattributes
Avoid using a map for log attributes
This commit is contained in:
commit
901fe35bd3
8 changed files with 70 additions and 50 deletions
|
@ -5,7 +5,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
@ -53,7 +52,8 @@ func WriteLogStream(ctx context.Context, w io.Writer, msgs <-chan *backend.LogMe
|
||||||
}
|
}
|
||||||
logLine := msg.Line
|
logLine := msg.Line
|
||||||
if config.Details {
|
if config.Details {
|
||||||
logLine = append([]byte(stringAttrs(msg.Attrs)+" "), logLine...)
|
logLine = append(attrsByteSlice(msg.Attrs), ' ')
|
||||||
|
logLine = append(logLine, msg.Line...)
|
||||||
}
|
}
|
||||||
if config.Timestamps {
|
if config.Timestamps {
|
||||||
// TODO(dperny) the format is defined in
|
// TODO(dperny) the format is defined in
|
||||||
|
@ -71,24 +71,26 @@ func WriteLogStream(ctx context.Context, w io.Writer, msgs <-chan *backend.LogMe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type byKey []string
|
type byKey []backend.LogAttr
|
||||||
|
|
||||||
func (s byKey) Len() int { return len(s) }
|
func (b byKey) Len() int { return len(b) }
|
||||||
func (s byKey) Less(i, j int) bool {
|
func (b byKey) Less(i, j int) bool { return b[i].Key < b[j].Key }
|
||||||
keyI := strings.Split(s[i], "=")
|
func (b byKey) Swap(i, j int) { b[i], b[j] = b[j], b[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 stringAttrs(a backend.LogAttributes) string {
|
func attrsByteSlice(a []backend.LogAttr) []byte {
|
||||||
var ss byKey
|
// Note this sorts "a" in-place. That is fine here - nothing else is
|
||||||
for k, v := range a {
|
// going to use Attrs or care about the order.
|
||||||
k, v := url.QueryEscape(k), url.QueryEscape(v)
|
sort.Sort(byKey(a))
|
||||||
ss = append(ss, k+"="+v)
|
|
||||||
|
var ret []byte
|
||||||
|
for i, pair := range a {
|
||||||
|
k, v := url.QueryEscape(pair.Key), url.QueryEscape(pair.Value)
|
||||||
|
ret = append(ret, []byte(k)...)
|
||||||
|
ret = append(ret, '=')
|
||||||
|
ret = append(ret, []byte(v)...)
|
||||||
|
if i != len(a)-1 {
|
||||||
|
ret = append(ret, ',')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sort.Sort(ss)
|
return ret
|
||||||
return strings.Join(ss, ",")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ type LogMessage struct {
|
||||||
Line []byte
|
Line []byte
|
||||||
Source string
|
Source string
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
Attrs LogAttributes
|
Attrs []LogAttr
|
||||||
Partial bool
|
Partial bool
|
||||||
|
|
||||||
// Err is an error associated with a message. Completeness of a message
|
// Err is an error associated with a message. Completeness of a message
|
||||||
|
@ -44,9 +44,11 @@ type LogMessage struct {
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogAttributes is used to hold the extra attributes available in the log message
|
// LogAttr is used to hold the extra attributes available in the log message.
|
||||||
// Primarily used for converting the map type to string and sorting.
|
type LogAttr struct {
|
||||||
type LogAttributes map[string]string
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
// LogSelector is a list of services and tasks that should be returned as part
|
// LogSelector is a list of services and tasks that should be returned as part
|
||||||
// of a log stream. It is similar to swarmapi.LogSelector, with the difference
|
// of a log stream. It is similar to swarmapi.LogSelector, with the difference
|
||||||
|
|
|
@ -524,10 +524,12 @@ func (r *controller) Logs(ctx context.Context, publisher exec.LogPublisher, opti
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the details out of the Attrs map
|
// parse the details out of the Attrs map
|
||||||
attrs := []api.LogAttr{}
|
var attrs []api.LogAttr
|
||||||
for k, v := range msg.Attrs {
|
if len(msg.Attrs) != 0 {
|
||||||
attr := api.LogAttr{Key: k, Value: v}
|
attrs = make([]api.LogAttr, 0, len(msg.Attrs))
|
||||||
attrs = append(attrs, attr)
|
for _, attr := range msg.Attrs {
|
||||||
|
attrs = append(attrs, api.LogAttr{Key: attr.Key, Value: attr.Value})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := publisher.Publish(ctx, api.LogMessage{
|
if err := publisher.Publish(ctx, api.LogMessage{
|
||||||
|
|
|
@ -458,22 +458,33 @@ func (c *Cluster) ServiceLogs(ctx context.Context, selector *backend.LogSelector
|
||||||
for _, msg := range subscribeMsg.Messages {
|
for _, msg := range subscribeMsg.Messages {
|
||||||
// make a new message
|
// make a new message
|
||||||
m := new(backend.LogMessage)
|
m := new(backend.LogMessage)
|
||||||
m.Attrs = make(backend.LogAttributes)
|
m.Attrs = make([]backend.LogAttr, 0, len(msg.Attrs)+3)
|
||||||
// add the timestamp, adding the error if it fails
|
// add the timestamp, adding the error if it fails
|
||||||
m.Timestamp, err = gogotypes.TimestampFromProto(msg.Timestamp)
|
m.Timestamp, err = gogotypes.TimestampFromProto(msg.Timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.Err = err
|
m.Err = err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodeKey := contextPrefix + ".node.id"
|
||||||
|
serviceKey := contextPrefix + ".service.id"
|
||||||
|
taskKey := contextPrefix + ".task.id"
|
||||||
|
|
||||||
// copy over all of the details
|
// copy over all of the details
|
||||||
for _, d := range msg.Attrs {
|
for _, d := range msg.Attrs {
|
||||||
m.Attrs[d.Key] = d.Value
|
switch d.Key {
|
||||||
|
case nodeKey, serviceKey, taskKey:
|
||||||
|
// we have the final say over context details (in case there
|
||||||
|
// is a conflict (if the user added a detail with a context's
|
||||||
|
// key for some reason))
|
||||||
|
default:
|
||||||
|
m.Attrs = append(m.Attrs, backend.LogAttr{Key: d.Key, Value: d.Value})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// we have the final say over context details (in case there
|
m.Attrs = append(m.Attrs,
|
||||||
// is a conflict (if the user added a detail with a context's
|
backend.LogAttr{Key: nodeKey, Value: msg.Context.NodeID},
|
||||||
// key for some reason))
|
backend.LogAttr{Key: serviceKey, Value: msg.Context.ServiceID},
|
||||||
m.Attrs[contextPrefix+".node.id"] = msg.Context.NodeID
|
backend.LogAttr{Key: taskKey, Value: msg.Context.TaskID},
|
||||||
m.Attrs[contextPrefix+".service.id"] = msg.Context.ServiceID
|
)
|
||||||
m.Attrs[contextPrefix+".task.id"] = msg.Context.TaskID
|
|
||||||
|
|
||||||
switch msg.Stream {
|
switch msg.Stream {
|
||||||
case swarmapi.LogStreamStdout:
|
case swarmapi.LogStreamStdout:
|
||||||
|
|
|
@ -157,6 +157,7 @@ import (
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/coreos/go-systemd/journal"
|
"github.com/coreos/go-systemd/journal"
|
||||||
|
"github.com/docker/docker/api/types/backend"
|
||||||
"github.com/docker/docker/daemon/logger"
|
"github.com/docker/docker/daemon/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -213,14 +214,11 @@ drain:
|
||||||
source = "stdout"
|
source = "stdout"
|
||||||
}
|
}
|
||||||
// Retrieve the values of any variables we're adding to the journal.
|
// Retrieve the values of any variables we're adding to the journal.
|
||||||
attrs := make(map[string]string)
|
var attrs []backend.LogAttr
|
||||||
C.sd_journal_restart_data(j)
|
C.sd_journal_restart_data(j)
|
||||||
for C.get_attribute_field(j, &data, &length) > C.int(0) {
|
for C.get_attribute_field(j, &data, &length) > C.int(0) {
|
||||||
kv := strings.SplitN(C.GoStringN(data, C.int(length)), "=", 2)
|
kv := strings.SplitN(C.GoStringN(data, C.int(length)), "=", 2)
|
||||||
attrs[kv[0]] = kv[1]
|
attrs = append(attrs, backend.LogAttr{Key: kv[0], Value: kv[1]})
|
||||||
}
|
|
||||||
if len(attrs) == 0 {
|
|
||||||
attrs = nil
|
|
||||||
}
|
}
|
||||||
// Send the log message.
|
// Send the log message.
|
||||||
logWatcher.Msg <- &logger.Message{
|
logWatcher.Msg <- &logger.Message{
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/docker/api/types/backend"
|
||||||
"github.com/docker/docker/daemon/logger"
|
"github.com/docker/docker/daemon/logger"
|
||||||
"github.com/docker/docker/daemon/logger/jsonfilelog/multireader"
|
"github.com/docker/docker/daemon/logger/jsonfilelog/multireader"
|
||||||
"github.com/docker/docker/pkg/filenotify"
|
"github.com/docker/docker/pkg/filenotify"
|
||||||
|
@ -27,11 +28,18 @@ func decodeLogLine(dec *json.Decoder, l *jsonlog.JSONLog) (*logger.Message, erro
|
||||||
if err := dec.Decode(l); err != nil {
|
if err := dec.Decode(l); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var attrs []backend.LogAttr
|
||||||
|
if len(l.Attrs) != 0 {
|
||||||
|
attrs = make([]backend.LogAttr, 0, len(l.Attrs))
|
||||||
|
for k, v := range l.Attrs {
|
||||||
|
attrs = append(attrs, backend.LogAttr{Key: k, Value: v})
|
||||||
|
}
|
||||||
|
}
|
||||||
msg := &logger.Message{
|
msg := &logger.Message{
|
||||||
Source: l.Stream,
|
Source: l.Stream,
|
||||||
Timestamp: l.Created,
|
Timestamp: l.Created,
|
||||||
Line: []byte(l.Log),
|
Line: []byte(l.Log),
|
||||||
Attrs: l.Attrs,
|
Attrs: attrs,
|
||||||
}
|
}
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,11 +68,6 @@ func (m *Message) AsLogMessage() *backend.LogMessage {
|
||||||
return (*backend.LogMessage)(m)
|
return (*backend.LogMessage)(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogAttributes is used to hold the extra attributes available in the log message
|
|
||||||
// Primarily used for converting the map type to string and sorting.
|
|
||||||
// Imported here so it can be used internally with less refactoring
|
|
||||||
type LogAttributes backend.LogAttributes
|
|
||||||
|
|
||||||
// Logger is the interface for docker logging drivers.
|
// Logger is the interface for docker logging drivers.
|
||||||
type Logger interface {
|
type Logger interface {
|
||||||
Log(*Message) error
|
Log(*Message) error
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package logger
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/docker/docker/api/types/backend"
|
||||||
|
)
|
||||||
|
|
||||||
func (m *Message) copy() *Message {
|
func (m *Message) copy() *Message {
|
||||||
msg := &Message{
|
msg := &Message{
|
||||||
Source: m.Source,
|
Source: m.Source,
|
||||||
|
@ -8,10 +12,8 @@ func (m *Message) copy() *Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Attrs != nil {
|
if m.Attrs != nil {
|
||||||
msg.Attrs = make(map[string]string, len(m.Attrs))
|
msg.Attrs = make([]backend.LogAttr, len(m.Attrs))
|
||||||
for k, v := range m.Attrs {
|
copy(msg.Attrs, m.Attrs)
|
||||||
msg.Attrs[k] = v
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.Line = append(make([]byte, 0, len(m.Line)), m.Line...)
|
msg.Line = append(make([]byte, 0, len(m.Line)), m.Line...)
|
||||||
|
|
Loading…
Add table
Reference in a new issue