зеркало из https://github.com/microsoft/docker.git
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:
Родитель
656cdbb0e9
Коммит
5794a0190d
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче