In your wrapper, I would reverse the order of the parameters of warn
to be consistent with SLF4J, and maybe check isWarnEnabled()
before doing any processing.
This:
new Log()
.warn((Exception)new RuntimeException().fillInStackTrace(), "I'm warning you.");
could be:
Log.warn("I'm warning you.", new Exception());
or you could just use SLF4J directly:
log.warn("I'm warning you.", new Exception());
If you don't want to use exceptions, you can create a stacktrace yourself:
private static String stackTrace() {
StringBuilder trace = new StringBuilder();
for(StackTraceElement element:Thread.currentThread().getStackTrace()) {
trace.append(" ").append(element).append("\n");
}
return trace.toString();
}
Performance
On my computer, I can call the method above 254,000 times a second, and your one
190,000 times a second.
Getting a stacktrace is relativly slow with any method, but that doesn't mean it'll
be a bottleneck. Yes, it takes a few microseconds but how much total time is that going
to be and how does it compare with everything else your program needs to do? If your
program's producing thousands of warnings a second, then the logs would become unmanageable
before there's a performance issue. Profile the full program with realistic inputs
to find if there is an issue. You can always disable the stacktrace later if needed.
Besides performance, are stacktraces useful?
Stacktraces are useful for actual exceptions because otherwise you wouldn't
even know where the error is. There can be many lines where the exception could have been
thrown from, and multiple layers of callers that could be the source of the error so
the stacktrace is essential in that case.
For warnings, I've never felt the need for stacktraces. They don't have the same usefulness. They might be useful for cases that border on errors. In which case, keep the exception as an optional parameter, and only use it in a few cases.
The drawbacks would be that it makes the code slightly more complex, and people could see the stacktrace and think that there was an exception when there wasn't.
Exception or currentThread().getStackTrace()?
Exceptions are slightly slower but if they're nowhere near a bottleneck then I would at least consider them over currentThread().getStackTrace()
. The code is simpler, you can remove your wrapper completely, and the stacktrace is kept separately from the message. This allows, for example, logging to a database with the stacktraces in separate tables.
Conclusion
There are enough layers of facades when logging so I'm reluctant to add any more. I'd just keep it simple and use SLF4J directly with log.warn("Message")
etc. If you want a stacktrace, just use log.warn("Message", new Exception())
. This keeps it to a few specific messages because it's unlikely you'd want every warning to have a stacktrace. With only a few messages, there's unlikely to be any performance issue and the program shouldn't really have that many active warnings anyway.