Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-users] Why are Loggers static members in classes

Am 25.11.2013 16:50, schrieb Joakim Erdfelt:

> Create a src/test/resources/ 
> Specify your own Logger implementation there.

in my testcases I use an Inner class deriving from StdErrLog,
so this way doesn't work.

> Static loggers are there to limit GC churn for something that
> is not instance dependant,

Given all the instance-members that single static member shouldn't
change anything at all in terms of GC-runtimes. E.g. AbstractLifeCycle
creates an ArrayList with every instantiation and non-static final
members being used as constants, so as long as Log.getLogger
isn't a bottleneck in terms of performance, the impact on memory
overhead should be minimal.

> and is an extremely common logger pattern.

A pattern that - in my eyes - is not a very good one because it
prevents you from a couple of things like changing the logger
during runtime and creates effects like the ones I described.

> You can also use Log.setLog(Logger) to specify your own Logger impl.

That's exactly what I already do and "now" doesn't work (as already
mentioned here in the list, I'm doing a migration from 7.0 to 9.x).
Here is what I do:

public class __Test_AuthServiceJettyLoginService extends TestCase {

    static LinkedList<String> messages = new LinkedList<String>();

        Log.setLog(new StdErrLog(){
            public void debug(String msg, Object... objects){
                super.debug(msg, objects);
                messages.add("D: " + msg);
            public void info(String msg, Object... objects){
      , objects);
                messages.add("I: " + msg);
            public void warn(String msg, Object... objects){
                super.warn(msg, objects);
                messages.add("E: " + msg);
            public void warn(String msg, Throwable t){
                super.warn(msg, t);
                if (t != null){
                    msg += "\r\n  " + t.getClass().getName() + ": " + t.getMessage();
                messages.add("E: " + msg);

    public void testStartStop() throws Exception {
        // reduced to the relevant part, there is more happening IRL of course
        AuthServiceJettyLoginService service = new AuthServiceJettyLoginService();

        assertEquals("check number of messages", 3, messages.size());
        assertEquals("check message", "D: Starting {}", messages.removeFirst());
        assertEquals("check message", "I: Starting", messages.removeFirst());
        assertEquals("check message", "D: STARTED {}", messages.removeFirst());
        assertEquals("check service is running", true, service.isRunning());

STDERR contains the following messages:

2013-11-25 17:15:57.743:DBUG:oejuc.AbstractLifeCycle:main: starting AuthServiceJettyLoginService[DEFAULT]
2013-11-25 17:15:57.743:INFO::main: Starting
2013-11-25 17:15:57.743:DBUG:oejuc.AbstractLifeCycle:main: STARTED AuthServiceJettyLoginService[DEFAULT]

The LinkedList doesn't contain any messages of AbstractLifeCycle
at the end (only the main-message coming from my own class). Reason
is that the ClassLoader already loaded AbstractLifeCycle which invoked
the static constructor. Reason can be a class in the import-list that
derives from AbstractLifeCycle or has members of Jetty-classes that
derives from it. You can throw away all imports which makes your
source-code a mess or you use wildcards with your imports and hope that
nobody (e.g. Eclipse) is changing that back to specific imports (e.g.
because the FindBugs-module suggests doing exactly that).

As I said, I solved that problem in my application by setting the
Logger in a class that is called before other classes using Jetty
are even loaded. But my testcases are doomed to fail at the moment.
The property-file isn't a real option here, either, so I'm screwed
in a way, technically speaking. Am I correct?

Regards, Lothar

Back to the top