Spark 2.2.0: Log4J configured before logger is instantiated - java

I have a project using custom log4j property files and levels that worked in Spark versions 2.0.2 or older. An upgrade to Spark 2.2.0 was needed to resolve some performance issues, but it breaks the log4j components.
The log4j properties file makes references to a system property "current.date", as well as a custom log level class in the package:
# Root logger option
log4j.rootLogger=INFO,file,file2
log4j.logger.com.package.project.PROJECTDriver=PROJECT#com.package.project.PROJECTLogLevel,file3
log4j.appender.file3=org.apache.log4j.RollingFileAppender
log4j.appender.file3.File=../../../../project/log/PROJECTUserLog_${current.date}.log
log4j.appender.file3.Append=false
log4j.appender.file3.MaxFileSize=100MB
log4j.appender.file3.MaxBackupIndex=1
log4j.appender.file3.layout=org.apache.log4j.PatternLayout
log4j.appender.file3.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
log4j.appender.file3.threshold=PROJECT#com.package.project.PROJECTLogLevel
log4j.appender.file3.filter.filter1=org.apache.log4j.varia.LevelRangeFilter
log4j.appender.file3.filter.filter1.levelMax=INFO
The references are declared in the code prior to instantiating the log4j logger:
val dateFormat = new SimpleDateFormat("yyyyMMddhhmmss")
System.out.println("Starting Project Driver")
System.setProperty("current.date", dateFormat.format(new Date()))
var log: Logger = LogManager.getLogger("com.package.project.PROJECTDriver")
After upgrading to Spark 2.2.0, Log4j started to complain that it could not find the custom log level class. It was also not appending the current.date value, just leaving it blank.
After some digging around and playing with log4j debug mode, I found that in Spark 2.2.0, log4j was being configured before the project code was ran. In the previous Spark versions, the debug output looks like this:
Starting Project Driver
log4j: *log4j configuration steps, going through the properties file*
In Spark 2.2.0, the order is reversed:
log4j: *log4j configuration steps, going through the properties file*
Starting Project Driver
I couldn't find any notes on this change in Spark 2.2.0. Is there any way to fix log4j so that configuration starts when the logger is called?

Related

Force a specific logger in Spring Boot

We wanted to switch from standard logback to log4j in Spring Boot 2.4.x.
For most modules, it is a no-brainer by simply removing the dependency of logback, but there are some modules, which are using pact-jvm as a shadow-jar dependency to be able to create the pact files from unit tests.
Now the odyssey begins, because pact needs logback and with the pact-jar on the classpath Spring recognizes the logback class it is looking for and decides to use logback instead of log4j as the logger in the tests.
Is there a possibility to create something like a log bean or a hidden configuration, which allows forcing Spring to use log4j instead of logback, also if logback is on the classpath?
Pact should not be an issue at this point, because the server is started as a standalone server from gradle. We only require the dependency to be able to start everything and to have the classes available.
Thanks!
You may follow these steps to configure log4j with spring boot
Add the log4j dependency to your module
Create logger object in your respective class and use the logger object to log the messages.
org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(<YourClassName>.class);
In your spring boot module/project add log4j.properties file in resources so that this will be available on class path at runtime. Following is sample content for the log4j.properties
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
Make sure that the spring boot module bundles the log4j jar when you build.
Once spring boot finds the log4j jar and the log4j.properties on the class path it will be able to initialize the log4j logger for you.
Yes, that's clear. The issue is, that Spring Boots Autoconfiguration is loading the logger for slf4j (sorry forgot that). So here it iterates over the supported candidates in the order:
logback
log4j
apache-log-commons
And it seems that it does not look for beans, it simply looks for the classes by reflection.
If we now start the app for testing together with pact server, Spring Boot resolves an Append* class and thinks, that this has to be the logger of our choice.
It creates the logback instance, which is searching for its config, but then it fails, because the config is for log4j.

Set JCS log level to ERROR - log4j

I have implemented JCS in my J2ee application which uses log4j for logging.
My Requirement
Set the application rootLogger in DEBUG level and jcs logs in ERROR mode.
What is tried
Tried the following in log4j properties
log4j.category.org.apache.common.jcs=ERROR
log4j.logger.org.apache.common.jcs=ERROR
But nothing is affecting the logging.
Whenever the cache access happens, it logs a bunch of returning first node messages.
Note : I am using the latest JCS commons-jcs-core-2.0-beta-1.jar
This is my complete log4j.properties
log4j.rootLogger=DEBUG, A1
# Use Console Appender for development
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern= %d [%t] %-5p - %m%n
log4j.logger.net.sf.jasperreports=ERROR
log4j.category.org.apache.common.jcs=ERROR
I missed an "s" in commons. Correcting it solved my problem.
Solution
Both the below statements can be used to configure JCS log level in log4j.
log4j.category.org.apache.commons.jcs=ERROR
log4j.logger.org.apache.commons.jcs=ERROR
JCS has a dependency on commons-logging for logging, and not log4j. Hence, log4j configurations won't matter unless you redirect commons-logging to log4j. To do that, create a file named commons-logging.properties and add the following in that.
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4jLogger

Can't configure Jetty and log4j

Recently I inherited a project and having some hard time configuring the logging in the sense I can't seem to configure it at all!
So let me first give you the context:
It runs under Jetty 9.2
It uses the Apache Commons logging library
It has a Maven dependency on log4j which I assume the apache commons will pick that up and use it.
There are no existing commons-logging.properties or log4j.properties so I assume it falls back to defaults.
There is no jetty-logging.properties either.
So here is my problem, it currently does not log the timestamp, the output is like this:
5027 [main] INFO org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped URL path [/css/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
and:
912562 [qtp760972690-15] DEBUG com.xxx.xx.Class - Some Action Log Msg
No idea what those fields before the DEBUG are. I had previously worked with Tomcat, sl4j and pretty sure Apache Commons logging too.
So I thought I would config files both 'commons-logging.properties' and 'log4j.properties' in the WAR file WEB-INF/classes.
Now it recognises and picks up the 'commons-logging.properties' but the 'log4j.properities' seems to have no effect at all.
So am I missing a step here, have I forgotten something? Is this a Jetty issue because it uses sl4j and I'm not?
Here is is m commons-logging.properties:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
log4j.configuration=log4j.properties
And here is my log4j.properties:
# Set root logger level to DEBUG.
log4j.rootLogger=DEBUG,stdout
# stdout is set to be a ConsoleAppender.
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# stdout uses PatternLayout.
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
Another note is that log lines from Jetty itself do have the nice date-stamp I want:
2014-09-06 19:36:19.356:INFO:/:main: Initializing Spring FrameworkServlet 'appServlet'
But not my main application logging.

Log4j doesn't log INFO Level

I have the following log4j.properties file, for an application deployed in WebSphere Portal:
log4j.rootLogger=DEBUG, InfoAppender, DebugAppender
log4j.appender.InfoAppender=org.apache.log4j.RollingFileAppender
log4j.appender.InfoAppender.Threshold=INFO
log4j.appender.InfoAppender.File=C:/info.log
log4j.appender.InfoAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.InfoAppender.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.DebugAppender=org.apache.log4j.RollingFileAppender
log4j.appender.DebugAppender.Threshold=DEBUG
log4j.appender.DebugAppender.File=C:/debug.log
log4j.appender.DebugAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.DebugAppender.layout.ConversionPattern=%d %p [%c] - %m%n
When I code, I define the logger at class level:
private static Logger logger = Logger.getLogger(IWannaLogThis.class);
And I log INFO messages with this:
logger.info(theObjectToLog);
When I deploy my application, the debug.log file gets everything I log with logger.debug() but ignores everything I write with logger.info(). On the other side, the info.log file keeps empty.
The weirdest thing is that in debug.log and info.log appears some INFO and DEBUG messages made by some JARS (like Hibernate Validator) I had in the classpath, but just ignores everything I try to log in my code.
Any ideas?
This is most likely a classloading-related problem. WebSphere Portal uses Log4J internally, so I'm guessing that you end up using WebSphere Portal's provided Log4J JAR file as well as its own Log4J properties.
You can verify that by adding the following to the JVM arguments of the server instance:
-Dlog4j.debug=true
And then inspect the SystemOut.log file. Log4J will spit out lots of tracing information about the configuration file(s) it reads.
The best way to avoid this is to do the following:
Bundle the Log4J JAR file with your application.
Associate a Shared Library with the server. In that Shared Library, place your Log4J configuration file.
As an alternative to step 2, you can bundle your Log4J configuration file with the application itself, however that would carry its own drawbacks (for example, having to repackage your application whenever you perform a Log4J configuration change).
Another common problem is that the JARs you have in your classpath also use log4j and also have their own appenders set. So depending on the settings that they use, and the packages that your classes reside in, this may lead to the problem you describe.
So:
Make sure that your package names are unique and not used by any of the third party libraries.
Check the log4j settings in all libraries in your classpath. They should not contain general settings which override yours.
Make sure your loggers use your log4j.properties (you can be sure if changes you make in your file affect your loggers as expected).
If you can, make sure that your log4j stuff loads last, in case any of the third party libs reset the configuration. They shouldn't, but who can stop them.
Normally, it should be one of these things. Post more explicit example if it doesn't work.
Good luck!
What I have done in the past is set specific logs for the classes I want to log. It sounds like you can try setting your root logger to INFO and see if that gets you the messages you want. Here's a little bit of my log4j property file. I set a logger for each class and assign it to my "data" appender, which defines the log layout. In the loggers I specify specific classes I want to log and set their Log level individually. Any class that logs that is not defined in the Loggers I have use the default log level for the rootCategory.
log4j.rootCategory=INFO, rollingFile, stdout
#GetData Loggers
log4j.logger.com.myapp.data=INFO, data
log4j.logger.com.myapp.data.SybaseConnection=DEBUG, data
log4j.logger.com.myapp.data.GetData=ERROR, data
# data appender
log4j.appender.data=org.apache.log4j.RollingFileAppender
log4j.appender.data.layout=org.apache.log4j.PatternLayout
log4j.appender.data.File=c\:\\Program Files\\MyApp\\logs\\MyApp-data.log
log4j.appender.data.Append=true
log4j.appender.data.layout.ConversionPattern=[%d{ISO8601}]%5p%6.6r[%t]%x - %C.%M(%F:%L) - %m%n
you root logger opens the log properties in the debug mode,
use INFO instead of DEbug in the first line of your properties file.

Tomcat App says "Unable to configure the logging system. No log.properties was found."

I have an embedded tomcat app and whenever I start it up I see this error printed to the console twice:
Unable to configure the logging system. No log.properties was found.
It seems stupid, but I've done some googling and searched stackoverflow and can't seem to find someone experiencing this problem.
My main class Looks roughly like this:
public class AuthServerEntryPoint {
static {
org.apache.log4j.PropertyConfigurator.configure("conf/log4j.properties");
}
public static void main(String[] args) {
// ...
}
"conf/log4j.properties" contains a seemingly valid configuration:
log4j.appender.mainAppend=org.apache.log4j.ConsoleAppender
log4j.appender.mainAppend.layout=org.apache.log4j.PatternLayout
log4j.appender.mainAppend.layout.ConversionPattern=%d %p [%t] %c -- %m%n
log4j.appender.fileAppend=org.apache.log4j.FileAppender
log4j.appender.fileAppend.layout=org.apache.log4j.PatternLayout
log4j.appender.fileAppend.layout.ConversionPattern=%d %p [%t] %c - %m%n
log4j.appender.fileAppend.file=logs/myservice.log
log4j.rootLogger = info, fileAppend
log4j.logger.com.mycompany.myservice = debug, fileAppend
And the logging actually does work - i.e., logs are correctly written to myservice.log. So what gives?
Thanks!
-Carl
By embedded Tomcat app, do you mean that you are starting Tomcat from Java code and are using the class org.apache.catalina.startup.Embedded?
If yes, my guess is that Tomcat might not be able to find its logging configuration file that is set up in catalina.sh (or equivalent) when using the scripts:
LOGGING_CONFIG="-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties"
The odd part is that this file is called logging.properties, not log.properties, so I'm really not sure. I didn't check Tomcat sources though, maybe they are doing some kind of black magic in there.
Could you just try to rename $CATALINA_BASE/conf/logging.properties into log.properties (or not) and to put it on the classpath of your app (or to set -Djava.util.logging.config.file)?
By default, log4j will look for a logging properties file on the classpath. Put your webapp's logging properties config file into its WEB-INF/classes directory; e.g.
$CATALINA_HOME/webapps/<yourApp>/WEB-INF/classes/log4j.properties
This is the simple approach to getting a webapp to use Log4j is recommended by the referenced documentation. And it is the approach I use myself for webapp logging.
There are various other ways to configure Log4j logging on Tomcat as well. It is possible that your Tomcat has been (partly) configured to use one of them, but something has not been done quite right.
Configuring Tomcat' log4j logging via the system properties is an option that avoids figuring out where log4j is looking ... and what is going wrong. But you are then stuck with creating/using a custom launch script or having to remember to set environment variables before launching Tomcat.
References:
Configuring logging on Tomcat 5.5
Configuring logging on Tomcat 6
The "Default Initialization under Tomcat" section of the Log4j Manual

Categories