feat(scripting): evaluators log through root script logger → script-log page (F8)

This commit is contained in:
Joseph Doherty
2026-06-10 12:03:51 -04:00
parent bf86b3def6
commit bd2dd05a0c
7 changed files with 245 additions and 36 deletions
@@ -5,7 +5,6 @@ using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms;
using ZB.MOM.WW.OtOpcUa.Core.Scripting;
using SerilogLogger = Serilog.ILogger;
using SerilogLog = Serilog.Log;
namespace ZB.MOM.WW.OtOpcUa.Host.Engines;
@@ -22,20 +21,24 @@ namespace ZB.MOM.WW.OtOpcUa.Host.Engines;
/// </summary>
public sealed class RoslynScriptedAlarmEvaluator : IScriptedAlarmEvaluator, IDisposable
{
private static readonly SerilogLogger ScriptLogger = SerilogLog.ForContext<RoslynScriptedAlarmEvaluator>();
private readonly ConcurrentDictionary<string, ScriptEvaluator<AlarmPredicateContext, bool>> _cache
= new(StringComparer.Ordinal);
private readonly ILogger<RoslynScriptedAlarmEvaluator> _logger;
private readonly SerilogLogger _scriptRoot;
private readonly TimeSpan _runTimeout;
private bool _disposed;
/// <summary>Initializes a new instance of the Roslyn scripted alarm evaluator.</summary>
/// <param name="logger">Logger for diagnostic messages.</param>
/// <param name="logger">Logger for diagnostic messages (host diagnostics).</param>
/// <param name="scriptRoot">Root script logger; user <c>ctx.Logger.*</c> output flows through this to the Script-log page.</param>
/// <param name="runTimeout">Optional timeout for script evaluation; defaults to 2 seconds.</param>
public RoslynScriptedAlarmEvaluator(ILogger<RoslynScriptedAlarmEvaluator> logger, TimeSpan? runTimeout = null)
public RoslynScriptedAlarmEvaluator(
ILogger<RoslynScriptedAlarmEvaluator> logger,
ScriptRootLogger scriptRoot,
TimeSpan? runTimeout = null)
{
_logger = logger;
_scriptRoot = (scriptRoot ?? throw new ArgumentNullException(nameof(scriptRoot))).Logger;
_runTimeout = runTimeout ?? TimeSpan.FromSeconds(2);
}
@@ -71,7 +74,12 @@ public sealed class RoslynScriptedAlarmEvaluator : IScriptedAlarmEvaluator, IDis
}
var readCache = BuildReadCache(dependencies);
var context = new AlarmPredicateContext(readCache, ScriptLogger);
// Per-evaluation script logger: bind both ScriptId and AlarmId from the alarm id so the
// Script-log page can attribute each line to the owning scripted alarm.
var scriptLog = _scriptRoot
.ForContext(ScriptLoggerFactory.ScriptIdProperty, alarmId)
.ForContext(ScriptLoggerFactory.AlarmIdProperty, alarmId);
var context = new AlarmPredicateContext(readCache, scriptLog);
try
{