Log4j selective appender - java

I have a java application which has 'hypotetically speaking' 3 objects...
1 of the class Animal, 1 of the class Food, those are not related by any inheritance or interface..and a last one of the class Manager wich is having a list of animals and list of Food, the manager is responsable for a zoo where those animals and Food are..
to the point...
Am using log4j and I need to log to the a txt file IF ONLY AND ONLY IF something in the animal list changes... (animal dies, borns or what ever...) and I need to log to the System.out IF AND ONLY IF something in the Food list changes... (new food is need, food was eaten, what ever...)
My question:
How can I do that with log4j?
I have found here:
Log4j : Creating/Modifying appenders at runtime, log file recreated and not appended
something like dynamically changing the appender
String targetLog="where ever you want your log"
FileAppender apndr = new FileAppender(new PatternLayout("%d %-5p [%c{1}] %m%n"),targetLog,true);
logger.addAppender(apndr);
logger.setLevel((Level) Level.ALL);
but I think this is very ugly and error prone to add and remove the appender constantly all over the hole application..
Is there any better way to handle this
can I have 2 logger (one for animals 1 for the food)??
any suggestion??
Thanks

You can do this strictly from the configuration in the log4j.xml file. You can define two appenders in there, and then have two logger elements, one that ties animals to the first appender, and one that ties the food to another appender. Probably you should have a element too, to define default behavior.

This is how I got it to work:
Configuring the properties
log4j.rootLogger=TRACE, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%5F:%t:%L] - %m%n
log4j.appender.animalLogger=org.apache.log4j.FileAppender
log4j.appender.animalLogger.File=animal.log
log4j.appender.animalLogger.layout=org.apache.log4j.PatternLayout
log4j.appender.animalLogger.layout.ConversionPattern=%d [%5F:%t:%L] - %m%n
log4j.category.animalLogger=DEBUG, animalLogger
log4j.additivity.animalLogger=false
log4j.category.foodlLogger=DEBUG, stdout
log4j.additivity.foodlLogger=false
static final Logger animalLogger = Logger.getLogger("animalLogger");
static final Logger foodlLogger = Logger.getLogger("foodlLogger");
and to load the logger and logging:
public static void main(String[] args) {
PropertyConfigurator.configure("log4j.properties");
animalLogger.debug("Hello animalLogger message");
foodlLogger.debug("Hello reportsLog message");
}

Related

logging using log4j into a separate files along with on to console

Here is my log4j.properties file
# Define the root logger
log4j.rootLogger = DEBUG, toConsole
# Define the console appender
log4j.appender.toConsole=org.apache.log4j.ConsoleAppender
log4j.appender.toConsole.layout=org.apache.log4j.PatternLayout
log4j.appender.toConsoleAppender.layout.ConversionPattern=%d{HH:mm:ss} %5p [%t] - %c.%M - %m%n
# Define the file appender
log4j.appender.success=org.apache.log4j.FileAppender
log4j.appender.success.File=logs/success.log
log4j.appender.success.Append=false
log4j.appender.success.layout=org.apache.log4j.PatternLayout
log4j.appender.success.layout.conversionPattern=%d{HH:mm:ss} %5p [%t] - %c.%M - %m%n
# Define the file appender
log4j.appender.failure=org.apache.log4j.FileAppender
log4j.appender.failure.File=logs/failure.log
log4j.appender.failure.Append=false
log4j.appender.failure.layout=org.apache.log4j.PatternLayout
log4j.appender.failure.layout.conversionPattern=%d{HH:mm:ss} %5p [%t] - %c.%M - %m%n
log4j.category.successLogger=DEBUG, success
log4j.additivity.successLogger=false
log4j.category.failureLogger=WARN, failure
log4j.additivity.failureLogger=false
and in java class I'm using it as:
static final Logger successLog = Logger.getLogger("successLogger");
static final Logger failureLog = Logger.getLogger("failureLogger");
and using it as:
successLog.warn("Connection is not established");
failureLog.error("Exception",e);
I'm able to get success.log and failure.log file but I was not able to print it on console. Right now, I need to print it on console as well (as just as the flow of our program i.e., need to print parallelly on console while writing to respective logs) and in future I may require only to print the statements only which are eligible to write into success.log
How can I achieve it ???? Thanks in advance
By default Log4j uses the appenders explicitly configured for a logger and the appenders of the parent logger. This behavior is called "additivity" by Log4j. You disabled it with the lines:
log4j.additivity.successLogger=false
log4j.additivity.failureLogger=false
You just need to restore additivity by deleting these lines or setting the value to true.
Alternatively, you can list multiple appenders for a given logger:
log4j.category.successLogger=DEBUG, success, toConsole

How to log different loggers into different files

Here is what i have in my java code
private static final Logger SUCCESS = LogManager.getLogger("success");
private static final Logger ERROR = LogManager.getLogger("error");
And I need to create 2 log files for these logs. (i tried to follow Creating multiple log files of different content with log4j) but I think its not exactly the same. But here goes what i created in log4j.properties.
log4j.rootLogger=TRACE, SuccessAppender, ErrorAppender
# setup SuccessAppender
log4j.appender.SuccessAppender=org.apache.log4j.RollingFileAppender
log4j.appender.SuccessAppender.Threshold=INFO
log4j.appender.SuccessAppender.File=success.log
log4j.appender.SuccessAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.SuccessAppender.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
# setup ErrorAppender
log4j.appender.ErrorAppender=org.apache.log4j.RollingFileAppender
log4j.appender.ErrorAppender.Threshold=INFO
log4j.appender.ErrorAppender.File=error.log
log4j.appender.ErrorAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.ErrorAppender.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
I was wondering how to map this "success" log into the "SuccessAppender".
First of all you have to make sure that the RootLogger is not logging anything. This can be achieved in different ways but my first solution is to let it append to the NullAppender.
log4j.rootLogger=OFF, NullAppender
# setup NullAppender
log4j.appender.NullAppender=org.apache.log4j.varia.NullAppender
Then you'll have to set the log level and the appender for your loggers (success and error):
log4j.logger.success = TRACE, SuccessAppender
log4j.logger.error = TRACE, ErrorAppender
And the rest of your log4j.properties is left as is.
An alternate solution if you don't want to use the NullAppender would be to set the additivity flag on the loggers:
log4j.rootLogger=OFF, SuccessAppender, ErrorAppender
log4j.logger.success = TRACE, SuccessAppender
log4j.additivity.success = false
log4j.logger.error = TRACE, ErrorAppender
log4j.additivity.error = false
Some more information about the additivity can be found in the Log4J manual.
Appender Additivity
The output of a log statement of logger C will go to all the appenders in C and its ancestors. This is the meaning of the term "appender additivity".
However, if an ancestor of logger C, say P, has the additivity flag set to false, then C's output will be directed to all the appenders in C and its ancestors upto and including P but not the appenders in any of the ancestors of P.
Loggers have their additivity flag set to true by default.
try
log4j.logger.success=TRACE, SuccessAppender

log4j - Why doesn't my appender show message?

At my work, I have inherited of the maintenance of a satandalone application.
The following code configures Log4J but no messages can be seen on the console.
LogManager.resetConfiguration();
PatternLayout layout = new PatternLayout();
layout.setConversionPattern("RECORD-BACKEND / (%-5p) %m (%F:%L)%n");
ConsoleAppender stderr = new ConsoleAppender();
stderr.setTarget(ConsoleAppender.SYSTEM_ERR);
stderr.setLayout(layout);
stderr.addFilter(new CurrentThreadLogFilter());
stderr.setThreshold(Level.INFO);
stderr.activateOptions();
Logger loggerRECORD = getLoggerRECORD();
loggerRECORD.setAdditivity(false);
loggerRECORD.addAppender(stderr);
Logger root = Logger.getRootLogger();
root.setLevel(Level.WARN);
root.addAppender(stderr);
// some lines forward ...
loggerRECORD.info("Process starting...");
What am I missing ?
Unfortunately you have not sent the code that actually prints the message. However I can assume that you try to do something like this:
logger.info("my message");
In this case your message will not be printed because it is filtered out by root logger defined to print warnings.
Loggers in Log4J are stored as hierarchical structure. The root logger is the entry point to this tree. Each logger filters log messages according to configured level. Therefore if upper level logger (root in your case) filters log message it even does not arrive to lower level logger and definitely does not arrive to appender.
The solution for you is to define root logger to allow ALL messages.
And the last note: do you have any special reasons to configure logger programmatically? Log4J can be configured using properties or (better) xml file. Take a look on this document.
And yet another note. Log4J has been deprecated by its creator. If you are starting now go forward to Logback as a logger and SLF4J as a light weight log interface.
Thanks to AlexR, here how I solved my problem:
LogManager.resetConfiguration();
PatternLayout layout = new PatternLayout();
layout.setConversionPattern("RECORD-BACKEND / (%-5p) %m (%F:%L)%n");
ConsoleAppender stderr = new ConsoleAppender();
stderr.setTarget(ConsoleAppender.SYSTEM_ERR);
stderr.setLayout(layout);
stderr.addFilter(new CurrentThreadLogFilter());
stderr.setThreshold(Level.INFO);
stderr.activateOptions();
Logger loggerRECORD = getLoggerRECORD();
loggerRECORD.setLevel( /* get Log Level from env. */ );
loggerRECORD.setAdditivity(false);
loggerRECORD.addAppender(stderr);
Logger root = Logger.getRootLogger();
root.setLevel(Level.WARN);
root.addAppender(stderr);
// some lines forward ...
loggerRECORD.info("Process starting...");
Since additivity is set to false for loggerRECORD, the appender sucessfully print any message from INFO to ERROR.

log4j in a JRuby on Rails app - redirecting logs to a separate file

I want to get more granular logging in my JRuby on Rails app. I introduced log4j. I currently have a properties file that looks like the following:
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
#
log4j.logger.Rails=INFO, A
log4j.appender.A=org.apache.log4j.RollingFileAppender
log4j.appender.A.File=/usr/share/tomcat6/logs/production.log
log4j.appender.A.MaxFileSize=10000KB
log4j.appender.A.MaxBackupIndex=5
log4j.appender.A.layout=org.apache.log4j.PatternLayout
log4j.appender.A.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
To get Rails.logger to use this, I pop in the following initializer:
org.apache.log4j.PropertyConfigurator.configure("#{::Rails.root.to_s}/config/log4j.properties")
Now, I want to be able to also do something like:
Rails.logger.feature_1("Log to feature_1.log")
Rails.logger.feature_N("Log to feature_N.log")
What's the best way of accomplishing this so not everything goes to one log file?
Also just to note, I am using the adapter that was blogged about here: http://squaremasher.blogspot.com/2009/08/jruby-rails-and-log4j.html
First, you should define an appender/logger configuration for each "feature" you need in your log4j.properties file :
...
log4j.logger.Rails=INFO, A
log4j.appender.A=org.apache.log4j.RollingFileAppender
log4j.appender.A.File=/usr/share/tomcat6/logs/production.log
...
log4j.logger.feature_1=INFO, feature_1
log4j.appender.feature_1=org.apache.log4j.RollingFileAppender
log4j.appender.feature_1.File=/path/to/your/feature_1.log
...
log4j.logger.feature_N=INFO, feature_N
log4j.appender.feature_N=org.apache.log4j.RollingFileAppender
log4j.appender.feature_N.File=/path/to/your/feature_N.log
This way each logger will have it own severity filter and destination file.
Then instead of always using the same logger you may select it depending on the method you called on the Ruby side of the moon (from the example adapter you provided) :
class Log4jAdapter
def method_missing(meth, *args)
# Checking the method name matches feature_N
if /\Afeature_(\d+)\z/ =~ method.to_s
# Retrieve the appropriate logger => getLogger('feature_N')
logger = org.apache.log4j.Logger.getLogger(method.to_s)
# Log !
logger.log *args
else
puts "UNSUPPORTED METHOD CALLED: #{meth}"
end
end
end
Untested but I think you'll get the idea.

read .properties file using slf4j

I want to read data from .properties file using slf4j,T i am able to output the data on console but what i want is to output the data on some file so i need file Appender for this which is declared in .properties file and i am not able to read the .properties file using slf4j.Can anyone help.
PS:I need an example that explains how to use.properties file in slf4j and how to initialize logger factory for that.
See http://slf4j.org/faq.html.
SLF4J is only a facade, meaning that it does not provide a complete
logging solution. Operations such as configuring appenders or setting
logging levels cannot be performed with SLF4J.
slf4j-simple doesn't provide extra configuration features at all.
For other implementations you should use the way to configure they provide.
For example, log4j.properties for slf4j-log4j. See http://logging.apache.org/log4j/1.2/manual.html#Configuration.
If using log4j, alternatively it can be used "Log4jLoggerAdapter", defining the configuration on a .properties file.
Code below.
The required jars:
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
If desired the source code (useful when debugging):
slf4j-api-1.7.5-sources.jar
slf4j-log4j12-1.7.5-sources.jar
The testing java class:
import org.apache.log4j.PropertyConfigurator;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.Log4jLoggerAdapter;
public class Slf4j_log4j_main {
private static Log4jLoggerAdapter log = (Log4jLoggerAdapter) LoggerFactory.getLogger(Slf4j_log4j_main.class);
public static void main(String[] args) {
PropertyConfigurator.configure(Slf4j_log4j_main.class.getClassLoader().getResource("basic/log4j.properties"));
log.debug( "a debug" );
log.info( "an info" );
log.warn("a warn");
log.error("an error");
//log.fatal("a fatal"); // slf4j misses fatal log.
log.trace("a fatal");
System.out.println("");
System.out.println("[INFO]: done");
}
}
The basic/log4j.properties
##FROM: log4j_slf4j.basic
##BASED: [BIN319P17]/[BIN319P42]
#using your own named logger.
# defining appender file
log=/home/alsdias/work/dev/java/lab/slf4j/log4j/log4j_slf4j/src/basic
# root logger setup
log4j.rootLogger = DEBUG, A1, FILE
#setting your own named logger. If more loggers, set additivity false (below)
log4j.logger.log4j.level=INFO,A1
log4j.additivity.log4j.level=false
# console appender config
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
# Print the date in ISO 8601 format
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
# file appender config
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=${log}/log.out
#setting the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true
#setting the threshold
log4j.appender.FILE.Threshold=debug
#setting the append to false, overwrite
log4j.appender.FILE.Append=false
#set a layout for the appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%d [%t] %-5p %c - %m%n
The generated output:
2013-06-14 11:47:00,473 [main] DEBUG basic.Slf4j_log4j_main - a debug
2013-06-14 11:47:00,474 [main] INFO basic.Slf4j_log4j_main - an info
2013-06-14 11:47:00,474 [main] WARN basic.Slf4j_log4j_main - a warn
2013-06-14 11:47:00,475 [main] ERROR basic.Slf4j_log4j_main - an error
[INFO]: done
slf4j is an API - if you consider it to consist only of interfaces and no classes, you are not far off.
The behavior you need is in the implementation of the interfaces, which for slf4j may be logback, AVSL, JDK14 (java.util.logging), log4j or Simple. Some can read properties, some cannot.
For logback you can use
<property file="src/main/java/chapters/configuration/variables1.properties" />
See http://logback.qos.ch/manual/configuration.html#definingProps for details.

Categories

Resources