Lightning Logger

In my Lightning components I always find logging and remembering how to navigate to urls using events to be an issue so I wrote this small utility base component that I then extend when creating new components. The base component share its helper with the subcomponents which allows for easy reuse of the utility functionality. The utility code provides both logging and various other utility functions such as navigating to other objects, presenting toasts etc.

Component definition of the base component is simple (note the {!v.body} which is key for abstract components to make sure the markup of child components appear):

<aura:component abstract="true" extensible="true">
 <aura:handler name="init" value="{!this}" action="{!c.doinit}" />
 {!v.body}
</aura:component>

Controller is likewise simple with basically only a callout to the helper to initialize a named Logger instance and store it in a variable called logger in the helper.

({
  doinit: function(component, event, helper) {
    const logger = helper.getLogger('SFLC_LightningHelper');
    logger.trace('Initializing LightningHelper');
    helper.logger = logger;
  }
})

To use it from another component you first extend the base component:

<aura:component implements="flexipage:availableForAllPageTypes,force:hasRecordId" extends="c:BaseComponent" controller="Foo_LCC">
  <aura:attribute name="recordId" type="Id" />
  <aura:handler name="init" value="{!this}" action="{!c.doinit}" />
  ...
  ...
</aura:component>

Then in the component controller initialization event create a named utility object (actually names the logger) and store it the “util” variable in the helper making it accessible using helper.util and the logger using helper.util.logger.

({
  doinit: function(component, event, helper) {
    // build utility
    const utility = helper.buildUtilityObject('MyComponent');
    helper.util = utility;
    
    // load data
    helper.loadData(component);
  }
})

From here on out you can simply use helper.util.logger.info, helper.util.logger.debug etc. to log for the component. All log messages are output using the named logger. The log level  which by default is NONE (meaning no output is output) is controllable using a URL parameter and loggers may be turned on and off using a URL parameter as well. Please note that the URL format used here doesn’t live up to the changes coming to Lightning URL’s in Summer ’18 or Winter ’18 (cannot remember which release).

Using the utility functionality can be done from controller and helper as shown in the loadData method using both utility functionality to invoke a remote action and to log:

({
  loadData: function(component) {
    // load data
    const helper = this;
    helper.util.invokeRemoteAction(component, 
      'getData', {'recordId': component.get("v.recordId")}, 
      function(err, data) {
        if (err) {
          helper.util.toast.error('Data Load Error', 'Unable to load data from server ('+ err +'). If the issue persists contact your System Administrator.', {sticky: true}); 
          return;
        }
        helper.util.log.debug('Received data from endpoint', data); 
      }
    )
  }
})

Zip file with Controller and Helper: BaseComponent

LotusScript.doc v2 – java.policy changes required

Strong: Just to clarify – LotusScript.doc v2 isn’t out yet. It is out in a very, very limited prebeta 1 (one person besides me) in preparation for a more general beta process hopefully in the very near future. See this post for a clarification on the progress.

LotusScript.doc v2 uses java.util.logging as its underlying logging framework. To spice things up a little it also uses some internal magic to ease troubleshooting and provide easy debugging. One of these tricks is to print out the XPath expression of the element being processed in the log. More on this another time.

In order to use java.util.logging and set custom Handlers and Formatters you need to tweek the java.policy a little bit. It’s quite easy as the only thing you have to add to your <Notes binary directory</jvm/lib/security/java.policy file is the following in the first “grant” section:

permission java.util.logging.LoggingPermission "control";

Here is a link to a default java.policy file and a changed java.policy file.

SWT@Notes 8: Logging from SWT components

As you probably know using System.out.println for logging in Java is a no-no and this is also the case when developing plugins for Notes 8 and Lotus Expeditor. This post outlines how to use the logging framework supplied with Lotus Expeditor, how to manage the logging and where the logs go.

You have probably been using log4j or similar logging framework for years. Avoiding writing to System.out is even more important when writing SWT components and plug-ins for Notes 8 a.k.a. Eclipse since the output goes to a log tucked away under the covers. Luckily there’s an approach which is so much better and more flexible.

Logging basics

Luckily logging has been built into the language (since Java 1.4) and into the Lotus Expeditor platform. Actually there is 5 different frameworks built into the Lotus Expeditor platform. Based on advise from the Lotus and personal experience I really recommend you use the java.util.logging framework built into the core Java language. This is also known as JSR47 loggers. The below graphics shows the logging sub-system of Lotus Expeditor.



Page 8 from the
IBM Lotus Expeditor 6.1 Client for Desktop Serviceability – Logging and IBM Support Assistant (PDF).

As you can see from the above you can use the following logging frameworks in Lotus Expeditor:

  • Eclipse Logging
  • OSGi Logging
  • IBM Commons Logging
  • Apache Jakarta Commons Logging
  • java.util.logging a.k.a. JSR47

I haven’t got experience with all of the these frameworks and luckily I don’t have to. I just have to know about java.util.logging and there’s an abundance of info on that on Google. The Sun tutorial might be the best place to start if you’ve never used java.util.logging. All this being equal the frameworks work the same with the only difference being how you obtain loggers and what the different logging levels are called. Log levels are called something different in the different frameworks but slide 7 in the Lotus Expeditor documentation on logging shows the mapping between the different frameworks.

Using loggers in code

Using java.util.logging in code is really easy and consists of 3 steps:

  1. Obtain the logger to use (normally in a static final variable).
  2. Write info to the logger.

The below is an example of using loggers.

package com.example.logging;

import java.util.logging.Logger;

public class MyLoggingClass {
   // logger
   private final Logger log = Logger.getLogger(
      this.getClass().getPackage().getName());

   public MyLoggingClass() {
      log.finest("Finest...");
      log.finer("Finer...");
      log.fine("Fine...");
      log.info("Info...");
      log.warning("Warning...");
      log.severe("Severe...");
   }
}

The above code creates a logger in a variable called “log” as a private variable. The logger itself is called com.example.logging which is the name used to control the log level (see below). I find it best to name the logger after the package name that contains the class. Sometimes it is however beneficial to also have a logger with more specialized names to log info on specific events.

Configuring the logger log levels

The log level for a single logger or multiple loggers can be controlled using the LogManager using the <Notes data directory>/workspace/.config/rcpinstall.properties file. To change the log level for the com.example.logging logger to FINEST add the following line to the file and restart the client:

com.example.logging.level=FINEST

To change the level dynamically use the OSGi console commands as described below.

Interacting with loggers from the OSGi console

If you start the Notes 8 client with the OSGi console visible you can interact directly with the loggers using the console command called setlogrlev. To set the log level for the com.example.logging logger to FINEST use the following command:

setlogrlev com.example.logging FINEST

Please note that the logger levels are case sensitive so you have to write “FINEST” and not “finest”.

Where the logging goes

All log messages are written to log files in the <Notes data directory>/workspace/logs directory. Opening the directory will reveal a number of files. The two most important are error-log-X.xml and trace-log-X.xml. The file names are quite explanatory and are, as the extension implies, XML-files. When you open them they’ll be rendered using a XSLT stylesheet to be displayed nicely. You can either read them using a browser or using the “Help/Support/View Log” and “Help/Support/View Trace” menu item in the Notes 8 client.

While the log files are usable I personally find it much easier and better to use the OSGi console when developing as I can adjust the log levels on the fly.

Further reading

Writing log messages in Sametime 7.5 plugins

Unfortunately the Sametime 7.5 SDK doesn’t contain any information that I can find on how to use log and debug messages in custom plugins. Furthermore all the Sametime 7.5 articles on developerWorks I have seen use System.out which is really a no, no. This post contain some information on logging that I have found out myself – partly through looking around in the Sametime 7.5 Connect client installation and partly by trial-and-error.

FYI: I’m doing a fair bit of Sametime 7.5 plugin development at the moment. For one because it’s fun and second because I’m writing an article for THE VIEW (slated for the March/April issue) on Sametime 7.5 development.

Introduction

Logging is at the heart of any development project whether that be a Notes database or a Java application. You can of cause resort to using System.out / System.err for logging but that’s clearly a no, no! If you are in doubt why I suggest you start here. Once you come to the conclusion that you really should be using a logging framework there basically is two options:

  • java.util.logging (available directly in the JDK since JDK 1.4)
  • Apache log4j

Many libraries will furthermore use Jakarta Commons Logging to isolate themselves from the underlying logging technology. In part because they cannot tell which logging framework will be used by clients and because it affords the client the choice.

However in the case of the Sametime 7.5 Connect client the choice has been made for you since Sametime 7.5 uses java.util.logging. You can choose to use Commons Logging but then the logging levels will not fit the ones used in Sametime.

I would suggest you stay with java.util.logging.

Please note: The way logging works while developing plugins in Eclipse is very much different from how it works in the *real* client. When developing all logging, incl. System.out, goes to the console.

Using java.util.logging

Obtaining a java.util.logging.Logger instance is easy:

Logger log = Logger.getLogger(this.getClass().getName());

I suggest you follow the above example and use the class name as the logger name which is also a best practice and the way that IBM does it.

Once you have the Logger-instance you can use it to log information using the different logging Levels (see the Javadoc for more information on java.util.logging).

Configuring logging in Sametime 7.5

The logs written are placed in the Sametime-directory under your using profile hereafter called the log-directory. On my Windows laptop this is “C:Documents and Settingslekkim.HQApplication DataSametime”. The logging itself is configured from the sametime.properties file in the Sametime 7.5 Connect client directory (again on my Windows laptop this is “C:Program FilesIBMSametime 7.5”).

The top of my default sametime.properties looks like this:

## G11N DNT
## Logging properties
.level=INFO
logger.filename=sametime.log
logger.includeClassInfo=true
logger.toConsole=true
logger.level=ALL
logger.limit=20000000
logger.count=7
org.apache.axis.level=INFO
redirectSystemOutput=true

## app properties
...
...

By default log-messages goes to sametime.log.0 in the log-directory with the maximum level of INFO (top bold line). To diagnose issues increase the log level to FINE, FINER, ALL etc. Be aware that the finer levels will produce *lots* of output. Note that messages written to System.out is directed to System.err by default (the second line in bold). To get this information change the redirectSystemOutput to false.

Doing this will cause output to be written to sametime.log in the log-directory instead. Restarting the Sametime 7.5 client while redirectSystemOutput is false will rotate the previous sametime.log to sametime.log.previous.

The nitty-gritty details

It appears that most of the java.util.logging configuration is done through the rcpinstall.properties file in /plugins/com.ibm.rcp.base_6.1.0.0-20060714/config/muservice. Although I wouldn’t suggest changing the file itself it may be beneficially to peruse the file to see how it’s done.

If you really want to know that is… 😉

Conclusion

It appears that Sametime uses java.util.logging and that is is quite straight forward to use – once you know how… Logging levels are easily controlled from sametime.properties and extending the logging framework to do central logging should be easily accomplished.

Happy logging…