|
CX Framework
Cross-platform C utility framework
|
Macros | |
| #define | withLogCtx(...) |
| #define | withLogLocal() blkWrap(_logLocalPush(), _logLocalPop()) |
Functions | |
| void | logCtxPop (void) |
| LogCtx * | logCtxCurrent (void) |
| LogCtx * | logCtxAcquire (LogCtx *ctx) |
| void | logCtxRelease (LogCtx **ctx) |
| LogCtx * | logCtxSwap (LogCtx *ctx) |
| void | logCtxRestore (LogCtx *ctx) |
| const LogCtx * | logCtxParent (const LogCtx *ctx) |
| uint32 | logCtxNumVars (const LogCtx *ctx) |
| const stvar * | logCtxVars (const LogCtx *ctx) |
| bool | logCtxShadowed (const LogCtx *top, const LogCtx *node, uint32 idx, const char *key) |
Correlation fields attached to everything logged on a thread, without threading a context object through every function that might log:
Contexts are immutable and shared. Entering one allocates a single node pointing at the enclosing context; a record snapshots the whole chain by taking one reference. Nothing is copied per record, and a record that outlives the block it was logged in still renders the fields that were in scope.
Fields are keyed variants, the same ones logFmt() takes (see stvark()). Structured destinations emit all of them; text destinations render a configured subset, or none, so a console does not fill up with correlation ids.
A message template can name them too, under the same keys, so a correlation id can appear in the sentence rather than only in the annotation a destination appends:
This costs the call site nothing it was not already paying: a keyed variant is invisible to an unkeyed placeholder, so context fields cannot renumber or otherwise disturb the arguments the call site wrote. An argument sharing a key with a context field wins, being the more specific of the two. A key that is in no context in scope leaves the placeholder unmatched, which fails the format like any other unmatched placeholder unless it carries a ;default.
Only logFmt() messages are templates. A logStr() message is literal, so one containing ${...} is delivered unchanged whether or not a context is in scope.
Nesting shadows rather than merges. An inner context that reuses a key wins; the outer value is still there but is not emitted twice.
Work that hops threads keeps its context. A task inherits the context of whoever submitted it, restored for the duration of its run and undone afterwards. Without that, correlation is lost the moment work is handed to a queue, which in an async server is immediately.
| #define withLogCtx | ( | ... | ) |
void withLogCtx(...)
Runs the following block with additional fields attached to everything logged on this thread
The context is popped when the block exits, including via break or continue. return is not allowed inside the block, as with every block-wrapping macro in cx.
| ... | Keyed variants, e.g. stvark(reqid, suid, id) |
| #define withLogLocal | ( | ) | blkWrap(_logLocalPush(), _logLocalPop()) |
void withLogLocal(void)
Runs the following block with everything logged on this thread kept on this machine
Records logged inside the block still reach every local destination, so whatever is running in there stays diagnosable; they simply never reach a destination that sends them elsewhere. Use it around the code that carries log traffic off the machine, so that a transport which logs about its own sends cannot feed itself.
The scope is popped when the block exits, including via break or continue. return is not allowed inside the block, as with every block-wrapping macro in cx.
Take a reference to a context
| ctx | Context to acquire, or NULL |
| LogCtx * logCtxCurrent | ( | void | ) |
The calling thread's current context, or NULL if it has none
Borrowed: valid until the thread leaves the context. Acquire it to keep it.
| uint32 logCtxNumVars | ( | const LogCtx * | ctx | ) |
How many fields this context node adds
Does not include fields inherited from logCtxParent(); walk the chain for the full set.
| ctx | Context to inspect |
The context this one was entered from, or NULL at the outermost
| ctx | Context to inspect |
| void logCtxPop | ( | void | ) |
Leave the innermost context on this thread
Only needed when the enter/leave pair cannot be a block; prefer withLogCtx().
| void logCtxRelease | ( | LogCtx ** | ctx | ) |
Release a reference to a context
| ctx | Context to release; set to NULL |
| void logCtxRestore | ( | LogCtx * | ctx | ) |
Put back a context taken by logCtxSwap()
Consumes the reference logCtxSwap() handed out.
| ctx | Context returned by logCtxSwap(), or NULL |
Has this key already been seen by a walk in progress?
Nesting shadows: an inner context that reuses a key wins, and the outer one should not be emitted a second time. A destination walking the chain from top calls this for each candidate field to find out whether a more deeply nested context already supplied it.
| top | Context the walk started at (the record's context) |
| node | Context node the candidate field belongs to |
| idx | Index of the candidate field within that node |
| key | The candidate field's key |
Replace this thread's context wholesale
For carrying a context across a thread boundary: capture logCtxCurrent() where the work is submitted, then swap it in where the work runs. Ownership of the returned context transfers to the caller, who must hand it to logCtxRestore().
| ctx | Context to install, or NULL for none |
This context node's fields
| ctx | Context to inspect |