From 71341a194843fadf836b5460d09f685bb6c465b4 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 7 Jan 2020 13:41:56 +0100 Subject: log: support --log-opt tag= support a custom tag to add to each log for the container. It is currently supported only by the journald backend. Closes: https://github.com/containers/libpod/issues/3653 Signed-off-by: Giuseppe Scrivano --- libpod/container.go | 7 +++++++ libpod/container_inspect.go | 30 +++++++++++++++++++----------- libpod/oci_conmon_linux.go | 37 ++++++++++++++++++++++++++++++++++--- libpod/options.go | 17 +++++++++++++++++ 4 files changed, 77 insertions(+), 14 deletions(-) (limited to 'libpod') diff --git a/libpod/container.go b/libpod/container.go index edf72f4ee..a046dcafc 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -379,6 +379,8 @@ type ContainerConfig struct { CgroupParent string `json:"cgroupParent"` // LogPath log location LogPath string `json:"logPath"` + // LogTag is the tag used for logging + LogTag string `json:"logTag"` // LogDriver driver for logs LogDriver string `json:"logDriver"` // File containing the conmon PID @@ -726,6 +728,11 @@ func (c *Container) LogPath() string { return c.config.LogPath } +// LogTag returns the tag to the container's log file +func (c *Container) LogTag() string { + return c.config.LogTag +} + // RestartPolicy returns the container's restart policy. func (c *Container) RestartPolicy() string { return c.config.RestartPolicy diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 639dd6e91..3f4ab394f 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -107,6 +107,7 @@ type InspectContainerData struct { OCIConfigPath string `json:"OCIConfigPath,omitempty"` OCIRuntime string `json:"OCIRuntime,omitempty"` LogPath string `json:"LogPath"` + LogTag string `json:"LogTag"` ConmonPidFile string `json:"ConmonPidFile"` Name string `json:"Name"` RestartCount int32 `json:"RestartCount"` @@ -629,17 +630,9 @@ type InspectNetworkSettings struct { MacAddress string `json:"MacAddress"` } -// Inspect a container for low-level information -func (c *Container) Inspect(size bool) (*InspectContainerData, error) { - if !c.batched { - c.lock.Lock() - defer c.lock.Unlock() - - if err := c.syncContainer(); err != nil { - return nil, err - } - } - +// inspectLocked inspects a container for low-level information. +// The caller must held c.lock. +func (c *Container) inspectLocked(size bool) (*InspectContainerData, error) { storeCtr, err := c.runtime.store.Container(c.ID()) if err != nil { return nil, errors.Wrapf(err, "error getting container from store %q", c.ID()) @@ -655,6 +648,20 @@ func (c *Container) Inspect(size bool) (*InspectContainerData, error) { return c.getContainerInspectData(size, driverData) } +// Inspect a container for low-level information +func (c *Container) Inspect(size bool) (*InspectContainerData, error) { + if !c.batched { + c.lock.Lock() + defer c.lock.Unlock() + + if err := c.syncContainer(); err != nil { + return nil, err + } + } + + return c.inspectLocked(size) +} + func (c *Container) getContainerInspectData(size bool, driverData *driver.Data) (*InspectContainerData, error) { config := c.config runtimeInfo := c.state @@ -732,6 +739,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data) HostsPath: hostsPath, StaticDir: config.StaticDir, LogPath: config.LogPath, + LogTag: config.LogTag, OCIRuntime: config.OCIRuntime, ConmonPidFile: config.ConmonPidFile, Name: config.Name, diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index 0312f0ba2..d4bdabaf5 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -14,6 +14,7 @@ import ( "strconv" "strings" "syscall" + "text/template" "time" "github.com/containers/libpod/libpod/config" @@ -532,7 +533,7 @@ func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options if logrus.GetLevel() != logrus.DebugLevel && r.supportsJSON { ociLog = c.execOCILog(sessionID) } - args := r.sharedConmonArgs(c, sessionID, c.execBundlePath(sessionID), c.execPidPath(sessionID), c.execLogPath(sessionID), c.execExitFileDir(sessionID), ociLog) + args := r.sharedConmonArgs(c, sessionID, c.execBundlePath(sessionID), c.execPidPath(sessionID), c.execLogPath(sessionID), c.execExitFileDir(sessionID), ociLog, "") if options.PreserveFDs > 0 { args = append(args, formatRuntimeOpts("--preserve-fds", fmt.Sprintf("%d", options.PreserveFDs))...) @@ -887,6 +888,27 @@ func waitPidStop(pid int, timeout time.Duration) error { } } +func (r *ConmonOCIRuntime) getLogTag(ctr *Container) (string, error) { + logTag := ctr.LogTag() + if logTag == "" { + return "", nil + } + data, err := ctr.inspectLocked(false) + if err != nil { + return "", nil + } + tmpl, err := template.New("container").Parse(logTag) + if err != nil { + return "", errors.Wrapf(err, "template parsing error %s", logTag) + } + var b bytes.Buffer + err = tmpl.Execute(&b, data) + if err != nil { + return "", err + } + return b.String(), nil +} + // createOCIContainer generates this container's main conmon instance and prepares it for starting func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) (err error) { var stderrBuf bytes.Buffer @@ -913,7 +935,13 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co if logrus.GetLevel() != logrus.DebugLevel && r.supportsJSON { ociLog = filepath.Join(ctr.state.RunDir, "oci-log") } - args := r.sharedConmonArgs(ctr, ctr.ID(), ctr.bundlePath(), filepath.Join(ctr.state.RunDir, "pidfile"), ctr.LogPath(), r.exitsDir, ociLog) + + logTag, err := r.getLogTag(ctr) + if err != nil { + return err + } + + args := r.sharedConmonArgs(ctr, ctr.ID(), ctr.bundlePath(), filepath.Join(ctr.state.RunDir, "pidfile"), ctr.LogPath(), r.exitsDir, ociLog, logTag) if ctr.config.Spec.Process.Terminal { args = append(args, "-t") @@ -1147,7 +1175,7 @@ func (r *ConmonOCIRuntime) configureConmonEnv(runtimeDir string) ([]string, []*o } // sharedConmonArgs takes common arguments for exec and create/restore and formats them for the conmon CLI -func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, pidPath, logPath, exitDir, ociLogPath string) []string { +func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, pidPath, logPath, exitDir, ociLogPath, logTag string) []string { // set the conmon API version to be able to use the correct sync struct keys args := []string{"--api-version", "1"} if r.cgroupManager == define.SystemdCgroupsManager && !ctr.config.NoCgroups { @@ -1194,6 +1222,9 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p if ociLogPath != "" { args = append(args, "--runtime-arg", "--log-format=json", "--runtime-arg", "--log", fmt.Sprintf("--runtime-arg=%s", ociLogPath)) } + if logTag != "" { + args = append(args, "--log-tag", logTag) + } if ctr.config.NoCgroups { logrus.Debugf("Running with no CGroups") args = append(args, "--runtime-arg", "--cgroup-manager", "--runtime-arg", "disabled") diff --git a/libpod/options.go b/libpod/options.go index 031f4f705..1d6863e7b 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1059,6 +1059,23 @@ func WithLogPath(path string) CtrCreateOption { } } +// WithLogTag sets the tag to the log file. +func WithLogTag(tag string) CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return define.ErrCtrFinalized + } + if tag == "" { + return errors.Wrapf(define.ErrInvalidArg, "log tag must be set") + } + + ctr.config.LogTag = tag + + return nil + } + +} + // WithNoCgroups disables the creation of CGroups for the new container. func WithNoCgroups() CtrCreateOption { return func(ctr *Container) error { -- cgit v1.2.3-54-g00ecf