This is a blog about logging framework implementations using Slf4j library using Jolokia API in JAVA web based application. Using this approach logging level like ERROR, DEBUG etc. can be changed without restarting the applications i.e. dynamically. It’s an application
level logging implementation.

  1. Introduction

 This blog is based on my previous blog series about the OData implementation. This blog is about logging framework implementation based on slf4j library and wrapper of Jolokia API, which helps to change the logs level without restarting the application, using this approach, you can change the log level dynamically by hitting a defined url. Jolokia is an agent basically which changes the log runtime.

For more refer details on Jolokia and slf4j

https://jolokia.org/reference/html/index.html

http://www.slf4j.org/

 

  1. Prerequisite Activities

2.1 Create and build JPA Project: You can refer my previous log series regarding project setup         blog series.

2.2 Get dependent Library:

In addition to the existing api added in previous blogs pom.xml, following api has to added

	<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.21</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.jolokia</groupId>
			<artifactId>jolokia-core</artifactId>
			<version>1.3.4</version>
		</dependency>
		<dependency>
			<groupId>org.jolokia</groupId>
			<artifactId>jolokia-jsr160</artifactId>
			<version>1.3.4</version>
		</dependency>
  1. Configuration and Implementation

3.1 Configure persistence.xml in JPA model: Refer to my previous blog series log series for this section

3.1.1 Configure resource.xml in JPA model: Refer to my previous blog series for this section

  1. Adding the spring-servlet.xml file under WEB-INF folder: Refer to my previous blog series for this section.

4.1. Spring-servlet has to be included in web.xml file, code snippet has to added : Refer to my previous blog series for this section.

4.2. Now create class where using JPAEntitymanager establish a connection, basically to connect to database.

@RestController
@RequestMapping("/v1")
public class RestServices {
	private EntityManagerFactory emf;
	
	final static Logger LOGGER = LoggerFactory.getLogger(RestServices.class);//ROOT logger	
	final static Logger CUSTOMLOGGER = LoggerFactory.getLogger("sampleRestServices");//Custom logger
	
	@PersistenceUnit
	public void setEntityManagerFactory(EntityManagerFactory emf) {
		this.emf = emf;
	}
	
	@RequestMapping(value = "/emp", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<Status> fetch() {
		EntityManager em = this.emf.createEntityManager();
		HttpHeaders httpHeaders = new HttpHeaders();
        try {
        	//LOGGER.getName();
        	//LOGGER.error(LOGGER.getName());
        	//Standard log
			LOGGER.info("\n\n=======RESTSERVICE LOG \t\t INFO Message LOG============\n\n");
			LOGGER.error("\n\n======RESTSERVICE LOG \t\t ERROR Message LOG===========\n\n");
			LOGGER.warn("\n\n=======RESTSERVICE LOG \t\t WARNING Message LOG=========\n\n");
			LOGGER.debug("\n\n======RESTSERVICE LOG \t\t DEBUG Message LOG =========\n\n");
			//Custom log
			CUSTOMLOGGER.info("\n\n=======REST2 LOG \t\t INFO Message LOG============\n\n");
			CUSTOMLOGGER.error("\n\n======REST2 LOG \t\t ERROR Message LOG===========\n\n");
			CUSTOMLOGGER.warn("\n\n=======REST2 LOG \t\t WARNING Message LOG=========\n\n");
			CUSTOMLOGGER.debug("\n\n======REST2 LOG \t\t DEBUG Message LOG =========\n\n");

			System.out.println("----------------------------------in rest block-----------------");
            Query query = em.createQuery("from Employee as p");
            return new ResponseEntity(new Status("Success","Records Returned",query.getResultList()), httpHeaders, HttpStatus.ACCEPTED);
        }
        finally {
            if (em != null) {
                em.close();
            }
        }
	}
	@RequestMapping(value = "/emp", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<Status> create(@RequestBody List<Employee> empLst) {
		EntityManager em = this.emf.createEntityManager();
		HttpHeaders httpHeaders = new HttpHeaders();
        try {
        	em.getTransaction().begin();
        	for(Employee obj:empLst){
        		 em.persist(obj);
        	}
            em.getTransaction().commit();
            return new ResponseEntity(new Status("Success","Records Created"), httpHeaders, HttpStatus.ACCEPTED);
        }
        finally {
            if (em != null) {
                em.close();
            }
        }
	}

}

4.3 Jolokia code snippet add in web.xml: Jolokia code snippet addition in web.xml along with the explanation of the servlet in description tag.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
	<display-name>Java Web Application</display-name>
	<resource-ref>
		<res-ref-name>jdbc/sampleTest-hdi</res-ref-name>
		<res-type>javax.sql.DataSource</res-type>
	</resource-ref>
	<servlet>
		<servlet-name>oDataServlet</servlet-name>
		<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
		<init-param>
			<param-name>javax.ws.rs.Application</param-name>
			<param-value>org.apache.olingo.odata2.core.rest.app.ODataApplication</param-value>
		</init-param>
		<init-param>
			<param-name>org.apache.olingo.odata2.service.factory</param-name>
			<param-value>com.sap.sample.fnd.odatafactory.SampleCustomOdataJpaServiceFactory</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>oDataServlet</servlet-name>
		<url-pattern>/sample.svc/v1/*</url-pattern>
	</servlet-mapping>	

	<servlet>
		<servlet-name>spring</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>spring</servlet-name>
		<url-pattern>/rest/api/*</url-pattern>
	</servlet-mapping>	
	
<!-- jolokia params add - RAJNISH -->
	<servlet>
		<servlet-name>jolokia-agent</servlet-name>
		<servlet-class>org.jolokia.http.AgentServlet</servlet-class>
		<init-param>
			<description>
        Class names (comma separated) of RequestDispatcher used in addition
        to the LocalRequestDispatcher
      </description>
			<param-name>dispatcherClasses</param-name>
			<param-value>org.jolokia.jsr160.Jsr160RequestDispatcher</param-value>
		</init-param>
		<init-param>
			<description>
        Debugging state after startup. Can be changed via
        the Config MBean during runtime
      </description>
			<param-name>debug</param-name>
			<param-value>false</param-value>
		</init-param>
		<init-param>
			<description>
        Entries to keep in the history. Can be changed during
        runtime via the config MBean
      </description>
			<param-name>historyMaxEntries</param-name>
			<param-value>10</param-value>
		</init-param>
		<init-param>
			<description>
        Maximum number of entries to keed in the local
        debug history if switched on. Can be change via
        the config MBean during runtime.
      </description>
			<param-name>debugMaxEntries</param-name>
			<param-value>100</param-value>
		</init-param>
		<init-param>
			<description>
        Maximum depth when traversing bean properties.
        If set to 0, depth checking is disabled
      </description>
			<param-name>maxDepth</param-name>
			<param-value>15</param-value>
		</init-param>
		<init-param>
			<description>
        Maximum size of collections returned when
        serializing to JSON. When set to 0
        collections are not truncated.
      </description>
			<param-name>maxCollectionSize</param-name>
			<param-value>0</param-value>
		</init-param>
		<init-param>
			<description>
        Maximum number of objects which is traversed
        when serializing a single response. Use this
        as airbag to avoid boosting your memory and
        network traffic. Nevertheless when set to 0
        not limit is used.
      </description>
			<param-name>maxObjects</param-name>
			<param-value>0</param-value>
		</init-param>
		<init-param>
			<description>
        Options specific for certain application
        server detectors. Detectors can evaluate these
        options and perform a specific initialization based
        on these options. The value is a JSON object with
        the detector's name as key and the options as value.
        E.g. '{glassfish: {bootAmx: false}}' would prevent
        the booting of the AMX subsystem on a glassfish with
        is done by default.
      </description>
			<param-name>detectorOptions</param-name>
			<param-value>{}</param-value>
		</init-param>
		<init-param>
			<description>
        This option specifies in which order the key-value properties within
        ObjectNames as returned by "list" or "search" are returned. By default
        this is the so called 'canonical order' in which the keys are sorted
        alphabetically. If this option is set to "false", then the natural
        order is used, i.e. the object name as it was registered. This option
        can be overridden with a query parameter of the same name.
      </description>
			<param-name>canonicalNaming</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<description>
        Whether to include a stacktrace of an exception in case
        of an error. By default it it set to "true" in which case
        the stacktrace is always included. If set to "false", no
        stacktrace is included. If the value is "runtime" a stacktrace
        is only included for RuntimeExceptions. This global option
        can be overridden with a query parameter.
      </description>
			<param-name>includeStackTrace</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<description>
        When this parameter is set to "true", then an exception thrown
        will be serialized as JSON and included in the response
        under the key "error_value". By default it is "false". This global
        option can be overridden by a query parameter of the same name.
      </description>
			<param-name>serializeException</param-name>
			<param-value>false</param-value>
		</init-param>
		<init-param>
			<description>
        If discoveryEnabled is set to true, then this servlet will listen
        for multicast discovery request and responds with its agent URL and
        other server specific information. Instead of setting this confog variable,
        discovery can be also enabled via the system property "jolokia.discoveryEnabled"
        or the environment variable "JOLOKIA_DISCOVERY_ENABLED".

        In addition the config parameter "discoveryAgentUrl" can be used to set the the agent's URL.
        By default, auto detection (after the first request was processed by the servlet)) of the URL is used.
        If the URL is set, then discovery is automatically enabled (i.e. there is
        no need to set "discoveryEnabled=true"). This configuration option
        is especially useful if the WAR is used in a proxy setup. Instead of setting the URL
        here, it can be set also either via the system property "jolokia.discoveryAgentUrl" or the
        environment variable "JOLOKIA_DISCOVERY_AGENT_URL".
      </description>
			<param-name>discoveryEnabled</param-name>
			<param-value>false</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>jolokia-agent</servlet-name>
		<url-pattern>/jolokia/*</url-pattern>
	</servlet-mapping>
</web-app>

In above code snippet as you can see that we are using the jolokia agent as wrapper on slf4j to change the log level. We need to make the debug to false by default and includestacktrace to true, since it prints the logs even the log level is set to error. In a similar way there are other params which basically serves the different purpose.

4.4 application.properties file addition in resource folder as shown below

Code snippet of application.properties
# parameters of sample application
xs.appname=sampleTest
logEnabled = true
odata.enableError = true
endpoints.jmx.domain=sampleTest
endpoints.jmx.unique-names=true
jolokia.config.debug=true
endpoints.jolokia.enabled=false

4.5 logback.xml file addition to following location in project under java_xs_buildpack

 

Code snippet for logback.xml

<?xml version="1.0" encoding="UTF-8"?>

<configuration>
	<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/>
	<conversionRule conversionWord="guid" converterClass="com.sap.xs.logging.logback.converters.UUIDGenerator"/>
	<conversionRule conversionWord="msgArgs" converterClass="com.sap.xs.logging.logback.converters.MSGArgs"/>
	<conversionRule conversionWord="msgArgsNo" converterClass="com.sap.xs.logging.logback.converters.MSGArgsNo"/>
	<conversionRule conversionWord="msgType" converterClass="com.sap.xs.logging.logback.converters.MsgType"/>
	<conversionRule conversionWord="msg" converterClass="com.sap.xs.logging.logback.converters.MSG"/>
	<conversionRule conversionWord="timeZone" converterClass="com.sap.xs.logging.logback.converters.TimeZone"/>
	
	<jmxConfigurator />
	
    <property name="max.retention.days" value="60" />
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>#2.0#%d{yyyy MM dd HH:mm:ss.SSS}#%timeZone#%level#%replace(%logger){'([\\#])','\\$1'}#%n%mdc{MsgCode}#%mdc{CSNComponent}#%mdc{DCComponent}#%guid#%mdc{DSRCorrelationId}#%replace(%mdc{Application}){'([\\#])','\\$1'}#%class#%replace(%mdc{User}){'([\\#])','\\$1'}#%mdc{Session}#%mdc{Transaction}#%mdc{DSRRootContextId}#%mdc{DSRTransaction}#%mdc{DSRConnection}#%mdc{DSRCounter}#%replace(%thread){'([\\#])','\\$1'}#%msgType#%mdc{ResourceBundle}#%n%msg#%msgArgsNo%msgArgs%n%n</pattern>
        </encoder>
    </appender>
    
    <!-- Deprecated Audit Log Loggers (remove in HANA 2 SP 1 or SP2)--> 
    <logger name="/Audit/Configuration" level="ALL" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>
    
    <logger name="/Audit/DataAccess" level="ALL" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>
    
    <logger name="/Audit/SecurityEvent" level="ALL" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>

    <logger name="org.apache.catalina" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>

    <logger name="org.apache.catalina.core.ContainerBase.[Catalina].[localhost]" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>

    <logger name="org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]" level="INFO"
        additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>

    <logger name="org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]" level="INFO"
        additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="com.sap.xs.logging.catalina.LoggingLevelChangeListener" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
     <logger name="/Performance" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
 	<logger name="/Applications" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/Applications/Common" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/Applications/Common/Security" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
     <logger name="/Applications/Common/Backup" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
     <logger name="/Applications/Common/Archiving" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
     <logger name="/Applications/Common/Resources" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
     <logger name="/Applications/Common/Configuration" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
     <logger name="/Applications/Common/Failover" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/Applications/Common/Infrastructure" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/System" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/System/Database" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/System/Network" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/System/Server" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/System/Security" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />        
    </logger>
    
    <logger name="/System/UserInterface" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/System/Configuration" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/System/Configuration/Logging" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/System/Logging" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/System/EnterpriseServices" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <logger name="/System/Changes" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
    </logger>

    <logger name="sampleRestServices" level="ERROR" additivity="true">
        <appender-ref ref="CONSOLE" />
    </logger>
    
    <root level="ERROR">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

 

As shown above in the code, you have custom logger name “sampleRestServices” and the same can be used in the application to log the messages as well you can define the default level also, which is ERROR now. Tag named additivity, if default level is false then you will not be able to see the logs in console, since it is not added to console, So it should always be true. If we do not have any custom logs name then y default logs will be added to root level tag and in given class we need to define the class name to implement the log level

Example for root level log

<root level="ERROR">
        <appender-ref ref="CONSOLE"/>
    </root>


In class log implementation:

final static Logger LOGGER = LoggerFactory.getLogger(RestServices.class);

Logger message would be

LOGGER1.error(“Standard Log messages for restclass”);

Example for custom logs based on the requirement

But if we have custom log name defined in logback.xml file

 <logger name="sampleRestServices" level="ERROR" additivity="true">
        <appender-ref ref="CONSOLE" />
    </logger>

In class log implementation:

final static Logger LOGGER1 = LoggerFactory.getLogger(“sampleRestServices“);

Logger message would be

LOGGER1.error(“Custom Log messages for restclass”);

In the above code base, if you have noticed there is tag for log display pattern like

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>#2.0#%d{yyyy MM dd HH:mm:ss.SSS}#%timeZone#%level#%replace(%logger){'([\\#])','\\$1'}#%n%mdc{MsgCode}#%mdc{CSNComponent}#%mdc{DCComponent}#%guid#%mdc{DSRCorrelationId}#%replace(%mdc{Application}){'([\\#])','\\$1'}#%class#%replace(%mdc{User}){'([\\#])','\\$1'}#%mdc{Session}#%mdc{Transaction}#%mdc{DSRRootContextId}#%mdc{DSRTransaction}#%mdc{DSRConnection}#%mdc{DSRCounter}#%replace(%thread){'([\\#])','\\$1'}#%msgType#%mdc{ResourceBundle}#%n%msg#%msgArgsNo%msgArgs%n%n</pattern>
        </encoder>
    </appender>

So we can even control the way log can be displayed and information, which we want to display to console.

  1. Logging implementation and explanations

We can log errors and actions applications encounter, which is pretty critical. Logging other things can be very informative e.g. the start and end of a batch process, amount of processed files, duration within a certain method call and so on.

We want the right kinds of information available to us, but don’t want to store tons of old logs that don’t mean anything to us a year later. We want to try to write concise informative messages that are self-explanatory and able to be dumped soon after, as needed.

Simple Logging Facade for Java (SLF4J) provides a Java logging API by means of a simple facade pattern. The underlying logging backend is determined at runtime by adding the desired binding to the classpath. The separation of the client API from the logging backend reduces the coupling between an application and any particular logging framework. This can make it easier to integrate with existing or third-party code or to deliver code into other projects that have already made a choice of logging backend. Jolokia is for changing the log level dynamically as standard way of changing log-level is not yet available in SAP cloudfoundary. For more about jolokia architecture

This rule is at the heart of logback. It assumes that levels are ordered as follows: TRACE < DEBUG < INFO <  WARN < ERROR.

In a more graphic way, here is how the selection rule works. In the following table, the vertical header shows the level of the logging request, designated by p, while the horizontal header shows effective level of the logger, designated by q. The intersection of the rows (level request) and columns (effective level) is the Boolean resulting from the basic selection rule.

Basic Selection Rule

A log request of level p issued to a logger having an effective level q, is enabled if p >= q.

  1. Loggers Type in application: In sample rest class (mentioned in section 4.2) we have implemented all the log levels message in GET method of rest class. Default log level would be ERROR as mentioned in logback.xml file.
	final static Logger LOGGER = LoggerFactory.getLogger(RestServices.class);//ROOT logger	
	final static Logger CUSTOMLOGGER = LoggerFactory.getLogger("sampleRestServices");//Custom logger
       	//Standard log
			LOGGER.info("\n\n=======RESTSERVICE LOG \t\t INFO Message LOG============\n\n");
			LOGGER.error("\n\n======RESTSERVICE LOG \t\t ERROR Message LOG===========\n\n");
			LOGGER.warn("\n\n=======RESTSERVICE LOG \t\t WARNING Message LOG=========\n\n");
			LOGGER.debug("\n\n======RESTSERVICE LOG \t\t DEBUG Message LOG =========\n\n");
			//Custom log
			CUSTOMLOGGER.info("\n\n=======REST2 LOG \t\t INFO Message LOG============\n\n");
			CUSTOMLOGGER.error("\n\n======REST2 LOG \t\t ERROR Message LOG===========\n\n");
			CUSTOMLOGGER.warn("\n\n=======REST2 LOG \t\t WARNING Message LOG=========\n\n");
			CUSTOMLOGGER.debug("\n\n======REST2 LOG \t\t DEBUG Message LOG =========\n\n");

As show above that we have implemented two types of logs and respective loggers were implemented the class.

6.1 Changing LogLevel Dynamically: log level can be changed via given url pattern once the application is deployed in server, extension can be following pattern.

Generic log level method

To get the logger level: root

<application-url>/jolokia//exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/getLoggerLevel/ROOT

Example

https://sample-java1.cfapps.sap.hana.ondemand.com/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/getLoggerLevel/ROOT

O/P

As shown in the above image that default log level is ERROR and argument is ROOT. It means that for root logger log level is ERROR.

Logs printed in console: Since default log level is error, only error log will be displayed,

2016-11-24T17:42:36.11+0530 [App/0]      OUT ###A8C47C840373476E9ADCED2F84A1C17D##sample-java1#com.sap.sample.restServices.RestServices########http-bio-0.0.0.0-61011-exec-8#PLAIN##

2016-11-24T17:42:36.11+0530 [App/0]      OUT ======RESTSERVICE LOG               ERROR Message LOG===========

To set the logger level: root

<application-url>/ jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/setLoggerLevel/ROOT/debug

Example

https://sample-java1.cfapps.sap.hana.ondemand.com/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/setLoggerLevel/ROOT/debug

O/P

As shown above after the execution of logs urls log level changed debug.

Logs printed in console: Since default log level is debug, all the log level will be printed to console (as mentioned in the log level hierarchy) as written in the code snippet.

 

2016-11-24T17:50:26.16+0530 [App/0]      OUT =======RESTSERVICE LOG              INFO Message LOG============

2016-11-24T17:50:26.16+0530 [App/0]      OUT #

2016-11-24T17:50:26.16+0530 [App/0]      OUT #2.0#2016 11 24 12:20:26.167#+00:00#ERROR#com.sap.sample.restServices.RestServices#

2016-11-24T17:50:26.16+0530 [App/0]      OUT ###D7DB9BC3DCDF486D9ED629AD51CB0813##sample-java1#com.sap.sample.restServices.RestServices########http-bio-0.0.0.0-61011-exec-10#PLAIN##

2016-11-24T17:50:26.16+0530 [App/0]      OUT ======RESTSERVICE LOG               ERROR Message LOG===========

2016-11-24T17:50:26.16+0530 [App/0]      OUT #2.0#2016 11 24 12:20:26.167#+00:00#WARN#com.sap.sample.restServices.RestServices#

2016-11-24T17:50:26.16+0530 [App/0]      OUT =======RESTSERVICE LOG              WARNING Message LOG=========

2016-11-24T17:50:26.16+0530 [App/0]      OUT #

2016-11-24T17:50:26.16+0530 [App/0]      OUT #

2016-11-24T17:50:26.16+0530 [App/0]      OUT ###AE1F1C5F45F14546A8CD8A4F1B8B81C8##sample-java1#com.sap.sample.restServices.RestServices########http-bio-0.0.0.0-61011-exec-10#PLAIN##

2016-11-24T17:50:26.16+0530 [App/0]      OUT #2.0#2016 11 24 12:20:26.167#+00:00#DEBUG#com.sap.sample.restServices.RestServices#

2016-11-24T17:50:26.16+0530 [App/0]      OUT ###A833A286D77C44BAAFFDDF2A2836112B##sample-java1#com.sap.sample.restServices.RestServices########http-bio-0.0.0.0-61011-exec-10#PLAIN##

2016-11-24T17:50:26.16+0530 [App/0]      OUT ======RESTSERVICE LOG               DEBUG Message LOG =========

2016-11-24T17:50:26.16+0530 [App/0]      OUT #

Similarly we can change of modify the log level for custom logger name and log level can be displayed, The basic idea behind the custom log is that based on requirements, if we have multiple packages in web applications and want to control the logs of different packages and want to see the logs specific to given package. In productive system where application is humongous and if anything went wrong then and if we aware that issue and will be in specific packages then it helps the developer life easier to found the issue in productive environment.

This blog is about implementation of logging framework in Java Web based application using slf4j library via jolokia agent, here jolokia act as agent which basically helps to change the implemented log level in the application level dynamically. Which helps the developers to see the specific logs based on the issue they are facing in applications. code location in github.

Hope it serves the purpose of developer to monitor the logs in the application and control the logs level based on the issue faced while debugging the applications.

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

  1. Roland Huss

    Nice Post !

    BTW, you can remove the jolokia-jsr160 dependency when you also remove the “dispatcherClasses” init parameter in web.xml. You need this only if you want to operate Jolokia as a JSR-160 proxy as described in https://jolokia.org/reference/html/proxy.html but this is not the case in your use case.

    Also remember that for production you should setup some sort of security for Jolokia as described in https://jolokia.org/reference/html/security.html , otherwise everybody can bring down you Tomcat with a single GET request 😉

    (1) 

Leave a Reply