When trying to add log4j logger to a Generic class, it does not generate logs.
This is the code used.
public class GenericClass<K extends Serializable, V extends Serializable> extends ... {
public static Logger log = Logger.getLogger(GenericClass.class.getName());
I am guessing the reason this code fails is because the class is not instantiated till runtime and the plain name that i have given no more resolves to the newly generated class.
Is there a way that generic classes can be logged at all?
Generics have nothing to do with this.
At runtime, a logger by the name of x.y.z.GenericClass (x.y.z being the package in which GenericClass is located). If nothing is logged, then it's either because your application isn't logging anything, or your Log4J configuration is faulty.
To decide which one is true, add -Dlog4j.debug=true to your server initialization parameters and give it a try.
Related
I have log4j appenders (appendersB, appendersC) and a specific class like below
class A { A{Parent a}}
where Parent is an interface with two implementations as below
class B implements Parent {..}
class C implements Parent {..}
now I want to tell log4j that whenever class A is instantiated with paramater B it should use appendersB and if it receives C then it should use appendersC.
Is this possible?
Choice of appender is done in the Log4j configuration file, based on the logger name, so to be able to configure it so logging entries go to different appenders, your code should use different loggers.
Normally, the logger name is the fully qualified class name, and the logger is created as a static field of the class. This is done for performance, low memory footprint, and convenience of naming.
You can however make the logger field non-static, and assign it with a dynamically generated name.
As an example, your A class would normally do this:
package org.example;
public class A {
private static final Logger log = LogManager.getLogger(A.class);
// rest of code
}
This will create a logger named org.example.A, which can be configured to write any any appender(s) of choice.
To base logger, and hence potentially the appender, on the actual class of object given as parameter to constructor, you could do this:
package org.example;
public class A {
private final Logger log; // not static
public A(Parent p) {
this.log = LogManager.getLogger(getClass().getName() + "." +
p.getClass().getSimpleName());
}
}
This will create a logger for each instance of A, and the name derives from constructor parameter, e.g.
new A(new B()) // Logger name: org.example.A.B
new A(new C()) // Logger name: org.example.A.C
You can now configure Log4j to direct logger org.example.A.B to appenderB, and logger org.example.A.C to appenderC.
You can of course build the dynamic logger name any way you want to. Logger names don't have to be based on class names, e.g. you could name them bravo.foo and charlie.foo.
I am using java.util.logging in different classes. The Log Level's default value is INFO. For example in one class Class1 it is setup this way:
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Class1 {
private static final Logger LOGGER = Logger.getLogger(Class1.class.getName());
static {
LOGGER.setLevel(Level.INFO);
for (Handler handler : LOGGER.getHandlers()) {
handler.setLevel(Level.INFO);
}
}
...
}
The above is the same way it is setup in different classes.
Now the Log Level could be changed at runtime. For example suppose it is changed to FINEST at runtime. In this case I want to get all the loggers which have been created so far and then change their Log Level to FINEST. How can I do that? I was thinking about creating another class say LogRepository which has a java.util.List and whenever a LOGGER is created, I add it into the java.util.List of LogRepository. But I think there may be another better way.
I believe this is just a matter of setting the level of the parent logger that all of the instances inherit from.
Logger.getLogger("").setLevel(Level.FINEST);
I know the question title is a bit raw, the more I tried to make it clear in a single statement the less I was successful.
Anyways, in a web application project I need to log every action (and the errors which occur inside them) with Log4j, there are hundreds of classes in the project and I want to avoid having a Logger object for each class. The level needed for logging is ERROR.
So, I've thought of a custom class containing a static method which handles the Logger object's "error()" method. As shown below:
public class LoggerUtil {
public static void error(String message, Object classObject) {
String className = classObject.getClass().getName();
Logger logger = LogManager.getLogger(className);
logger.error(message);
}
}
So that whenever "LoggerUtil.error(message, this.getClass().getName())" is called anywhere in the project, we are able to log something by current class' related logger.
Problem is that this doesn't seem to work, I guess it is not possible to instantiate a logger related to a specific class in another class.
When our LoggerUtil.error() is called in one class the ERROR log that is given shows an unrelated class as it's source (java.lang.String). I wonder if there's a way to make this idea work?
[UPDATE]: Problem solved. There was a problem in design, which was fixed in this way:
public class LoggerUtil {
public static void error(String message, String className) {
Logger logger = LogManager.getLogger(className);
logger.error(message);
}
}
The second argument was changed into String so the class name is passed to the method directly. The logger works fine now.
Your method expects an object as argument, and gets the class of this object to get the appropriate logger.
But when you call your method, you call it with
LoggerUtil.error("Error", this.getClass().getName());
So, what you pass as argument is not the object for which to log (i.e. the CustomClass instance), but the name of its class ("com.foo.CustomClass"), which is a String. And in the method, you just ask a logger for the name of the class of the object "com.foo.CustomClass", which is thus java.lang.String.
In short you're getting the name of the class oof the object twice: once in the caller, and once in the called method.
So, change your call to
LoggerUtil.error("Error", this);
and you'll get the desired result.
I need to get class and method names to Log4j logger. What is the best way of doing that? Also I would like to create one instance of logger for whole application - it is quite boring to declare logger in each class. What is the way to solve these problems.
You can use %C and %M placeholders in your PatternLayout. Please be advised, their use is not recommended for performance reasons.
There are several ideas on how to avoid declaring loggers for each class. For example, if creating a common base class is a viable option, you can declare a protected final logger like this:
abstract class Base {
protected final Logger logger = Logger.getLogger(getClass());
}
class Concrete extends Base {
public void testLogger() {
logger.info("It works!");
}
}
Or, you may try injecting loggers with a dependency injection framework such as Weld.
Actually, creating one Logger for whole application, is not a good idea at all. It's easy to mess up loggers, levels of logging, configuration, etc.
But, if you still want it, you could create a logger instance in main method, and pass it for each of the class (e.g. using setLogger() in every class you use or passing as argument to class constructor). But again, is 100% bad idea to do this.
make your Logger Instance static
Every class has its own Logger => Logger.getLogger(xyz.class)
Use 2. than you can configure log4j
From java.util.logging.Logger:
Logger names can be arbitrary strings, but they should normally be based on the package name or class name of the logged component, such as java.net or javax.swing
Could anyone explain this sentence to me ?
Logger names can be arbitrary strings, but they should normally be based on the package name or class name of the logged component, such as java.net or javax.swing"
"Logger names can be arbitrary strings ...":
public class Foo {
private static final Logger logger = Logger.getLogger("specify logger name here - you can use any logger name you want, even supercalifragilisticexpialidocious");
}
Any code that wants the same logger instance just has to specify the same logger name (good luck spelling "supercalifragilisticexpialidocious" the same way twice).
However, you might want to share loggers more easily, get a handle to a specific class' logger for configuration, or have a hierachical relationship between loggers (e.g. organize loggers to into parents and children). Classes and packages are already organized hierarchically, so they recommend that logger names:
"... should normally be based on the package name or class name of the logged component ..."
package com.example.stackoverflow;
public class Foo {
private static final Logger logger = Logger.getLogger("com.example.stackoverflow.Foo");
}
Now I can easily get a handle to any logger for any class from anywhere (I just need to know its fully qualified class name). Also, now the the Logger framework can see which loggers are related to which, e.g. that the logger for "com.example.stackoverflow" is the parent of the logger for "com.example.stackoverflow.Foo".
But what if the package name changes or your class name changes? This code below does exactly the same thing as the code above, but in a less redundant and more maintainable manner:
package com.example.stackoverflow;
public class Foo {
private static final Logger logger = Logger.getLogger(Foo.class.getName());
}
Now if the package changes, the logger name is handled automatically. If the class is renamed in an IDE, the IDE will likely notice the Foo.class literal in the getLogger call above and update the Foo.class literal accordingly.
It is a way to create a hierarchical set of loggers that allows you to easily identify where each log entry came from. This is a typical scenario
public class MyClass
{
private static Logger sLog = Logger.getLogger(MyClass.class.getName());
}
I believe it relates the name you pass to the constructor when you initialise the logger. It is suggesting a structure name (string) being passed that relates to the actual class you are logging from. Generally you can get this from the class itself
For example
import java.util.logging.Logger;
...
private final static Logger LOGGER = Logger.getLogger(MyClass.class.getName());
Here, MyClass.class.getName() is returning the full class name to be used as the logger name.
A logger usually writes the "logger name" you give it, to the log file. In order to avoid having confusing logger names in one log file, each component should use a unique name. A unique name is the class name of the class doing the logging. This allows you to easily use tools later to extract the log messages for a single class, if desired.
We may think the name as "from which class or package the log is generated".