mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 13:11:22 +00:00
feat: Add --localTime option to logs command for local timezone display (#13818)
* feat: add --localTime options to make logs to show time with local time zone fix #12447 * fix: prep logs local-time option and docs (#13818) (thanks @xialonglee) --------- Co-authored-by: xialonglee <li.xialong@xydigit.com> Co-authored-by: Sebastian <19554889+sebslight@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Command } from "commander";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { formatLogTimestamp } from "./logs-cli.js";
|
||||
|
||||
const callGatewayFromCli = vi.fn();
|
||||
|
||||
@@ -53,6 +54,40 @@ describe("logs cli", () => {
|
||||
expect(stderrWrites.join("")).toContain("Log cursor reset");
|
||||
});
|
||||
|
||||
it("wires --local-time through CLI parsing and emits local timestamps", async () => {
|
||||
callGatewayFromCli.mockResolvedValueOnce({
|
||||
file: "/tmp/openclaw.log",
|
||||
lines: [
|
||||
JSON.stringify({
|
||||
time: "2025-01-01T12:00:00.000Z",
|
||||
_meta: { logLevelName: "INFO", name: JSON.stringify({ subsystem: "gateway" }) },
|
||||
0: "line one",
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const stdoutWrites: string[] = [];
|
||||
const stdoutSpy = vi.spyOn(process.stdout, "write").mockImplementation((chunk: unknown) => {
|
||||
stdoutWrites.push(String(chunk));
|
||||
return true;
|
||||
});
|
||||
|
||||
const { registerLogsCli } = await import("./logs-cli.js");
|
||||
const program = new Command();
|
||||
program.exitOverride();
|
||||
registerLogsCli(program);
|
||||
|
||||
await program.parseAsync(["logs", "--local-time", "--plain"], { from: "user" });
|
||||
|
||||
stdoutSpy.mockRestore();
|
||||
|
||||
const output = stdoutWrites.join("");
|
||||
expect(output).toContain("line one");
|
||||
const timestamp = output.match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z?/u)?.[0];
|
||||
expect(timestamp).toBeTruthy();
|
||||
expect(timestamp?.endsWith("Z")).toBe(false);
|
||||
});
|
||||
|
||||
it("warns when the output pipe closes", async () => {
|
||||
callGatewayFromCli.mockResolvedValueOnce({
|
||||
file: "/tmp/openclaw.log",
|
||||
@@ -82,4 +117,49 @@ describe("logs cli", () => {
|
||||
|
||||
expect(stderrWrites.join("")).toContain("output stdout closed");
|
||||
});
|
||||
|
||||
describe("formatLogTimestamp", () => {
|
||||
it("formats UTC timestamp in plain mode by default", () => {
|
||||
const result = formatLogTimestamp("2025-01-01T12:00:00.000Z");
|
||||
expect(result).toBe("2025-01-01T12:00:00.000Z");
|
||||
});
|
||||
|
||||
it("formats UTC timestamp in pretty mode", () => {
|
||||
const result = formatLogTimestamp("2025-01-01T12:00:00.000Z", "pretty");
|
||||
expect(result).toBe("12:00:00");
|
||||
});
|
||||
|
||||
it("formats local time in plain mode when localTime is true", () => {
|
||||
const utcTime = "2025-01-01T12:00:00.000Z";
|
||||
const result = formatLogTimestamp(utcTime, "plain", true);
|
||||
// Should be local time without 'Z' suffix
|
||||
expect(result).not.toContain("Z");
|
||||
expect(result).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
|
||||
// The exact time depends on timezone, but should be different from UTC
|
||||
expect(result).not.toBe(utcTime);
|
||||
});
|
||||
|
||||
it("formats local time in pretty mode when localTime is true", () => {
|
||||
const utcTime = "2025-01-01T12:00:00.000Z";
|
||||
const result = formatLogTimestamp(utcTime, "pretty", true);
|
||||
// Should be HH:MM:SS format
|
||||
expect(result).toMatch(/^\d{2}:\d{2}:\d{2}$/);
|
||||
// Should be different from UTC time (12:00:00) if not in UTC timezone
|
||||
const tzOffset = new Date(utcTime).getTimezoneOffset();
|
||||
if (tzOffset !== 0) {
|
||||
expect(result).not.toBe("12:00:00");
|
||||
}
|
||||
});
|
||||
|
||||
it("handles empty or invalid timestamps", () => {
|
||||
expect(formatLogTimestamp(undefined)).toBe("");
|
||||
expect(formatLogTimestamp("")).toBe("");
|
||||
expect(formatLogTimestamp("invalid-date")).toBe("invalid-date");
|
||||
});
|
||||
|
||||
it("preserves original value for invalid dates", () => {
|
||||
const result = formatLogTimestamp("not-a-date");
|
||||
expect(result).toBe("not-a-date");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user