blob: d7cab3692cb9c68827a1c6de41b2f31859fda514 [file] [edit]
package logger
import (
"fmt"
"os"
"regexp"
"strings"
"time"
"github.com/moby/moby/v2/daemon/internal/stringid"
)
// Common log-opts to include extra attributes through [Info.ExtraAttributes]
// and [loggerutils.ParseLogTag].
const (
AttrEnv = "env" // Comma-separated list of env-vars to include as log-metadata.
AttrEnvRegex = "env-regex" // Regular Expression to match environment variables to include as log-metadata.
AttrLabels = "labels" // Comma-separated list of labels to include as log-metadata.
AttrLabelsRegex = "labels-regex" // Regular Expression to match labels to include as log-metadata.
AttrLogTag = "tag" // Log "tag" log-metadata. Can be either a literal value or a Go template to use for templating the "tag" log-metadata.
)
// Info provides enough information for a logging driver to do its function.
type Info struct {
Config map[string]string
ContainerID string
ContainerName string
ContainerEntrypoint string
ContainerArgs []string
ContainerImageID string
ContainerImageName string
ContainerCreated time.Time
ContainerEnv []string
ContainerLabels map[string]string
LogPath string
DaemonName 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 (info *Info) ExtraAttributes(keyMod func(string) string) (map[string]string, error) {
extra := make(map[string]string)
if labels, ok := info.Config[AttrLabels]; ok && labels != "" {
for l := range strings.SplitSeq(labels, ",") {
if v, ok := info.ContainerLabels[l]; ok {
if keyMod != nil {
l = keyMod(l)
}
extra[l] = v
}
}
}
if labelsRegex, ok := info.Config[AttrLabelsRegex]; ok && labelsRegex != "" {
re, err := regexp.Compile(labelsRegex)
if err != nil {
return nil, err
}
for k, v := range info.ContainerLabels {
if re.MatchString(k) {
if keyMod != nil {
k = keyMod(k)
}
extra[k] = v
}
}
}
envMapping := make(map[string]string)
for _, e := range info.ContainerEnv {
if k, v, ok := strings.Cut(e, "="); ok {
envMapping[k] = v
}
}
// Code below is only to handle adding attributes based on env-vars.
if len(envMapping) == 0 {
return extra, nil
}
if env, ok := info.Config[AttrEnv]; ok && env != "" {
for l := range strings.SplitSeq(env, ",") {
if v, ok := envMapping[l]; ok {
if keyMod != nil {
l = keyMod(l)
}
extra[l] = v
}
}
}
if envRegex, ok := info.Config[AttrEnvRegex]; ok && envRegex != "" {
re, err := regexp.Compile(envRegex)
if err != nil {
return nil, err
}
for k, v := range envMapping {
if re.MatchString(k) {
if keyMod != nil {
k = keyMod(k)
}
extra[k] = v
}
}
}
return extra, nil
}
// Hostname returns the hostname from the underlying OS.
func (info *Info) Hostname() (string, error) {
hostname, err := os.Hostname()
if err != nil {
return "", fmt.Errorf("logger: can not resolve hostname: %v", err)
}
return hostname, nil
}
// Command returns the command that the container being logged was
// started with. The Entrypoint is prepended to the container
// arguments.
func (info *Info) Command() string {
terms := []string{info.ContainerEntrypoint}
terms = append(terms, info.ContainerArgs...)
command := strings.Join(terms, " ")
return command
}
// ID returns the container ID-prefix (truncated ID).
func (info *Info) ID() string {
return stringid.TruncateID(info.ContainerID)
}
// FullID returns the container ID.
func (info *Info) FullID() string {
return info.ContainerID
}
// Name returns the container name.
func (info *Info) Name() string {
return strings.TrimPrefix(info.ContainerName, "/")
}
// ImageID returns the ID-prefix (truncated ID) of the image the container was created from.
func (info *Info) ImageID() string {
return stringid.TruncateID(info.ContainerImageID)
}
// ImageFullID returns the ID (digest) of the image the container was created from.
func (info *Info) ImageFullID() string {
return info.ContainerImageID
}
// ImageName returns the name of the image the container was created from.
func (info *Info) ImageName() string {
return info.ContainerImageName
}