// New creates a new logger that logs to Google Cloud Logging using the application // default credentials. // // See https://developers.google.com/identity/protocols/application-default-credentials func New(ctx logger.Context) (logger.Logger, error) { initGCP() var project string if projectID != "" { project = projectID } if projectID, found := ctx.Config[projectOptKey]; found { project = projectID } if project == "" { return nil, fmt.Errorf("No project was specified and couldn't read project from the meatadata server. Please specify a project") } c, err := logging.NewClient(context.Background(), project, "gcplogs-docker-driver") if err != nil { return nil, err } if err := c.Ping(); err != nil { return nil, fmt.Errorf("unable to connect or authenticate with Google Cloud Logging: %v", err) } l := &gcplogs{ client: c, container: &containerInfo{ Name: ctx.ContainerName, ID: ctx.ContainerID, ImageName: ctx.ContainerImageName, ImageID: ctx.ContainerImageID, Created: ctx.ContainerCreated, Metadata: ctx.ExtraAttributes(nil), }, } if ctx.Config[logCmdKey] == "true" { l.container.Command = ctx.Command() } if onGCE { l.instance = &instanceInfo{ Zone: zone, Name: instanceName, ID: instanceID, } } // The logger "overflows" at a rate of 10,000 logs per second and this // overflow func is called. We want to surface the error to the user // without overly spamming /var/log/docker.log so we log the first time // we overflow and every 1000th time after. c.Overflow = func(_ *logging.Client, _ logging.Entry) error { if i := atomic.AddUint64(&droppedLogs, 1); i%1000 == 1 { logrus.Errorf("gcplogs driver has dropped %v logs", i) } return nil } return l, nil }
// New creates a gelf logger using the configuration passed in on the // context. Supported context configuration variables are // gelf-address, & gelf-tag. func New(ctx logger.Context) (logger.Logger, error) { // parse gelf address address, err := parseAddress(ctx.Config["gelf-address"]) if err != nil { return nil, err } // collect extra data for GELF message hostname, err := ctx.Hostname() if err != nil { return nil, fmt.Errorf("gelf: cannot access hostname to set source field") } // remove trailing slash from container name containerName := bytes.TrimLeft([]byte(ctx.ContainerName), "/") // parse log tag tag, err := loggerutils.ParseLogTag(ctx, "") if err != nil { return nil, err } extra := map[string]interface{}{ "_container_id": ctx.ContainerID, "_container_name": string(containerName), "_image_id": ctx.ContainerImageID, "_image_name": ctx.ContainerImageName, "_command": ctx.Command(), "_tag": tag, "_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 gelfWriter, err := gelf.NewWriter(address) if err != nil { return nil, fmt.Errorf("gelf: cannot connect to GELF endpoint: %s %v", address, err) } return &gelfLogger{ writer: gelfWriter, ctx: ctx, hostname: hostname, extra: extra, }, nil }
// New creates a gelf logger using the configuration passed in on the // context. Supported context configuration variables are // gelf-address, & gelf-tag. func New(ctx logger.Context) (logger.Logger, error) { // parse gelf address address, err := parseAddress(ctx.Config["gelf-address"]) if err != nil { return nil, err } // collect extra data for GELF message hostname, err := ctx.Hostname() if err != nil { return nil, fmt.Errorf("gelf: cannot access hostname to set source field") } // remove trailing slash from container name containerName := bytes.TrimLeft([]byte(ctx.ContainerName), "/") // parse log tag tag, err := loggerutils.ParseLogTag(ctx, "") if err != nil { return nil, err } fields := gelfFields{ hostname: hostname, containerID: ctx.ContainerID, containerName: string(containerName), imageID: ctx.ContainerImageID, imageName: ctx.ContainerImageName, command: ctx.Command(), tag: tag, created: ctx.ContainerCreated, } // create new gelfWriter gelfWriter, err := gelf.NewWriter(address) if err != nil { return nil, fmt.Errorf("gelf: cannot connect to GELF endpoint: %s %v", address, err) } return &gelfLogger{ writer: gelfWriter, ctx: ctx, fields: fields, }, nil }
// New creates a gelf logger using the configuration passed in on the // context. The supported context configuration variable is gelf-address. func New(ctx logger.Context) (logger.Logger, error) { // parse gelf address address, err := parseAddress(ctx.Config["gelf-address"]) if err != nil { return nil, err } // collect extra data for GELF message hostname, err := ctx.Hostname() if err != nil { return nil, fmt.Errorf("gelf: cannot access hostname to set source field") } // parse log tag tag, err := loggerutils.ParseLogTag(ctx, loggerutils.DefaultTemplate) if err != nil { return nil, err } extra := map[string]interface{}{ "_container_id": ctx.ContainerID, "_container_name": ctx.Name(), "_image_id": ctx.ContainerImageID, "_image_name": ctx.ContainerImageName, "_command": ctx.Command(), "_tag": tag, "_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 } rawExtra, err := json.Marshal(extra) if err != nil { return nil, err } // create new gelfWriter gelfWriter, err := gelf.NewWriter(address) if err != nil { return nil, fmt.Errorf("gelf: cannot connect to GELF endpoint: %s %v", address, err) } if v, ok := ctx.Config["gelf-compression-type"]; ok { switch v { case "gzip": gelfWriter.CompressionType = gelf.CompressGzip case "zlib": gelfWriter.CompressionType = gelf.CompressZlib case "none": gelfWriter.CompressionType = gelf.CompressNone default: return nil, fmt.Errorf("gelf: invalid compression type %q", v) } } if v, ok := ctx.Config["gelf-compression-level"]; ok { val, err := strconv.Atoi(v) if err != nil { return nil, fmt.Errorf("gelf: invalid compression level %s, err %v", v, err) } gelfWriter.CompressionLevel = val } return &gelfLogger{ writer: gelfWriter, ctx: ctx, hostname: hostname, rawExtra: rawExtra, }, nil }