Logging in Xamarin application: Building infrastructure with MvvmCross

Denys Fiediaiev
4 min readJun 30, 2020

--

In my previous post about logging in Xamarin, I outlined what things need to be logged and how to log them in your mobile app.

The next important step is to ensure that the logging infrastructure follows the “Don’t repeat yourself” (DRY) and “Separation of concerns” (SoC) principles.

You can significantly reduce the long-term cost of codebase development and maintenance by using a simple logging API.

In this post, I will define the logging infrastructure implementation using MvvmCross, AppCenter, and Serilog in six steps:

  1. Define logging targets map
  2. Setup logging libraries
  3. Logging application events
  4. Logging core MvvmCross events (no action required)
  5. Logging method execution time (optional)
  6. Logging FFImageLoading events (bonus)
Logging infrastructure overview

1. Define logging targets map

As the first step, it is crucial to decide what logging target will be used depending on the logging data type, current environment, and the event level.

For instance, reporting crashes during debugging is useless and leads to a blurry picture of the app state.

When using AppCenter, the logging targets mapping table looks like this:

Logging targets mapping

2. Setup logging libraries

MvvmCross has its own logging mechanism that supports some popular logging frameworks, including Serilog.

NuGet packages needed at this step: Serilog, Serilog.Sinks.File, Serilog.Sinks.Xamarin and SByteDev.Serilog.Sinks.AppCenter.

The configuration is almost the same on the iOS and Android platforms:

Serilog logger configuration example

The only difference being in the console sink: NSLog on iOS and AndroidLog on Android. This configuration writes all events to the console and file. AppCenter will also handle events with Information level and higher.

For more information on creating logger configuration, see the Serilog documentation.

This implementation follows the defined targets map, but it does not care about the current app environment, e.g. the AppCenter sink will be enabled in Debug mode.

The DEBUG symbol can be checked, or the simple Feature Registry plugin can be applied to activate sinks conditionally:

Conditional sinks activation with Feature Registry plugin

3. Logging application events

Now application-level events can be logged using a shared logger interface (IMvxLog) that is accessible from any View Model or Service.

The MvxNavigationViewModel base class is useful when a logger is required in the View Model, as it already contains the Log property.

When the logger instance is needed at the Service level, it must be passed to the constructor or initialized manually through the IoCProvider:

var logProvider = Mvx.IoCProvider.Resolve<IMvxLogProvider>();
var log = logProvider.GetLogFor("Name");

Here is a complete example of the View Model implementation:

Internal MvvmCross logger usage example
  1. When the View is created, the View Model writes an informational message that will be redirected to App Center Analytics.
  2. Then it performs some dangerous operation and tracks its successful result (if any).
  3. In case of failure in the release version of the app, the error will be redirected to App Center Crashes.

All the logs will also be written to the console or file, depending on the current configuration.

4. Logging core MvvmCross events

It is useful for developers to keep the internal MvvmCross logs as well. Why is it important? There are several reasons:

  • The most common issue is an error during the binding View Model to the View. If developers ignore a “binding failed” log message, they will never know why users stopped using the application: users will face an empty table, empty label, etc.
  • Other useful messages are related to navigation failures. Yes, MvvmCross provides ViewModel-driven navigation, but it can fail in some cases, mainly if there are custom presenters.
  • All third-party plugins also use this logging mechanism and often post events.
Log events produced by MvvmCross at the application start

5. Logging method execution time

Users like apps that run smoothly. Another step for debugging performance is to register the execution time for some critical methods.

The easiest way to get method execution time is to use the Fody.MethodTimer library.

The only thing to do is to add the Time attribute to the particular method and implement a custom interceptor that uses the internal IMvxLog:

Method time logger interceptor implementation

The logger output will look like this: SomeViewModel.ViewCreated 155 milliseconds.

6. Logging FFImageLoading events

FFImageLoading is a popular cross-platform image loading library and provides some logging functionality.

Developers can track image processing failures and events by implementing the IMiniLogger:

IMiniLogger custom implementation

The implementation of IMiniLogger needs to be set right in Setup.CreateLogProvider method:

ImageService.Instance.Config.Logger = new ImageLoaderLogger(logProvider);

The logger will produce the output like this: Generating/retrieving image: https://images.com/image;CircleTransformation,borderSize=5,borderHexColor=#FF7F7F7F.

Building a logging infrastructure for a Xamarin application is simple, and can be achieved using existing mechanisms, but adds significant value to the codebase quality.

Please share your custom logger implementations for popular libraries in the comments section below!

--

--

Denys Fiediaiev
Denys Fiediaiev

Written by Denys Fiediaiev

Xamarin | iOS | Android Developer with 8 years of experience. All things actionable tips, real-life examples and coding guides to help you grow professionally.

No responses yet