I've extended the Log4J Logger class and created a custom Logger class that decides whether to to log or not.
My pattern layout has the %F and %M parameters to show the class name and method name from where the log was executed.
The problem is that instead of showing the exception caller class and method name it show my custom logger's class and method name!
What do I need to do to shows the correct information?
You need to provide your class as the fully qualified class name for the forcedLog() method.
private static final String FQCN = MyCustomLogger.class.getName();
...
public void info(Object message) {
if(repository.isDisabled(Level.INFO_INT))
return;
if(Level.INFO.isGreaterOrEqual(this.getEffectiveLevel()))
forcedLog(FQCN, Level.INFO, message, null);
}
....
I'm not sure what you're attempting to filter out, but it might be better to use a filter rather than extend the logger.
Related
I need to do some enhancements to Log4j2 so that the message gets altered prior to logging. Now, I know that I can write a custom converter and define the pattern so that it uses my custom converter, however, this will not work for me.
The scenario is that, depending on the class that calls the logger, I must do some changes or not. And this needs to be done dynamically from the code.
Let's assume I have this interface:
public interface LogMessageAlter {
String alterMessage(Message message);
}
Now, I have multiple classes that implement this interface: "RemoveIpAlter" and "RemoveEndpointAlter".
How can I specify to the converter what alterers to use when doing the conversion?
One approach would be to write my own logger and overwrite the logMessage method:
public class MyLogger extends Logger {
public void logMessage(..., Message message) {
alterList.forEach(alter -> alter.altermessage(message));
super(..., message)
}
}
However, I can't figure out how to tell Log4J to instanciate my custom logger when Logmanager.getLogger() is called instead of using the default Logger class.
Other ideas are also appreciated.
Later edit: I know that using LogManager.getLogger("aName") can be used to return a custom logger, but this does not solve my problem because I want a per-class list of modifiers. I want to be able to do something like this:
LogManager.getLogger(MyClass.class, modifierList);, or in a wrapper
MyLogger logger = Logmanager.getLogger(MyClass.class);
logger.setModifiers(modifierList);
Log4j pattern layout docs warns that generating caller class information is costly and should be used only when performance is not a concern. I want to have the class name in logs for easy analysis and also doesn't want to have an impact in performance. Having stated that I have two options,
Store class name using getClass().getName() in every class and use that string in logging
String class = getClass().getName();
...
...
logger.debug(class + "log message");
Hardcode the class name and give it in log
String class = "com.foo.myclass";
...
...
logger.debug(class + "log message");
Which would give better performance or is there any other way to log fully qualified class name and method name without affecting performance. Thanks in Advance!
Note: I am using log4j 1.2.16
Generating the caller class name is costly but if you're following the typical Log4J design pattern of one Logger per class with the Logger name being the same as the class name
private static final Logger LOG = Logger.getLogger(ThisClassName.class);
then it may be sufficient to simply use %c instead of %C in your layout pattern. This uses the logger name (which is a property of the logger itself) rather than inspecting the call stack, and does not involve the overhead incurred with patterns like %C or %L.
If you really do need the runtime class of the caller rather than the static name of the class that textually encloses a particular logging call, then you could use a per-instance logger rather than (or as well as) the per-class one
private final Logger instLog = Logger.getLogger(this.getClass());
and now the logger name will be the runtime type of this, i.e. if B extends A and we call a method on an instance of B then the logger name will be B, even for methods that are actually defined by the superclass A.
A usual pattern for loging with log4j is the following
public class Foo {
private static final Logger LOG = Logger.getLogger(Foo.class);
someMethod(){
...
if(LOG.isDebugEnabled()){
LOG.debug("log message");
}
}
}
The classname is the logger name so it will (by default) appears in the log message.
Most importantly regarding performance: there is a guard preventing the overhead of the computation of the log message when the log level is not enabled.
I understand that java.lang.SecurityManager is used to check and constrain class access or file access based on a specific scenario.
I need to identify the caller for Log4J Helper class which needs to return the Logger instance based on Class which calls the Helper class.
There are two ways to do this.
Using Threads
public static Logger getLogger() {
final Throwable thread = new Throwable();
final StackTraceElement callerMethod = thread .getStackTrace()[1];
final Logger logger = Logger.getLogger(callerMethod .getClassName());
return logger;
}
This is a performance bottleneck since it involves get the current stacktrace for each call to getLogger
Second Approach
Logging helper to extend java.lang.SecurityManager in which case i can use
getClassContext()[2].getName();
to get the absolute class name for instantiating the Logger.
The LoggingHelper extending the SecurityManager doesn't seem to be a good design principle considering its usage.
Would there any be any reason i can extend SecurityManager to a Logging Utility or is there a better approach?
Note : The application will be running in app server instance.
If you're using Java EE 6 you could use CDI to inject your logger.
public class LoggerProducer {
#Produces
public Log createLogger(final InjectionPoint injectionPoint) {
final String name = injectionPoint.getMember().getDeclaringClass().getName();
return Logger.getLogger(name);
}
}
I currently am using the SocketAppender in Log4J and have run into some issues with passing data over to a remote host, specifically around losing LocationInfo (class name, line number, etc). What I have done is the following:
import org.apache.commons.logging.impl.Log4JLogger;
public class MyLogger extends Log4JLogger
{
...
public void debug(Object message)
{
String extra = "Extra!";
super.debug(message + extra);
}
...
}
At runtime how can I change the following code to grab MyLogger instead of Log4JLogger?
private static Log logger = LogFactory.getLog(Test.class);
You don't have to extends Logger but implement your own Appender or extend the base Log4J Appender you need.
For example you can extend AppenderSkeleton.
I cannot imagine exactly why do you need it. Another possibility could be use Log4J Mapped Diagnostic Context.
I have a class in which I see the following things:
this.logger.severe("");
this.logger.warning("");
this.logger.info("");
I do not understand several things:
How can we use a method that was not defined earlier? I mean, there are no "logger" methods defined in the class. I thought that these methods could be defined because the considered class is an extension of another class in which the "logger" is defined. But in the definition of the class there no "extends" statement (only "implements").
I can understand things like that: "objectName.methodName". But what is that "objectName.something1.something2"? "something1.something2" is name of a method? Can method names contain dots?
What exactly these "logger.*" do? I think they save information about the execution of the code. They kind of write report about what happened during the execution. But where I can find this information?
ADDED:
In the beginning of the file I have: import java.util.logging.Logger;
And then in the class I have: private Logger logger = Logger.getLogger("a.b.c.d");
So, logger is an object of the class Logger (but I do not understand why they could not instantiate the class in a usual way using "new Logger()). I also do not understand what exactly logger.severe("") do.
The logger doesn't make anything special. It's all just Java code.
public class SomeClass {
private Logger logger = LogFactory.getLogger(SomeClass.class);
public void doSomething() {
this.logger.debug("foo");
}
}
The this.logger just points to the instance variable named logger of the current instance (this). The this. prefix is by the way superflous in this example. One could also just do logger.debug("foo") here.
If it is not declared in the SomeClass itself, then it's likely been declared in the extending class. Check the class which is declared in extends.
As to your objectName.something1.something2 doubt, have you already looked how System.out.println() works? The System.out returns a PrintStream object which in turn has a println() method. Thus, if objectName.something returns a fullworthy Object with methods, then you can just continue chaining method calls.
Basically,
objectName.something1.something2;
can be translated as
SomeObject someObject = objectName.something1;
someObject.something2;
But if you don't need someObject anywhere else in the code, then it can just be shortened as in your example.
Update: as per your update:
So, logger is an object of the class Logger (but I do not understand why they could not instantiate the class in a usual way using "new Logger()). I also do not understand what exactly logger.severe("") do.
Just read the javadoc of the class in question what it all does. As to why it can't be instantiated, it's because of the factory pattern.
Update 2: as per the another confusion:
I do not understand why they use "this". I mean, if I use just field name, will it not be, by default, the field of this object? I there any difference between "this.x" and "x"?
This way you can be more explicit about which one you'd like to access. If the method contains for example an argument or a local variable with the name logger, then this.logger would still refer to the instance variable.
public class SomeClass {
private Logger logger = LogFactory.getLogger(SomeClass.class);
public void doSomething(Logger logger) {
this.logger.debug("foo"); // Refers to the instance variable.
logger.debug("foo"); // Refers to the method argument.
}
public void doSomethingElse() {
Logger logger = LogFactory.getLogger(SomeClass.class);
this.logger.debug("foo"); // Refers to the instance variable.
logger.debug("foo"); // Refers to the method local variable.
}
}
The logger usually refers to the usage of a class in log4j.
The logger is a member object whose function e.g. severe is called.
The logger usually logs into a file (this can be configured through log4j.xml or some other config file or during the program start).
Edit: Changed the log4j link.
The 'logger' will be another object, not a method. This logger class will have methods defined on it like public void severe(String message)
'something1' will be an object contained by 'objectName'. For example, Car.Engine.Cylinder.Fire(), it's considered bad practise to use a method to fire a car's cylinders like this, and you should do something more like Car.StartEngine() (see the law of demeter for more info)
The logger will keep a record of what's happened in your program, so if there's a crash or a bug later on, you can see what happened. Whether this is recorded to a text file, or to a database somewhere, will be down to the implementation of your logger.
logger is not a method but a class variable which seems to be an object that exposes the methods "severe", "warning" and "info".
Check your class for something like "someClass logger = new someClass();"
The java.util.Logger class is the main access point to the Java logging API. Here is how you create a logger:
Logger logger = Logger.getLogger("myLogger");
The string passed as parameter to the getLogger() factory method is the name of the Logger to create. You can choose the name freely, but the name implies where the Logger is located in the Logger hierarchy. Every . (dot) in the name is interpreted as a branch in the hierarchy.