Logging Monitor Activity

This article will describe how to enable logging in the Telerik Analytics monitor. Logging will show the overall events in the monitor and also very detailed information as to what errors may be occuring.

Why logging?

In short, logging is the way the monitor can tell you if something is wrong.

The API methods on a created monitor object are designed to never fail. You can read more about this in the article about the monitor's General Behavior.

The main reasoning behind this design is to allow you to place calls to the monitor API at any place in your application without having to worry about checking for errors. That way including monitor API calls does not introduce any friction with your existing code.

However, just because the API calls cannot fail as seen from the outside does not mean that everything will always work. Your arguments to the API can be invalid, data can fail to be saved or sent, when running very low on memory the monitor itself may even fail.

Without error codes, how do you detect any such misbehavior? The answer: via logging.

How monitor logging works

Logging works by introducing a logger to receive messages from the monitor:

How logging works in the Telerik Analytics monitor

Whenever the monitor has something interesting to say, it will tell it to the associated logger. You can install your own logger or you can use the built-in logger offered by the monitor.

Here is an example of the output from running a .NET app:

Example of logging from the Telerik Analytics monitor

What is logged?

The monitor is not very chatty. It prints just enough logging to reassure users that things are working and yet little enough to not be annoying. It will only notify you about monitor start and stop, when it has succeeded or failed to send statistics to the server, or if any errors occur. You can see this in the example above.

Purely informative messages are sent to the LogMessage method, while errors go to the LogError method. If you are looking for problems then look at LogError messages.

All messages will be prefixed with Telerik Analytics Monitor: so that they are still distinctive and recognizable even if logged out to some common debugging console, like the Debug console in Windows.

Note: the callback names varies slightly across platforms but there should be no confusion as to what is the message-callback and the errormessage-callback.

How to enable logging

Logging is enabled by setting the LoggingInterface property in the settings to some instance of an ILogAnalyticsMonitor object, and creating the monitor from those settings. Note that logging is turned off by default.

You can create your own custom logger by inheriting from the ILogAnalyticsMonitor interface. Alternatively, and much easier for getting started, the monitor factory can create a logger for you that does logging in a sensible manner for each particular platform.

Here are examples in all languages of installing the factory-provided logger:

    // C# for .NET, WinRT, Silverlight etc
    IAnalyticsMonitorSettings settings = AnalyticsMonitorFactory.CreateSettings("key");
    settings.LoggingInterface = AnalyticsMonitorFactory.CreateTraceMonitor();
    IAnalyticsMonitor monitor = AnalyticsMonitorFactory.CreateMonitor(settings);
    ' VB.NET
    Dim settings As IAnalyticsMonitorSettings = AnalyticsMonitorFactory.CreateSettings("key")
    settings.LoggingInterface = AnalyticsMonitorFactory.CreateTraceMonitor
    Dim monitor As IAnalyticsMonitor = AnalyticsMonitorFactory.CreateMonitor(settings)
    // Javascript for AppBuilder
    var settings = global.plugins.EqatecAnalytics.Factory.CreateSettings("key", "1.0");
    settings.LoggingInterface = global.plugins.EqatecAnalytics.Factory.CreateTraceLogger();
    var monitor = global.plugins.EqatecAnalytics.Factory.CreateMonitor(settings);
    // Javascript for web apps
    var settings = window._eqatec.createSettings("key", "1.0");
    settings.loggingInterface = window._eqatec.createTraceLogger();
    var monitor = window._eqatec.createMonitor(settings);
    // C++ for Windows
    IAnalyticsMonitorSettings *settings = AnalyticsMonitorFactory::CreateSettings("key", "1.0");
    settings->SetLoggingInterface(AnalyticsMonitorFactory::CreateTraceMonitor());
    IAnalyticsMonitor *monitor = AnalyticsMonitorFactory::CreateMonitorWithSettings(settings);
    // C for Windows
    Eqatec_IAnalyticsMonitorSettings *settings =
         Eqatec_AnalyticsMonitorFactory_CreateSettings("key", "1.0");
    Eqatec_AnalyticsMonitorSettings_SetLoggingInterface(settings,
         Eqatec_AnalyticsMonitorFactory_CreateTraceMonitor());
    Eqatec_IAnalyticsMonitor *monitor =
         Eqatec_AnalyticsMonitorFactory_CreateMonitorWithSettings(settings);
    // Objective-C for iOS and MacOSX
    EQATECAnalyticsMonitorSettings *settings =
         [EQATECAnalyticsMonitorSettings settingsWithProductId:@"key" version:@"1.0"];
    [settings setLoggingDelegate:[EQATECTraceLogger traceLogger]];
    EQATECAnalyticsMonitor *monitor = [EQATECAnalyticsMonitor monitorWithSettings:settings];
    // Java for Android and Java
    IAnalyticsMonitorSettings settings =
         AnalyticsMonitorFactory.createSettings("key", new Version("1.0"));
    settings.setLoggingInterface(AnalyticsMonitorFactory.createTraceMonitor());
    IAnalyticsMonitor monitor = AnalyticsMonitorFactory.createMonitor(settings);

Where is the default logging printed to?

The factory-provided logger created by AnalyticsMonitorFactory.CreateTraceMonitor will output the log messages in a platform-dependent manner. Here is the complete overview:

Platform Print to
.NET (all platforms) System.Diagnostics.Debug.WriteLine()
C, C++ (Windows) OutputDebugString()
iOS and MacOSX NSLog
Java System.out.println()
AppBuilder, Javascript console.log()

Note for AppBuilder: console.log() does currently not produce any output for Windows Phone apps when using the native AppBuilder Windows client. This will be added in the Q2 2014 release of AppBuilder.

Most IDEs will show these messages in some kind of output window when running your application within them. For instance, when developing and running a Windows Phone app in Visual Studio, sending the log messages to System.Diagnostics.Debug.WriteLine() will make them appear in Visual Studio's Output window.

You can also employ other tools to view this debug output, e.g. DebugView for Windows.

Note that the output will appear also in release mode for all platforms. This goes for the .NET platform as well: even in release mode .NET monitors will still print to Debug.WriteLine as they would in Debug mode. If you want to disable logging in release mode then you should simply not install a logger.

Creating a custom logger

The factory-provided logger is great for getting started but there are compelling reasons for creating a custom logger and using that instead. With a custom logger you can, for instance

  • direct output to your favorite choice of logging mechanism (a window, log4net, file, etc)
  • notice and take special care of error-messages
  • turn your logging-output on or off at runtime

Here are examples in all languages of creating and installing a custom logger:

    // C# for .NET, WinRT, Silverlight etc
    internal class MyLogger : ILogAnalyticsMonitor
    {
      public void LogMessage(string message)
      {
        Console.WriteLine("Log Message: " + message);
      }
      public void LogError(string errorMessage)
      {
        Console.WriteLine("Error Message: " + errorMessage);
      }
    }
    ...
    IAnalyticsMonitorSettings settings = AnalyticsMonitorFactory.CreateSettings("key");
    settings.LoggingInterface = new MyLogger();
    IAnalyticsMonitor monitor = AnalyticsMonitorFactory.CreateMonitor(settings);
    ' VB.NET
    Public Class MyLogger
      Implements ILogAnalyticsMonitor
      Public Sub LogMessage(message As String) Implements ILogAnalyticsMonitor.LogMessage
        Console.WriteLine("Log Message: " + message)
      End Sub
      Public Sub LogError(errorMessage As String) Implements ILogAnalyticsMonitor.LogError
        Console.WriteLine("Error Message: " + errorMessage)
      End Sub
    End Class
    ...
    Dim settings As IAnalyticsMonitorSettings = AnalyticsMonitorFactory.CreateSettings("key")
    settings.LoggingInterface = new MyLogger
    Dim monitor As IAnalyticsMonitor = AnalyticsMonitorFactory.CreateMonitor(settings)
    // Javascript for AppBuilder
    var settings = global.plugins.EqatecAnalytics.Factory.CreateSettings("key");
    settings.LoggingInterface = {
        LogMessage: function (message) { console.log("Log Message: " + message); }
        LogError: function (errorMessage) { console.log("Log Error: " + errorMessage); },
    };
    var monitor = global.plugins.EqatecAnalytics.Factory.CreateMonitor(settings);
    // Javascript for web apps
    var settings = window._eqatec.createSettings("key", "1.0");
    settings.LoggingInterface = {
        LogMessage: function (message) { console.log("Log Message: " + message); }
        LogError: function (errorMessage) { console.log("Log Error: " + errorMessage); },
    };
    var monitor = window._eqatec.CreateMonitor(settings);
    // C++ for Windows
    using namespace EQATECAnalytics;
    class MyLogger : public ILogAnalyticsMonitor
    {
    public:
      MyLogger(void) {};
      void LogMessage(const char *message) 
      {
        std::cerr << "Log Message: " << message << std::endl;
      }
      void LogError(const char *errorMessage) 
      {
        std::cerr << "Error Message: " << errorMessage << std::endl;
      }
      // Easier logger lifetime management; when monitor is done using the logger
      // then it will call this method. We use that to delete the logger instance.
      void OnRelease()
      {
        delete this;
      }
    };
    ....
    IAnalyticsMonitorSettings *settings = AnalyticsMonitorFactory::CreateSettings("key", "1.0");
    settings->SetLoggingInterface(new MyLogger());
    IAnalyticsMonitor *monitor = AnalyticsMonitorFactory::CreateMonitorWithSettings(settings);
    // C for Windows
    void __stdcall Eqatec_SampleLogAnalyticsMonitor_LogMessage(void *context, const wchar_t *message)
    {
      fwprintf(stderr, L"Log Message: %s\n", message);
    }
    void __stdcall Eqatec_SampleLogAnalyticsMonitor_LogError(void *context, const wchar_t *errorMessage)
    {
      fwprintf(stderr, L"Log Error: %s\n", errorMessage);
    }
    ...
    Eqatec_ILogAnalyticsMonitor logger = {0};
    logger.Eqatec_ILogAnalyticsMonitor_LogError = Eqatec_SampleLogAnalyticsMonitor_LogError;
    logger.Eqatec_ILogAnalyticsMonitor_LogMessage = Eqatec_SampleLogAnalyticsMonitor_LogMessage;
    ...
    Eqatec_IAnalyticsMonitorSettings *settings =
            Eqatec_AnalyticsMonitorFactory_CreateSettings("key", "1.0");
    Eqatec_IAnalyticsMonitorSettings_SetLoggingInterface(settings, logger);
    Eqatec_IAnalyticsMonitor *monitor =
            Eqatec_AnalyticsMonitorFactory_CreateMonitorWithSettings(settings);
    // Objective-C for iOS and MacOSX
    @interface MyLogger : NSObject <EQATECLogAnalyticsMonitor> 
    @end
    ...
    @implementation MyLogger
    -(void) didLogMessage: (NSString*)message
    {
      NSLog(@"Log Message: %@", message);
    }
    -(void) didLogError:(NSError *)error
    {
      NSLog(@"Error Message: %@", [error localizedDescription]);
    }
    @end
    ...
    EQATECAnalyticsMonitorSettings *settings =
            [EQATECAnalyticsMonitorSettings settingsWithProductId:@"key" version:@"1.0"];
    [settings setLoggingDelegate:[[MyLogger alloc] init]];
    EQATECAnalyticsMonitor *monitor = [EQATECAnalyticsMonitor monitorWithSettings:settings];
    // Java for Android and Java
    public class MyLogger implements ILogAnalyticsMonitor
      @Override
      public void logMessage(String message) {
        System.out.println("Log Message: " + message);
      }
      @Override
      public void logError(String errorMessage) {
        System.out.println("Error Message: " + errorMessage);
      }
    }
    ...
    IAnalyticsMonitorSettings settings =
           AnalyticsMonitorFactory.createSettings("key", new Version("1.0"));
    settings.setLoggingInterface(new MyLogger());
    IAnalyticsMonitor monitor = AnalyticsMonitorFactory.createMonitor(settings);

Conclusion

The Monitor API methods do not return error codes. Instead, progress and errors are signalled via an associated logger. This article has shown how to install a built-in logger and how to install your very own logger.

Start a free trial Request a demo
Contact us: +1-888-365-2779
sales@telerik.com
Copyright © 2016-2017, Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.