log4j 2.2 issues after migrating from log4j 1.2.17 - java

I have migrated from log4j 1.2.17 to log4j 2.2. and I'm getting the following issues:
My AsyncLogger is working like a sync one. This is my config for this logger:
<RollingFile name="ACCESS_LOG"
fileName="${sys:log.dir}vproxy_access.${date:yyyy-MM-dd}"
filePattern="${sys:log.dir}vproxy_access.${date:yyyy-MM-dd}"
append="true"
bufferedIO="true"
bufferSize="8192"
immediateFlush="false">
<PatternLayout>
<Pattern>%m%d{yyyy-MM-dd HH:mm:ss}%n
</PatternLayout>
<Policies/>
</RollingFile>
<AsyncLogger name="LOGGER_ACCESS" level="info" includeLocation="true" additivity="false">
<AppenderRef ref="ACCESS_LOG"/>
</AsyncLogger>
The log creation is correct but everything I log to this file is not buffered and the lines are committed immediately. I've been compared my config with others I've seen in other posts and I can't see what's wrong.
When I shutdown my application, now I'm getting the following error:
Exception in thread "pool-1-thread-1" java.lang.NoClassDefFoundError: org/apache/logging/log4j/message/ParameterizedMessage
at org.apache.logging.log4j.message.ParameterizedMessageFactory.newMessage(ParameterizedMessageFactory.java:47)
at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:737)
at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:708)
at org.apache.logging.log4j.spi.AbstractLogger.error(AbstractLogger.java:314)
at org.apache.logging.log4j.core.util.DefaultShutdownCallbackRegistry.run(DefaultShutdownCallbackRegistry.java:77)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassNotFoundException: org.apache.logging.log4j.message.ParameterizedMessage
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1680)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
... 6 more
When this error appears I'm not logging anything. The last line I log is shown correctly in its corresponding log.
When logging to a file with a sync logger, strange characters occasionally appear. See below "^[[?1;2c^[[?1;2c" (this didn't happen with 1.2.17).
2015-04-02 13:58:51 Starting messaging service ...
^[[?1;2c^[[?1;2c2015-04-02 13:59:06 Messaging service successfully started.
2015-04-02 13:59:06 Starting balancer test port ...
2015-04-02 13:59:06 Balancer test port successfully started.
Thanks in advance.
Joan.

This is the expected behaviour. The background thread is simply keeping up with the log events your application is putting in the queue. Note that with log4j2, async logging will flush the buffer if the queue is empty, so results are immediately visible on disk. (See the docs for FileAppender immediateFlush.)
You may need to add the log4j-web module to your deployment. This is necessary to clean up log4j resources in a web application, and will also disable the shutdown hook. See https://logging.apache.org/log4j/2.x/manual/webapp.html
This one is trickier... Can you provide your full log4j2 config? Any chance there are 2 processes writing to the same file?

Related

Circuit breaker for Log4j 2

Context: Java web application running in Tomcat, Log4j 2 version 2.5. Logging set up to go to one Sentry instance using the Raven connector and one ELK (ElasticSearch + Logstash + Kibana) instance.
Configuration looks like this (anonymized):
<configuration>
<appenders>
<Raven name="Sentry">
<dsn>https://foo#bar.baz/1</dsn>
</Raven>
<Socket name="Logstash" host="1.2.3.4" port="1234">
<SerializedLayout />
</Socket>
</appenders>
<loggers>
<root level="info">
<appender-ref ref="Sentry" level="warn" />
<appender-ref ref="Logstash" />
</root>
</loggers>
</configuration>
Problem is that if Sentry or ELK starts acting up (long response times, unreachable, ...), the application threads get blocked trying to log and the application effectively dies.
Is there a preferred solution to this problem? Some kind of circuit breaker would be ideal here: after detecting a problem with the remote logging destination Log4j 2 would disable the appender for some time.
We use another appender wrapped in an <Async/> appender, but as far as I understand that is a good solution to make the logging... well, asynchronous, but not to fix the problem of unresponsive log destination.
In our system we have a special component called logs-forwarder that collects all the logs by log4j and other systems and forwards them to logstash / splunk etc. what might have you. So that's one valid option.

How to disable request-level logging with the AWS Java SDK?

I'm trying to disable request level logging by the AWS Java SDK with Tomcat 8 on Linux. It's a fresh installation of tomcat 8 and my test servlet (which works) just prints to standard out, which by default goes to /var/log/tomcat8/catalina.out.
I'd like to disable the request level logging like - Sending Request... by the AWS SDK, so I've tried adding the following to my logging config at /usr/share/tomcat8/conf/logging.properties:
log4j.logger.com.amazonaws = WARN
log4j.logger.org.apache.http.wire = WARN
log4j.logger.com.amazonaws.request = WARN
...like the docs say here, but it's still doing the verbose logging. My tomcat startup information shows that the logging.properties file is being used:
org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/share/tomcat8/conf/logging.properties
Is there anything else I need to do to?
If you are using Logback, instead of Log4J or Java14 logging, put the following in logback.xml:
<configuration>
...
<logger name="org.apache.http.wire" level="WARN"/>
<logger name="com.amazonaws" level="WARN"/>
...
To specify an external logback.xml and using Spring Boot
-Dlogging.config="C:\logback\logback.xml"
or if you are not
-Dlogback.configurationFile=file:///C:/logback/logback.xml
Logback configuration via jvm argument
I had the same issue, none of the above helped actually.
Creating a logback.xml and putting it on classpath with below config fixed it:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<logger name="org.apache" level="ERROR" />
<logger name="httpclient" level="ERROR" />
</configuration>
Hope it helps the others.
"logging.properties" is the configuration file for Java Util Logging (JUL), witch is a different framework then Log4J. You can try to create a Log4J config file "log4j.properties" in the root of your classpath and insert the code from above: "log4j.logger.com.amazonaws = WARN" .
By Mark
Perhaps I should have been clearer: log4j is not required to control logging in the SDK. The SDK uses Apache Commons Logging, which is, as I already mentioned, an industry standard. Commons Logging is just a dispatch layer to an underlying logging implementation, so that customers can plug in any compliant logging framework and have it work. I used log4j in my examples because it's the one most commonly used, and therefore the most likely to be helpful in this public forum.
If your logging system works with Commons Logging, then you already know how to configure it. If it doesn't, then feel free to turn off Commons Logging altogether by passing the appropriate command-line argument to your JVM, as in my above response. If for some reason you can't change the java command line for your application, then you can use the following snippet in a Main class, to the same effect:
static {
System.setProperty("org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.NoOpLog");
}
Again, to be absolutely clear: the SDK doesn't need log4j. Unfortunately, because all the underlying log implementations are configured differently, this means that we can't tell you exactly how to configure the logging unless we know which implementation your application uses. For that reason, we often use log4j syntax in our examples.
For more information about how Apache Commons Logging works and how to configure it, please read:
http://commons.apache.org/logging/guide.html

separate log4j2 files for web applications in single weblogic container

We have following Set up:
Application Server : Weblogic 10.3.6
We have 2 Managed Servers and we have 3 web applications wars deployed on both the managed servers.
All log4j2 jars are kept in server lib and loaded on server start up.
Now we want each web application to have its own logj2 configuration as we want to have control on logs levels.
we made separate log4j2 configuration file for each web application using tried initialising same using log4j2-web.jar in web.xml but we observed that when we load first web application, the log4j2 configuration file get loaded but when we try to load 2nd and 3rd web application,with their separate log4j config xmls,it doesnt load the new config file but sets log4j2 configurations of first web applications which got deployed first.
I tried to debug same and got to the point that as log4j2 jars are present in server class loader so they are common to all web application and log4j2 uses class loader to load logger context.
Now i want each application to have its separate log4j2 implementation which will not be common to other web application.so logging will be different for each application.
Kindly note, i cannot copy log4j2 libraries in WEB-INF/lib of each web applications as we already have size constrain for war.
Kindly suggest how can i implement separate log4j2 configuration for each web application in single weblogic container.
I tried to use JNDIContextSelector but its not working in Weblogic or i dont know how to make it work in weblogic as after doing all the required changes mentioned in log4j2 website,it was not able to find loggers.
Kindly help as i m stuck in same issue from last week.
Unfortunately by far the easiest solution that I am aware of is to include the log4j2 libraries in WEB-INF/lib of each web application...
If the log4j2 jar files are in the shared library directory, they are loaded by the shared classloader, and the configuration is shared between all web applications. This is how web containers and log4j2 are designed...
I would focus on this size constraint you mention. Why is there a size constraint on your war file? Perhaps there is another way to get around this size constraint? Would buying extra hard disk or a bigger server solve the issue? (Hardware is much much cheaper than the time you and perhaps your dev team are spending on this...)
If you are really desperate you can try to have one configuration with differently named loggers that log to different files or filter on different levels. When your application calls LogManager.getLogger, the string you pass becomes the name of the logger. This string can be used in the configuration to control filtering and the target appender. One thing you can do in your application, is giving loggers application-unique names like this:
// App.getPrefix() returns "app1." or "app2." etc: a unique name for each web app
Logger logger = LogManager.getLogger(App.getPrefix() + getClass().getName());
Then have different loggers and appenders in your configuration:
<Configuration status="debug">
<Appenders>
<File name="app1File" ...
<File name="app2File" ...
</Appenders>
<Loggers>
<Logger name="app1" level="TRACE">
<AppenderRef ref="app1File"/>
</Logger>
<Logger name="app2" level="TRACE">
<AppenderRef ref="app2File"/>
</Logger>
</Loggers>
</Configuration>
This is obviously a bit of a hack, and won't work for the classes outside your dev team's control...
You can also ask on the log4j-user mailing list to see if any of the other log4j2 team members have any ideas.
I have the same problem but using Tomcat9. I resolved this by explicitly providing a configuration location to each application when it is initializing logger context through a listener.
URL configLocation = Class.forName("com.example.MyAppListener").getResource("/log4j2.xml");
LoggerContext context = (LoggerContext) LogManager.getContext(false);
context.setConfigLocation(configLocation.toURI());
if(!context.isInitialized()) {
context.initialize();
}else {
context.reconfigure();
}

Filtering out log4j messages from third-party frameworks?

How do I filter log messages from external third party frameworks? I am using Hibernate and Spring framework and I would like to suppress the logs so that only my log4j logs appears.
In my log4j.properties file I set the root logger logging level to ERROR. Then for packages I specifically want to log, like my application code, I set the logging level to INFO or DEBUG.
log4j.rootLogger=ERROR, stdout
log4j.logger.com.initech.tps=DEBUG
log4j.logger.org.hibernate.SQL=INFO
I see co-workers who set root logging low and then end up listing everything they don't want to see, that just seems backward to me. I would rather list what I want to log than all the things I don't want to log.
BTW turning logging off entirely for a third-party component seems like a bad idea to me. For instance, Spring is relatively noisy and uses WARN for things I really don't need to know about, but if it logs an ERROR entry for something I want to see it.
You can do it by changing logger level in log4j.properties/log4j.xml file.
You need to set logger's <level value="off"/> if you want to filter logs from package but keep logger configuration for later use.
You could also set it to highest level to log only in case of error or fatal issue.
Following entries should be added to log4j.xml to turn off logging from hibernate and springframework packages:
<logger name="org.springframework">
<level value="off"/>
</logger>
<logger name="org.hibernate">
<level value="off"/>
</logger>
In log4j.properties you can define individual levels on a per logger basis:
log4j.logger.<name>=FATAL
In log4j.xml the syntax is
<logger name="<name>">
<level value="fatal"/>
</logger>
<name> is often the full qualified classname. You might want to use WARN or ERROR instead of FATAL
Just don't add those packages in your log4j.properties. For instance, you must have this for Spring in your properties file. Take it out if you have some entries like below (anything that starts with org.springframework). Same needs to be done for hibernate.
#Logs the SQL from Spring
log4j.logger.org.springframework.jdbc.core.JdbcTemplate=ERROR
#Logs the SQL parameters from Spring
log4j.logger.org.springframework.jdbc.core.StatementCreatorUtils=ERROR
Also as it was mentioned you should also set the following. I forgot to mention this.
log4j.rootLogger=FATAL
or
log4j.rootLogger=ERROR

How to ouput text to console from Servlet

I have a servlet. But it is not working as desired. Hence for debugging purposes, I want to print statements to the java console(the one that can be opened using the java icon in taskbar). However, if I use System.out.println("message"), it doesnt display in java console.
Is there any alternative way where I can display messages to the console from the servlet?
Or can anyone suggest me an alternative way to display messages to any other console?
In which console do you expect it to appear?
Depending on the servlet container (I assume Tomcat), the logs are stored in a logs folder. For Tomcat this is tomcat/logs (or more often referred to as CATALINA_HOME/logs). If you are running it from within an IDE - they should be in the IDE console.
As a sidenote, using System.out isn't advisable for a real product - use a logging framework (like log4j).
Servlet (HttpServlet) has a method log(String s) inherited from GenericServlet class.
So you can just include
log("output text")
in the servlet's code and see output.
If you use Eclipse log goes right into console.
If you use IntellijIdea log goes into Run --> "Tomcat Localhost Log" tab.
I want to print statements to the java console(the one that can be opened using the java icon in taskbar)
You need to realize that servlets actually runs at the server side, not at the client side. Those are in fact two physically different environments which communicates with each other through the network using the HTTP protocol. That Java console will only work for Java programs which runs at the client side, such as applets and JNLP.
In your case, you just need to read the server logs. That's where the stdout will by default print to, or use a better configureable logging framework such as logback. The server logs are usually found in a straightforward folder/file in the server installation directory, such as /logs in case of Tomcat.
Look for the log file in the log-folder of your servlet container (i.e. Tomcat).
As suggested use log4j to generate debug messages. This logging framework provides a configuration file where you can set things like where the logs should be written into or how the log messages should be formatted. As soon it's in place you can replace
System.out.println("message");
with
log.debug("your debug message");
or
log.info("in case of a message with info character");
log.error("routine foo has experienced an exception", e);
Now your code is much cleaner and there is even another benefit - when being placed correctly these logs act as documentation for your code segments.
You should use logging, e.g. java.util.logging or log4j
Example of relevant log4j configuration:
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
</layout>
</appender>
<root>
<priority value ="debug" />
<appender-ref ref="console" />
</root>

Categories

Resources