mirror of
https://github.com/psviderski/uncloud.git
synced 2026-10-08 14:14:52 +00:00
fix(logs): resolve time ranges using client local time zone for logs commands
This commit is contained in:
1 parent
e3479409b1
commit
5fa236871f
13 files changed
+282
-16
No files matched your search
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/psviderski/uncloud/pkg/api"
|
||||
)
|
||||
@@ -31,11 +32,11 @@ func logs(ctx context.Context, unit string, opts api.ServiceLogsOptions) (io.Rea
|
||||
|
||||
if opts.Since != "" {
|
||||
args = append(args, "-S")
|
||||
args = append(args, opts.Since)
|
||||
args = append(args, journalTimestamp(opts.Since))
|
||||
}
|
||||
if opts.Until != "" {
|
||||
args = append(args, "-U")
|
||||
args = append(args, opts.Until)
|
||||
args = append(args, journalTimestamp(opts.Until))
|
||||
}
|
||||
|
||||
cmd := commandContext(ctx, journalctl, args...)
|
||||
@@ -51,6 +52,18 @@ func logs(ctx context.Context, unit string, opts api.ServiceLogsOptions) (io.Rea
|
||||
return p, cmd.Wait, nil
|
||||
}
|
||||
|
||||
// journalTimestamp formats normalised client timestamps for journalctl versions that do not
|
||||
// accept RFC 3339 timezone suffixes. Support for timestamps containing T and Z was added in
|
||||
// systemd 255 (6 December 2023). Debian 12 ships systemd 252, so it still needs this conversion.
|
||||
// Journald timestamps have microsecond precision.
|
||||
func journalTimestamp(value string) string {
|
||||
if t, err := time.Parse(time.RFC3339Nano, value); err == nil {
|
||||
return t.UTC().Format("2006-01-02 15:04:05.999999") + " UTC"
|
||||
}
|
||||
// Preserve raw filters from older clients and SDK callers.
|
||||
return value
|
||||
}
|
||||
|
||||
// follow synchronously follows the io.Reader, writing each new journal entry to channel.
|
||||
// It stops when the reader is exhausted or the context is cancelled.
|
||||
func follow(ctx context.Context, reader io.Reader, outCh chan api.LogEntry) {
|
||||
|
||||
@@ -115,6 +115,9 @@ func TestEntry(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLogs(t *testing.T) {
|
||||
originalCommandContext := commandContext
|
||||
t.Cleanup(func() { commandContext = originalCommandContext })
|
||||
|
||||
commandContext = func(ctx context.Context, _ string, _ ...string) *exec.Cmd {
|
||||
return exec.CommandContext(ctx, "/usr/bin/tail", "testdata/logs")
|
||||
}
|
||||
@@ -150,3 +153,38 @@ func TestLogs(t *testing.T) {
|
||||
// Still six because heartbeats are not written here and Tail is ignored as the command is overridden.
|
||||
assert.Equal(t, 6, i)
|
||||
}
|
||||
|
||||
func TestLogs_TimeFilters(t *testing.T) {
|
||||
originalCommandContext := commandContext
|
||||
t.Cleanup(func() { commandContext = originalCommandContext })
|
||||
|
||||
var args []string
|
||||
commandContext = func(ctx context.Context, command string, commandArgs ...string) *exec.Cmd {
|
||||
assert.Equal(t, "journalctl", command)
|
||||
args = commandArgs
|
||||
return exec.CommandContext(ctx, "/usr/bin/tail", "testdata/logs")
|
||||
}
|
||||
|
||||
ch, err := Logs(context.Background(), "uncloud", api.ServiceLogsOptions{
|
||||
Since: "2026-07-01T10:30:45.123456789+10:00",
|
||||
Until: "2026-07-01T01:30:45Z",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
for range ch {
|
||||
}
|
||||
assert.Equal(t, []string{
|
||||
"-u", "uncloud", "--no-hostname", "-n", "0", "-o", "short-unix",
|
||||
"-S", "2026-07-01 00:30:45.123456 UTC",
|
||||
"-U", "2026-07-01 01:30:45 UTC",
|
||||
}, args)
|
||||
|
||||
// Older clients and SDK callers can still pass journalctl's native filters.
|
||||
ch, err = Logs(context.Background(), "uncloud", api.ServiceLogsOptions{Since: "1h ago", Until: "today"})
|
||||
require.NoError(t, err)
|
||||
for range ch {
|
||||
}
|
||||
assert.Equal(t, []string{
|
||||
"-u", "uncloud", "--no-hostname", "-n", "0", "-o", "short-unix",
|
||||
"-S", "1h ago", "-U", "today",
|
||||
}, args)
|
||||
}
|
||||
Reference in new issue
Block a user