Change log level of project with single call? - java

I have configured the log level in properties to DEBUG and works fine, but i want to change the log level of whole project if some event occurs.Apparently my project has many classes and they use the logging like below
private static final Logger log = Logger.getLogger(CommandOperations.class);
I am able to change the log level individually for each class by calling log.setLevel(Level.INFO) but I rather want project wide change. How to do it?

Try Logger.getLogger("com.xx").setLevel(..); where com.xx is the package prefix to all your classes. Do not set levels for individual classes.
When you give com.xx it will be applicable to all subpackages also.

Have you tried using?
LogManager.getRootLogger().setLevel((Level)Level.DEBUG);

Related

Two logs for one class

I'm working on jdk 1.6 and I have a class that needs to log to 2 different log files using log4j. I have read many other answers, but I can't get mine to work the way I want it. This is my log4j properties.
log4j.debug=false
log4j.rootLogger=ERROR, appLog
log4j.logger.com.my.apps.idm.transactionalemail=DEBUG, appLog, infoLog
log4j.appender.appLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.appLog.File=/opt/apps/logs/${ni.cluster}/TransactionalEmail/1.0/TransactionalEmail.log
log4j.appender.appLog.DatePattern='.'yyyy-MM-dd
log4j.appender.appLog.layout=org.apache.log4j.PatternLayout
log4j.appender.appLog.layout.ConversionPattern=DATE: %d{DATE}%nPRIORITY: %p%nCATEGORY: %c%nTHREAD: %t%nNDC: %x%nMESSAGE:%m%n%n
log4j.appender.infoLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.infoLog.File=/opt/apps/logs/${ni.cluster}/TransactionalEmail/1.0/Info.log
log4j.appender.infoLog.DatePattern='.'yyyy-MM-dd
log4j.appender.infoLog.layout=org.apache.log4j.PatternLayout
log4j.appender.infoLog.layout.ConversionPattern=DATE: %d{DATE}%nPRIORITY: %p%nCATEGORY: %c%nTHREAD: %t%nNDC: %x%nMESSAGE:%m%n%n
And the way I want this to work is like this
public class MyClass{
private static final LOG = Logger.getLogger("appLog");
private static final INFO_LOG = Logger.getLogger("infoLog");
public void myMethod(){
INFO_LOG.debug("This is info");
LOG.debug("This is debug");
}
}
What happens when I run my app is that the Info.log has the same information as TransactionalEmail.log, and also, the line "This is a test" doesn't show up in either of the log files.
What am I doing wrong?
I would recommend against using multiple logger instances for classes. Utilize log4j's configuration to handle logging events as they are generated. You may want to look at the Routing File Appender to decide how log events are handled. From the link
The RoutingAppender evaluates LogEvents and then routes them to a subordinate Appender. The target Appender may be an appender previously configured and may be referenced by its name or the Appender can be dynamically created as needed. The RoutingAppender should be configured after any Appenders it references to allow it to shut down properly.

Logging in AppEngine

I've having issues getting logging set up properly on my development app server (launched from Eclipse). I have the correct logging.properties location in my appengine-web.xml, and the most global parameter is working:
.level=ALL
If I change that to INFO everything quiets down and all is good. But trying to add any sort of override for my packages appears to do nothing at all:
.level=ALL
com.company.level=INFO
(I am using my real package name, using the above as an example)
When I try to a full package path such as com.company.user.level or even a class name such as com.company.user.User.level I still get no change. I've also tried moving my entry above and below the .level statement with no luck. As a last resort I tried taking out .level altogether, but that resulted in no change to my custom class logging.
Between each change I fully stop and restart the development appserver to make sure the file is re-read. Again, if I change .level I see a change in logging level output, but nothing else works. I'm stumped? Any suggestions?
AppEngine SDK: 1.9.17 (1.9.18 is the latest as of this writing but there is nothing to indicate this would be fixed in the change logs).
Thanks!!
UPDATE (Solution)
Thanks to #farrellmr below!!
I was doing the following:
private static final Logger log = Logger.getLogger("MyClass"); // wrong
When I should have been doing:
private static final Logger log = Logger.getLogger(MyClass.class.getName()); // correct
You need to define your logger as -
package test;
private static final Logger LOGGER = Logger.getLogger(MyClass.class.getName());
Then you can define your package log configuration as -
test.level = INFO

Log4j For Each Class in Project

I have a project containing classes.
I would like to do logging per class instead of wrapping them up altogether in a single log file. I am using Java.
Like for example I have
foo.bar.class1
foo.bar.class2
How can I achieve log file per class?
So that I could have a log file named "class1.log" and "class2.log" containing their own respective log data. What should I do in log4j.properties or on classes?
Any help would be appreciated, thanks.
I'm not sure you can do this in log4j.xml or log4j.properties. So what you can actually do is this (untested, but should work in this fashion):
static {
Logger LOG = LoggerFactory.getLogger(MyClass.class);
try {
((FileAppender)LOG.getAppender()).setFile("class-" + MyClass.name());
} catch (...) {}
}

a way to use log4j pass set flags in my code

I need to pass some value to enable certain code in may app (in this case is to optionally enable writing some stats to a file in certain conditions, but it might be anything generally).
My java app is installed as a service. So every way I have thought of has some drawbacks:
Add another param to main(): cumbersome as customers already have the tool installed, and the command line would need to be changed every time.
Adding java -DmyEnvVar=A_VALUE to my command line: same as above.
Set an environment variable: service should at least be restarted, and even then you must take care of what user is the service running under etc.
Adding the property in the config file: I prefer not to have this visible on the config file so the user does not see it, it is something for debugging etc.
So I thought maybe there is some way (or hack) to use log4j loggers to pass that value to my code. I have thought of one way already, although is very limited:
Add a dummy class to my codebase com.dummy.DevOptions
public class DevOptions {
public static final Logger logger = Logger.getLogger(DevOptions.class);
In my code, use it like this:
if (DevOptions.logger.isInfoEnabled()){
//do my optional stuff
}
//...
if (DevOptions.logger.isDebugEnabled()){
//do other stuff
}
This allows me to use discriminate among various values, and I could increase the number by adding more loggers to DevOptions. But I wonder whether there is a cleaner way, possibly by configuring the loggers only in log4j.xml??
In log4j you dont need Java classes at all to create loggers (This may come as a surprise). All you need is a package qualified string and not a Java class to create logger category. If I were you I would do the following
PS: Code not guaranteed to compile/run
public class SomeAppCode {
public static final Logger specialLogger = Logger.getLogger("com.mypackage.mysubpackage.speciallogger");
public void someMethod() {
if(specialLogger.isDebugEnabled()) {
//do low level stuff
}
}
}
In your log4j.xml add a category for this string mentioned and if you want you could set "additivity" to be true/false (depending on whether you want to propogate this log message to multiple loggerS)
PS: Note specialLogger is public static and such can be used by 100s of classes like it were their own loggers.
ok I think I found what I needed, wasn't that difficult actually...
public class DevOptions{
public static boolean isEnabled(String myvalue){
Logger logger = Logger.getLogger(myvalue);
return logger.isDebugEnabled();
}
}
public class SomeAppCode {
public void someMethod() {
if(DevOptions.isEnabled("value.A")) {
//do low level stuff
}
}
}
And I can add as many values like value.A in log4j.xml:
<logger name="value.A" additivity="true"><level value="debug" /></logger>
This way I can add as many values as I want by only modifying log4j.xml, no need to add more loggers to DevOptions, only one is sufficient.

Best Practice of Using org.apache.commons.logging.LogFactory.getLog

May I know what is the best practice of using org.apache.commons.logging.LogFactory.getLog?
For me, I use it the following way :
public class A
{
private static final Log log = LogFactory.getLog(A.class);
}
public class B
{
private static final Log log = LogFactory.getLog(B.class);
}
So, if I have 100 of classes, 100 of static log object will be created?
Or is it best to do it this way?
public class A
{
private static final Log log = LogFactory.getLog(Main.class);
}
public class B
{
private static final Log log = LogFactory.getLog(Main.class);
}
All the 100 classes are referring to a same single same log?
Thank you.
Please remember the 'static problem', which most of java developer ignore and which affect log4j, java.util.Logger, and SLF4J as well. You can read about it in the Apache Commons Wiki. As reported, if you're developing a library, planning to release it in a container (such as a j2ee container), shared among many application, is better use something like
private transient final Log logger = LogFactory.getLog( this.getClass() );
The first option - have a logger per class (or functionality). As most logging systems - log4j, logback, java util logging, etc. have the notion of logger hierarchy, you can match that to your package hierarchy and have finer control of which functionality you want to be logged at which level. For example:
com.example=WARN # global setting
com.example.web=INFO # increase logging for the web controllers
com.example.dao=DEBUG # trying to track bugs in the database layer
In the vast majority of cases, your way is the way to go.
The main advantage is that there is a logger (or category, or whatever) for each class that can be configured individually, like
log4j.logger.org.springframework.transaction=DEBUG
(assuming log4j) which will set the log level just for that class or package. If you use only one logger, you cannot do that.

Categories