FileAppender with runtime defined file path - java

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.

Related

Disable Azure service bus printing logs in cloud watch

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>

Log4J1.2.12 jars imported when log4j2 dependencies state 2.11.2

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");

How to open log4j2 logs with Apache Chainsaw

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.

How configure SLF4J underlying configuration file location [duplicate]

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

Write simple logs using log4j 2

I've looked everywhere but couldn't find any guides (that made sense to me) on how to use log4j 2. As a background, I'm extremely new to log4j or any type of logging, and the closest to logging I've ever gotten was System.out.println() or PrintWriter in Java (if that's even considered logging).
I went to Apache Log4j 2 page to download the jar files, but there are 36 jar files and I have no clue which one to use.
Can anyone get me started on how to append simple String messages to a log file from my server code (in Java)? For instance, when a user connects to my server, I have a simple
System.out.println("user A connected to server at " + time);
code, which serves me no good during real usage. I'd like to replace all my System.out statements to logging using Log4j, so that I can read them later and detect any bugs/crashes in my server code.
Thanks in advance!
Is this a webapp? In other words, does it have a WEB-INF folder? If so, create a simple log4j.properties file that contains something like:
# Define the root logger with appender file
log4j.rootLogger = DEBUG, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=log.out
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n
Make sure on this line:
log4j.appender.FILE.File=log.out
that you have a file actually created for it. I used log.out as an example.
Place this in your WEB-INF folder.
If it's a Maven project, find a place in your project for the file and add it manually by right clicking Run->Run Configuration -> [classpath tab] -> click on user Entries -> Advanced -> Select Add Folder -> and adding the directory where you put the file.
In your class, import:
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.FileAppender;
Then instantiate your logger object:
static Logger log = Logger.getLogger(LdapPurge.class.getName());
Try that and see if it works.
I've been working with Log4j version 2.x and recently wrote a post about its use. You can review it, maybe it will help you:
To use Log4j 2.x 2 libraries are required:
<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>
Create the log42.xml file in the resources folder:
<?xml version="1.0" encoding="UTF-8"?>
<!--https://logging.apache.org/log4j/2.x/manual/configuration.html-->
<Configuration status="TRACE" monitorInterval="30">
<!-- The properties that are needed in the configuration of the appenders are defined | property definition -->
<Properties>
<!--The pattern is defined. For writing in logs -->
<Property name="LOG_PATTERN">%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} [%t] %-5level %logger{36} - %msg%n</Property>
<!--Storage location is defined -->
<Property name="APP_LOG_ROOT">var/log/tomcat0</Property>
</Properties>
<Appenders>
<!-- Configuration for writing events to console (cmd, ide, terminal)-->
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${LOG_PATTERN}" />
</Console>
<!--
Configuration for writing debug events.
for more information about properties: https://logging.apache.org/log4j/2.x/manual/appenders.html
-->
<RollingFile name="debugLog"
fileName="${APP_LOG_ROOT}/logs/automatizador-debug.log"
filePattern="${APP_LOG_ROOT}/logs/$${date:yyyy-MM}/automatizador-debug-%d{yyyy-MM-dd}-%i.log.gz">
<LevelRangeFilter minLevel="DEBUG" maxLevel="DEBUG" onMatch="ACCEPT"
onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<!--Define the logger-->
<Loggers>
<!--only log events from type "debug" for the package: com.advanced.development -->
<Logger name="com.advanced.development" additivity="false"
level="trace">
<AppenderRef ref="debugLog" />
<AppenderRef ref="Console" />
</Logger>
<Root level="error">
<AppenderRef ref="debugLog"/>
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
For more details: https://su9.co/9BaE74E

Categories

Resources