Java: Is it possible to automatically add log statements to methods? - java

Most of the methods in my application are written like this:
public void m() {
long t1 = System.currentTimeMillis();
log.info("begin - m()");
/* method body */
long t2 = System.currentTimeMillis();
log.info("end - m(), took " + (t2 - t1) + "ms.");
}
I wish I could simply annotate my method and have the log statements be automagically generated instead:
#Log("executionTime")
public void m() {
/* method body */
}
Any ideas on how to proceed with this approach ? Is there any known solution ?
Someone suggested AOP for this. The problem is that with AspectJ or Spring AOP I would have to describe all the methods which ammounts to as much code as the log calls in the method itself.

AspectJ and Spring AOP support something like:
execution(* com.company.project..*.*(..))
which will cover all methods in all sub-packages of project. So no need to define all methods one by one.

As has been suggested to you, AOP fits well to serve this requirement. Not sure what you meant by "having to describe all methods". From what I know there are ways to use wildcards to specify methods to which aspects apply, which could ease your work of "describing"..this is true at least in the case of Spring AOP..not sure about others.
And yes, CGLIB suggested by Maurice is another good candidate for your consideration. Never used it though.

CGLIB let you modify method code at runtime

AspectJ has the concept of a join point, which is like a wildcard that can specify any methods that match that wildcard (you can specify particular methods in a class or any class that matches the wildcard). Then you can create an aspect which contains before advice and after advice, which are methods that run before and after the method matched by the join point. You can generate your log methods this way.

Perf4j supports getting timing information for methods using annotations. See here in their developer guide.

While this is not an actual practical answer to your question just yet (some good answers have been with respect to AOP), I believe the concept of ARM in Java 7 should be a viable option for implementing something like this on a small scale.
You could define a utility logging class and a factory to produce that class, something like the following:
public class TimerFactory
{
private static final Logger log = ...; // Obtain however
static class Timer implements Disposable<RuntimeException>
{
private final long startTime;
private final String name;
private Timer(String name)
{
this.name = name;
startTime= System.currentTimeMillis();
log.info("begin - " + name);
}
public void close()
{
final long t2 = System.currentTimeMillis();
log.info("end - " + name + ", took " + (t2 - t1) + "ms.");
}
}
public static Timer getTimer(String name)
{
return new Timer(name);
}
}
Now with that boilerplate out of the way (essentially an encapsulation of your logging behaviour), it could be called as follows:
public void m() {
try (TimerFactory.getTimer("m()")) {
/* method body */
}
}
The first log method would be called at the entrance to the try block, and the start time recorded. When the try block was exited, the resource (the Timer in this case) would automatically be "closed", which would cause the final time to be calculated and logged. Note as well that because this is a try block, the end logging will happen regardless of whether an exception is thrown or not. Your original code should probably use a try-finally block to ensure that the logging is actually completed.
Obviously this still requires you to put some logging code at each site, so is not really a replacement for clever pointcuts and AOP, even once Java 7 is released. However, if you find yourself dropping the logging in every now and then into perhaps a handful of methods, this pattern is a good way to abstract out the logging concerns and allow you to reuse it with the minimum of boilerplate.

You should use an aspect to this requirement. This requirement is a crosscuting concern (a concern that "cuts" between many classes).
To capture the methods that you want match you should create a pointcut that matches one or more join points. A join point is something that can be executed on your code (a method for example).
Look at this simple examples about tracing and logging and at this link about wildcards and pointcuts.

Try #Loggable annotation from jcabi-aspects (powered by AspectJ):
#Loggable(Loggable.DEBUG)
public String load(URL url) {
return url.openConnection().getContent();
}
It logs through SLF4J, which you can redirect to your own logging facility like, say, log4j.

Comment out the logging or profiling calls with a unique search term:
void myfunc() {
//log-call-123: try { long log_t1 = System.currentTimeMillis();
//log-call-123: log.info("begin - myfunc()"); {
...
normal method code
...
//log-call-123: } } finally { long log_t2 = System.currentTimeMillis();
//log-call-123: log.info("end - myfunc(), took " + (log_t2 - log_t1) + "ms."); }
}
When you search and replace:
Search for: "//log-call-123:"
Replace with: "/* log-call-123 */"
Do the reverse search and replace when you want to turn off extra logging or profiling calls.

Related

Java - insert println() in each method of given class

I have created a java class which delegates all calls to another class.
I want that on each method call program will output some info - method name and arguments.
There are very many methods in that class, so I don't want to insert System.out.println() in each method manually.
Is there any way to do it with regex?
here is a sample method with required println() line:
private final PreparedStatement statement;
#Override
public void setNull(int parameterIndex, int sqlType) throws SQLException {
System.out.println("setNull: parameterIndex=" + ", sqlType" + sqlType);
statement.setNull(parameterIndex, sqlType);
}
For this cases and similar we do not updated every function to add println, we usually use something that called AOP (Aspect Oriented Programming).
AOP is a useful technique that enables adding executable blocks to the source code without explicitly changing it. In our example, we don't want to log method execution inside the class. Instead, we want some other class to intercept every call to method power(), measure its execution time and send this information to slf4j.
please read this for more details aop-aspectj-java-method-logging and
logging-with-aop-in-spring
AOP give you ability to intercept method execution and add your logic before,after or around the execution, so in your case you can add before execution interceptor and print the msg that you want.
AOP example :
#Aspect
public class MyLogger {
private Logger log = Logger.getLogger(getClass());
#before("execution(* *(..))") // after execution of any function
public void log(JoinPoint point) {
System.out.println(point.getSignature().getName() + " called...");
}
}
You can also use point.getArgs() to get all method arags

Record method calls in one session for replaying in future test sessions?

I have a backend system which we use a third-party Java API to access from our own applications. I can access the system as a normal user along with other users, but I do not have godly powers over it.
Hence to simplify testing I would like to run a real session and record the API calls, and persist them (preferably as editable code), so we can do dry test runs later with API calls just returning the corresponding response from the recording session - and this is the important part - without needing to talk to the above mentioned backend system.
So if my application contains line on the form:
Object b = callBackend(a);
I would like the framework to first capture that callBackend() returned b given the argument a, and then when I do the dry run at any later time say "hey, given a this call should return b". The values of a and b will be the same (if not, we will rerun the recording step).
I can override the class providing the API so all the method calls to capture will go through my code (i.e. byte code instrumentation to alter behavior of classes outside my control is not necessary).
What framework should I look into to do this?
EDIT: Please note that bounty hunters should provide actual code demonstrating the behavior I look for.
Actually You can build such framework or template, by using proxy pattern. Here I explain, how you can do it using dynamic proxy pattern. The idea is to,
Write a proxy manager to get recorder and replayer proxies of API on demand!
Write a wrapper class to store your collected information and also implement hashCode and equals method of that wrapper class for efficient lookup from Map like data structure.
And finally use recorder proxy to record and replayer proxy for replaying purpose.
How recorder works:
invokes the real API
collects the invocation information
persists data in expected persistence context
How replayer works:
Collect the method information (method name, parameters)
If collected information matches with previously recorded information then return the previously collected return value.
If returned value does not match, persist the collected information (As you wanted).
Now, lets look at the implementation. If your API is MyApi like bellow:
public interface MyApi {
public String getMySpouse(String myName);
public int getMyAge(String myName);
...
}
Now we will, record and replay the invocation of public String getMySpouse(String myName). To do that we can use a class to store the invocation information like bellow:
public class RecordedInformation {
private String methodName;
private Object[] args;
private Object returnValue;
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
public Object getReturnValue() {
return returnType;
}
public void setReturnValue(Object returnValue) {
this.returnValue = returnValue;
}
#Override
public int hashCode() {
return super.hashCode(); //change your implementation as you like!
}
#Override
public boolean equals(Object obj) {
return super.equals(obj); //change your implementation as you like!
}
}
Now Here comes the main part, The RecordReplyManager. This RecordReplyManager gives you proxy object of your API , depending on your need of recording or replaying.
public class RecordReplyManager implements java.lang.reflect.InvocationHandler {
private Object objOfApi;
private boolean isForRecording;
public static Object newInstance(Object obj, boolean isForRecording) {
return java.lang.reflect.Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new RecordReplyManager(obj, isForRecording));
}
private RecordReplyManager(Object obj, boolean isForRecording) {
this.objOfApi = obj;
this.isForRecording = isForRecording;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
if (isForRecording) {
try {
System.out.println("recording...");
System.out.println("method name: " + method.getName());
System.out.print("method arguments:");
for (Object arg : args) {
System.out.print(" " + arg);
}
System.out.println();
result = method.invoke(objOfApi, args);
System.out.println("result: " + result);
RecordedInformation recordedInformation = new RecordedInformation();
recordedInformation.setMethodName(method.getName());
recordedInformation.setArgs(args);
recordedInformation.setReturnValue(result);
//persist your information
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " +
e.getMessage());
} finally {
// do nothing
}
return result;
} else {
try {
System.out.println("replying...");
System.out.println("method name: " + method.getName());
System.out.print("method arguments:");
for (Object arg : args) {
System.out.print(" " + arg);
}
RecordedInformation recordedInformation = new RecordedInformation();
recordedInformation.setMethodName(method.getName());
recordedInformation.setArgs(args);
//if your invocation information (this RecordedInformation) is found in the previously collected map, then return the returnValue from that RecordedInformation.
//if corresponding RecordedInformation does not exists then invoke the real method (like in recording step) and wrap the collected information into RecordedInformation and persist it as you like!
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " +
e.getMessage());
} finally {
// do nothing
}
return result;
}
}
}
If you want to record the method invocation, all you need is getting an API proxy like bellow:
MyApi realApi = new RealApi(); // using new or whatever way get your service implementation (API implementation)
MyApi myApiWithRecorder = (MyApi) RecordReplyManager.newInstance(realApi, true); // true for recording
myApiWithRecorder.getMySpouse("richard"); // to record getMySpouse
myApiWithRecorder.getMyAge("parker"); // to record getMyAge
...
And to replay all you need:
MyApi realApi = new RealApi(); // using new or whatever way get your service implementation (API implementation)
MyApi myApiWithReplayer = (MyApi) RecordReplyManager.newInstance(realApi, false); // false for replaying
myApiWithReplayer.getMySpouse("richard"); // to replay getMySpouse
myApiWithRecorder.getMyAge("parker"); // to replay getMyAge
...
And You are Done!
Edit:
The basic steps of recorder and replayers can be done in above mentioned way. Now its upto you, that how you want to use or perform those steps. You can do what ever you want and whatever you like in the recorder and replayer code blocks and just choose your implementation!
I should prefix this by saying I share some of the concerns in Yves Martin's answer: that such a system may prove frustrating to work with and ultimately less helpful than it would seem at first blush.
That said, from a technical standpoint, this is an interesting problem, and I couldn't not take a go at it. I put together a gist to log method calls in a fairly general way. The CallLoggingProxy class defined there allows usage such as the following.
Calendar original = CallLoggingProxy.create(Calendar.class, Calendar.getInstance());
original.getTimeInMillis(); // 1368311282470
CallLoggingProxy.ReplayInfo replayInfo = CallLoggingProxy.getReplayInfo(original);
// Persist the replay info to disk, serialize to a DB, whatever floats your boat.
// Come back and load it up later...
Calendar replay = CallLoggingProxy.replay(Calendar.class, replayInfo);
replay.getTimeInMillis(); // 1368311282470
You could imagine wrapping your API object with CallLoggingProxy.create prior to passing it into your testing methods, capturing the data afterwards, and persisting it using whatever your favorite serialization system happens to be. Later, when you want to run your tests, you can load the data back up, create a new instance based on the data with CallLoggingProxy.replay, and passing that into your methods instead.
The CallLoggingProxy is written using Javassist, as Java's native Proxy is limited to working against interfaces. This should cover the general use case, but there are a few limitations to keep in mind:
Classes declared final can't be proxied by this method. (Not easily fixable; this is a system limitation)
The gist assumes the same input to a method will always produce the same output. (More easily fixable; the ReplayInfo would need to keep track of sequences of calls for each input instead of single input/output pairs.)
The gist is not even remotely threadsafe (Fairly easily fixable; just requires a little thought and effort)
Obviously the gist is simply a proof of concept, so it's also not been very thoroughly tested, but I believe the general principle is sound. It's also possible there's a more fully baked framework out there to achieve this sort of goal, but if such a thing does exist, I'm not aware of it.
If you do decide to continue with the replay approach, then hopefully this will be enough to give you a possible direction to work in.
I had the same needs some months ago for non-regression testing when planning a heavy technical refactoring of a large application and... I have found nothing available as a framework.
In fact, replaying may be particularly difficult and may only work in a specific context - no (or few) application with a standard complexity can be really considered as stateless. It is a common problem when testing persistence code with a relational database. To be relevant, the complete system initial state must be restored and each replay step must impact the global state the same way. It becomes a challenge when a system state is distributed into pieces like databases, files, memory... Let's guess what happens if a timestamp taken from a system's clock is used somewhere !
So a more pratical option is to only record... and then do a clever comparison for subsequent runs.
Depending of the number of runs you plan, a human-driven session on the application may be enough, or you have to investing in an automated scenario in a robot playing with your application user interface.
First to record: you can use dynamic proxy interface or aspect programming to intercept method call and to capture state before and after invocation. It may mean: dump concerned database tables, copy some files, serialize Java objects in text format like XML.
Then compare this reference capture with a new run. This comparison should be tuned to exclude any irrelevant elements from each piece of state, like row identifiers, timestamps, file names... to only compare data where your backend's added value shines.
Finally nothing really standard, and often a few specific scripts and codes may be enough to achieve the aim: detect as much errors as possible and try to prevent non-expected side-effects.
This can be done with AOP, aspect oriented programming. It allows to intercept method calls by byte code manipulation. Do a bit of search for examples.
In one case this can do recording, in the other replaying.
Pointers: wikipedia, AspectJ, Spring AOP.
Unfortunately one moves a bit outside the java syntax, and a simple example can better be sought elsewhere. With explanation.
Maybe combined with unit tests / some mocking test framework for offline testing with recorded data.
you could look into 'Mockito'
Example:
//You can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
//stubbing
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());
//following prints "first"
System.out.println(mockedList.get(0));
//following throws runtime exception
System.out.println(mockedList.get(1));
//following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));
after you could replay each test more times and it will return data that you put in.
// pseudocode
class LogMethod {
List<String> parameters;
String method;
addCallTo(String method, List<String> params):
this.method = method;
parameters = params;
}
}
Have a list of LogMethods and call new LogMethod().addCallTo() before every call in your test method.
The idea of playing back the API calls sounds like a use case for the event sourcing pattern. Martin Fowler has a good article on it here. This is a nice pattern that records events as a sequence of objects which are then stored, you can then replay the sequence of events as required.
There is an implementation of this pattern using Akka called Eventsourced, which may help you build the type of system you require.
I had a similar problem some years ago. None of the above solutions would have worked for methods that are not pure functions (side effect free). The major task is in my opinion:
how to extract a snapshot of the recorded object(s) (not only restricted to objects implementing Serializable)
how to generate test code of a serialized representation in a readable way (not only restricted to beans, primitives and collections)
So I had to go my own way - with testrecorder.
For example, given:
ResultObject b = callBackend(a);
...
ResultObject callBackend(SourceObject source) {
...
}
you will only have to annotate the method like this:
#Recorded
ResultObject callBackend(SourceObject source) {
...
}
and start your application (the one that should be recorded) with the testrecorder agent. Testrecorder will manage all tasks for you, such as:
serializing arguments, results, state of this, exceptions (complete object graph!)
finding a readable representation for object construction and object matching
generating a test from the serialized data
you can extend recordings to global variables, input and output with annotations
An example for the test will look like this:
void testCallBackend() {
//arrange
SourceObject sourceObject1 = new SourceObject();
sourceObject1.setState(...); // testrecorder can use setters but is not limited to them
... // setting up backend
... // setting up globals, mocking inputs
//act
ResultObject resultObject1 = backend.callBackend(sourceObject1);
//assert
assertThat(resultObject, new GenericMatcher() {
... // property matchers
}.matching(ResultObject.class));
... // assertions on backend and sourceObject1 for potential side effects
... // assertions on outputs and globals
}
If I understood you question correctly, you should try db4o.
You will store the objects with db4o and restore later to mock and JUnit tests.

how to create a plugin for web application to calculate the each and every invoked method execution time

My application file (EAR) consists of combination of EJB and WAR. FrameWork is JSF and IDE is Netbeans 6.9.1 applition server is glassfich V2.x. I want to calculate the execution time fro each and every invoked method in my application. i have gone through so many blogs. most of them suggested to use AOP. but nobody tell me how to configure and how to use it in my application. could anybody tell me ragarding this. I have some code here and i made use of AOP and JAMon to calculate the method execution time. but i confused about how to configure this because for every method invocation this calss should be invoked for that what to do i dont know. could anybody give some suggestions on it.If you any additional details to answer this i will provide. Code is:
public class PerformanceMonitorIncptr implements MethodInterceptor{
/** Creates a new instance of PerformanceMonitorIncptr */
public PerformanceMonitorIncptr() {
}
public Object invoke(MethodInvocation mi) throws Throwable {
String mName = mi.getMethod().getDeclaringClass().getName() + "." + mi.
getMethod().getName();
Monitor mon = MonitorFactory.start(mName);
// long l = System.currentTimeMillis();
Object returnValue = null;
try {
returnValue = mi.proceed();
} finally {
mon.stop();
System.out.println(mon);
}
System.out.println(mName);
// System.out.println(l - System.currentTimeMillis());
return returnValue;
}
}
AOP is best suited here.
You need to configure #PointCut #Around each method you want to log the time of execution
Have a look at this tutorial .
Update
I hope 20 methods you are talking about /can be are Spring Service methods, and you don't need to alter them at all you just need to configure a #Aspect that will involve all the methods. read more
AOP is the solution.
But why would you write it yourself.
Use Javamelody -> EJB configuration documentation.
We use it with Spring, and it's great. There are also such solutions as AppDynamics, DynaTrace, NewRelic, JXInsight, CorrelSense, Nastel.
As for me Javamelody is free, opensource and very easy to use.

Modify a method using Annotations

How can I change what a method is doing in Java ?
I mean, I am trying to use annotations to make the following code
#Anno1(Argument = "Option1")
public class TestClass
{
#Anno2
public void test()
{
}
}
Into
public class TestClass
{
private static StaticReference z;
public void test()
{
z.invokeToAll();
}
}
This is a very simplified example of what I am trying to do. Anno1 will have many possible combinations, but this is not my problem so far. My problem is how to add code to method test()
I am looking for a more generic solution if possible. Eg. A way to add every kind of code in the method (not just a way to .invokeToAll())
So far I am using import javax.annotation.processing.*; and I have the following code, but I don't know how to go on from there
private void processMethodAnnotations(RoundEnvironment env)
{
for (Element e : env.getElementsAnnotatedWith(Anno2.class))
{
//If it is a valid annotation over a method
if (e.getKind() == ElementKind.METHOD)
{
//What to do here :S
}else
{
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,"Not a method!", e);
}
}
}
I have found something about Java Reflection but I have not found any source to help me with what I am doing.
Obviously I extends AbstractProcessor in my code
I have found this tutorial (http://www.zdnetasia.com/writing-and-processing-custom-annotations-part-3-39362483.htm) But this concerns creating a new class, not just changing a method. and the javax.lang.model.elements do not provide any way of editing that element (which in my case represents a Method).
I hope my question is clear and inline with the rules. If not please comment and I will clarify. Thanks.
Annotation processing is the wrong way to go for you, from Wikipedia:
When Java source code is compiled,
annotations can be processed by
compiler plug-ins called annotation
processors. Processors can produce
informational messages or create
additional Java source files or
resources, which in turn may be
compiled and processed, but annotation
processors cannot modify the annotated
code itself.
People suggested to you the right way - AOP. Specifically, you can use AspectJ. "Quick result" way is (if you use Eclipse):
Install AJDT (AspectJ Development Tools)
Create an AspectJ project and add there your classes and annotations
Create Aspect:
public aspect Processor {
private StaticReference z;
pointcut generic()
// intercept execution of method named test, annotated with #Anno1
// from any class type, annotated with #Anno2
: execution(#Anno2 * (#Anno1 *).test())
// method takes no arguments
&& args ();
// here you have written what you want the method to actually do
void around () : generic() {
z.invokeToAll();
}
}
now you can execute a test and you will see that it works ;) AJDT compiles code for you automatically, so do not need any manual work to do, hope that's what you called "magic" ;)
UPDATE:
if your code in the test() method depends on the Anno1 annotation value, then inside aspect you can get class annotation for which it is executed this way:
void around () : generic() {
Annotation[] classAnnotations = thisJoinPoint.getThis().getClass().getAnnotations();
String ArgumentValue = null;
for ( Annotation annotation : classAnnotations ) {
if ( annotation instanceof Anno1 ) {
ArgumentValue = ((Anno1) annotation).Argument();
break;
}
}
if ( ArgumentValue != null && ArgumentValue.equals("Option1")) {
z.invokeToAll();
}
}
where thisJoinPoint is a special reference variable.
UPDATE2:
if you want to add System.out.println( this ) in your aspect, you need to write there System.out.println( thisJoinPoint.getThis() ), just tested and it works. thisJoinPoint.getThis() returns you "this" but not exactly; in fact this is Object variable and if you want to get any propery you need either to cast or to use reflection. And thisJoinPoint.getThis() does not provide access to private properties.
Well, now seems that your question is answered, but if I missed anything, or you get additional question/problems with this way - feel free to ask ;)
It's perfectly possible to do what you ask, although there is a caveat: relying on private compiler APIs. Sounds scary, but it isn't really (compiler implementations tend to be stable).
There's a paper that explains the procedure: The Hacker's Guide to Javac.
Notably, this is used by Project Lombok to provide automatic getter/setter generation (amongst other things). The following article explains how it does it, basically re-iterating what is said the aforementioned paper.
Well, you might see if the following boilerplate code will be useful:
public void magic(Object bean, String[] args) throws Exception {
for (Method method : bean.getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(Anno2.class)) {
// Invoke the original method
method.invoke(bean, args);
// Invoke your 'z' method
StaticReference.invokeAll();
}
}
}
As an alternative your might employ aspect oriented programming, for instance you have the AspectJ project.
I'm not sure at all if it is even possible to change the source or byte code via annotations. From what your describing it looks as if aspect oriented programming could provide a solution to your problem.
Your annotations are pretty similiar to the pointcut concept (they mark a location where code needs to be inserted) and the inserted code is close the advice concept.
Another approach would be parsing the java source file into an abstract syntax tree, modify this AST and serialize to a java compiler input.
If your class extends a suitable interface, you could wrap it in a DynamicProxy, which delegates all calls to the original methods, except the call to test.

Making simple performance modifications to an already compiled jar?

Like many log4j users, we often have debug level logging that is expensive to evaluate. So we guard those cases with code like:
if( _logger.isDebugEnabled )
_logger.debug("Interesting, my foojes are goofed up: " + getFullDetails())
However, that is uglier than a plain _logger.debug call, and sometimes the programmer doesn't realize the evaluation could be expensive.
It seems like it should be fairly simple to write a program that takes a compiled jar and guards all the _logger.debug calls with the isDebugEnabled check. We would likely be willing to accept the extra overhead of checking isDebugEnabled in all cases.
Has anyone tried this approach, or done similar post-processing of a jar?
Rather than looking at modifying the jar, I'd search for a solution using Bytecode Instrumentation. The problem will be to identify those parts of the code you want to wrap inside a .isDebugEnabled() - you will have to identify objects that are only used for log4j invocations.
Have you looked at AspectJ ? This supports aspects using bytecode weaving, and can interceptions into a previously compiled .jar file.
I believe a good solution would be that the code would be efficient as is.
Consider that log4j is deprecated. Its author itself left it as is, to avoid breaking compatibility, but he created a new one, SLF4J (http://www.slf4j.org/ ). He provides both a facade and an implementation, according to the distinction commons-logging/log4j, but without the flaws of each...
I believe that, in this new logging facility, you can send Object parameters to the logging, and that the level is evaluated before converting the Objects (to String or otherwise). The idea is to use a format string, and parameters.
Our code doesn't use slf4j, but we have utility methods that do exactly that.
It is coded roughly as follow (from memory):
public enum LogLevel {
FATAL, ERROR, WARNING, INFO, DEBUG;
public void log(Logger logger, String format, Object... parameters) {
if (isEnabled(logger)) {
logImpl(logger, String.format(format, parameters));
}
}
public boolean isEnabled(Logger logger) {
switch(this) {
case WARNING : return logger.isWarningEnabled();
case INFO : return logger.isInfoEnabled();
case DEBUG : return logger.isDebugEnabled();
default: return true;
}
}
private void logImpl(Logger logger, String message) {
switch(this) {
case WARNING : logger.warn(message);
// other cases
}
}
}
It is used as:
public void myMethod(Object param) {
LogLevel.WARNING.log(LOGGER, "What is my message ....", "myMethod", param);
}
UPDATE : If you need to call a method in the log...
One possibility is to use toString method. This is appropriate if your logging is 'technical', and will be used also when debugging.
If your logging is more functional (not targeted to the developper), I suggest to define an interface (it is functionally sound in that case, so it is useful to provide meaning) :
public interface Detailable { // the name could also suggest logging?
String getFullDetails();
}
Implement that interface in any object that need to be passed as logging object, with a complex calculation to build the log.

Categories