SLF4J(Simple logging facade for JAVA) is a abstraction layer or facade for different logging frameworks like log4j,Logback etc which allows you to plugin the desired logging framework at deployment time. Also logback is a framework that implements the SLF4j api so it allows easy switching between different logging frameworks and it also provides more optimized logging than log4j by providing features such as parametrized logging. To learn more about these frameworks refer to the comprehensive documentation at the following sites:- 1. SLF4J 2. Logback I will here explain how to do logging using SLF4J and Logback. The below mentioned example has the following features provided by the logback implementation.
- It has a rolling file appender with capability to archive the log files. The rolling policy for the appender will be configured to archive the log file if its size increases 100MB or at the month's end which ever happens earlier. The archived files will then be zipped.
- It uses a MDCInsertingServletFilter that inserts the following
keys into the Mapped Diagnostic Context :-
- req.remoteHost:- It is set to the value returned by the getRemoteHost() of the ServletRequest api
- req.xForwardedFor:- It is set to the value of the HTTP header X-Forwarded-For. It is useful to identify the originating ip address of the request in case the request is forwarded to the web server by a proxy server or load balancer.
- req.requestURI:- To the value returned by getRequestURI().
- req.requestURL:- To the value returned by getRequestURL().
- req.queryString:- To the value returned by getQueryString().
- req.userAgent:- To the value returned by getUserAgent().
- The encoder pattern which inserts the value obtained from the Mapped Diagnostic Context.
- Parametrized Logging
You will have to place the following code into a file named as logback.xml in your classpath. The code represents the configuration required for accomplishing the aforementioned features.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <configuration debug="true"> <contextName>Your Context</contextName> <appender name="ROLLINGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>/oracle/logs/application.log</file> <append>true</append> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>/oracle/archivedapplicationlogs/applicationlog-%d{yyyy-MM}.%i.zip </fileNamePattern> <maxHistory>10</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>Proxy forwarding for %X{req.xForwardedFor} %n %d{dd-mm-yyyy hh:mm:ss}- %-5level %logger{15} - %msg%n</pattern> </encoder> </appender> <root> <appender-ref ref="ROLLINGFILE" /> </root> <logger name="com.blogspot.ramannanda" level="info"> <appender-ref ref="ROLLINGFILE" /> </logger> </configuration> |
- The above mentioned configuration has a rolling file appender configured with time and size based triggering policy. The file name pattern in itself signifies that the file should be zipped and archived at the end of the month, whereas the time and name based triggering policy signifies the maximum size of the log file after which it will be archived. The MaxHistory attribute signifies the number of archived files to be kept on the system. After which they will be automatically deleted.
- The pattern will print the originating ip address in case your application is behind a load-balancer or proxy followed by the time, the level of the log message,the name given to the logger (The name by which it is instantiated by your class) and finally the log message.
- The logger can be used by any class under the package com.blogspot.ramannanda and it's level is info so any log messages above or at info level will be logged.
- The %X{key} signifies that the value must be taken from the mapped diagnostic context.
- The debug=true attribute will print the information during instantiation (using the logback.xml file) and configuration errors will be reported.
To use the MDCInsertingServletFilter you will have to configure it in the web.xml configuration.
1 2 3 4 5 6 7 8 9 10 11 12 | .... <filter> <filter-name>MDCInsertingServletFilter</filter-name> <filter-class> ch.qos.logback.classic.helpers.MDCInsertingServletFilter</filter-class> </filter> <filter-mapping> <filter-name>MDCInsertingServletFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> ... |
Now all you need to do enable logging is place the following jars in your classpath logback-classic, logback-core and slf4j-api.jar. The class that uses the logging is mentioned below. It only needs to use the LoggerFactory.getInstance(String loggername) method to get the logger instance. The following code snippet for a DAO class shows the usage.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package com.blogspot.ramannanda.db; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FileStoreDAO { public static Logger logger=(Logger) LoggerFactory.getLogger("com.blogspot.ramannanda.db.FileStoreDAO"); ..... public void removeData(String fileName){ Connection conn = null; PreparedStatement pstmt = null; try{ conn = new DBConnection(); pstmt = conn.getPreparedStatement("delete from temp_table where file_name = ?"); pstmt.setString(1, fileName); int count=pstmt.executeUpdate(); logger.info(" The user has deleted {} file {} ",count,fileName); } catch (SQLException e) { logger.error("An exception has occured {} {} while deleting files", e, e.getMessage()); } finally { try { if (pstmt != null) { pstmt.close(); } conn.closeConnection(); } catch (Exception e1) { logger.error("An exception has occured while closing connection or prepared statement {}", e1); } } } ..... } |
The above code shows the usage of parametrized logging provided by logback implementation. The values in {} are replaced by the parameters at run-time if needed. Also the number of parameters that can be specified is not limited to 1 as can be seen from the code above.