feat(logging): carry ExecutionId across actor hops onto other actors' log lines (ScadaBridge#56)
LogContext is an AsyncLocal and does not cross an Akka message hop, so the run's id now rides the message: Commons.Observability.IExecutionCorrelated (explicit interface member, no wire change) on SetStaticAttributeCommand, AttributeValueChanged (not for an inferred writer), ScriptCallRequest and the four RouteTo*Requests, plus a new additive SourceExecutionId on GetAttributeRequest, WaitForAttributeRequest, WriteAttributeBatchRequest, WriteTagRequest and WriteTagBatchRequest. ScriptRuntimeContext stamps its id on the requests it sends, the Instance Actor hands it on to the DCL, and the Instance, Script, Alarm, Deployment Manager and both DCL actors re-push it per message in AroundReceive (ExecutionLogContext.PushFor: one type test when the message names no execution). The inbound executor pushes the request's ExecutionId for the method execution. Tests (TestKit): Instance Actor line carries the message's id, no leak from the sender's ambient context, scope ends with the message, per-write ids inside a batched SetAttributes, ids forwarded on DCL writes, ScriptRuntimeContext stamps; DCL adapter lines on single/batch writes carry the id; inbound executor lines carry the request id; Commons mapping + no serialized member. Each mutation- proved. Still open on #56: a queryable per-execution sink and a Flow Debugger section. The DCL actors' own Akka _log lines bypass Serilog (filed #120). Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -233,6 +233,26 @@ public class DataConnectionManagerActor : ReceiveActor
|
||||
_log.Warning("No connection actor for {0} during alarm unsubscribe", request.ConnectionName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ScadaBridge#56: while handling a message sent on behalf of an execution
|
||||
/// (<see cref="IExecutionCorrelated"/>), every line this actor logs - and every line logged by
|
||||
/// a continuation it starts - carries that execution's <c>ExecutionId</c>. A message that names
|
||||
/// no execution costs one type test.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Enrichment reaches lines written through a Serilog-backed <c>ILogger</c> - here, the protocol
|
||||
/// adapter's own logging on the write path, whose <c>WriteAsync</c> starts inside this scope. This
|
||||
/// actor's own Akka <c>_log</c> lines go through Akka's logger, not Serilog, and are not enriched.
|
||||
/// </remarks>
|
||||
/// <param name="receive">The behaviour that handles the message.</param>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <returns>Whether the message was handled.</returns>
|
||||
protected override bool AroundReceive(Receive receive, object message)
|
||||
{
|
||||
using (ExecutionLogContext.PushFor(message))
|
||||
return base.AroundReceive(receive, message);
|
||||
}
|
||||
|
||||
private void HandleRouteWrite(WriteTagRequest request)
|
||||
{
|
||||
if (_connectionActors.TryGetValue(request.ConnectionName, out var actor))
|
||||
|
||||
Reference in New Issue
Block a user