84 lines
3.5 KiB
C#
84 lines
3.5 KiB
C#
using System.Diagnostics;
|
|
using System.Text.Json;
|
|
using Autodesk.AutoCAD.ApplicationServices;
|
|
using Autodesk.ProcessPower.PlantInstance;
|
|
|
|
namespace PRecAnnot.Plant3D2026;
|
|
|
|
internal static class RuntimeDiagnostics
|
|
{
|
|
private static readonly object Gate = new();
|
|
private static readonly string LogDirectory = Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
|
"Promhimproekt", "PRecAnnot2026", "Logs");
|
|
|
|
public static string RuntimeMode => Environment.GetEnvironmentVariable("P_REC_ANNOT_RUNTIME_MODE") ?? "Normal";
|
|
|
|
public static bool IsOrthoStructureDiagnosticsEnabled =>
|
|
string.Equals(RuntimeMode, "DryRun", StringComparison.OrdinalIgnoreCase) &&
|
|
string.Equals(Environment.GetEnvironmentVariable("P_REC_ANNOT_DIAGNOSTICS"), "OrthoStructure", StringComparison.OrdinalIgnoreCase);
|
|
|
|
public static void Write(
|
|
string eventType,
|
|
string level = "INFO",
|
|
string? operationId = null,
|
|
string? commandName = null,
|
|
string? resultStatus = null,
|
|
System.Exception? exception = null,
|
|
Document? document = null,
|
|
IReadOnlyDictionary<string, object?>? details = null)
|
|
{
|
|
try
|
|
{
|
|
var payload = new Dictionary<string, object?>(StringComparer.Ordinal)
|
|
{
|
|
["Timestamp"] = DateTimeOffset.UtcNow,
|
|
["Level"] = level,
|
|
["OperationId"] = operationId,
|
|
["EventType"] = eventType,
|
|
["AssemblyVersion"] = typeof(EntryPoint).Assembly.GetName().Version?.ToString(),
|
|
["AutoCADVersion"] = typeof(Document).Assembly.GetName().Version?.ToString(),
|
|
["PlantVersion"] = typeof(PlantApplication).Assembly.GetName().Version?.ToString(),
|
|
["ProcessId"] = Environment.ProcessId,
|
|
["ThreadId"] = Environment.CurrentManagedThreadId,
|
|
["ApartmentState"] = Thread.CurrentThread.GetApartmentState().ToString(),
|
|
["ActiveDocumentName"] = SafeDocumentName(document),
|
|
["CommandName"] = commandName,
|
|
["ResultStatus"] = resultStatus,
|
|
["ExceptionType"] = exception?.GetType().FullName,
|
|
["ExceptionMessage"] = exception?.Message,
|
|
["StackTrace"] = level.Equals("ERROR", StringComparison.OrdinalIgnoreCase) ? exception?.StackTrace : null,
|
|
["RuntimeMode"] = RuntimeMode
|
|
};
|
|
|
|
if (details is not null)
|
|
foreach (var item in details) payload[item.Key] = item.Value;
|
|
|
|
var line = JsonSerializer.Serialize(payload) + Environment.NewLine;
|
|
lock (Gate)
|
|
{
|
|
Directory.CreateDirectory(LogDirectory);
|
|
File.AppendAllText(Path.Combine(LogDirectory, "runtime.jsonl"), line);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Runtime diagnostics must never prevent AutoCAD command execution.
|
|
}
|
|
}
|
|
|
|
private static string? SafeDocumentName(Document? document)
|
|
{
|
|
try { return document is null ? null : Path.GetFileName(document.Name); }
|
|
catch { return null; }
|
|
}
|
|
}
|
|
|
|
internal sealed class SmokeWriteBlockedException() : InvalidOperationException("SMOKE_WRITE_BLOCKED");
|
|
|
|
internal static class SmokeGuard
|
|
{
|
|
public static bool IsSmoke => string.Equals(RuntimeDiagnostics.RuntimeMode, "Smoke", StringComparison.OrdinalIgnoreCase);
|
|
public static void EnsureReadOnly() { if (IsSmoke) throw new SmokeWriteBlockedException(); }
|
|
}
|