« Back

Using SLF4J and Liferay Logging Framework in custom plugins

Technical Blogs February 28, 2014 By Denis Signoretto

SLF4J LogoBefore starting this post I would like to recall a previous excellent article of Brett Swaim "Using log4j to ensure each portlet has it's own log file". In his post Brett summarizes (look at the article and comments) pros and cons of Log4j versus Liferay Logging Framework as the logging API to use in your custom plugins (portlets, web, hooks and so on).

In this article I would like to describe the SLF4J alternative. Starting from version 6.1.0 GA1 (LPS-24342) Liferay introduced SLF4J (http://www.slf4j.org) and the related Liferay Logging Framework SLF4J Adapter.

The combination of the two brings many benefits; in particular you can achieve:

  • SLFJ4 API:

    • the SFL4J logging API to ensure portability

    • SFL4J can safely be used with service builder

  • Liferay Logging Framework SLF4J Adapter:

    • adjust the logging on the fly through Control Panel

    • configure custom plugin logging without modifying portal files

    • let your plugin log in it's own separate log file

  • Log4j and extras (Liferay Logging Framework relies on it):

    • format your log strings

    • rotate your log file

    • compress your rotated log files and store them in a separate directory.

 

Using SLF4J in your custom plugins

To use SLF4J in your portlets or in general in Liferay plugins, you just need to:

  • Add SLF4J to your imports and declare a logger

  • Add SLF4J dependencies to your plugin. You can do that manually copying slf4j-api.jar and util-slf4j.jar (the Liferay SLF4J adapter) into your plugin WEB-INF\lib directory or include them as portal dependencies in liferay-plugin-package.properties (Liferay will add it for you during the auto deployment phase - if you are using Maven just add them as provided dependencies).

 

Let your plugin log in a separate file without modify portal files

During hot deployment phase Liferay checks if “META-INF/portal-log4j.xml” exists in the classpath of your custom plugin (just create it under /WEB-INF/classes/META-INF/portal-log.xml). If it exists, the Liferay plugin hot deploy listener invoke the initLogger() that will reinitialize the Liferay logging system merging your appenders with those defined in Liferay.

To get it working successfully avoiding Log4j classloader exceptions (LPS-9376) you need to remove the log4j dependency from your plugin (or start your JMV with the system property -Dlog4j.ignoreTCL=true).To prevent Log4j being copied to WEB-INF\lib during the auto deploy process, there are couple of alternatives:

  • add auto.deploy.copy.log4j=false to your portal-ext.properties (affects all plugins)

  • add deploy-excludes=**/WEB-INF/lib/log4j.jar in the liferay-plugin-package.properties file of your plugin (affects only your plugin)

 

Leverage Log4j Companion Extras to format, rotate and compress rotated files

As you probably already know Liferay Logging Framework is based upon Log4j 1.2.x. Starting from version 6.1 (LPS-18970 and LPS-33129) Liferay introduced the Log4j Extras Companion handling its deployment in custom plugins as well. (Apache Extras Companion for Apache log4j is a collection of appenders, filters, layouts, and receivers for Apache log4j 1.2 originally developed in the discontinued Apache log4j 1.3 and backported to 1.2).

Then you can take advantage of:

  • TimeBasedRollingPolicy, that offers:

    • automatic file compression. This feature is enabled if the value of the FileNamePattern option ends with .gz or .zip

    • decoupling the location of the active log file and the archived log files. Setting the ActiveFileName option you can decouple the location of the active log file and the location of the archived log files.

  • EnhancedPatternLayout: A flexible layout configurable with pattern string. The goal of this class is to format a LoggingEvent and return the results in a StringBuffer.

You can find a working slf4j sample portlet here: https://github.com/denissignoretto/slf4j-logging-sample-portlet

Hopefully this article helps and expands the range of choices for logging in your Liferay projects !

Denis.

 

 

Threaded Replies Author Date
I got this to work for the most part, but can't... Jan Eerdekens March 6, 2014 4:43 AM
Hi Jan, happy to hear that you tryied and it... Denis Signoretto March 7, 2014 12:21 AM
As Jan reported in... Denis Signoretto March 7, 2014 12:26 AM
I tried some (very) quick debugging yesterday... Jan Eerdekens March 7, 2014 12:44 AM
I opened a feature request to add MDC (Mapped... Denis Signoretto March 7, 2014 1:09 AM
Hi Denis, I have follow you steps but it's... abdo koptan June 17, 2014 6:52 AM
How would you log from a managedbean in a jsf... Eric Soucy June 17, 2014 11:48 AM
Hi, It's working partially for me, I see my log... Eric Soucy June 17, 2014 1:18 PM
Hi Eric, it seems, you have setup correclty... Denis Signoretto June 18, 2014 2:41 AM
Hi Denis, The example is working great for... Thomas Hii June 22, 2014 8:25 PM
Finally figured out that the problem is due to... Thomas Hii June 23, 2014 1:59 AM
Hi Tomas, thanks for sharing this info! Denis Signoretto June 23, 2014 3:36 AM
Hi, Denis Thank you Denis for the information. ... Alberto de Francisco Martín June 25, 2015 9:53 AM
Thank you very much sharing details. In your... Nagendra Kumar Busam October 9, 2015 9:02 AM
Hi Nagendra, Liferay SLF4J layer came in with... Denis Signoretto October 12, 2015 5:41 AM
Hi Denis, As per your blog I am trying to... parikshit sharma December 23, 2015 8:22 AM
It is also not working for me on jboss EAP 6.2.... sandeep l February 4, 2016 9:10 AM
[...] NOTE: This article is based on previous... Anonymous August 1, 2016 8:50 PM

I got this to work for the most part, but can't seem to get MDC to work. I add values to the MDC and use a pattern that should print them, but no values get printed, but the rest of the log line does.
Posted on 3/6/14 4:43 AM.
Hi Jan,

happy to hear that you tryied and it works. I can confirm that MDC(Mapped Diagnostic Context) doesn't work using Liferay Logging Framework SLF4J Adapter (util-slf4j.jar). Looking at source code of org.slf4j.impl.StaticMDCBinder (https://github.com/liferay/liferay-portal/blob/6.2.0-ga1/util-slf4j/src/org/slf­4j/impl/StaticMDCBinder.java) it returns a BasicMDCAdapter and as BasicMDCAdapter javadoc reports "can be used with logging systems that lack out-of-the-box MDC support". It seems it's still an unsupported feature.

I've just seen, commented and voted your reported https://issues.liferay.com/browse/LPS-44869.

Thanks,
Denis.
Posted on 3/7/14 12:21 AM in reply to Jan Eerdekens.
As Jan reported in https://issues.liferay.com/browse/LPS-44869 switching to slf4j-log4j12 MDC works as expected.
Posted on 3/7/14 12:26 AM in reply to Denis Signoretto.
I tried some (very) quick debugging yesterday and found that stuff got put into the MDC correctly, but when the log message is being formatted the values aren't there anymore. Didn't have the time yet to delve in deeper to see what causes it.
Posted on 3/7/14 12:44 AM in reply to Denis Signoretto.
I opened a feature request to add MDC (Mapped Diagnostic Context) support to Liferay Logging API (https://issues.liferay.com/browse/LPS-44900) and extend it to SLF4J Adapter (https://issues.liferay.com/browse/LPS-44869).
Posted on 3/7/14 1:09 AM in reply to Jan Eerdekens.
Hi Denis,

I have follow you steps but it's not working for me, i am using liferay 6.1 - Jboss 7.1

Thank you
Posted on 6/17/14 6:52 AM.
How would you log from a managedbean in a jsf portlet?
what import statements are needed ?
Posted on 6/17/14 11:48 AM.
Hi,
It's working partially for me, I see my log output in the console, and in the liferay.log file
my custom rolling appender file gets created but my logout output is not in the file.
I do see other lines being logged in the file, but not the ones I logged from my managed bean.
Posted on 6/17/14 1:18 PM.
Hi Eric,

it seems, you have setup correclty the Liferay logging system to log on a separate file but you are not sending log to Liferay logging system. Check your slf4j imports in your class and use an slf4j Logger instance for logging.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

You can find a working slf4j sample portlet here: https://github.com/denissignoretto/slf4j-logging-sample-portlet

Hope it can help!
Denis.
Posted on 6/18/14 2:41 AM in reply to Eric Soucy.
Hi Denis,

The example is working great for Liferay 6.2 running on Tomcat. However when I tried it with Liferay 6.2 running on JBoss 7 or JBoss EAP 6, the log file is created but nothing is written to it. Any idea on what might cause this problem?
Posted on 6/22/14 8:25 PM.
Finally figured out that the problem is due to JBoss class loading. By default, JBoss always load its version of log4j and slf4j. These need to be excluded via the jboss-deployment-structure.xml file. App Manager seems to generate this file during deployment, but org.slf4j is not in the exclusion list. After adding org.slf4j, the custom logging works nicely on JBoss 7.1 and JBoss EAP 6.2.
Posted on 6/23/14 1:59 AM in reply to Thomas Hii.
Hi Tomas,

thanks for sharing this info!
Posted on 6/23/14 3:36 AM in reply to Thomas Hii.
Hi, Denis
Thank you Denis for the information.

Thanks
Alberto de Francisco
Posted on 6/25/15 9:53 AM.
Thank you very much sharing details. In your portlet you are using slf4j - where does Liferay's slf4j layer came in?
Posted on 10/9/15 9:02 AM.
Hi Nagendra,

Liferay SLF4J layer came in with util-slf4j.jar bridge that implement the slf4j logging adapter for Liferay logging interface.
Posted on 10/12/15 5:41 AM in reply to Nagendra Kumar Busam.
Hi Denis,
As per your blog I am trying to implement the logs for custom portlet on bundled JBOSS server 7.1.1, but it's generating the blank log file, could you please guide me what I am missing. Below are the configurations I have done to implement it.
1.Added the dependencies for slf4j-api.jar and util-slf4j.jar file in pom.xml.
2.If I add the log4j.jar dependency in pom.xml , at the time of deployment it raise below exception.

java.lang.ClassCastException: org.apache.log4j.EnhancedPatternLayout cannot be cast to org.apache.log4j.Layout

I searched for it , and found that by adding the log4j.jar in portlet I am initializing it again, as it is already initialized by JBOSS. So I added below configuration

Added jboss-deployment-structure.xml ,with below configuration
<exclusions>
<module name="javaee.api"></module>
<module name="org.apache.log4j"></module>
<module name="org.slf4j"></module>
<module name="org.slf4j.impl"></module>
<module name="org.jboss.logging"></module>
<module name="org.jboss.logging.jul-to-slf4j-stub"></module>
<module name="org.jboss.logmanager"></module>
<module name="org.jboss.logmanager.log4j"></module>
</exclusions>
But still it raise the same exception.

Thanks.
Parikshit
Posted on 12/23/15 8:22 AM.
It is also not working for me on jboss EAP 6.2. I have excluded all the modules still no luck.

<exclusions>
<module name="javaee.api" />
<module name="org.apache.log4j" />

<module name="org.apache.commons.logging" />
<module name="org.jboss.logging" />
<module name="org.jboss.logging.jul-to-slf4j-stub" />
<module name="org.jboss.logmanager" />
<module name="org.jboss.logmanager.log4j" />
<module name="org.slf4j" />
<module name="org.slf4j.impl" />

</exclusions>
Posted on 2/4/16 9:10 AM.
[...] NOTE: This article is based on previous work by Denis Signoretto in his article Using SLF4J and Liferay Logging Framework in custom plugins with further investigation by the author to support... [...] Read More
Posted on 8/1/16 8:50 PM.