which logger to use when using getlogger? - java

I have two loggers :
root and
test1
If I use getlogger("test1"), it will use test1, is that right?
when using getlogger(typeof(Program)), will it use root?

The logger that is used is defined in your log4j.properties/log4j.xml and that is based on the name of your package.
The getLogger(name) is used to log the name of the current class.
If you input "test1" as a parameter, the log4j log line for your call will contain the "test1".

When you do getLogger("test1") it will use the logger named test1.
When using getLogger(class), it will retrieve the logger that has been named using the class name.
If you are trying to get root logger, use getRootLogger() instead.
See http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Logger.html#getLogger%28java.lang.String%29 for more
Your class should use root by default depending on your configuration. See https://logging.apache.org/log4j/1.2/manual.html
"As a side note, let me mention that in log4j child loggers link only to their existing ancestors. In particular, the logger named com.foo.Bar is linked directly to the root logger, thereby circumventing the unused com or com.foo loggers. This significantly increases performance and reduces log4j's memory footprint." - from the manual

Related

Log4j incorrect class using Spring AOP

I am trying to make an trace logger using AOP programming, simular to this. The problem is that even after getting a new logger like this:
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass().getName());
All logs are still like this:
TRACE 2015-11-05 14:35:43,588 LoggingAspect.logMethod(LoggingAspect.java:42) - Some log
Instead of:
TRACE 2015-11-05 14:35:43,588 MyClass.SomeMethod(MyClass.java:10) - Some log
The class to log from does not change. Any suggestions?
joinPoint.getTarget()
returns the target object the method is executed on. This may be null if your object was executed in a static context, I think. But it may be null. So do not use it. And as you can see, It behaves a little bit strange (I think it has to do with proxying or subclassing).
You should better use
joinPoint.getSignature()
to retrieve the signature of the method, containing the defining class. So better use
joinPoint.getSignature().getDeclaringType()
to retrieve the class for the logger.

How to set log level per instance and per package hierarchy

My application manages devices in a network. Those are represented in my application by objects and compositions of objects.
Each of these devices has an ID and each object related to a device knows about its ID.
When configuring logging, in addition to set the log level per the package hierarchy, I would like to be able to set it per device - that is, all instances related to one device should be eg. put in DEBUG level.
How can I set the log level by the package hierarchy and also by an instance ID?
My thoughts so far:
Currently my loggers are created the "standard" way, by the class type
public class Thermometer extends AnalogDevice {
private static final Logger logger = LoggerFactory.getLogger(Thermometer.class);
...
}
But I want to be able to choose the log level for specific devices. My current idea would be to use the ID in the logger name, like this:
public class Thermometer extends AnalogDevice {
private final Logger logger;
public Thermometer(String deviceId){
logger = LoggerFactory.getLogger(deviceId+"."+Thermometer.class);
...
}
...
}
(and the same for other classes in the hierarchy and other classes bound to this device) This would allow to configure log4j to have all messages for device "mydevice123" on DEBUG level.
log4j.logger.mydevice123=DEBUG
But this will potentially create many loggers (per device / per class):
mydevice123.com.example.dev.Thermometer.class
mydevice123.com.example.dev.AnalogDevice.class
mydevice123.com.example.dev.SomeOtherDeviceSpecific.class
...
Also I now lost the possibility to set the level on a package hierarchy. This won't work anymore.
log4j.logger.com.example.dev=DEBUG
What's a better way?
Use logback as your logging implementation.
Set your device id in the MDC (Mapped Diagnostic Context) (*)
Set up a DynamicThresholdFilter
(*) IMHO a good approach to set the device id in the MDC is using an aspect applied on every business method which will get the device id from the targeted object (exemple with spring aspects), set the id in context before the method invocation and remove it after

Migrating from log4j 1.2 to log4j 2 - how to get list of all appenders and rolling file strategy

I am in the process of migrating my application from log4j 1.2 to log4j 2.0
I have existing code:
Enumeration appenders = logger.getAllAppenders();
.
.
.
fileBackupIndex = rollingFileAppender.getMaxBackupIndex();
In log4j 2.0 I could not find way to replace above java code. How to get list of all appenders and how to get the max value defined for RollingFile appender programatically?
With log4j2, there is a separation between API and CORE. This allows the team to make changes to the implementation without breaking client code.
So, if your code depends on implementation details, be aware that in the future this may change and your code may break.
That said, you can get a map of the appenders like this:
Logger logger = LogManager.getLogger();
Map<String, Appender> appenderMap =
((org.apache.logging.log4j.core.Logger) logger).getAppenders();
You can loop over the map until you find a RollingFileAppender. From this point it gets really ugly... The information you want is all in private fields, so you would need to use reflection to do the following:
get the fileAppender's "manager" field and cast it to RollingFileManager
get the manager's "strategy" field and cast it to DefaultRolloverStrategy
get the defaultRolloverStrategy's "maxIndex" field
This would obviously be pretty fragile... If you really need this you can request this feature on the log4j-dev mailing list or create a JIRA ticket. The quickest way to get this feature is if you provide a patch with the feature request.
I've added accessors for
minIndex, maxIndex, and compressionLevel.
triggeringPolicy and rolloverStrategy.
See our SVN trunk.

Log4j notifying on logging level changes

Is there anyway , or any configuration in log4j that tell him to log a line whenever some "logging level" configurations occur ?
I mean someone changed in some package the debug level from INFO to DEBUG , I want that event being logged by log4j.
Thanks
I'm not sure if it's your case, but if you are reloading the configuration file using configureAndWatch you should be able to see the information you need setting the system property -Dlog4j.debug=true.
See
http://logging.apache.org/log4j/1.2/apidocs/index.html?org/apache/log4j/xml/DOMConfigurator.html
There is a LogLog, the self logging of Log4J. I have never used it but if the solution exists it is there. I'd suggest you to download the source code of log4j and try to investigate it where it "knows" that the log level is being changed. Once you found the code see whether it prints something to self log and configure it as you need.
I'd be appreciate if you can post here more concrete answer if you find it. Good luck.
At runtime, if you have a servlet, jsp or a screen on your application where you are able to change log levels, you will most likely be doing something like this
public void changeLogLevel(String className, String logLevel){
Logger logger = Logger.getLogger(className);
Level level = Level.toLevel(logLevel);
logger.setLevel(level);
}
in order to log this event, all you would have to do is add an extra logger statement for this event
private static Logger classLogger = Logger.getLogger(ThisClass.class);
public void changeLogLevel(String className, String logLevel){
Logger logger = Logger.getLogger(className);
Level level = Level.toLevel(logLevel);
logger.setLevel(level);
classLogger.debug("The Level of " + className + " has changed to " + logLevel);
}
Then each time a log level occurs, you can log it here. If you want to get fancy, just send this log to its own file. You may want to advance the method even further to include an IP/username of the user who changed the log level.
If you have control over your application, ensure this is your only point in the application where a user can change your logging levels.
This doesn't answer your question, but the built-in java.util.logging.LogManager implementation has an addPropertyChangeListener() method that does exactly what you want.
I couldn't find anything comparable in Log4J, but I didn't look that hard...

Using getSimpleName() vs getName() for acquiring logger

I've seen code that uses log4j, which acquires logger for a given Logger using
static public Logger getLogger(String name)
and
static public Logger getLogger(Class clazz)
with the former api passed explicitly with getSimpleName(), while the latter uses getName() on the passed Class. Is there a difference between these two? Would it affect if I configure various packages to log at different level in log4j.properties file?
Yes there is a huge difference.
I never use simpleName for Logger instance as it strips down the package name.
Apart from having problems when same class name exists in two different packages (leading to both classes getting the same logger instance), you lose the ability to control logger inheritance.
e.g. for two loggers:
com.foo.A
com.foo.B
in properties, i can just have:
log4j.logger.com.foo=DEBUG,CONSOLE
E.g. My class ShapeDemo.java resides in com.test package, and I have written code like below.
System.out.println("Name-->"+ShapeDemo.class.getName());
System.out.println("SimpleName-->"+ShapeDemo.class.getSimpleName());
This will output following
Name-->com.test.ShapeDemo
SimpleName-->ShapeDemo
Using of this.getClass().getName();
Returns : alin.iwin.flickrbrowser.GetRawData
Meanwhile
private String LOG_TAG = this.getClass().getSimpleName();
Return only : GetRawData.
I prefer using the full name (Class.getName()). When packages are organized correctly, this allows tuning log4j to handle differently log messages originating from different parts of the java packages tree.
For example, you can easily configure all classes in packages starting with "com.mycompany.infra" to use a specific appender, and log only messages of level WARN or above.
You might get confused if you have many classes with the same simpleName in different packages. Having many loggers with the same name should not be a problem otherwise - just could be confusing.

Categories