Context fields
This example shows how context_fields add shared payload data to every emitted outcome of a decorated event.
It also shows an important timing detail: context fields are resolved separately for each outcome.
Example
from mvx.common.logger import LogContextProto, log_invocation
class Connection:
def __init__(self, log_context: LogContextProto) -> None:
self._log_context = log_context
self.state = "closed"
def get_log_context(self) -> LogContextProto | None:
return self._log_context
@log_invocation(
"open",
context_fields=("state=self.state",),
)
async def open(self) -> None:
self.state = "opened"
The decorated public API operation is open.
The selected context field is:
state=self.state
This means:
payload key -> state
value path -> self.state
Emitted records
A successful call:
await connection.open()
emits records conceptually equivalent to:
[
{
"event_name": "open",
"event_outcome": "invoke",
"payload": {
"state": "closed",
},
},
{
"event_name": "open",
"event_outcome": "success",
"payload": {
"state": "opened",
},
},
]
The invoke outcome is emitted before the method body runs, so self.state is still "closed".
The success outcome is emitted after the method body completes, so self.state has become "opened".
Why this matters
The decorator captures the bound function arguments once when the wrapper is called.
However, context_fields are resolved again before each emitted outcome. Attribute paths are evaluated at that moment.
This allows context fields to describe the current operation state.
Stable identifiers are common context fields:
request_id
message_id
connection_id
Dynamic state can also be useful:
state=self.state
phase=self.phase
retry_count=self.retry_count
Use dynamic context fields when the value at each lifecycle point matters.
What this example demonstrates
This example demonstrates that context_fields are not just copied once at invocation time.
They are evaluated for each emitted outcome:
invoke -> state before the operation body
success -> state after the operation body
The same rule applies to failed and cancelled outcomes: context fields are resolved when that outcome is emitted.