Components written against log4j1 are not logging after log4j2 upgrade - java

I've been banging my head over this one for a few days and can't get it figured out. Log4j2 is backwards compatible if you add the log4j1 compatibility library.
My web-inf\lib has:
slf-api
log4j-1.2-api (backwards compat. library)
log4j-api (log4j2)
log4j-core (log4j2)
log4j-web (auto-wiring for web applications)
My web.xml has:
<!-- log4j2 auto-wiring -->
<context-param>
<param-name>log4jConfiguration</param-name>
<param-value>file:///${catalina.base}/conf/log4j2.xml</param-value>
</context-param>
My [tomcat]/conf/log4j2.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug">
<Appenders>
<!-- Appends to CONSOLE -->
<Console name="consoleAppender" target="SYSTEM_OUT">
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="%5p (%F:%L) - %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="com.mycompany.componentA" level="WARN" />
<Logger name="com.mycompany.componentA.QueryLogger" level="DEBUG" />
<Logger name="com.mycompany.mycode" level="DEBUG" />
<Root level="WARN">
<AppenderRef ref="consoleAppender" />
</Root>
</Loggers>
</Configuration>
I have upgraded code under my control (com.mycompany.mycode) to log4j2 APIs and they work/log flawlessly. Code that is not under my control but was written against log4j1 (com.mycompany.componentA) just simply fails to log at all. No errors, no debugs, nothing.
Something interesting though... when I start the application I get a log4j1 warning about incorrect configurations when the application starts. This also stumps me because there are no log4j1 libraries (except the compatibility API) in the WAR. Warning is:
log4j:WARN No appenders could be found for logger (com.mycompany.componentB)
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

EDIT: I (finally) figured out what's going on. One of my dependencies did a horribly bad thing and BUNDLED the log4j1 classes into it's final jar. So there are no log4j1 jars on the classpath, but there are log4j1 CLASSES on the classpath.
The only way I was able to get this working was to:
Create BOTH a log4j1 and log4j2 XML configuration files (even though the log4j2 configuration contained all the loggers I wanted)
Let Log4j2 auto-wire itself via the 'log4j-web' artifact + 'log4jConfiguration' web.xml parameter
Manually wire log4j1 by calling the deprecated Log4jConfigurer.initLogging(...) API on server startup
This is probably horribly incorrect, but as indicated above, it was the only way I got it working after weeks of fooling around.
My understanding of the lo4j1 bridge is that wiring up log4j2 and including the bridge is all that should be required (e.g. no need to manually wire log4j1). In practice, that does not seem to be occurring.

That error message means you still have the log4j-1.x jar in your application. Look for it in your WEB-INF/lib and remove it and then it should work.

If not in WEB-INF/lib, then perhaps in your web container (Tomcat?) shared lib folder? Ralph is right that this error message is generated by Log4j-1.2, so it is on the classpath somewhere... Try printing the value of System property java.class.path if necessary.
Update: another way to find the location of the Log4j1 jar is by printing the value of org.apache.log4j.AppenderSkeleton.class.getResource("/org/apache/log4j/AppenderSkeleton.class") from your application.
(I originally suggested Category but this also exists in the Log4j 1 bridge, so AppenderSkeleton is better.)

Related

ERROR StatusLogger No log4j2 configuration file found. While updating the version 2.5.12 of Struts

As per the requirement and for security purpose I am updating Struts project. Before the Struts version is 2.3.24 and now I am updating it to 2.5.12. I have downloaded all the required jar files of Struts and applied to project but I am getting the below error
ERROR StatusLogger No log4j2 configuration file found. Using default
configuration: logging only errors to the console. Set system property
'org.apache.logging.log4j.simplelog.StatusLogger.level' to TRACE to
show Log4j2 internal initialization logging.
But I am not using any logger in my project. I have added all the dependency jar files and I am not using Maven, but added related libraries in lib folder. Any suggestions please.
Struts framework is using a logging framework log4j second version.
Struts 2.3 to 2.5 migration
Please be aware that the framework is using Log4j2 now as a main logging layer, the existing old logging layer is deprecated and will be removed soon. Log4j2 supports many different logging implementations, please check documentations for more details.
The file log4j2.xml is required to bootstrap the logging framework. But it's missing from the classpath. It's also missing from the Struts framework.
You should find some log4j2.xml, i.e. from the struts-showcase application or read a step 4 in this tutorial How To Create A Struts 2 Web Application
Step 4 - Add Logging
To see what’s happening under the hood, the example application for this tutorial uses log4j2. You’ll need to add a dependency node for log4j2 to the pom:
pom.xml log4j dependency node
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
Using both log4j-core and log4j-api allows to use the latest version of Log4j2 without a clash with version provided by the framework. Setup a log4j2.xml configuration in the src/main/resources folder which contains the following
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="com.opensymphony.xwork2" level="debug"/>
<Logger name="org.apache.struts2" level="debug"/>
<Root level="warn">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
Note the above log4j2 configuration specifies the console as the log target.
No log4j2 configuration file found means log4j2.xml configuration file is not in your classpath.
Check your project jar contains log4j confuguration file or not.
Otherwise you can set log4j confuguration file path as system property in your build script.
<sysproperty key="log4j.configurationFile" value="file:///${basedir}/src/log4j2.xml" />
Check https://logging.apache.org/log4j/2.x/manual/configuration.html for log4j configuration

How to setup Log4j2 for an application deployed in WildFly 9?

When I test my application with JUnit, it is printing the log as specified by layout pattern in log4j2.xml, but when I deploy my application
in WildFly 9, I am no more getting the same format. Even the log level in Log4j2 is also not reflecting while deployed in server.
JUnit log example:
2016-02-15 11:14:16,314 DEBUG [main] b.t.r.c.XAPool - a connection's
state changed to IN_POOL, notifying a thread eventually waiting for a
connection
Server log example:
11:11:33,796 INFO [org.quartz.core.QuartzScheduler] (ServerService
Thread Pool -- 89) Scheduler
quartzScheduler_$_anindya-ubuntu1455514892022 started.
Log4j2.xml:
<Configuration status="WARN" name="myapp" monitorInterval="5">
<Appenders>
<RollingFile name="RollingFile" fileName="${myapp.log-dir}/myapp.log"
filePattern="${myapp.log-dir}/$${date:yyyy-MM}/myapp-%d{MM-dd-yyyy}-%i.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy size="25 MB"/>
</Policies>
<DefaultRolloverStrategy max="100">
<Delete basePath="${myapp.log-dir}" maxDepth="2">
<IfFileName glob="*/myapp-*.log">
<IfLastModified age="7d">
<IfAny>
<IfAccumulatedFileSize exceeds="1 GB" />
<IfAccumulatedFileCount exceeds="1" />
</IfAny>
</IfLastModified>
</IfFileName>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="com.company.myapp" level="trace" additivity="false">
<AppenderRef ref="RollingFile"/>
</Logger>
<Root level="info">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
While starting the server, I am providing below starup properties as JAVA_OPTS:
export JAVA_OPTS="$JAVA_OPTS -Dspring.profiles.active='qa'
-Dlog4j.configurationFile=/home/anindya/1.0/log4j2.xml -myapp.log-dir=/home/anindya/log -Dorg.jboss.logging.provider=log4j"
I have no specific setup in web.xml as it is Servlet 3.1 container. But I have a jboss-deployment-structure.xml in my WEB-INF as below:
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<!-- Exclusions allow you to prevent the server from automatically adding some dependencies -->
<exclusions>
<module name="org.apache.logging.log4j" />
</exclusions>
</deployment>
</jboss-deployment-structure>
And finally, here are my classpath dependencies (only the relevant parts are mentioned here):
hibernate-5.0.7.Final dependencies
jbpm-6.3.0.Final dependencies
spring-4.2.4.RELEASE dependencies
commons-logging-1.2.jar
log4j-1.2-api-2.5.jar
log4j-api-2.5.jar
log4j-core-2.5.jar
log4j-jcl-2.5.jar
log4j-slf4j-impl-2.5.jar
log4j-web-2.5.jar
jboss-logging-3.3.0.Final.jar
With all of the above setup, I am still not able to configure Log4j2 in WildFly environment according to my log4j2.xml. Can someone please help?
NOTE: I am running WildFly in standalone mode and I would like to avoid using jboss-cli.
I managed to get it working by using the below jboss-deployment-structure.xml.
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<exclusions>
<module name="org.apache.logging.log4j" />
</exclusions>
<exclude-subsystems>
<subsystem name="logging"/>
</exclude-subsystems>
</deployment>
</jboss-deployment-structure>
All I had to do is to exclude the logging subsystem.
Late to the game but I needed support for log4j2 in Wildfly and thought I would share some details for anyone else facing this. This solution will let you configure logging through standalone.xml, that is no log4j2.xml will be used/picked up. The solution I chose is to bridge log4j2 to slf4j. Wildfly supports slf4j out-of-the-box. For the advanced users the solution in one sentence is 'Create a Wildfly module and use it', for others like me the solution follows a bit more detailed below...
First create a wildfly module, I will not give all the details how this is done, but my module.xml ended up looking like this
<module xmlns="urn:jboss:module:1.1" name="org.apache.logging.log4j2">
<resources>
<resource-root path="log4j-api-2.11.1.jar"/>
<resource-root path="log4j-to-slf4j-2.11.1.jar"/>
</resources>
<dependencies>
<module name="org.slf4j" />
</dependencies>
</module>
(Basically make sure this xml is in your module path, typically you would add it at $JBOSS_MODULEPATH/org/apache/logging/log4j2/main/module.xml, and add the referenced jar-files in the same directly as well)
Next step is to add a dependency to this module from my application. This is accomplished using a jboss-deployment-structure.xml. If you are not familiar with this file please look it up. Add a line like this
<module name="org.apache.logging.log4j2" export="true" />
You might also need to exclude log4j-api-2.11.1.jar from your application deployment, I am not 100% sure it is needed but I always do when I create a module.
After this you should be able to see log4j2 messages in your server.log
I hope this can help someone out there!
I want to offer to have a look at the problem from another side.
You can in your code, use log4j2 interfaces, as a logging bridge. For instance you can use MDC, Suppliers, ClosableThreadContext. The features which are not availble in slf4j/logback at the moment:
import org.apache.logging.log4j.CloseableThreadContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
private static final Logger logger = LogManager.getLogger(SomeClass.class.getName());
public void doLog() {
try (final CloseableThreadContext.Instance ctc =
CloseableThreadContext.put("user", UUID.randomUUID().toString())) {
String note = "(originally, log4j2 war)";
logger.info(() -> "This is an info message, via supplier, " + note); // == INFO
logger.error("This is an error message, {}", note); // == ERROR
logger.warn("This is a warning message, {}", note); // == WARNING
logger.debug("Here is a debug message, {}", note); // == DEBUG
logger.info(logger.getClass().getName());
}
}
But you add a dependency to delegate all log4j2 calls to slf4j:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.14.0</version>
</dependency>
You do not need any other hacks. It works fine (checked on Wildfly 10).
The main advantages:
you have modern API for logging and some great features. Slf4j is going to support those features, but they are not yet included into the last final version.
which is more important, when you work with WildFly, you can adopt logging configuration via WildFly at runtime with CLI. It is very important possibility for production. Delivering a config file, like Log4j2.xml is a bad alternative. You need literally to change the content of this file. Most oftern, it means to rebuild the project, cause the logging config file is usually part of the resources. And it also means you need to redeploy the application.
With WildFly CLI I can temporary enable DEBUG mode for a certain package.
There is no module org.apache.logging.log4j. The module name you should be using is org.apache.log4j.
I'm not sure why you don't want to use CLI, but you could also set the add-logging-api-dependencies to false.
/subsystem=logging:write-attribute(name=add-logging-api-dependencies, value=false)

Prevent Spring Boot from printing logs to console

I am using spring boot for my application and I am using default spring boot logging.
In my application.properties, I have added file path for logging.file,
logging.file= ${logger_path}
and my pom.xml contains
<logger_path>/tmp/app.log</logger_path>
When I start the application, it prints the logging messages to the file at /tmp/app.log, but the problem is it also prints the log messages on the console. I really don't understand why it is printing on console (though it is printing them to the specified file) when I have specified a log file.
Is there any configuration to prevent spring boot from printing the log messages to console?
Spring boot comes with build-in logback logger, which is configured to print to the console by default.
You need to overwrite the logback configuration (providing your own logback.xml on the classpath).
This is described here - - section 66.1
How to disable logback logging read here -
as you can see you have to provide the value OFF...something like:
<configuration>
<include resource="base.xml" />
.
.
<property name="root.level.console" value="OFF" />
</configuration>
Note: Keep in mind that the general idea here is that the logback configuration coming from spring-boot is minimal. The intention is that you provide your own logback configuration and completely overwrite the existing one - e.g. providing your own logback configuration with only log file-appender configured - this should be your general approach.
Include file-appender.xml and not console-appender with following configuration in logback-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
You also need to add logging.file to your application.properties
This is in compliance to what is mentioned in spring boot documentation - http://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html
I tried removing console configuration from logback.xml. But, It was still logging in console. So What I did is, I just removed the appender being added in the logging configuration by springboot. Thereby, we can stop springboot logging in console and separate log file. Add the below lines at the end of your application specific appenders are added. Your custom appender should not match any of these appender names. It worked for me.
// get instance of your log4j instance
Logger logger = LogManager.getRootLogger();
logger.removeAppender("CONSOLE"); // stops console logging
logger.removeAppender("LOGFILE"); // stops file logging
A similar discussion can be found here.
My logback.xml looks like that:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
Just in case you still experience an issue: I have read many discussions about that topic and it was not working at all for me. Unfortunately I have made a really stupid mistake when I have created the file logback.xml for the very first time: A space was added at the beginning of the filename. Therefore the file was never used. So just have another look on the filename, add the file in "src/main/resources" and remove any "logging.config" entries from your property files.
Tested with latest 1.3.1 release, with newer releases base.xml has been renamed to defaults.xml
Answer here

Connection to database in a managed thread, Debug values doesn't appear in Tomcat console or logs

I am facing this trouble for a long time now without accessing the debug logs of the managed Threads in my Spring boot application when run on Tomcat. All the logs appear when run on the Eclipse/STS.
In Tomcat logs, I can only see the main Tread Logs.
I am connection to a database through JDBC and this is happening in a separate thread. I tried to follow the log configuration documentation but none of them helps to get the debug logs of these threads. So I do not actually see the exact problem of what is causing the connection to fail.
Here is what I tried so far:
I tried with the following logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<Target>System.out</Target> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p
%c{1}:%L - %m%n</pattern> </encoder> </appender> <logger name="com.biscoind"
additivity="false" level="TRACE"> <appender-ref ref="stdout" /> </logger>
<root level="debug"> <appender-ref ref="stdout" /> </root> -->
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.springframework.web" level="DEBUG" />
</configuration>
When that did not resolve the issue I removed this file and see if by default, if it logs all the treads. But it did not.
So, I added the following configurations to the application.properties
logging.level.org.springframework.web:TRACE
logging.level.org.hibernate:ERROR
Then It seemed to me that this is only logging out the above namespaces, I again added
debug=true
logging.level.org.springframework.web:DEBUG
logging.level.org.hibernate:DEBUG
Tried and it did not work.
I added my namespaces also and tried as follwing,
debug=true
logging.level.com.mydomain:DEBUG
logging.level.org.springframework.web:DEBUG
logging.level.org.hibernate:DEBUG
That did not work also, I am now confused on the what should I do with the config relative to logging to make the logs to appear for the tread executions.
Irrespective of the treads, because of the property spring.jpa.show-sql=true it logs the queries that are made.
It was not a problem with the threads at all. The application was working correctly in the development environment. The problem was in the deployment environment.
It turned out to be a Java version miss-match with the jar files and the JVM version. The jars were build using Java 8 and it was running on Java 7 JVM.
When the JMV was changed to Java-8. It worked fine. So Next time I will be more careful with the version mismatch.

Log4j2.xml configuration file location for EAR

I have a Java EE application packaged with ejbs and war. Following is the structure of the EAR:
myapp.ear
-lib
-META-INF
-ejbjar1.jar
-ejbjar2.jar
-mywebapp.war
I need to use log4j2 so I have tried to configure it at first from the web.xml by following instructions to initialize Log4j 2 in a web application but when I am creating the Logger in an EJB it is throwing:
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.
The instruction given here is not much clear to me, but what I understand that I need to place the log4j2.xml in a shared location.
I have tried to place the xml inside the EAR, inside the EAR/lib, inside the EAR/META-INF but I got same result. In these case I haven't configured anything in the web.xml.
How can I configure log4j2 for an EAR so that the configuration will be available for all the classes (classes for ejb-module, web-module)?
I am using Weblogic 12C. Previously I have successfully used log4j2 in Weblogic 11G but in that case the packaging was a WAR file.
You can package the log4j2.xml file in one of your ejbjar1.jar or create a new configonly.jar if you like. It should then be shared across your ejb modules and war. Also if you want to separate the logs from ejb and war you can configure two different file appenders and two different loggers one for ejb and one for war. Here is a working sample log4j2.xml with GlassFish v4.1 Please note the status="trace" to trace any configuration issue.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{yyyy-MMM-dd EEE HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" />
</Console>
<!-- for GlassFish v4.1 the logs will be in the domains directory -->
<RollingFile name="appServerRollingFile" fileName="../app-logs/app-server.log"
append="true"
filePattern="../app-logs/$${date:yyyy-MMM}/app-server-%d{yyyy-MMM-dd}-%i.log.zip"
ignoreExceptions="false">
<PatternLayout
pattern="%d{yyyy-MMM-dd EEE HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" />
<Policies>
<OnStartupTriggeringPolicy />
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="20 MB" />
</Policies>
</RollingFile>
<!-- for GlassFish v4.1 the logs will be in the domains directory -->
<RollingFile name="appWebRollingFile" fileName="../app-logs/app-web.log"
append="true"
filePattern="../app-logs/$${date:yyyy-MMM}/app-web-%d{yyyy-MMM-dd}-%i.log.zip" ignoreExceptions="false">
<PatternLayout
pattern="%d{yyyy-MMM-dd EEE HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" />
<Policies>
<OnStartupTriggeringPolicy />
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="20 MB" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef ref="Console" level="TRACE"/>
</Root>
<Logger name="test.business" level="TRACE" additivity="false">
<AppenderRef ref="Console" />
<AppenderRef ref="appServerRollingFile" />
</Logger>
<Logger name="test.web" level="TRACE" additivity="false">
<AppenderRef ref="Console" />
<AppenderRef ref="appWebRollingFile" />
</Logger>
</Loggers>
</Configuration>
Just to be sure, lets quote the sections that matter from the documentation you were referring to:
Java EE Applications
A Java EE application will consist of one or more WAR files and
possible some EJBs, typically all packaged in an EAR file. Usually, it
is desirable to have a single configuration that applies to all the
components in the EAR. The logging classes will generally be placed in
a location shared across all the components and the configuration
needs to also be shareable. Be sure to follow the instructions to
initialize Log4j 2 in a web application.
From "Using Log4j 2 in Web Applications":
Configuration
Log4j allows the configuration file to be specified in
web.xml using the log4jConfiguration context parameter. Log4j will
search for configuration files by:
If a location is provided it will be searched for as a servlet context
resource. For example, if log4jConfiguration contains "logging.xml"
then Log4j will look for a file with that name in the root directory
of the web application.
If no location is defined Log4j will search
for a file that starts with "log4j2" in the WEB-INF directory. If more
than one file is found, and if a file that starts with "log4j2-name"
is present, where name is the name of the web application, then it
will be used. Otherwise the first file will be used.
The "normal"
search sequence using the classpath and file URLs will be used to
locate the configuration file.
Note that when starting from an EAR, each module therein starts typically using it's own isolated classloader.
First attempt at making it to work might by by providing the log4j2 as part of the individual embedded war components.
So, I am not sure what you are using to assemble your EAR, but easiest would be to drop it in the WEB-INF of (each of) your webModule (war) packaged within your EE Application (EAR).
If you are using maven, you would have separate projects for your individual EJB and web modules. As such, you should be able to provide the log4j2 file in following locations:
Web Module: src/main/webapp/WEB-INF
EJB: src/main/resources (which should let maven copy it to the META-INF within your jar).
To still provide the log4j2 file as part of your EAR (shared by modules), I think a Class-Path entry needs to be made in your META-INF/MANIFEST.MF. You would provide the directory, or your resource jar location as part of the Class-Path. For providing a directory, a trailing path separator will be needed.
I didn't try it out just now, but I hope it will get you a clue and you will correct me where needed.
Also Log4j2 has the feature to automatically reload on changes and adapt to it on the fly. For that to work in your advantage, I would strongly urge for you to provide the Log4j2 file as part of the Server's class path, and not embedded deep within your jar, war, or ear. It will just be easier to find and modify.

Categories

Resources