I'm having hard time opening my logs with Apache Chainsaw v2.
I wasn't able to succesfully open my logs with zeroconf, neither with default xmllayout. It worked like a charm for me in .net. But in Java it's a nightmare.
Main class:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Start {
public static Logger logger = LogManager.getLogger(Start.class);
public static void main(String[]args){
logger.info("Example log info");
logger.trace("Example log trace");
logger.debug("Example log debug");
logger.error("Example log error");
logger.fatal("Example log fatal");
logger.warn("Example log warn");
return;
}
}
Log4j2 configuration
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ALL" advertiser="multicastdns">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="custom layout %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="log4j2Chainsaw" fileName="output.log" bufferedIO="false" advertiseURI="file:///C:/Users/gswiec/IdeaProjects/Log4j2ChainsawExample/output.log" advertise="true">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
<File name="xmlLayoutForChainsaw" fileName="output.xml" bufferedIO="false" >
<XmlLayout/>
</File>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="log4j2Chainsaw"/>
<AppenderRef ref="xmlLayoutForChainsaw"/>
</Root>
</Loggers>
</Configuration>
Here is pom, all needed dependencies seems to be there.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>swiec.eu</groupId>
<artifactId>Log4j2ChainsawExample</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--Log4j2 and apache chainsaw zeroconf dependencies-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>javax.jmdns</groupId>
<artifactId>jmdns</artifactId>
<version>3.4.1</version>
</dependency>
<!--XmlLayout dependencies-->
<dependency>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
<version>5.0.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
</project>
Whole example project is available at https://github.com/swiec/eu.swiec.log4j2apacheexample
I would appreciate your help, also if you suggest different approach to get logs more readable. Apache chainsaw doesn't seems to be live project, I'm not sure if it's good idea using it.
You should test with an app that doesn't start and immediately exit, or it won't have time to advertise & have Chainsaw receive events.
I just added this to your Start.java file:
import java.util.Scanner;
...
public static void main(String[]args){
Scanner in = new Scanner(System.in);
int i = in.nextInt();
I also updated your log4j config - you need to use %m not %msg for the PatternLayout used to generate output.log
<File name="log4j2chainsawappender" fileName="output.log" bufferedIO="false" advertiseURI="file://Users/scott/eu.swiec.log4j2apacheexample/output.log" advertise="true">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %m"/>
I then started Chainsaw v2 (very latest version in git), and started your app.
Once your app was started, I selected Chainsaw's 'connect to, log4j2chainsawappender', and a new tab appeared and correctly formatted your log events, parsing 'Start' as your logger, correct severity levels etc.
Related
I was getting following error message in aws lambda logs :
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
so i added maven depdenecies as :
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
But on adding slfj4j dependencies unwated logs from azure service bus are also getting printed now eg.
[ReactorThread1288184d-400a-4928-b174-b819c8bd9ee1] INFO com.microsoft.azure.servicebus.primitives.MessagingFactory - starting reactor instance.
my log4j.xml looks like this :
<?xml version="1.0" encoding="UTF-8"?>
<Configuration packages="com.amazonaws.services.lambda.runtime.log4j2">
<Appenders>
<Lambda name="Lambda">
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1}:%L - %m%n</pattern>
</PatternLayout>
</Lambda>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Lambda" />
</Root>
</Loggers>
</Configuration>
How can i disable these logs getting printed ?
I think the problem is related with the logging dependencies of your project.
On one hand, you have AWS Lambda over Log4j2, which uses Log4j2 for logging. On the other hand you have Azure Service Bus, which uses the SLF4J API facade for logging. You need to configure your system to support both logging approaches.
First of all, you need the following dependencies in your pom.xml file:
<dependencies>
...
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-log4j2</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.13.2</version>
</dependency>
....
</dependencies>
The first dependency allows you to emit log traces to AWS Lambda.
The last one is the Log4j2 SLF4J java bridge, necessary for Azure Service Bus logging.
Please, also remove the dependency slf4j-simple associated with the group org.slf4j, it will be no necessary.
With this dependencies in place, please, include the following line:
<Logger name="com.microsoft.azure.servicebus" level="OFF"/>
In your XML configuration file (by convention, it is better to name your Log4j2 configuration file like log4j2.xml instead of log4j.xml, more appropriate for the old Log4j library version).
Your log4j2.xml should looks something like the following:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration packages="com.amazonaws.services.lambda.runtime.log4j2">
<Appenders>
<Lambda name="Lambda">
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1}:%L - %m%n</pattern>
</PatternLayout>
</Lambda>
</Appenders>
<Loggers>
<Logger name="com.microsoft.azure.servicebus" level="OFF"/>
<Root level="info">
<AppenderRef ref="Lambda" />
</Root>
</Loggers>
</Configuration>
Firstly, this is not an error. The message means that there is no logger implementation present in the classpath and hence it is defaulting to NOP (No-operation) log. And as SLF4J is an abstraction of different logging frameworks, you also need to include specific logging framework in your classpath apart from only having SLF4J. Since you are trying to use Lambda appender, you need to add aws-lambda-java-log4j2 to your classpath. This will bring in required SLF4J dependencies also.
Latest version as of May 05, 2020:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-log4j2</artifactId>
<version>1.2.0</version>
</dependency>
In my Maven project, Log4j2 latest dependencies state version 2.11.2. However; 1.2.12 is being imported instead. The only logging dependencies stated in the POM.XML file are as follow:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
In the repository folder located within the .m2 folder, there exists a 'log4j' folder that has a folder with the title '1.2.12'. Inside the 1.2.12 folder the following items exist:
_remote.repositories
log4j-1.2.12
log4j-1.2.12.jar.sha1
log4j-1.2.12.pom
log4j-1.2.12.pom.sha1
My log4j2.xml configuration file is as follow:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<Configuration status="WARN">
<Properties>
<Property name="basePath">./logs</Property>
</Properties>
<Appenders>
<RollingFile name="File" filePattern="${basePath}/prints-%d{yyyy-MM-dd}.log" fileName="${basePath}/prints.log">
<PatternLayout pattern="%d{ yyyy-MMMM-dd: hh:mm a :ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<SizeBasedTriggeringPolicy size="500"/>
</RollingFile>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{ yyyy-MMMM-dd: hh:mm a :ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
Log4j2.xml file is located under a package named resources which is situated under a source folder named src/main/java of the Maven project. I also get an occasional message (1 out of 5 times) stating that log4j2 configuration file can not be found. I have tried cleaning the project in addition to deleting the jars and re-including the dependencies but nothing seems to work.
log4j2:WARN No appenders could be found for logger (....) comes when application is not able to locate log4j2.xml/properties file.
/src/main/resources is the standard placement for this.
You mentioned yours is under src/main/java, please keep it under /src/main/resources. If log4j2.properties/xml file is not found under /src/main/resources then use -
PropertyConfigurator.configure("log4j2.properties/xml");
I use log4j 2.x in our maven java war application running on jetty9.
All I need is follow structure:
Single point of code (function) lo log message.
Log function calls org.apache.logging.log4j.core.Logger.[info, error ...] function.
log4j facility writes to main jetty9 log AND to log reside in appropriate folder defined on run time.
I have follow log4j2.xml config:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%-5L - %m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
I use follow dependency in maven pom:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
And follow imports:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
And I try to make brainstorming voodoo with huge amount of log4j classes:
//Configuration c = new AbstractConfiguration
//PatternLayout layout = new PatternLayout();
//FileAppender appender = new FileAppender("printlog", Layout.);
//logger.addAppender(null);
//OHH MY GOD!!!!
I searched a lot in documentation such as https://logging.apache.org/log4j/2.x/manual/appenders.html#FileAppender but I don't find anything close to solve the problem.
All I found is manual for hardcode path to file appender in the configuration.
How to do it programmatically???
I need programmatically defined FileAppender inherits the PatternLayout from ConsoleAppender defined in xml config, because code reuse and single point of control issues.
I found many link that helped me building the logger. Some here in SO and others in other pages.
This answer here: https://stackoverflow.com/questions/7624895/how-to-use-log4j-with-multiple-classes#= is the best that I have found.
It is already some years old thought and some things now are different.
My goal is to have one single logger shared among all of the java classes that print messages to the log, both console and file.
I am using LOG4J2: http://logging.apache.org/log4j/2.x/manual/configuration.html
main():
import org.apache.logging.log4j.Logger;
public class App {
private static final Logger LOGGER = Logger.getLogger("GLOBAL");
public static void main(){
...calling other classes
}
}
anyOtherClass:
import org.apache.logging.log4j.Logger;
public class secondClass {
private final Logger LOGGER = Logger.getLogger("GLOBAL");
public void writeLog(){
LOGGER.log(Level.INFO, "A simple string");
}
}
log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<Properties>
<Property name="basePath">/var/log</Property>
</Properties>
<Appenders>
<RollingFile name="fileLogger" fileName="${basePath}/myApp.log" filePattern="${basePath}/myApp-%d{yyyy-MM-dd}.log">
<PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="java.util.logging.Logger" level="ALL" additivity="true">
<appender-ref ref="fileLogger" level="ALL" />
</Logger>
<Root level="ALL" additivity="false">
<appender-ref ref="console" />
</Root>
</Loggers>
</Configuration>
I (more or less) know that I should use LogManager, truth is I should call it as:
private static final Logger logger = LogManager.getLogger(MyApp.class);
or, in the main(), probably like this:
private static Logger LOGGER = null;
#BeforeClass
public static void setLogger() {
System.setProperty("log4j.configurationFile","log4j.xml");
LOGGER = LogManager.getLogger();
}
Because, I believe, using LogManager I can point the Log to the xml file for its settings.
But when I build it and run it, the CLI rage quits at the first ever LOG, reporting: Exception in thread "main" java.lang.NullPointerException at myapp.modules.Database.<init>(Database.java:67)
Expected Result:
All I want to do is being able to have the log on all of my classes and that this is written to a file.
I just can't get this working. And when I do not use LogManager, I only see the logs on console but no file is created.
I'm using both Windows and Linux (that's why /var/log/ but I change it to C:\ too).
Other website I used:
https://howtodoinjava.com/log4j2/configure-log4j2-for-junit/
Log4J loggers for different classes <-- did not help me
..And many other search results are more than 6 years old.
POM.xml:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
You're wrong on several levels: you're mixing JDK's logger with Log4j2's Logger, you're not logging to several appenders, etc.
Here's what you should do:
/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>log4j2test</artifactId>
<version>0.1</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
</dependencies>
</project>
This is basically the only place where you have no error.
/src/main/java/so47656300/App.java
package so47656300;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App {
private static final Logger logger = LogManager.getLogger(App.class);
public static void main(String[] args) {
logger.info("App.main - starting");
new SecondClass();
logger.info("App.main - ending");
}
}
Here, your error was to use java.util.logger.Logger instead of org.apache.logging.log4j.Logger.
/src/main/java/so47656300/SecondClass.java
package so47656300;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class SecondClass {
private static final Logger logger = LogManager.getLogger(SecondClass.class);
public SecondClass() {
logger.info("SecondClass - starting");
logger.info("SecondClass - ending");
}
}
Here, your error was also to use the wrong Logger class. Use only classes from org.apache.logging.log4j.*.
/src/main/resources/log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="basePath">/var/log</Property>
</Properties>
<Appenders>
<RollingFile name="fileLogger" fileName="${basePath}/myApp.log" filePattern="${basePath}/myApp-%d{yyyy-MM-dd}.log">
<PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="console"/>
<AppenderRef ref="fileLogger"/>
</Root>
</Loggers>
</Configuration>
Here, your errors are the following:
Wrong file name: Log4J 2 requires a name log4j2.xml. For your tests, create a file /src/test/resources/log4j2-test.xml.
You want only one logger, so use only one: the root one. You created several, but you don't need them.
Add appenders to the logger (the Root-one)
Output
Console
[INFO ] 2017-12-05 16:52:32.218 [main] App - App.main - starting
[INFO ] 2017-12-05 16:52:32.221 [main] SecondClass - SecondClass - starting
[INFO ] 2017-12-05 16:52:32.222 [main] SecondClass - SecondClass - ending
[INFO ] 2017-12-05 16:52:32.222 [main] App - App.main - ending
/var/log/myApp.log
[INFO ] 2017-12-05 16:52:32.218 [main] App - App.main - starting
[INFO ] 2017-12-05 16:52:32.221 [main] SecondClass - SecondClass - starting
[INFO ] 2017-12-05 16:52:32.222 [main] SecondClass - SecondClass - ending
[INFO ] 2017-12-05 16:52:32.222 [main] App - App.main - ending
I have the followed imports:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
and the following instantiation:
private static Logger logger = LoggerFactory.getLogger(Test.class);
and the following in my Main method:
logger.info("SOME MESSAGE: ");
However, I'm not able to find the output anywhere. All I see is that in my console there is:
21:21:24.235 [main] INFO some_folder.Test - SOME MESSAGE:
How do I locate the log file?
Note that the following are on my build path:
slf4j-api-1.7.5.jar
slf4j-log4j12-1.6.4.jar
I read the answer to similar questions but nobody actually says how to fix the problem.
slf4j is only an API. You should have a concrete implementation (for example log4j). This concrete implementation has a config file which tells you where to store the logs.
When slf4j catches a log messages with a logger, it is given to an appender which decides what to do with the message. By default, the ConsoleAppender displays the message in the console.
The default configuration file is :
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<!-- By default => console -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
If you put a configuration file available in the classpath, then your concrete implementation (in your case, log4j) will find and use it. See Log4J documentation.
Example of file appender :
<Appenders>
<File name="File" fileName="${filename}">
<PatternLayout>
<pattern>%d %p %C{1.} [%t] %m%n</pattern>
</PatternLayout>
</File>
...
</Appenders>
Complete example with a file appender :
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<File name="File" fileName="${filename}">
<PatternLayout>
<pattern>%d %p %C{1.} [%t] %m%n</pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
As already mentioned its just a facade and it helps to switch between different logger implementation easily. For example if you want to use log4j implementation.
A sample code would looks like below.
If you use maven get the dependencies
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
Have the below in log4j.properties in location src/main/resources/log4j.properties
log4j.rootLogger=DEBUG, STDOUT, file
log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
log4j.appender.STDOUT.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=mylogs.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{dd-MM-yyyy HH:mm:ss} %-5p %c{1}:%L - %m%n
Hello world code below would prints in console and to a log file as per above configuration.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
It does not write to a file by default. You would need to configure something like the RollingFileAppender and have the root logger write to it (possibly in addition to the default ConsoleAppender).
The log file is not visible because the slf4j configuration file location needs to passed to the java run command using the following arguments .(e.g.)
-Dlogging.config={file_location}\log4j2.xml
or this:
-Dlog4j.configurationFile={file_location}\log4j2.xml