Log4j define multiple loggers - java

I'm writing a REST service in Java ( with JAX-RS standard on Tomcat 9 ) and I want to add logs to my program for tracing his work when is called.
So I'm using Log4j (version 1.2.17) for writing my logs, and I want to write a different log file for each of my services running on my REST Service but I need to use only one log4j properties for the entire application
So I want this kind of logs in my log folder
--------------------------------
| Method | Log File |
|------------------------------|
| /A | MyRestService_A.log |
| /B | MyRestService_B.log |
--------------------------------
So I write this as configuration of Log4j ( restServiceLogger.properties ):
log4j.rootLogger=A,B
#/A
log4j.appender.A=org.apache.log4j.RollingFileAppender
log4j.appender.A.File=logs/MyRestService_A.log
log4j.appender.A.MaxFileSize=5MB
log4j.appender.A.MaxBackupIndex=5
log4j.appender.A.layout=org.apache.log4j.PatternLayout
log4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n
#/B
log4j.appender.B=org.apache.log4j.RollingFileAppender
log4j.appender.B.File=logs/MyRestService_B.log
log4j.appender.B.MaxFileSize=5MB
log4j.appender.B.MaxBackupIndex=5
log4j.appender.B.layout=org.apache.log4j.PatternLayout
log4j.appender.B.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n
Then in the /A method I initialize the logger with this:
PropertyConfigurator.configure("conf/restServiceLogger.properties");
Logger log = Logger.getLogger("A");
Then in the /B method I initialize the logger with this:
PropertyConfigurator.configure("conf/restServiceLogger.properties");
Logger log = Logger.getLogger("B");
The problem is that when i write my logs they are all written in the /A log file (MyRestService_A.log).
How can I fix this by using only one properties for the entire project?
Thank you

You need to define logger in your configuration file each and use the same to get the Logger instance in you class file
e.g.
log4j.logger.A=,A
log4j.additivity.A=false
and your class file, get the logger by name
e.g. in class A
Logger logger = Logger.getLogger("A");`
Your log4j.properties files should be like below.
log4j.rootLogger=A,B
#/A
log4j.logger.A=,A
log4j.additivity.A=false
log4j.appender.A=org.apache.log4j.RollingFileAppender
log4j.appender.A.File=logs/MyRestService_A.log
log4j.appender.A.MaxFileSize=5MB
log4j.appender.A.MaxBackupIndex=5
log4j.appender.A.layout=org.apache.log4j.PatternLayout
log4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n
#/B
log4j.logger.B=,B
log4j.additivity.B=false
log4j.appender.B=org.apache.log4j.RollingFileAppender
log4j.appender.B.File=logs/MyRestService_B.log
log4j.appender.B.MaxFileSize=5MB
log4j.appender.B.MaxBackupIndex=5
log4j.appender.B.layout=org.apache.log4j.PatternLayout
log4j.appender.B.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n

Related

log4j2 properties file for a custom appender

I created a custom appender and it's not getting called when I run my test. Here's what the properties look like:
name=config
appenders=console, myCustomAppender
appender.console.type=Console
appender.console.name=STDOUT
appender.console.layout.type=PatternLayout
#appender.console.layout.pattern =%d{HH:mm:ss} [%t] %c{1} [%-5level] - %msg%n
appender.console.layout.pattern=%d{dd-MM-yyyy HH:mm:ss} [%-5p] (%F:%L) - %m%n
appender.myCustomAppender = com.myCompany.logging.log4j.WindowsEventLogAppender
appender.myCustomAppender.name = WindowsEventLogAppender
appender.myCustomAppender.type = WindowsEventLogAppender
rootLogger.level=info
rootLogger.appenderRefs=stdout, myCustomAppender
rootLogger.appenderRef.stdout.ref=STDOUT
My appender is called a WindowsEventLogAppender. Any idea what's wrong with my properties file? I see the console test messages but none of the messages from my appender. Right now I'm just doing a System.out.println in my custom appender to verify it's getting called.
BTW, I've found lot's of XML examples out there for log4j2 configurations with custom appenders but none for using a properties file for configuration.
Thanks,
-Mike
I might be quite late here, but I think my answer can help other people looking for answers. Please accept this as an answer if this is correct!
If you have created a custom appender having annotation like this:
#Plugin(name = "MyCustomAppender", category = "Core",
elementType = "appender", printObject = true)
public final class MyCustomAppenderImpl extends AbstractAppender {
// other code for the plugin....
}
The log4j2 manual about Configuring Appenders states that:
"An appender is configured either using the specific appender plugin's name or with an appender element and the type attribute containing the appender plugin's name"
Meaning the type for appender should be Appender Plugin's Name attribute value.
Which in above case is MyCustomAppender (appender.identifierName.type=MyCustomAppender)
So, the Properties file configuration for this to work should be:
(Note : I have added a stdout(console) appender just to show
relevance/similarity of usage with OOTB appenders, and 2 example
usages with RootLogger and a custom logger)
# this packages attribute is important, please put comma seperated package(s) to the
# plugin(s) you have created
packages = com.package.to.your.plugin
# Example: Declare and Define OOTB Console appender, which sends log events to stdout
appender.console.name = stdout
appender.console.type = Console
# Declare and define the custom appender like this
# Note that the "abc" in "appender.abc.type" can be anything
# and the value for "appender.abc.type" should be the same as
# "Name" attribute value given in custom appender plugin which is "MyCustomAppender"
appender.abc.name=arbitrary_name
appender.abc.type=MyCustomAppender
rootLogger.appenderRef.stdout.ref = stdout
rootLogger.appenderRef.abc.ref = arbitrary_name
logger.loggeridentifier.name = com.test.SomeClass
logger.loggeridentifier.appenderRef.stdout.ref = stdout
logger.loggeridentifier.appenderRef.abc.ref = arbitrary_name
# Also note that the value of appenderRef should be the same name given to your
# appender in properties file, which in this case is "arbitrary_name" (as given above)
Try adding the packages property.
Like: packages = com.myCompany
You haven't included the package info
try the below configuration.
name=config
appenders=console, myCustomAppender
appender.console.type=Console
appender.console.name=STDOUT
appender.console.layout.type=PatternLayout
#appender.console.layout.pattern =%d{HH:mm:ss} [%t] %c{1} [%-5level] - %msg%n
appender.console.layout.pattern=%d{dd-MM-yyyy HH:mm:ss} [%-5p] (%F:%L) - %m%n
appender.myCustomAppender = com.myCompany.logging.log4j.WindowsEventLogAppender
appender.myCustomAppender.name = WindowsEventLogAppender
appender.myCustomAppender.type = WindowsEventLogAppender
rootLogger.level=info
rootLogger.appenderRefs=stdout, myCustomAppender
rootLogger.appenderRef.stdout.ref=STDOUT
rootLogger.com.mycompany.example=INFO,STDOUT

Log4j not printing lower levels than WARN and creating no log files

I have the following log4j2.properties file
# Root logger option
log4j.rootLogger=DEBUG, stdout
## Direct log messages to file
log4j.appender.fileout=org.apache.log4j.FileAppender
log4j.appender.fileout.File=/logs/bbt_${current.date}.log
log4j.appender.fileout.ImmediateFlush=true
log4j.appender.fileout.Threshold=info
log4j.appender.fileout.Append=false
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.conversionPattern=%5p | %d | %m%n
# Direct log messages to terminal
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=%5p | %d | %m %n
and the following temporary test class
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Temp {
private static Logger log = LogManager.getLogger();
public static void main(String[] args) {
log.error("error");
log.debug("debug");
log.info("info");
log.fatal("fatal");
log.trace("trace");
log.warn("warn");
}
}
However, when I run the test class I get the following output:
11:32:19.295 [main] ERROR Temp - error
11:32:19.298 [main] FATAL Temp - fatal
Additionally, no /logs/ folder or log files are created. I thought the issue with the log levels might be caused by the fact that I'm setting a treshold in the first block (for the file), but commenting out this block makes no difference. Does anyone have an idea what could be the cause here?
It looks to me like you've used a properties file from Log4J version 1, but are trying to use Log4J version 2.
This version 2 properties file, named as log4j2.properties on the classpath, worked for me:
name=PropertiesConfig
rootLogger.level=debug
rootLogger.appenderRefs=stdout, file
rootLogger.appenderRef.stdout.ref=StandardOutput
rootLogger.appenderRef.file.ref=LogFile
appenders=console, file
## Direct log messages to file
appender.file.type=File
appender.file.name=LogFile
appender.file.fileName=logs/bbt_${current.date}.log
appender.file.layout.type=PatternLayout
appender.file.layout.pattern=%5p | %d | %m%n
# Direct log messages to terminal
appender.console.type=Console
appender.console.name=StandardOutput
appender.console.layout.type=PatternLayout
appender.console.layout.pattern=%5p | %d | %m %n

how to make Log4j configuration properly

I am new to the Log4j framework and after reading some stuff i got some fare idea about logging mechanism, but still
i have some doubt about the following properties.
log4j.category.com.cloud.sample=INFO, file, C
log4j.additivity.com.cloud.sample=true
log4j.appender.C=org.apache.log4j.ConsoleAppender
log4j.appender.C.Target=System.out
log4j.appender.C.ImmediateFlush=true
log4j.appender.C.layout=org.apache.log4j.PatternLayout
log4j.appender.C.layout.ConversionPattern=%-5p %d [%t] %m%n
#log4j.rootLogger=INFO, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
### direct messages to file ###
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=${catalina.home}/var/basic/logs/sample.log
log4j.appender.file.Append=true
log4j.appender.file.MaxFileSize=10MB
# mylog.log.10 \u307e\u3067\u4fdd\u6301
log4j.appender.file.MaxBackupIndex=50
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %5p [%t] %c{1} - %m%n
log4j.rootLogger=INFO, C, file
In the first line of the above code contains two appenders(file, C) after that we will be having appender for both file and C. So as per my understanding logs will of category will be stored to Console and sample.log. Please let me know if i am wrong.
log4j.rootLogger=INFO, A1 and respective properties are not used right?
log4j.rootLogger=INFO, C, file: This line is about root logger, I think in my case it is not useful, because it is defined at the last line and there is no properties defined over here.
Please could any body confirm my understanding and suggest me if any changes required in the above configuration
The root logger resides at the top of the logger hierarchy. It is exceptional in three ways:
it always exists,
its level cannot be set to null
it cannot be retrieved by name.
The rootLogger is the father of all appenders. Each enabled logging request for a given logger will be forwarded to all the appenders in that logger as well as the appenders higher in the hierarchy (including rootLogger).

Log4j config - different logs to different files

This might be a very easy question for some, but personally I find Log4j config to be nightmarishly difficult and that learning to perform brain surgery might be less challenging.
I am trying to lave multiple loggers logging into different files.
Here is what I have in my log4j.properties file:
# Root logger option
log4j.rootLogger=INFO, file, admin
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=/home/nick/logging/file.log
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
log4j.appender.admin=org.apache.log4j.RollingFileAppender
log4j.appender.admin.File=/home/nick/logging/admin.log
log4j.appender.admin.MaxFileSize=1MB
log4j.appender.admin.MaxBackupIndex=1
log4j.appender.admin.layout=org.apache.log4j.PatternLayout
log4j.appender.admin.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
And here is my (very simple) Java app used to test the config:
public static void main(String[] args) throws Exception {
Properties resource = new Properties();
InputStream in = new FileInputStream("/home/nick/logging/log4j.properties");
resource.load(in);
PropertyConfigurator.configure(resource);
Logger admin = Logger.getLogger("admin");
Logger file = Logger.getLogger("file");
admin.info("hello admin");
file.info("hello file");
}
I have 2 problems:
One problem I always get an exception in the line PropertyConfigurator.configure(resource);:
java.io.FileNotFoundException: /home/nick/logging (Is a directory)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
at java.io.FileOutputStream.<init>(FileOutputStream.java:136)
at org.apache.log4j.FileAppender.setFile(FileAppender.java:289)
at org.apache.log4j.RollingFileAppender.setFile(RollingFileAppender.java:167)
at org.apache.log4j.FileAppender.activateOptions(FileAppender.java:163)
at org.apache.log4j.config.PropertySetter.activate(PropertySetter.java:256)
The 2nd problem is that both messages are written to both logs. Here is the actual result:
File admin:log:
2014-04-27 11:55:30 INFO admin - hello admin
2014-04-27 11:55:30 INFO file - hello file
File file.log:
2014-04-27 11:55:30 INFO admin - hello admin
2014-04-27 11:55:30 INFO file - hello file
Here is the required result:
File admin:log:
2014-04-27 11:55:30 INFO admin - hello admin
File file.log:
2014-04-27 11:55:30 INFO file - hello file
What is causing the exception, and how can I achieve the required result?
Log4J makes a distinction between loggers, which are responsible for generating log messages, and appenders, which are responsible for sending those messages somewhere (a file, the console, a database, etc.). Loggers form a hierarchy, the root logger is the parent of the logger named admin, which is the parent of admin.component1, etc., and you can attach appenders to any logger in the hierarchy. By default a logger will send messages to all appenders that are attached directly to it, or to any of its ancestors in the hierarchy (this is why loggers are conventionally named like Java classes, e.g. you can control logging for com.example.Class1 and com.example.subpkg.AnotherClass by configuring the com.example logger).
Loggers and appenders form separate namespaces and this is the source of your confusion - the logger named admin and the appender named admin are two separate entities.
The configuration you have given in the question defines one logger (the root logger) which sends all the messages it generates to two separate appenders, one for each of the two files. Your code then requests two different loggers and generates one log message with each logger. Both these loggers inherit the appender configuration from the root logger, so they both send their messages to both of the configured appenders.
Instead of attaching the two appenders to the root logger, you should attach the file appender to the file logger and the admin appender to the admin logger:
log4j.rootLogger=INFO
log4j.logger.file=INFO, file
log4j.logger.admin=INFO, admin
This way the file logger will send messages only to file.log, the admin logger only to admin.log, and all messages from other loggers will be silently discarded, as there are no appenders attached to the root.
The additivity flag is the exception to this rule - setting a logger's additivity to false essentially disconnects the arrow from a logger up to its parent, so messages generated by that logger (or flowing into it from one of its children) will not go any further up the tree, they will only go to appenders attached directly to the logger in question.
To answer my own question, this is what I needed:
log4j.logger.file=DEBUG, fileAppender
log4j.logger.admin=DEBUG, adminAppender
log4j.additivity.file=false
log4j.additivity.admin=false
log4j.appender.fileAppender=org.apache.log4j.RollingFileAppender
log4j.appender.fileAppender.File=/home/nick/logging/file.log
log4j.appender.fileAppender.MaxFileSize=1MB
log4j.appender.fileAppender.MaxBackupIndex=1
log4j.appender.fileAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.fileAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
log4j.appender.adminAppender=org.apache.log4j.RollingFileAppender
log4j.appender.adminAppender.File=/home/nick/logging/admin.log
log4j.appender.adminAppender.MaxFileSize=1MB
log4j.appender.adminAppender.MaxBackupIndex=1
log4j.appender.adminAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.adminAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
You don't need to load the properties file. Just place it inside the src folder that will automatically added in class path.
Sample code:
public static void main(String[] args) throws Exception {
Logger admin = Logger.getLogger("admin");
Logger file = Logger.getLogger("file");
admin.info("hello admin");
file.info("hello file");
}
First: log4j recommands to use xml format file for properties.
Second: its better to load the properties file in the classloader.
Third: there is inheritance in logger, but you can cut it with additivity property see log4j.properties file - multiple loggers in same class

Log4j Logging to multiple files

In my Java console app, I want to log certain events to a log file and certain others to console. This is what I've got now
log4j.rootLogger=error, 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{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.appender.L1=org.apache.log4j.FileAppender
log4j.appender.L1.layout=org.apache.log4j.PatternLayout
log4j.appender.L1.layout.ConversionPattern=%-22d{dd/MMM/yyyy HH:mm:ss} – %m%n
log4j.appender.L1.file=failedtoaddusers.log
In my Java app, I instantiate two log instances using
private static Logger log = Logger.getLogger(ActiveDirectoryManage.class);
private static Logger failedToAddUsersLogger = Logger.getLogger("FailedToAddUsersLogging");
My issue is that failedToAddUsersLogger.warn("xyz") also writes to the console in addition to the log file failedtoaddusers.log.
I just want it to write to the log file and not to the console.
How do I accomplish that?
You need to set additivity to "false" (read more on logger additivity in the Appenders and Layouts section of the log4j manual):
log4j.additivity.FailedToAddUsersLogging=false
log4j.logger.FailedToAddUsersLogging = your level, L1
Also, make sure you have one of new versions of log4j, "additivity" setting was not available from beginning.

Categories