a25593a9c6
Group all 69 projects into category subfolders under src/ and tests/ so the Rider Solution Explorer mirrors the module structure. Folders: Core, Server, Drivers (with a nested Driver CLIs subfolder), Client, Tooling. - Move every project folder on disk with git mv (history preserved as renames). - Recompute relative paths in 57 .csproj files: cross-category ProjectReferences, the lib/ HintPath+None refs in Driver.Historian.Wonderware, and the external mxaccessgw refs in Driver.Galaxy and its test project. - Rebuild ZB.MOM.WW.OtOpcUa.slnx with nested solution folders. - Re-prefix project paths in functional scripts (e2e, compliance, smoke SQL, integration, install). Build green (0 errors); unit tests pass. Docs left for a separate pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
66 lines
2.5 KiB
C#
66 lines
2.5 KiB
C#
using Serilog;
|
|
using Serilog.Core;
|
|
using Serilog.Events;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
|
|
|
/// <summary>
|
|
/// Serilog sink that mirrors script log events at <see cref="LogEventLevel.Error"/>
|
|
/// or higher to a companion logger (typically the main <c>opcua-*.log</c>) at
|
|
/// <see cref="LogEventLevel.Warning"/>. Lets operators see script errors in the
|
|
/// primary server log without drowning it in Debug/Info/Warning noise from scripts.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// Registered alongside the dedicated <c>scripts-*.log</c> rolling file sink in
|
|
/// the root script-logger configuration — events below Error land only in the
|
|
/// scripts file; Error/Fatal events land in both the scripts file (at original
|
|
/// level) and the main log (downgraded to Warning since the main log's audience
|
|
/// is server operators, not script authors).
|
|
/// </para>
|
|
/// <para>
|
|
/// The forwarded message preserves the <c>ScriptName</c> property so operators
|
|
/// reading the main log can tell which script raised the error at a glance.
|
|
/// Original exception (if any) is attached so the main log's diagnostics keep
|
|
/// the full stack trace.
|
|
/// </para>
|
|
/// </remarks>
|
|
public sealed class ScriptLogCompanionSink : ILogEventSink
|
|
{
|
|
private readonly ILogger _mainLogger;
|
|
private readonly LogEventLevel _minMirrorLevel;
|
|
|
|
public ScriptLogCompanionSink(ILogger mainLogger, LogEventLevel minMirrorLevel = LogEventLevel.Error)
|
|
{
|
|
_mainLogger = mainLogger ?? throw new ArgumentNullException(nameof(mainLogger));
|
|
_minMirrorLevel = minMirrorLevel;
|
|
}
|
|
|
|
public void Emit(LogEvent logEvent)
|
|
{
|
|
if (logEvent is null) return;
|
|
if (logEvent.Level < _minMirrorLevel) return;
|
|
|
|
var scriptName = "unknown";
|
|
if (logEvent.Properties.TryGetValue(ScriptLoggerFactory.ScriptNameProperty, out var prop)
|
|
&& prop is ScalarValue sv && sv.Value is string s)
|
|
{
|
|
scriptName = s;
|
|
}
|
|
|
|
var rendered = logEvent.RenderMessage();
|
|
if (logEvent.Exception is not null)
|
|
{
|
|
_mainLogger.Warning(logEvent.Exception,
|
|
"[Script] {ScriptName} emitted {OriginalLevel}: {ScriptMessage}",
|
|
scriptName, logEvent.Level, rendered);
|
|
}
|
|
else
|
|
{
|
|
_mainLogger.Warning(
|
|
"[Script] {ScriptName} emitted {OriginalLevel}: {ScriptMessage}",
|
|
scriptName, logEvent.Level, rendered);
|
|
}
|
|
}
|
|
}
|