Skip to content

feat(api): add ContainerLogOptions {since, timestamps} to ContainerClient.logs (CHAOS-1322)#11

Open
chrisgeo wants to merge 1 commit into
mainfrom
feat/chaos-1322-log-options
Open

feat(api): add ContainerLogOptions {since, timestamps} to ContainerClient.logs (CHAOS-1322)#11
chrisgeo wants to merge 1 commit into
mainfrom
feat/chaos-1322-log-options

Conversation

@chrisgeo
Copy link
Copy Markdown

@chrisgeo chrisgeo commented May 2, 2026

Staging branch — fork-internal review before any apple/container upstream filing.

Linear: CHAOS-1322

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

External orchestrators that drive the API server (the canonical use case is a Compose-spec orchestrator implementing compose logs --since <ts> / --timestamps) need to retrieve only recent log output and optionally annotate lines with timestamps. Today ContainerClient.logs(id:) returns raw containerLog + bootlog file handles unconditionally; consumers either replay the entire log buffer or implement a client-side line filter.

Surfacing the parameters at the API boundary keeps line scanning where the file lives — server-side — and matches the docker-compose UX users expect.

What this PR changes

  • Sources/ContainerResource/Container/ContainerLogOptions.swift (new): Sendable + Codable struct with since: Date? / timestamps: Bool fields and a .default zero-config equivalent to the original logs(id:) call.
  • Sources/Services/ContainerAPIService/Client/XPC+.swift: two new XPCKeys cases (logSince, logTimestamps) for the optional parameters.
  • Sources/Services/ContainerAPIService/Client/ContainerClient.swift: new logs(id:options:) overload. Existing logs(id:) retained as a thin wrapper over .default for source compatibility.
  • Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift: matching logs(id:options:) overload + a private filterFileHandleSince that parses ISO-8601 timestamps from line starts and drops older lines (lines without a parseable timestamp pass through unchanged).
  • Sources/Services/ContainerAPIService/Server/Containers/ContainersHarness.swift: parses the two optional XPC keys, builds ContainerLogOptions, forwards to the new service overload.

Total: 5 files (1 new + 4 modified), +122/−7.

Wire compatibility

XPC calls without the new keys decode as sinceRaw.timeIntervalSince1970 == 0 (the harness treats this as "no since filter") and timestamps == false, so older clients hitting a newer server see unchanged behavior. Newer clients hitting an older server send the keys; an old harness silently drops them and runs the original codepath.

Known limitations (intentional, follow-up work)

  • options.timestamps is plumbed end-to-end but not yet line-decorating. The daemon does not currently annotate raw log lines that lack a timestamp prefix. Line decoration is a deliberate follow-up; keeping the parameter on the API surface today avoids a second wire-format break later.
  • filterFileHandleSince slurps the file into memory then returns a Pipe-backed FileHandle. Fine for typical container log sizes; for very large logs a streaming line iterator would be a worthwhile optimization. Filed as a known-issue for the timestamp-decoration follow-up.

Testing

  • Tested locally (full swift build clean on macOS 26 / Apple silicon, all targets including downstream consumers of ContainerClient.logs).
  • Added/updated tests — none yet; can add an in-process round-trip test against the harness if desired.
  • Added/updated docs — public API doc comments added on the new type, fields, XPC keys, and overload.

Status

Draft, fork-staged. Routing to full-chaos/container:main first so we can review the surface internally before opening the apple/container companion issue + upstream PR (the same pattern we ran for CHAOS-1319 → apple#1502 + apple#1504 and CHAOS-1320 → apple#1501 + apple#1503).

@linear
Copy link
Copy Markdown

linear Bot commented May 2, 2026

@chrisgeo chrisgeo force-pushed the feat/chaos-1322-log-options branch 4 times, most recently from 3e5a31a to 1df3acb Compare May 14, 2026 19:43
@chrisgeo chrisgeo marked this pull request as ready for review May 14, 2026 19:43
…ient.logs

Adds an additive overload to ContainerClient.logs that accepts a
ContainerLogOptions { since: Date?, timestamps: Bool } and plumbs the
two parameters through XPC into the daemon's existing log-handle path.

Motivation
----------

External orchestrators that drive the API server (the canonical use
case is a Compose-spec orchestrator implementing 'compose logs --since
<timestamp>' and '--timestamps') need to retrieve only recent log
output and optionally annotate lines with timestamps. Today
ContainerClient.logs(id:) returns raw containerLog + bootlog file
handles unconditionally; consumers either replay the entire log buffer
or implement their own line-by-line filter on the client. Surfacing
the parameters at the API boundary keeps the line scanning where the
file lives — server-side — and matches the docker-compose UX users
expect.

What this PR changes
--------------------

- Sources/ContainerResource/Container/ContainerLogOptions.swift (new):
  the ContainerLogOptions struct, Sendable + Codable, with a static
  '.default' equivalent to the original logs(id:) zero-config call.
- Sources/Services/ContainerAPIService/Client/XPC+.swift: two new
  XPCKeys cases ('logSince', 'logTimestamps') for the optional
  parameters.
- Sources/Services/ContainerAPIService/Client/ContainerClient.swift:
  new logs(id:options:) overload. The existing logs(id:) is retained
  as a thin wrapper over .default for source compatibility.
- Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift:
  matching logs(id:options:) overload; when options.since is provided,
  applies a private 'filterFileHandleSince' that parses ISO-8601
  timestamps from line starts and drops older lines (lines without a
  parseable timestamp pass through unchanged).
- Sources/Services/ContainerAPIService/Server/Containers/ContainersHarness.swift:
  parses the two optional XPC keys, builds ContainerLogOptions, and
  forwards to the new service overload.

Wire compatibility
------------------

XPC calls without the new keys decode as 'sinceRaw.timeIntervalSince1970
== 0' (the harness treats this as 'no since filter') and 'timestamps =
false', so older clients hitting a newer server see unchanged behavior.
Newer clients hitting an older server send the keys; an old harness
will silently drop them and run the original codepath.

Known limitations (intentional, follow-up work)
-----------------------------------------------

- The 'options.timestamps' parameter is plumbed end-to-end but the
  daemon does not currently decorate raw log lines that lack a
  timestamp prefix. Line decoration is a deliberate follow-up; keeping
  the parameter on the API surface today avoids a second wire-format
  break later.
- 'filterFileHandleSince' currently slurps the file into memory then
  returns a Pipe-backed FileHandle. For the typical container log
  size this is fine; for very large logs a streaming line iterator
  would be a worthwhile optimization. Filed as a known-issue for the
  follow-up timestamp-decoration PR.

Verification
------------

Full 'swift build' clean on macOS 26 / Apple silicon (release config,
all targets including downstream consumers of ContainerClient.logs).
@chrisgeo chrisgeo force-pushed the feat/chaos-1322-log-options branch from 1df3acb to 067c177 Compare May 15, 2026 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant