From 788bb68d1d8571c21aee19d687a40c46124e3abf Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Wed, 10 Jun 2026 12:08:29 -0400 Subject: [PATCH] fix(scripting): companion sink falls back to ScriptId for the main-log mirror (T3 review) --- .../ScriptLogCompanionSink.cs | 3 +- .../ScriptLogCompanionSinkTests.cs | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting/ScriptLogCompanionSink.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting/ScriptLogCompanionSink.cs index 4f955ead..fb1aff35 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting/ScriptLogCompanionSink.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting/ScriptLogCompanionSink.cs @@ -47,7 +47,8 @@ public sealed class ScriptLogCompanionSink : ILogEventSink if (logEvent.Level < _minMirrorLevel) return; var scriptName = "unknown"; - if (logEvent.Properties.TryGetValue(ScriptLoggerFactory.ScriptNameProperty, out var prop) + if ((logEvent.Properties.TryGetValue(ScriptLoggerFactory.ScriptNameProperty, out var prop) + || logEvent.Properties.TryGetValue(ScriptLoggerFactory.ScriptIdProperty, out prop)) && prop is ScalarValue sv && sv.Value is string s) { scriptName = s; diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptLogCompanionSinkTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptLogCompanionSinkTests.cs index dd456eb3..1169b6ed 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptLogCompanionSinkTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests/ScriptLogCompanionSinkTests.cs @@ -136,6 +136,36 @@ public sealed class ScriptLogCompanionSinkTests Should.NotThrow(() => companion.Emit(ev)); } + /// + /// Tests that an Error event carrying only ScriptId (no ScriptName) is mirrored + /// with the ScriptId value — not the "unknown" fallback. + /// Evaluators built by ScriptLoggerFactory bind ScriptId, not ScriptName. + /// + [Fact] + public void ScriptId_used_as_fallback_when_ScriptName_absent() + { + var mainSink = new CapturingSink(); + var mainLogger = new LoggerConfiguration() + .MinimumLevel.Verbose().WriteTo.Sink(mainSink).CreateLogger(); + + var scriptLogger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.Sink(new ScriptLogCompanionSink(mainLogger)) + .CreateLogger(); + + // Bind ScriptId only — no ScriptName — as the evaluator path does. + scriptLogger.ForContext(ScriptLoggerFactory.ScriptIdProperty, "script-abc-123") + .Error("evaluator error"); + + mainSink.Events.Count.ShouldBe(1); + var forwarded = mainSink.Events[0]; + // ScriptName property in the forwarded event must be the ScriptId value, not "unknown". + forwarded.Properties.ShouldContainKey("ScriptName"); + ((ScalarValue)forwarded.Properties["ScriptName"]).Value + .ShouldBe("script-abc-123", + "companion sink should fall back to ScriptId when ScriptName is absent"); + } + /// Tests that null main logger is rejected. [Fact] public void Null_main_logger_rejected()