summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpod/container_log.go4
-rw-r--r--libpod/container_log_linux.go8
-rw-r--r--libpod/logs/log.go8
-rw-r--r--pkg/api/handlers/compat/containers_logs.go14
-rw-r--r--test/apiv2/python/rest_api/test_v2_0_0_container.py13
5 files changed, 38 insertions, 9 deletions
diff --git a/libpod/container_log.go b/libpod/container_log.go
index 43b3f7736..743c9c61b 100644
--- a/libpod/container_log.go
+++ b/libpod/container_log.go
@@ -56,7 +56,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption
for _, nll := range tailLog {
nll.CID = c.ID()
nll.CName = c.Name()
- if nll.Since(options.Since) {
+ if nll.Since(options.Since) && nll.Until(options.Until) {
logChannel <- nll
}
}
@@ -88,7 +88,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption
}
nll.CID = c.ID()
nll.CName = c.Name()
- if nll.Since(options.Since) {
+ if nll.Since(options.Since) && nll.Until(options.Until) {
logChannel <- nll
}
}
diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go
index 892ee34e3..9f9dd3b0d 100644
--- a/libpod/container_log_linux.go
+++ b/libpod/container_log_linux.go
@@ -97,6 +97,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
}
}()
+ beforeTimeStamp := true
afterTimeStamp := false // needed for options.Since
tailQueue := []*logs.LogLine{} // needed for options.Tail
doTail := options.Tail > 0
@@ -156,6 +157,13 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
}
afterTimeStamp = true
}
+ if beforeTimeStamp {
+ entryTime := time.Unix(0, int64(entry.RealtimeTimestamp)*int64(time.Microsecond))
+ if entryTime.Before(options.Until) || !options.Until.IsZero() {
+ continue
+ }
+ beforeTimeStamp = false
+ }
// If we're reading an event and the container exited/died,
// then we're done and can return.
diff --git a/libpod/logs/log.go b/libpod/logs/log.go
index 308053b47..1a0223edc 100644
--- a/libpod/logs/log.go
+++ b/libpod/logs/log.go
@@ -34,6 +34,7 @@ type LogOptions struct {
Details bool
Follow bool
Since time.Time
+ Until time.Time
Tail int64
Timestamps bool
Multi bool
@@ -184,7 +185,12 @@ func (l *LogLine) String(options *LogOptions) string {
// Since returns a bool as to whether a log line occurred after a given time
func (l *LogLine) Since(since time.Time) bool {
- return l.Time.After(since)
+ return l.Time.After(since) || since.IsZero()
+}
+
+// Until returns a bool as to whether a log line occurred before a given time
+func (l *LogLine) Until(until time.Time) bool {
+ return l.Time.Before(until) || until.IsZero()
}
// NewLogLine creates a logLine struct from a container log string
diff --git a/pkg/api/handlers/compat/containers_logs.go b/pkg/api/handlers/compat/containers_logs.go
index cb4dee4d2..656e2c627 100644
--- a/pkg/api/handlers/compat/containers_logs.go
+++ b/pkg/api/handlers/compat/containers_logs.go
@@ -72,11 +72,12 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
var until time.Time
if _, found := r.URL.Query()["until"]; found {
- // FIXME: until != since but the logs backend does not yet support until.
- since, err = util.ParseInputTime(query.Until)
- if err != nil {
- utils.BadRequest(w, "until", query.Until, err)
- return
+ if query.Until != "0" {
+ until, err = util.ParseInputTime(query.Until)
+ if err != nil {
+ utils.BadRequest(w, "until", query.Until, err)
+ return
+ }
}
}
@@ -84,6 +85,7 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
Details: true,
Follow: query.Follow,
Since: since,
+ Until: until,
Tail: tail,
Timestamps: query.Timestamps,
}
@@ -119,7 +121,7 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
for line := range logChannel {
if _, found := r.URL.Query()["until"]; found {
- if line.Time.After(until) {
+ if line.Time.After(until) && !until.IsZero() {
break
}
}
diff --git a/test/apiv2/python/rest_api/test_v2_0_0_container.py b/test/apiv2/python/rest_api/test_v2_0_0_container.py
index 2fab4aeb9..f252bd401 100644
--- a/test/apiv2/python/rest_api/test_v2_0_0_container.py
+++ b/test/apiv2/python/rest_api/test_v2_0_0_container.py
@@ -1,5 +1,6 @@
import random
import unittest
+import json
import requests
from dateutil.parser import parse
@@ -97,6 +98,18 @@ class ContainerTestCase(APITestCase):
def test_logs(self):
r = requests.get(self.uri(self.resolve_container("/containers/{}/logs?stdout=true")))
self.assertEqual(r.status_code, 200, r.text)
+ r = requests.post(
+ self.podman_url + "/v1.40/containers/create?name=topcontainer",
+ json={"Cmd": ["top", "ls"], "Image": "alpine:latest"},
+ )
+ self.assertEqual(r.status_code, 201, r.text)
+ payload = r.json()
+ container_id = payload["Id"]
+ self.assertIsNotNone(container_id)
+ r = requests.get(self.podman_url + f"/v1.40/containers/{payload['Id']}/logs?follow=false&stdout=true&until=0")
+ self.assertEqual(r.status_code, 200, r.text)
+ r = requests.get(self.podman_url + f"/v1.40/containers/{payload['Id']}/logs?follow=false&stdout=true&until=1")
+ self.assertEqual(r.status_code, 200, r.text)
def test_commit(self):
r = requests.post(self.uri(self.resolve_container("/commit?container={}")))