Browse Source

Add a simple non-serilog debug log sink.

pull/4135/head
Steven Kirk 6 years ago
parent
commit
ccd6d54b38
  1. 7
      samples/ControlCatalog.NetCore/Program.cs
  2. 178
      src/Avalonia.Base/Logging/DebugLogSink.cs
  3. 26
      src/Avalonia.Controls/LoggingExtensions.cs

7
samples/ControlCatalog.NetCore/Program.cs

@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading;
using Avalonia;
using Avalonia.ReactiveUI;
using Avalonia.Dialogs;
using Avalonia.OpenGL;
using Avalonia.ReactiveUI;
namespace ControlCatalog.NetCore
{
@ -69,7 +67,8 @@ namespace ControlCatalog.NetCore
})
.UseSkia()
.UseReactiveUI()
.UseManagedSystemDialogs();
.UseManagedSystemDialogs()
.LogToDebug();
static void SilenceConsole()
{

178
src/Avalonia.Base/Logging/DebugLogSink.cs

@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Avalonia.Utilities;
namespace Avalonia.Logging
{
public class DebugLogSink : ILogSink
{
private readonly LogEventLevel _level;
private readonly IList<string> _areas;
public DebugLogSink(
LogEventLevel minimumLevel,
IList<string> areas = null)
{
_level = minimumLevel;
_areas = areas?.Count > 0 ? areas : null;
}
public bool IsEnabled(LogEventLevel level) => level >= _level;
public void Log(LogEventLevel level, string area, object source, string messageTemplate)
{
if (IsEnabled(level, area))
{
Debug.WriteLine(Format<object, object, object>(area, messageTemplate, source));
}
}
public void Log<T0>(LogEventLevel level, string area, object source, string messageTemplate, T0 propertyValue0)
{
if (IsEnabled(level, area))
{
Debug.WriteLine(Format<T0, object, object>(area, messageTemplate, source, propertyValue0));
}
}
public void Log<T0, T1>(LogEventLevel level, string area, object source, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
{
if (IsEnabled(level, area))
{
Debug.WriteLine(Format<T0, T1, object>(area, messageTemplate, source, propertyValue0, propertyValue1));
}
}
public void Log<T0, T1, T2>(LogEventLevel level, string area, object source, string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
{
if (IsEnabled(level, area))
{
Debug.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1, propertyValue2));
}
}
public void Log(LogEventLevel level, string area, object source, string messageTemplate, params object[] propertyValues)
{
if (IsEnabled(level, area))
{
Debug.WriteLine(Format(area, messageTemplate, source, propertyValues));
}
}
private bool IsEnabled(LogEventLevel level, string area) => IsEnabled(level) && (_areas?.Contains(area) ?? true);
private static string Format<T0, T1, T2>(
string area,
string template,
object source,
T0 v0 = default,
T1 v1 = default,
T2 v2 = default)
{
var result = new StringBuilder(template.Length);
var r = new CharacterReader(template.AsSpan());
var i = 0;
result.Append('[');
result.Append(area);
result.Append("] ");
while (!r.End)
{
var c = r.Take();
if (c != '{')
{
result.Append(c);
}
else
{
if (r.Peek != '{')
{
result.Append('\'');
result.Append(i++ switch
{
0 => v0,
1 => v1,
2 => v2,
_ => null
});
result.Append('\'');
r.TakeUntil('}');
r.Take();
}
else
{
result.Append('{');
r.Take();
}
}
}
if (source is object)
{
result.Append(" (");
result.Append(source.GetType().Name);
result.Append(" #");
result.Append(source.GetHashCode());
result.Append(')');
}
return result.ToString();
}
private static string Format(
string area,
string template,
object source,
object[] v)
{
var result = new StringBuilder(template.Length);
var r = new CharacterReader(template.AsSpan());
var i = 0;
result.Append('[');
result.Append(area);
result.Append(']');
while (!r.End)
{
var c = r.Take();
if (c != '{')
{
result.Append(c);
}
else
{
if (r.Peek != '{')
{
result.Append('\'');
result.Append(i < v.Length ? v[i++] : null);
result.Append('\'');
r.TakeUntil('}');
r.Take();
}
else
{
result.Append('{');
r.Take();
}
}
}
if (source is object)
{
result.Append('(');
result.Append(source.GetType().Name);
result.Append(" #");
result.Append(source.GetHashCode());
result.Append(')');
}
return result.ToString();
}
}
}

26
src/Avalonia.Controls/LoggingExtensions.cs

@ -0,0 +1,26 @@
using Avalonia.Controls;
using Avalonia.Logging;
namespace Avalonia
{
public static class LoggingExtensions
{
/// <summary>
/// Logs Avalonia events to the <see cref="System.Diagnostics.Debug"/> sink.
/// </summary>
/// <typeparam name="T">The application class type.</typeparam>
/// <param name="builder">The app builder instance.</param>
/// <param name="level">The minimum level to log.</param>
/// <param name="areas">The areas to log. Valid values are listed in <see cref="LogArea"/>.</param>
/// <returns>The app builder instance.</returns>
public static T LogToDebug<T>(
this T builder,
LogEventLevel level = LogEventLevel.Warning,
params string[] areas)
where T : AppBuilderBase<T>, new()
{
Logger.Sink = new DebugLogSink(level, areas);
return builder;
}
}
}
Loading…
Cancel
Save