Solution 1:

You have to pin your loggers in memory or setup a logging.properties config file. From the java.util.logging.Logger docs:

Logger objects may be obtained by calls on one of the getLogger factory methods. These will either create a new Logger or return a suitable existing Logger. It is important to note that the Logger returned by one of the getLogger factory methods may be garbage collected at any time if a strong reference to the Logger is not kept.

When a new logger is returned the log level is determined by the LogManager which by default uses settings from a logging.properties file. In your example, it is possible to see the following:

  1. Call to getLogger creates a new logger and sets level from LogManager.
  2. Your code sets the logger level to OFF.
  3. G.C. runs and destroys your logger along with settings you just applied.
  4. Selenium calls getLogger and creates a new logger and sets level from LogManager.

Here is an example test case to prove the point:

    public static void main(String[] args) {
        String name = "com.gargoylesoftware.htmlunit";
        for (int i = 0; i < 5; i++) {
            System.out.println(Logger.getLogger(name).getLevel());
            Logger.getLogger(name).setLevel(Level.OFF);
            System.runFinalization();
            System.gc();
            System.runFinalization();
            Thread.yield();
        }
    }

Which will output null instead of OFF.

If you pin your logger by holding a strong reference then step #3 never happens and Selenium should instead find the logger you created which has the level set to OFF.

private static final Logger[] pin;
static {
    pin = new Logger[]{
        Logger.getLogger("com.gargoylesoftware.htmlunit"),
        Logger.getLogger("org.apache.commons.httpclient"),
        Logger.getLogger("org.openqa.selenium.remote.ProtocolHandshake")
    };

    for (Logger l : pin) {
        l.setLevel(Level.OFF);
    }
}