`Logger` today emits flat `(level, message, source)` records. Real distributed-system debugging needs context that travels alongside the message — correlation IDs, trace IDs, user IDs — so log lines from different actors / services / hops stitch together into a coherent trail.
Akka calls this MDC (Mapped Diagnostic Context). In TypeScript the right primitive is `AsyncLocalStorage` from `node:async_hooks` (also available in Bun) — a per-async-call-stack key-value store the logger reads automatically.
API:
```ts
import { LogContext } from 'actor-ts';
LogContext.run({ correlationId: 'abc-123', userId: 'u-42' }, () => {
// every log call inside this scope auto-includes the context
this.log.info('processing payment');
// and it propagates through tells/asks too
paymentRouter.tell({ kind: 'charge', amount: 100 });
});
```
When `paymentRouter` 's actor logs, the same `{correlationId, userId}` is attached because the message-dispatch wraps `onReceive` in a `LogContext.run(...)` from the originating context.
Components:
| File |
Task |
| `src/Logger.ts` |
Read context from `AsyncLocalStorage` and merge into every log record. |
| `src/LogContext.ts` (new) |
Public API: `run(ctx, fn)`, `get()`, `with(ctx, fn)`. |
| `src/internal/ActorCell.ts` |
Wrap mailbox dispatch in `LogContext.run(envelope.context, ...)`; the envelope carries the originating context. |
| `src/cluster/RemoteActorRef.ts` |
Carry context across the wire as part of `EnvelopeMsg`. |
| `tests/unit/Logger.test.ts` |
Context propagates through tells; `run` is properly scoped. |
| `tests/multi-node/log-context-cross-node.test.ts` (new) |
Originating tell on A; remote actor on B logs with the same correlationId. |
Estimate: 2-3 days.
Verification:
- Local: tell from a wrapped scope; receiver's log includes the context.
- Remote: same, but the receiver is on another node.
- No-op: outside `LogContext.run`, log records don't carry stale context (defensive — empty ctx).
Out of scope:
`Logger` today emits flat `(level, message, source)` records. Real distributed-system debugging needs context that travels alongside the message — correlation IDs, trace IDs, user IDs — so log lines from different actors / services / hops stitch together into a coherent trail.
Akka calls this MDC (Mapped Diagnostic Context). In TypeScript the right primitive is `AsyncLocalStorage` from `node:async_hooks` (also available in Bun) — a per-async-call-stack key-value store the logger reads automatically.
API:
```ts
import { LogContext } from 'actor-ts';
LogContext.run({ correlationId: 'abc-123', userId: 'u-42' }, () => {
// every log call inside this scope auto-includes the context
this.log.info('processing payment');
// and it propagates through tells/asks too
paymentRouter.tell({ kind: 'charge', amount: 100 });
});
```
When `paymentRouter` 's actor logs, the same `{correlationId, userId}` is attached because the message-dispatch wraps `onReceive` in a `LogContext.run(...)` from the originating context.
Components:
Estimate: 2-3 days.
Verification:
Out of scope: