using Avalonia; using Serilog; using ZB.MOM.WW.OtOpcUa.Client.Shared; namespace ZB.MOM.WW.OtOpcUa.Client.UI; public class Program { [STAThread] public static void Main(string[] args) { ConfigureLogging(); try { BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); } finally { Log.CloseAndFlush(); } } public static AppBuilder BuildAvaloniaApp() { return AppBuilder.Configure() .UsePlatformDetect() .WithInterFont() .LogToTrace(); } /// /// Initializes the Serilog root logger with a console sink + a rolling daily file sink /// under {LocalAppData}/OtOpcUaClient/logs/. CLAUDE.md mandates Serilog with a /// rolling daily file sink as the project standard; this is also the only way the swallow /// blocks in the alarms / subscriptions / redundancy view-models surface a diagnosable /// trace when an operator hits a problem in the field. /// private static void ConfigureLogging() { var logsDir = Path.Combine(ClientStoragePaths.GetRoot(), "logs"); try { Directory.CreateDirectory(logsDir); } catch { // Best-effort; file sink will gracefully fall back if the dir can't be created. } Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .Enrich.FromLogContext() .WriteTo.Console() .WriteTo.File( path: Path.Combine(logsDir, "client-ui-.log"), rollingInterval: RollingInterval.Day, retainedFileCountLimit: 14, shared: true) .CreateLogger(); } }