Developer

Add Logging to your Windows Application

Add logging to your native Windows OData app, upload logs to the server, and view the logs.

Logging

Use logging features provided by supportability and logging libraries.

  • Logger Creation and Setup
    The Supportability framework provides advanced logging capabilities. Instantiate dedicated and custom logger objects using ClientLogManager’s GetLogger method. The various SDK components use specific loggers internally.
    1. Add this to import the required classes from the namespaces:
      using SAP.Supportability;
      using SAP.Supportability.Logging;
       
    2. Query the default client log manager:
      // Get ClientLogManager instance
      var logManager = SAP.Supportability.SupportabilityFacade.Instance.ClientLogManager;
       
      By default, loggers persist their logs in a local file system. If you need the logs to also appear in the console, you can override the default using the ClientLogManager’s SetLogDestination API. The API expects values defined in an EnumSet of ClientLogDestinations types, and therefore can be combined using the OR operator:
      // Gets it for every logger
      logManager.SetLogDestination((ClientLogDestinations.Console | ClientLogDestinations.FileSystem));
      
    3. Set the log output destination and log level. Two log destinations are supported:
      • Console logs are displayed in the debug console
      • FileSystem logs are persisted in the clients local storage
      ClientLogManager’s SetLogLevel method allows setting of the global log level. The default log level is ERROR, which makes your logs less verbose; however, if you need more detailed log messages, you can lower the log level to Warning or Debug:
      // Set the desired log level on all the loggers
      logManager.SetLogLevel(ClientLogLevel.Warning);
          
      // Set the desired log level for a particular logger // optional: default is ErrorClientLogLevel
      logManager.SetLogLevel(ClientLogLevel.Info, "LOGGER_PARSER");
      logManager.SetLogLevel(ClientLogLevel.Fatal, "LOGGER_SERVER");
          
      // Set the log destination for a particular logger
      logManager.SetLogDestination(ClientLogDestinations.Console, "LOGGER_PARSER");
      
      To instantiate a custom logger, provide a unique ID to every particular custom logger. Reusing the same logger ID produces the same logger instance:
      // Instantiate a custom logger
      IClientLogger customLogger = SAP.Supportability.SupportabilityFacade.Instance.ClientLogManager.GetLogger("LOGGER_PARSER");
      
    4. Log a warning using the newly created logger:
      customLogger.LogWarning("Warning message goes here");
  • Fine Tune Logger Settings

    The global setting applies for all existing logger instances, and provides default values for loggers to be created later. (If no global setting is made, the original defaults apply; Error for log level and File system for log destination.)

    Global settings can be overridden on a per logger basis, which is useful if you want to silence some components, while enabling logging for a group of selected loggers (for example, to identify issues in a specific part of the project, or focus on a small subset of components).
    // Set log level to DEBUG for this very logger
    logManager.SetLogLevel(ClientLogLevel.Debug, "CustomLogger");
    
    // Do not persist logs, just display them in the console window
    logManager.SetLogDestination(ClientLogDestinations.Console, " CustomLogger");
    
    
  • Client Log Levels
    The default log level setting is ERROR. The following log levels are supported:
    ClientLogLevel.Fatal > ClientLogLevel.Error > ClientLogLevel.Warning > ClientLogLevel.Info > ClientLogLevel.Debug..
    Lower levels automatically enable higher ones. For example, setting the log level to WARNING means that all WARNINGs, ERRORs and FATAL log messages are logged, while INFO and DEBUG messages are not:
    FATAL > ERROR > WARNING > INFO > DEBUG
    
    Setting the log level to FATAL silences all other log levels:
    FATAL > ERROR > WARNING > INFO > DEBUG
    
    Enabling the DEBUG log level is equivalent to enabling ALL log levels:
    FATAL > ERROR > WARNING > INFO > DEBUG
  • Retrieving Logs

    ClientLogManager provides APIs to retrieve the logs that have been produced by the app.

    Use IClientLogManager’s GetLogEntriesAsync to sequentially retrieve all logs with the specified and more critical level. Alternatively, use GetLogEntriesForLoggerAsync(string loggerId, ClientLogLevel logLevel) to fetch logs for a given logger.

    Retrieve logs that are below a certain ClientLogLevel:
    var entries = (IReadOnlyList<IClientLogEntry>)await logManager.GetLogEntriesAsync(ClientLogLevel.Warning);
    Or use this code for a custom logger:
    var entries  = await SupportabilityFacade.Instance.ClientLogManager.GetLogEntriesForLoggerAsync(
       "CustomLogger", ClientLogLevel.All);
    
    If the raw log data is needed for some other purpose, you can use the IEnumerable<string> TestGetRawLogData():
    var rawLogs = await logManager.GetRawLogDataAsync();
    The log is returned in a series of strings that can be cast to a List:
    rawLogs.ToList(); 
    After getting the entries the user can read each IClientLogEntry. You can persist these entries by storing the Message and additional details, such as:

    Type

    Attribute

    DateTimeOffset

    EntryDateTime

    TimeSpan

    TimeZone

    ClientLogLevel

    Severity

    string

    SourceName

    int

    MessageCode

    string

    DCComponent

    Guid?

    Guid

    string

    CorrelationId

    string

    Application

    string

    Location

    string

    User

    Guid?

    RootContextId

    Guid?

    TransactionId

    string

    Message

  • Client-side Log Persistence
    Since it is difficult to predict how many logs will be produced by an app, persisting them on the client is intentionally temporary. Logs are removed:
    • After being successfully uploaded to the server or
    • Once their expiation date is reached. By default log entries are purged after one week.
    • If the coded limit is reached: Logs are generated into various log files that are created as the logs are generated. If the sum of the logs reach a limit that can be modified by the API user, the oldest logsegment file is deleted.
    The default settings for log file persistence are:
    • File age: 604800000 ms (7 days)
    • Max. file size: 102400 (100 KB)
    • Max. number of files: 10
  • Uploading Logs to the Server

    SAP Mobile Platform Server supports uploading of client log files. Access is controlled by the security configuration associated with the given application. Therefore, prior to uploading logs, the Server Administer must set the appropriate settings. See http://help.sap.com/saphelp_smp307svr/helpdata/en/e6/46aa8668a64efb94ec30e198a0b009/content.htm (or perform a Web search for “SMP” “Defining Client Log and Trace Policies”). Additionally, the application connection ID must be passed as a “X-SMP-APPCID” header field.

    The following code attempts to upload client logs to SAP Mobile Platform Server. You must supply a valid SAP Mobile Platform Server log upload URL in the form “http(s)://host:port/clientlogs”, and the client log policy must be configured to accept log uploads on the Management Cockpit. See http://help.sap.com/saphelp_smp307svr/helpdata/en/e6/46aa8668a64efb94ec30e198a0b009/content.htm for details.
    try {
       await SAP.Supportability.SupportabilityFacade.Instance.ClientLogManager.UploadClientLogsAsync(
       new DefaultUploader(httpClient, this.pageContext.ServerUri, UploadType.Log, this.logCancellationTokenSource.Token));
    }
    catch (Exception ex) {
    	var supportabilityException = ex as SAP.Supportability.ISupportabilityException;
    	message = ex.Message + ((supportabilityException != null) ? ("(" + 
    	supportabilityException.UploadResult.ResponseStatusCode + ")\r\n") : "\r\n");
    	throw new Exception(ex.Message);
    }
    
    It’s practical to enclose the code in an event that gets called when a button is pressed. The button event that calls the uploader is in this code:
    private CancellationTokenSource logCancellationTokenSource = new CancellationTokenSource();
    
    private async void Button_UploadLogsClick(object sender, RoutedEventArgs e) {
    	this.pageContext.IsUploadingLogs = true;
    	string message = null;
    	try {
    		await SAP.Supportability.SupportabilityFacade.Instance.ClientLogManager.UploadClientLogsAsync(
    			new DefaultUploader(httpClient, this.pageContext.ServerUri, false, 
    			this.logCancellationTokenSource.Token)
    		);
    	} catch (Exception ex) {
    		var supportabilityException = ex as SAP.Supportability.ISupportabilityException;
    		message = ex.Message + ((supportabilityException != null) ? ("(" + 
    		supportabilityException.UploadResult.ResponseStatusCode + ")") : "");
    	}
    
    	this.pageContext.ReloadLogsAsync();
    	if (this.logCancellationTokenSource.IsCancellationRequested) {
    		this.logCancellationTokenSource.Dispose();
    		this.logCancellationTokenSource = new CancellationTokenSource();
    	}
    	this.pageContext.IsUploadingLogs = false;
    	await Dispatcher.BeginInvoke((Action)(() => {
    		MessageBox.Show(message ?? "Logs were successfully uploaded", message == null ? "Information" : "Error", 
    		MessageBoxButton.OK, ((message == null) ? MessageBoxImage.Information : MessageBoxImage.Error));
    	}));
    }
    
    private void Button_CancelUploadingLogsClick(object sender, RoutedEventArgs e) {
    	this.logCancellationTokenSource.Cancel();
    }
    
  • Viewing Logs on the Server

    Logs that are successfully uploaded to the server can be viewed and filtered to analyze and troubleshoot issues. See : http://help.sap.com/saphelp_smp307svr/helpdata/en/81/540a14ddb04e00a73ddaaa10c7260f/content.htm