diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container_log_linux.go | 45 | ||||
-rw-r--r-- | libpod/container_log_unsupported.go | 4 | ||||
-rw-r--r-- | libpod/logs/log.go | 12 | ||||
-rw-r--r-- | libpod/oci_conmon_linux.go | 8 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 11 |
5 files changed, 62 insertions, 18 deletions
diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index 4eb600bfe..ca1e11ef5 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -12,6 +12,7 @@ import ( "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/events" "github.com/containers/podman/v3/libpod/logs" + "github.com/coreos/go-systemd/v22/journal" "github.com/coreos/go-systemd/v22/sdjournal" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -29,6 +30,19 @@ func init() { logDrivers = append(logDrivers, define.JournaldLogging) } +// initializeJournal will write an empty string to the journal +// when a journal is created. This solves a problem when people +// attempt to read logs from a container that has never had stdout/stderr +func (c *Container) initializeJournal(ctx context.Context) error { + m := make(map[string]string) + m["SYSLOG_IDENTIFIER"] = "podman" + m["PODMAN_ID"] = c.ID() + m["CONTAINER_ID_FULL"] = c.ID() + history := events.History + m["PODMAN_EVENT"] = history.String() + return journal.Send("", journal.PriInfo, m) +} + func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error { journal, err := sdjournal.NewJournal() if err != nil { @@ -63,12 +77,12 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption } // API requires Next() immediately after SeekHead(). if _, err := journal.Next(); err != nil { - return errors.Wrap(err, "initial journal cursor") + return errors.Wrap(err, "next journal") } // API requires a next|prev before getting a cursor. if _, err := journal.Previous(); err != nil { - return errors.Wrap(err, "initial journal cursor") + return errors.Wrap(err, "previous journal") } // Note that the initial cursor may not yet be ready, so we'll do an @@ -77,10 +91,10 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption var cursorError error for i := 1; i <= 3; i++ { cursor, cursorError = journal.GetCursor() - if err != nil { + if cursorError != nil { + time.Sleep(time.Duration(i*100) * time.Millisecond) continue } - time.Sleep(time.Duration(i*100) * time.Millisecond) break } if cursorError != nil { @@ -104,6 +118,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption tailQueue := []*logs.LogLine{} // needed for options.Tail doTail := options.Tail > 0 + lastReadCursor := "" for { select { case <-ctx.Done(): @@ -113,18 +128,25 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption // Fallthrough } - if _, err := journal.Next(); err != nil { - logrus.Errorf("Failed to move journal cursor to next entry: %v", err) - return + if lastReadCursor != "" { + // Advance to next entry if we read this one. + if _, err := journal.Next(); err != nil { + logrus.Errorf("Failed to move journal cursor to next entry: %v", err) + return + } } - latestCursor, err := journal.GetCursor() + + // Fetch the location of this entry, presumably either + // the one that follows the last one we read, or that + // same last one, if there is no next entry (yet). + cursor, err = journal.GetCursor() if err != nil { logrus.Errorf("Failed to get journal cursor: %v", err) return } - // Hit the end of the journal. - if cursor == latestCursor { + // Hit the end of the journal (so far?). + if cursor == lastReadCursor { if doTail { // Flush *once* we hit the end of the journal. startIndex := int64(len(tailQueue)-1) - options.Tail @@ -145,8 +167,9 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption journal.Wait(sdjournal.IndefiniteWait) continue } - cursor = latestCursor + lastReadCursor = cursor + // Read the journal entry. entry, err := journal.GetEntry() if err != nil { logrus.Errorf("Failed to get journal entry: %v", err) diff --git a/libpod/container_log_unsupported.go b/libpod/container_log_unsupported.go index d10082141..a551df942 100644 --- a/libpod/container_log_unsupported.go +++ b/libpod/container_log_unsupported.go @@ -13,3 +13,7 @@ import ( func (c *Container) readFromJournal(_ context.Context, _ *logs.LogOptions, _ chan *logs.LogLine) error { return errors.Wrapf(define.ErrOSNotSupported, "Journald logging only enabled with systemd on linux") } + +func (c *Container) initializeJournal(ctx context.Context) error { + return errors.Wrapf(define.ErrOSNotSupported, "Journald logging only enabled with systemd on linux") +} diff --git a/libpod/logs/log.go b/libpod/logs/log.go index 1a0223edc..a584de0ee 100644 --- a/libpod/logs/log.go +++ b/libpod/logs/log.go @@ -251,11 +251,19 @@ func (l *LogLine) Write(stdout io.Writer, stderr io.Writer, logOpts *LogOptions) switch l.Device { case "stdout": if stdout != nil { - fmt.Fprintln(stdout, l.String(logOpts)) + if l.Partial() { + fmt.Fprint(stdout, l.String(logOpts)) + } else { + fmt.Fprintln(stdout, l.String(logOpts)) + } } case "stderr": if stderr != nil { - fmt.Fprintln(stderr, l.String(logOpts)) + if l.Partial() { + fmt.Fprint(stderr, l.String(logOpts)) + } else { + fmt.Fprintln(stderr, l.String(logOpts)) + } } default: // Warn the user if the device type does not match. Most likely the file is corrupted. diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index ff25be234..c14911980 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -625,9 +625,11 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http. if err != nil { break } - _, err = httpBuf.Write([]byte("\n")) - if err != nil { - break + if !logLine.Partial() { + _, err = httpBuf.Write([]byte("\n")) + if err != nil { + break + } } err = httpBuf.Flush() if err != nil { diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 02bbb6981..52072b0f3 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -462,8 +462,15 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai ctrNamedVolumes = append(ctrNamedVolumes, newVol) } - if ctr.config.LogPath == "" && ctr.config.LogDriver != define.JournaldLogging && ctr.config.LogDriver != define.NoLogging { - ctr.config.LogPath = filepath.Join(ctr.config.StaticDir, "ctr.log") + switch ctr.config.LogDriver { + case define.NoLogging: + break + case define.JournaldLogging: + ctr.initializeJournal(ctx) + default: + if ctr.config.LogPath == "" { + ctr.config.LogPath = filepath.Join(ctr.config.StaticDir, "ctr.log") + } } if !MountExists(ctr.config.Spec.Mounts, "/dev/shm") && ctr.config.ShmDir == "" { |