add labels/env log option for gelf

this allows gelf logger to collect extra metadata from containers with
`--log-opt labels=label1,label2 --log-opt env=env1,env2`

Additional log field will be prefixed with `_` as per gelf protocol
https://www.graylog.org/resources/gelf/

Signed-off-by: Daniel Dao <dqminh@cloudflare.com>
This commit is contained in:
Daniel Dao 2015-10-04 21:03:11 +00:00 коммит произвёл Vincent Demeester
Родитель 656cdbb0e9
Коммит 5794a0190d
2 изменённых файлов: 68 добавлений и 36 удалений

Просмотреть файл

@ -22,6 +22,44 @@ type Context struct {
LogPath string LogPath string
} }
// ExtraAttributes returns the user-defined extra attributes (labels,
// environment variables) in key-value format. This can be used by log drivers
// that support metadata to add more context to a log.
func (ctx *Context) ExtraAttributes(keyMod func(string) string) map[string]string {
extra := make(map[string]string)
labels, ok := ctx.Config["labels"]
if ok && len(labels) > 0 {
for _, l := range strings.Split(labels, ",") {
if v, ok := ctx.ContainerLabels[l]; ok {
if keyMod != nil {
l = keyMod(l)
}
extra[l] = v
}
}
}
env, ok := ctx.Config["env"]
if ok && len(env) > 0 {
envMapping := make(map[string]string)
for _, e := range ctx.ContainerEnv {
if kv := strings.SplitN(e, "=", 2); len(kv) == 2 {
envMapping[kv[0]] = kv[1]
}
}
for _, l := range strings.Split(env, ",") {
if v, ok := envMapping[l]; ok {
if keyMod != nil {
l = keyMod(l)
}
extra[l] = v
}
}
}
return extra
}
// Hostname returns the hostname from the underlying OS. // Hostname returns the hostname from the underlying OS.
func (ctx *Context) Hostname() (string, error) { func (ctx *Context) Hostname() (string, error) {
hostname, err := os.Hostname() hostname, err := os.Hostname()

Просмотреть файл

@ -21,20 +21,10 @@ import (
const name = "gelf" const name = "gelf"
type gelfLogger struct { type gelfLogger struct {
writer *gelf.Writer writer *gelf.Writer
ctx logger.Context ctx logger.Context
fields gelfFields hostname string
} extra map[string]interface{}
type gelfFields struct {
hostname string
containerID string
containerName string
imageID string
imageName string
command string
tag string
created time.Time
} }
func init() { func init() {
@ -71,15 +61,24 @@ func New(ctx logger.Context) (logger.Logger, error) {
return nil, err return nil, err
} }
fields := gelfFields{ extra := map[string]interface{}{
hostname: hostname, "_container_id": ctx.ContainerID,
containerID: ctx.ContainerID, "_container_name": string(containerName),
containerName: string(containerName), "_image_id": ctx.ContainerImageID,
imageID: ctx.ContainerImageID, "_image_name": ctx.ContainerImageName,
imageName: ctx.ContainerImageName, "_command": ctx.Command(),
command: ctx.Command(), "_tag": tag,
tag: tag, "_created": ctx.ContainerCreated,
created: ctx.ContainerCreated, }
extraAttrs := ctx.ExtraAttributes(func(key string) string {
if key[0] == '_' {
return key
}
return "_" + key
})
for k, v := range extraAttrs {
extra[k] = v
} }
// create new gelfWriter // create new gelfWriter
@ -89,9 +88,10 @@ func New(ctx logger.Context) (logger.Logger, error) {
} }
return &gelfLogger{ return &gelfLogger{
writer: gelfWriter, writer: gelfWriter,
ctx: ctx, ctx: ctx,
fields: fields, hostname: hostname,
extra: extra,
}, nil }, nil
} }
@ -106,19 +106,11 @@ func (s *gelfLogger) Log(msg *logger.Message) error {
m := gelf.Message{ m := gelf.Message{
Version: "1.1", Version: "1.1",
Host: s.fields.hostname, Host: s.hostname,
Short: string(short), Short: string(short),
TimeUnix: float64(msg.Timestamp.UnixNano()/int64(time.Millisecond)) / 1000.0, TimeUnix: float64(msg.Timestamp.UnixNano()/int64(time.Millisecond)) / 1000.0,
Level: level, Level: level,
Extra: map[string]interface{}{ Extra: s.extra,
"_container_id": s.fields.containerID,
"_container_name": s.fields.containerName,
"_image_id": s.fields.imageID,
"_image_name": s.fields.imageName,
"_command": s.fields.command,
"_tag": s.fields.tag,
"_created": s.fields.created,
},
} }
if err := s.writer.WriteMessage(&m); err != nil { if err := s.writer.WriteMessage(&m); err != nil {
@ -143,6 +135,8 @@ func ValidateLogOpt(cfg map[string]string) error {
case "gelf-address": case "gelf-address":
case "gelf-tag": case "gelf-tag":
case "tag": case "tag":
case "labels":
case "env":
default: default:
return fmt.Errorf("unknown log opt '%s' for gelf log driver", key) return fmt.Errorf("unknown log opt '%s' for gelf log driver", key)
} }