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);
}
}
Related
I am having a util class as below, which has a static method to do rest invocation which is calling from many beans in the spring boot application. I only have logger as a instance variable in the Util class.
public class Util{
private static final Logger LOGGER = LoggerFactory.getLogger(Util.class);
public static String post(RestTemplate restTemplate){
restTemplate.exchange();
}
}
I would like to get clarify below points.
Even I dont have a instance variable relate to RestTemplate in my util class, I notice with in RestTemplate class it has inner classes and maintain instance variables with in it. Would that be a issue when multiple users concurrently access the post method.
Is it ok to use org.slf4j.Logger as a instance variable here? Do I need to pass LOGGER as a method local parameter as well?
Part 1
Every time a third-party API is called via RestTemplate it will create new Httpconnection and will close it once it is done. You can create RestTemplate's own connection pool using HttpComponentsClientHttpRequestFactory like so:
new org.springframework.web.client.RestTemplate(new HttpComponentsClientHttpRequestFactory())
So it should not create any problems if the connections are new with each method call. Check this answer of mine here -- How does resttemplate.exchange() execute on a different thread?
Part 2
Having a static variables in a util class with static methods only is fine. Having said that, Adding --
private static final Logger LOGGER = LoggerFactory.getLogger(Util.class);
-- in each of the classes seems to more of a boilerplate code which can be avoided if you use Lombok's #Slf4j annotation like so --
#Slf4j
public class LogExample {
}
This will generate somethig like this:
public class LogExample {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
}
is it possible to determine the class of an implementing class in a static context. Given i want to create a logger in the superclass which logs its messages under the class name of the implementing classes.
Currently i'm trying to use this approach:
public abstract class GenericDao<T, ID extends Serializable>
{
protected static Logger logger = Logger.getLogger(new Object() { }.getClass().getEnclosingClass());
...
}
But i still get the superclass. Is there any way to do this or should i give up and include the class in the actual logging method when i have access to "this".
Static variables and methods always belong to the declaring class, GenericDao in this case. If you create a new subclass SpecificDao then it is not accessing a new copy of logger if it accesses it, it is accessing the exact same logger as is in GenericDao.
You will need to create the Logger as a non-static member and have one per object (potentially very inefficient) , or declare the logger in each class.
What should work to give you what you want though is if you have an abstract method getLogger() in GenericDao and no Logger at all..
Whenever it wants to log GenericDao calls getLogger().log
The implementing classes then define their own private static Logger logger. They override the getLogger() abstract method and return the static one from that.
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 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 recently inherited some Java code and need to integrate it into a project that I am working on. My project is a service agent that processes and transforms XML messages. While looking through the new code, I discovered the following logging class:
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class MyLogger {
private static MyLogger instance = null;
protected final static Logger log = Logger.getLogger(MyLogger.class);
private MyLogger() {
super();
}
public static MyLogger getInstance(){
if(instance == null){
instance = new MyLogger();
BasicConfigurator.configure();
log.setLevel(Level.ALL);
}
return instance;
}
public void info(String myclass, String msg) {
log.info("[" + myclass + "] " + msg);
}
public void error(String myclass, String msg, Exception ce) {
log.error("[" + myclass + "] " + msg, ce);
}
public void warning(String myclass, String msg) {
log.warn("[" + myclass + "] " + msg);
}
}
This class basically wraps log4j with (another) singleton. All of the logging in the classes that I need to integrate look something like this:
public class MyClass {
private final static MyLogger log = MyLogger.getInstance();
private final static String myclass = MyClass.class.getName();
...
log.info(myclass, "Information message...");
}
I do not see any obvious benefit to using an extra class for logging, thus I am considering refactoring this code to remove the MyLogger class and log in the following fashion:
import org.apache.log4j.Logger;
public class MyClass {
private static Logger log = Logger.getLogger(MyClass.class);
...
log.info("Information Message...");
}
This would make the logging mechanism consistent across the project. Before I do this, I would like to know if there are any benefits to wrapping Log4j with a singleton class that I may be missing. Thanks!
EDIT: Thanks everyone for the helpful answers - I pickup up several new insights from each. Accepted Nathan Hughes' answer for pointing out lost functionality by leaving the class intact - I had been assuming that the biggest downside to leaving the singleton alone was simply code bloat. I will trash the class.
Get rid of it. Using this monstrosity means all logging that goes through it will be listed with the same logger (MyLogger) and method (which is why the arguments to its methods include the class of the thing being logged). That means not only do you have to add any class, method, and line number information to each logger call, but you can't do any filtering on log levels for different packages the way you could using the typical log4j approach with classes as loggers.
This thing is a piece of junk and you are better off without it.
The only benefit that I could see is that it would be easy to swap out the log4j implementation with another logging implementation, or get the logging to do something much more customised such as log to one of your own databases.
That said, I would still refactor the code to use log4j directly. Or, more likely in my case, to use SLF4J.
One thing your inherited code does that log4j does is make thing non-thread safe. Since there is no locking in getInstance() you can potentially hand out more than one instance and break the singleton intentions of the code.
You also lose the ability to set logging levels for each class depending on what you are doing.
The only flaw I can tell is, because of this declaration:
protected final static Logger log = Logger.getLogger(MyLogger.class);
The logger is, essentially, hooked to object MyLogger and all logging information/errors/warnings, etc. will be "linked" to MyLogger. You have no idea which object added the logging information, none whatsoever.
The only advantage I see with this Singleton, is:
Single instantation: You never have to worry of declaring a static final Logger implementation all the time.
You don't have to worry what type of Logger you are using. One can change the type of Logger only in this Singleton class. Any further changes to logging is done only in the Singleton.
I have seen this in my company as well, but I don't suggest that type of setup. Rather use SLF4J or the Java Logging Framework.