mirror of
https://github.com/MaSzyna-EU07/StarterNG.git
synced 2026-10-16 23:49:19 +02:00
log avalonia warnings and write bledy.txt as it goes
This commit is contained in:
@@ -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 =>
|
||||
|
||||
85
StarterNG/Infrastructure/DiagnosticsLogSink.cs
Normal file
85
StarterNG/Infrastructure/DiagnosticsLogSink.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user