-
Notifications
You must be signed in to change notification settings - Fork 4
Display NLog LogEvents in .NET MAUI View
This guide shows a simple way to display NLog log events directly inside a .NET MAUI application.
The approach consists of three steps:
- Define a
LogRecord - Add NLog events to the collection
ObservableCollection<LogRecord> - Display the collection using a MAUI
CollectionView
The result is a simple in-app log viewer without introducing a dedicated logging UI component.
First, define the information you want to display.
public sealed record LogRecord(
DateTime Timestamp,
NLog.LogLevel Level,
string Logger,
string Message,
Exception? Exception);Use an NLog MethodCallTarget for converting LogEventInfo and adding to the LogRecords-collection.
The method can look like this:
public static class MauiProgram
{
public static ObservableCollection<LogRecord> LogRecords { get; } = new();
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.Logging.ClearProviders();
var logViewerTarget = new MethodCallTarget("MauiLogViewer", (logEvent, args) => AddLogEvent(logEvent));
NLog.LogManager.Setup()
.RegisterMauiLog()
.LoadConfiguration(cfg => cfg
.ForLogger()
.FilterMinLevel(NLog.LogLevel.Info)
.WriteToMauiLog()
.WriteTo(logViewerTarget));
builder.Logging.AddNLog();
builder.UseMauiApp<App>();
return builder.Build();
}
private static void AddLogEvent(LogEventInfo logEvent)
{
var record = new LogRecord(
logEvent.TimeStamp,
logEvent.Level,
logEvent.LoggerName,
logEvent.FormattedMessage,
logEvent.Exception);
// MainThread ensure log events coming from background threads are added using the UI-thread.
MainThread.BeginInvokeOnMainThread(() =>
{
LogRecords.Add(record);
const int maxRecords = 500;
// Avoid growing the collection indefinitely.
while (LogRecords.Count > maxRecords)
LogRecords.RemoveAt(0);
});
}
}The target is simply another destination for NLog events; your existing logging calls do not need to change.
The maximum number of records is controlled by the code adding records to the collection, keeping the in-memory log bounded.
MAUI's CollectionView can display the ObservableCollection directly.
The local XAML namespace must reference the namespace containing MauiProgram. For example, if MauiProgram is in the MauiApp2 namespace, add the following to your ContentPage:
<ContentPage
...
xmlns:local="clr-namespace:MauiApp2">You can then bind the CollectionView directly to the static LogRecords collection:
<CollectionView
ItemsSource="{x:Static local:MauiProgram.LogRecords}"
ItemsUpdatingScrollMode="KeepLastItemInView">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid
Padding="8,4"
ColumnDefinitions="Auto,Auto,Auto,*"
ColumnSpacing="12">
<Label Grid.Column="0"
Text="{Binding Timestamp, StringFormat='{0:HH:mm:ss.fff}'}" />
<Label Grid.Column="1"
Text="{Binding Level}" />
<Label Grid.Column="2"
Text="{Binding Logger}" />
<Label Grid.Column="3"
Text="{Binding Message}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>You now have a simple log view showing:
| Timestamp | Level | Logger | Message |
|---|---|---|---|
| 12:31:02.123 | Info | MyApp.Api | Request started |
| 12:31:03.002 | Warn | MyApp.Database | Query took 842 ms |
| 12:31:03.114 | Error | MyApp.Api | Request failed |
The basic LogRecord can be extended to also include structured information like IReadOnlyDictionary<string, object?> Properties if needed.
You can also add filtering, searching, level-specific colors, a clear button, or control automatic scrolling without changing the basic NLog integration.
The complete setup is intentionally simple:
LogEventInfo
↓
MethodCallTarget
↓
LogRecord
↓
ObservableCollection<LogRecord>
↓
CollectionView
This approach provides a lightweight in-app log viewer without changing existing logging calls, while leaving the UI and functionality entirely under your control. It can be further extended to meet your application's requirements, or serve as an example of using MethodCallTarget as a bridge to an existing LogViewer control.