log avalonia warnings and write bledy.txt as it goes

This commit is contained in:
maj00r
2026-08-31 00:44:36 +02:00
parent b5fabf79f5
commit eb304aa4c7
3 changed files with 164 additions and 10 deletions

View File

@@ -15,6 +15,9 @@ public static class Diagnostics
private static readonly object Gate = new();
private static readonly List<string> Lines = new();
private static StreamWriter? _writer;
private static bool _writerFailed;
public static string LogPath =>
Path.Combine(Directory.GetCurrentDirectory(), "starter", "bledy.txt");
@@ -25,13 +28,29 @@ public static class Diagnostics
public static void Clear()
{
lock (Gate) Lines.Clear();
lock (Gate)
{
Lines.Clear();
CloseWriter();
try
{
if (File.Exists(LogPath))
File.Delete(LogPath);
}
catch
{
}
}
}
public static void Log(string message)
{
string line = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)} {message}";
lock (Gate)
Lines.Add($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)} {message}");
{
Lines.Add(line);
Append(line);
}
}
public static void Log(IEnumerable<string> messages)
@@ -45,22 +64,66 @@ public static class Diagnostics
public static void Flush()
{
string[] snapshot;
lock (Gate)
{
if (Lines.Count == 0) return;
snapshot = Lines.ToArray();
if (Lines.Count == 0)
return;
try
{
_writer?.Flush();
}
catch (Exception ex)
{
_writerFailed = true;
Lines.Add($"log flush failed: {ex.GetType().Name}: {ex.Message}");
}
if (!_writerFailed && _writer is not null)
return;
try
{
Directory.CreateDirectory(Path.GetDirectoryName(LogPath)!);
File.WriteAllLines(LogPath, Lines);
}
catch
{
}
}
}
private static void Append(string line)
{
if (_writerFailed)
return;
try
{
string dir = Path.GetDirectoryName(LogPath)!;
Directory.CreateDirectory(dir);
File.WriteAllLines(LogPath, snapshot);
if (_writer is null)
{
Directory.CreateDirectory(Path.GetDirectoryName(LogPath)!);
_writer = new StreamWriter(LogPath, append: false) { AutoFlush = true };
}
_writer.WriteLine(line);
}
catch
{
_writerFailed = true;
CloseWriter();
}
}
private static void CloseWriter()
{
try
{
_writer?.Dispose();
}
catch
{
}
_writer = null;
}
private static Window? Owner =>

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Logging;
namespace StarterNG.Infrastructure;
public sealed class DiagnosticsLogSink : ILogSink
{
private const int MaxDistinctMessages = 200;
private readonly LogEventLevel _minimumLevel;
private readonly HashSet<string> _seen = new(StringComparer.Ordinal);
private readonly object _gate = new();
private bool _capped;
private DiagnosticsLogSink(LogEventLevel minimumLevel) => _minimumLevel = minimumLevel;
public static void Install(LogEventLevel minimumLevel = LogEventLevel.Warning) =>
Logger.Sink = new DiagnosticsLogSink(minimumLevel);
public bool IsEnabled(LogEventLevel level, string area) => level >= _minimumLevel;
public void Log(LogEventLevel level, string area, object? source, string messageTemplate) =>
Write(level, area, source, messageTemplate, null);
public void Log(LogEventLevel level, string area, object? source, string messageTemplate,
params object?[] propertyValues) =>
Write(level, area, source, messageTemplate, propertyValues);
private void Write(LogEventLevel level, string area, object? source, string messageTemplate,
object?[]? propertyValues)
{
if (!IsEnabled(level, area))
return;
string line = $"[Avalonia/{area}/{level}] {Format(messageTemplate, propertyValues)}";
if (source is not null)
line += $" (source: {source.GetType().Name})";
lock (_gate)
{
if (_capped || !_seen.Add(line))
return;
if (_seen.Count >= MaxDistinctMessages)
{
_capped = true;
Diagnostics.Log(line);
Diagnostics.Log($"[Avalonia] {MaxDistinctMessages} distinct messages logged, muting the rest");
return;
}
}
Diagnostics.Log(line);
}
private static string Format(string template, object?[]? values)
{
if (values is null || values.Length == 0 || template.IndexOf('{') < 0)
return template;
var sb = new StringBuilder(template.Length + 32);
int next = 0;
for (int i = 0; i < template.Length; i++)
{
if (template[i] != '{')
{
sb.Append(template[i]);
continue;
}
int close = template.IndexOf('}', i);
if (close < 0)
{
sb.Append(template, i, template.Length - i);
break;
}
sb.Append(next < values.Length ? values[next]?.ToString() ?? "null" : template[i..(close + 1)]);
next++;
i = close;
}
return sb.ToString();
}
}

View File

@@ -5,7 +5,7 @@ using StarterNG.Infrastructure;
namespace StarterNG;
class Program
static class Program
{
[STAThread]
@@ -39,9 +39,15 @@ class Program
}
}
private static AppBuilder WithDiagnosticsLogging(this AppBuilder builder)
{
DiagnosticsLogSink.Install();
return builder;
}
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
.WithDiagnosticsLogging();
}