using Avalonia;
using Serilog;
using ZB.MOM.WW.OtOpcUa.Client.Shared;
namespace ZB.MOM.WW.OtOpcUa.Client.UI;
/// Entry point for the OPC UA client UI application.
public class Program
{
/// Main entry point for the application.
/// Command-line arguments passed to the application.
[STAThread]
public static void Main(string[] args)
{
ConfigureLogging();
try
{
BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
}
finally
{
Log.CloseAndFlush();
}
}
/// Builds the Avalonia AppBuilder with platform-specific configuration.
/// Configured AppBuilder for desktop lifetime.
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();
}
}