Skip to content

Logs

The Ops Feed (<director-ops-feed>) is a unified surface over logging and tracing. This page describes the log path; Traces covers the rest.

The two log mounts

DirectorServiceTargets.observability.logging = ['system.observability.logging', 'system.logging']. The first is canonical; the second is compat. DirectorRuntimeAdapter.queryOpsFeed uses invokeFirst to call logging.search (when there's a text filter) or logging.query (without text), against either mount until one responds.

Filter shape

IDirectorOpsFilter (src/types.ts):

ts
{
  scope:  'all' | 'selected',
  text:   string,
  kind:   'all' | 'rpc' | 'log' | 'tool-call' | 'message' | 'inference' | 'activity',
  window: '15m' | '1h' | '24h' | '7d' | 'all',
}

Logs come into the feed when kind === 'all' or kind === 'log'. Other kind values pull from the tracing service only.

Outbound payload

For logging.search/logging.query:

ts
{
  text?: string,             // user-typed search
  source?: string,           // selected mount (when scope === 'selected')
  limit:   number,           // backendLimit = max(limit*3, 120)
}

The default limit for the displayed list is 60 (line 557 of DirectorRuntimeAdapter.ts); the adapter requests max(limit*3, 120) upstream to allow client-side dedup.

Result shape (after mapping)

_mapLogRecords() normalizes responses into IDirectorFeedRecord:

ts
{
  kind: 'log',
  phase?: string,
  op?: string,
  source?: string,
  target?: string,
  text?: string,
  ts?: number,           // unix ms
  durationMs?: number,
  spanId?: string,
  parentSpanId?: string,
  traceId?: string,
  sessionId?: string,
  requestId?: string,
}

queryOpsFeed then merges log + trace records, dedupes by _feedRecordToken, filters by window/text on the client, sorts descending by ts, and slices to the requested limit.

What the UI shows

DirectorOpsFeed.ts is split via <mx-split> into a list (records) and a detail pane (records related to the selected one). Each list row shows:

  • timestamp (relative)
  • kind chip
  • source mount (clickable → opens the actor)
  • single-line text (record.text or op or phase)

Clicking a row dispatches director:ops-record-selected, which DirectorApp resolves via DirectorRuntimeAdapter.loadOpsDetail. That call fans out to trace.request (by requestId), trace.thread (by sessionId), trace.get (by traceId), and trace.activity (by source mount), returning the first list of related records.

Per record:

  • Open actor — emits director:ops-open-actor-requested (or …open-canonical-actor-requested if the source mount is a compat alias).
  • Open package root — emits director:ops-open-package-root-requested if the source belongs to a known package family.
  • Open workstream — emits director:ops-open-workstream-requested if the source mount is a known workstream.

Limits

  • No live tail. The feed is request-driven (refresh button or filter change). There's no streaming subscription on the logging service today.
  • Window is wall-clock. _windowStart returns Date.now() - windowMs; entries with no ts are kept regardless of window.
  • Backend dependency. If system.observability.logging is not registered (and system.logging is also missing), the feed returns empty without erroring. Verify with matrix invoke system.observability.logging logging.query '{}'.

See also

Source: projects/matrix-3/packages/director/src/components/DirectorOpsFeed.ts, src/services/DirectorRuntimeAdapter.ts:549-756, 1857-1877.