feat(scripting): evaluators log through root script logger → script-log page (F8)
This commit is contained in:
@@ -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
|
||||
{
|
||||
|
||||
@@ -5,7 +5,6 @@ using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.VirtualTags;
|
||||
using SerilogLogger = Serilog.ILogger;
|
||||
using SerilogLog = Serilog.Log;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Host.Engines;
|
||||
|
||||
@@ -23,20 +22,24 @@ namespace ZB.MOM.WW.OtOpcUa.Host.Engines;
|
||||
/// </summary>
|
||||
public sealed class RoslynVirtualTagEvaluator : IVirtualTagEvaluator, IDisposable
|
||||
{
|
||||
private static readonly SerilogLogger ScriptLogger = SerilogLog.ForContext<RoslynVirtualTagEvaluator>();
|
||||
|
||||
private readonly ConcurrentDictionary<string, ScriptEvaluator<VirtualTagContext, object?>> _cache
|
||||
= new(StringComparer.Ordinal);
|
||||
private readonly ILogger<RoslynVirtualTagEvaluator> _logger;
|
||||
private readonly SerilogLogger _scriptRoot;
|
||||
private readonly TimeSpan _runTimeout;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>Initializes a new RoslynVirtualTagEvaluator with the given logger and optional timeout.</summary>
|
||||
/// <param name="logger">Logger for recording compilation and execution errors.</param>
|
||||
/// <summary>Initializes a new RoslynVirtualTagEvaluator with the given loggers and optional timeout.</summary>
|
||||
/// <param name="logger">Logger for recording compilation and execution errors (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">Maximum execution time for each script; defaults to 2 seconds if not specified.</param>
|
||||
public RoslynVirtualTagEvaluator(ILogger<RoslynVirtualTagEvaluator> logger, TimeSpan? runTimeout = null)
|
||||
public RoslynVirtualTagEvaluator(
|
||||
ILogger<RoslynVirtualTagEvaluator> logger,
|
||||
ScriptRootLogger scriptRoot,
|
||||
TimeSpan? runTimeout = null)
|
||||
{
|
||||
_logger = logger;
|
||||
_scriptRoot = (scriptRoot ?? throw new ArgumentNullException(nameof(scriptRoot))).Logger;
|
||||
_runTimeout = runTimeout ?? TimeSpan.FromSeconds(2);
|
||||
}
|
||||
|
||||
@@ -84,12 +87,18 @@ public sealed class RoslynVirtualTagEvaluator : IVirtualTagEvaluator, IDisposabl
|
||||
}
|
||||
|
||||
var readCache = BuildReadCache(dependencies);
|
||||
// Per-evaluation script logger: bind both ScriptId and VirtualTagId from the virtual-tag id
|
||||
// (in the live path the script id equals the virtual-tag id) so the Script-log page can
|
||||
// attribute each line. EquipmentId stays unbound for now.
|
||||
var scriptLog = _scriptRoot
|
||||
.ForContext(ScriptLoggerFactory.ScriptIdProperty, virtualTagId)
|
||||
.ForContext(ScriptLoggerFactory.VirtualTagIdProperty, virtualTagId);
|
||||
var context = new VirtualTagContext(
|
||||
readCache,
|
||||
setVirtualTag: (path, _) =>
|
||||
_logger.LogDebug("VirtualTag {Id}: cross-tag write to {Path} dropped (single-tag adapter)",
|
||||
virtualTagId, path),
|
||||
logger: ScriptLogger);
|
||||
logger: scriptLog);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -109,13 +109,17 @@ if (hasDriver)
|
||||
// Replaces the F8-default NullVirtualTagEvaluator so VirtualTagActor evaluates real user
|
||||
// scripts at runtime.
|
||||
builder.Services.AddSingleton<RoslynVirtualTagEvaluator>(sp =>
|
||||
new RoslynVirtualTagEvaluator(sp.GetRequiredService<ILoggerFactory>().CreateLogger<RoslynVirtualTagEvaluator>()));
|
||||
new RoslynVirtualTagEvaluator(
|
||||
sp.GetRequiredService<ILoggerFactory>().CreateLogger<RoslynVirtualTagEvaluator>(),
|
||||
sp.GetRequiredService<ScriptRootLogger>()));
|
||||
builder.Services.AddSingleton<IVirtualTagEvaluator>(sp => sp.GetRequiredService<RoslynVirtualTagEvaluator>());
|
||||
|
||||
// F9b — same pattern for scripted-alarm predicates. The actor preserves prior state on
|
||||
// any Failure result, so a misbehaving script can't flip Active/Inactive spuriously.
|
||||
builder.Services.AddSingleton<RoslynScriptedAlarmEvaluator>(sp =>
|
||||
new RoslynScriptedAlarmEvaluator(sp.GetRequiredService<ILoggerFactory>().CreateLogger<RoslynScriptedAlarmEvaluator>()));
|
||||
new RoslynScriptedAlarmEvaluator(
|
||||
sp.GetRequiredService<ILoggerFactory>().CreateLogger<RoslynScriptedAlarmEvaluator>(),
|
||||
sp.GetRequiredService<ScriptRootLogger>()));
|
||||
builder.Services.AddSingleton<IScriptedAlarmEvaluator>(sp => sp.GetRequiredService<RoslynScriptedAlarmEvaluator>());
|
||||
|
||||
// Script-log fan-out (Layer 0). The DPS publisher resolves the ActorSystem lazily so it never
|
||||
|
||||
Reference in New Issue
Block a user