MetroLog.Maui: logging taylor-made for Maui
The amazing performance-driven MetroLog logging library was finally ported to .net 6 and MAUI!
Platform | Logo | Package |
---|---|---|
MetroLog.Maui |
Github Repository: https://github.com/roubachof/MetroLog
Logging is your best friend
So, I'm a big fan of logging cause:
- It helps you to understand what's happening in your app
- It increases your debug session productivity tremendously
- You can retrieve logs from your users to investigate a crash
Years ago, when your core project was still a PCL library, I came across MetroLog
who is a really simple logging framework with a very small CPU footprint, which is just what we need for our mobile apps.
Issue: it has never been ported to netstandard
. But since the api used fits into the netstandard
api surface, you could just restore the package with .net45 target. And it worked flawlessly with just a little warning in your VS.
Eventually with the rise of .net 6 and MAUI, I got tired of this little warning and decided to port it to .net 6 and microsoft logging extensions.
But also to add some MAUI goodness out of the box like:
- Share logs as zip
- Display logs in a Page
- Shake the device to display the log Page
Setup
What I always liked about MetroLog, is the simplicity of the setup. Configuration is made through the crossing of a target and log levels.
A target specify how the logs will be stored. For example, you can use the TraceTarget
to show your logs in the debug output. Or you could use the FileSnapshotTarget
to store your logs in a file.
The log levels describe the level of criticality. You bind each target to a set of log levels. It goes from Trace
to Fatal
.
Here there is no weird xml or json config, very simple code, that explains it all. On top of this very easy way to configure your logger I added a layer that is compatible with the microsoft logging extensions abstractions. So the setup is even smoother and very MAUI friendly.
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>()
.ConfigureFonts(
fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
builder.Logging
#if DEBUG
.AddTraceLogger(
options =>
{
options.MinLevel = LogLevel.Trace;
options.MaxLevel = LogLevel.Critical;
}) // Will write to the Debug Output
#endif
.AddInMemoryLogger(
options =>
{
options.MaxLines = 1024;
options.MinLevel = LogLevel.Debug;
options.MaxLevel = LogLevel.Critical;
})
#if RELEASE
.AddStreamingFileLogger(
options =>
{
options.RetainDays = 2;
options.FolderPath = Path.Combine(
FileSystem.CacheDirectory,
"MetroLogs");
})
#endif
.AddConsoleLogger(
options =>
{
options.MinLevel = LogLevel.Information;
options.MaxLevel = LogLevel.Critical;
}); // Will write to the Console Output (logcat for android)
builder.Services.AddSingleton(LogOperatorRetriever.Instance);
builder.Services.AddSingleton<MainPage>();
return builder.Build();
}
}
In this cas we add 3 different targets to our configuration:
- Trace target (
Trace -> Critical
): only available for DEBUG builds, will write logs to the Debug Output - In memory target (
Debug -> Critical
) - File target (
Info -> Critical
): only available for RELEASE builds
We only specify the levels for the in memory logger, it means the other loggers will have the default min/max levels.
Default min level is Info
, default max level is Fatal
.
Usage
You can now inject your ILogger
in your constructor, and use it as you want.
public class DownloadService
{
private readonly ILogger _logger;
public DowloadService(ILogger<DownloadService> logger)
public async Task<File> DowloadAsync()
{
_logger.Info("DowloadAsync()");
try
{
await _client.GetAsync();
}
catch (Exception exception)
{
_logger.Error("Oops something bad happened", exception);
}
}
}
MAUI Goodness
With the MetroLog.Maui
package, you gain access to some sweet candies. First you get a LogController
.
LogController
The package provides a LogController that acts like a view model providing commands and service to a view.
public class LogController : INotifyPropertyChanged
{
public ICommand ToggleShakeCommand { get; }
public ICommand GoToLogsPageCommand { get; }
public ICommand ClosePageCommand { get; }
public bool CanGetCompressedLogs => LogCompressor != null;
public bool CanGetLogsString => LogLister != null;
public bool IsShakeEnabled
{
get => _isShakeEnabled;
set
{
if (_isShakeEnabled != value)
{
ToggleAccelerometer(value);
_isShakeEnabled = value;
}
OnPropertyChanged();
}
}
public static void SuspendShake();
public static void ResumeShakeIfNeeded();
public async Task<MemoryStream?> GetCompressedLogs();
public async Task<List<string>?> GetLogList();
}
We can see that you will be able to retrieve your compressed logs and even your logs as a list of string that you will be to display or whatever.
To use it, just instantiate it, it will be ready for a spin!
var logController = new LogController();
// will show the MetroLogPage by default
logController.GoToLogsCommand.Execute();
By setting IsShakeEnabled
to true, you can display your log page by simply shaking your device.
Because there is several navigation frameworks out there, you first need to initialize the LogController
with the navigation function, and the pop page function.
using MetroLog.Maui;
namespace MetroLogSample.Maui;
public partial class App : Application
{
public App(MainPage mainPage)
{
InitializeComponent();
MainPage = new NavigationPage(mainPage);
LogController.InitializeNavigation(
page => MainPage!.Navigation.PushModalAsync(page),
() => MainPage!.Navigation.PopModalAsync());
}
}
MetroLogPage
The package provides a default log page bound to the LogController
.
This page displays the logs, and give the possibility to share your logs as a zip and refresh them.
WARNING
- you need to add the
MemoryTarget
if you want to display the logs (theAddInMemoryLogger
extension). - you need to add the
StreamingFileTarget
if you want to share the logs (theAddStreamingFileLogger
extension).
Wrap-Up
Use MetroLog.Maui
to handle all your logging needs in your MAUI app.
You can also use the MetroLog.Net6
package in your .net6 libs/backend/console app/whatever.
You can access a sample app here to help you understand better the full potential of the library: https://github.com/roubachof/MetroLog