Log4j - Subclassing Logger, "incompatible types" on logger declaration

Striker181
Striker181 used Ask the Experts™
on
Hi,

I created a new Level "ACTION". I can log to it fine using "log.log(LCLevel.ACTION,"TESTME")", but that's too much typing each time.

I want to be able to do
   LCLogger log=LCLogger.getLogger("com.lexi.adam");
   PropertyConfigurator(/*yadda yadda*/);
   log.action("TEST");

so I subclassed the Logger and LoggerFactory classes and they compiled fine. But when I try to compile the test file I get

    [javac] Compiling 1 source file to C:\projects\LCLevel\build\WEB-INF\classes

    [javac] C:\projects\LCLevel\src\com\lexi\adam\log4j\LCLevelTest.java:9: inco
mpatible types
    [javac] found   : org.apache.log4j.Logger
    [javac] required: com.lexi.adam.log4j.LCLogger
    [javac]         LCLogger log=LCLogger.getLogger("com.lexi.adam");
    [javac]                                        ^
    [javac] 1 error


I know that my LCLogger.getLogger returns a Logger, but there appears to be nothing I can really do about that since it wont let me override Log4j's getLogger function.

Please let me know if you have anby ideas. Code follows:

------------------
LCLevel.java
------------------

package com.lexi.adam.log4j;

import org.apache.log4j.*;
import java.io.*;
import java.util.*;


class LCLevel extends Level {    

    public final static int ACTION_INT=Level.ERROR_INT+1;
    public final static String ACTION_STR        = "ACTION";

    public final static LCLevel ACTION = new LCLevel(ACTION_INT,ACTION_STR, 2);
    LCLevel(int level, String levelStr, int syslogEquivalent) {
        super(level, levelStr, syslogEquivalent);
    }

    public static Level toLevel(String sArg) {
        return (Level) toLevel(sArg, Level.DEBUG);
    }

    public static Level toLevel(String sArg, Level defaultValue) {
        if (sArg == null) {
            return defaultValue;
        }
        String stringVal = sArg.toUpperCase();
        if (stringVal.equals(ACTION_STR)) {
            return LCLevel.ACTION;
        }
        return Level.toLevel(sArg, (Level) defaultValue);
    }

    public static Level toLevel(int i) throws IllegalArgumentException {
         switch(i) {
            case ACTION_INT: return LCLevel.ACTION;
        }
        return Level.toLevel(i);
    }
}


-------------------
LCLogger.java
-------------------

package com.lexi.adam.log4j;

import org.apache.log4j.*;
import java.io.*;

class LCLogger extends Logger {
    private static final String FQCN = Level.class.getName();

    private static LCLoggerFactory LCFactory = new LCLoggerFactory();

    public LCLogger(String name){
      super(name);
    }

    public static Logger getLogger(String name){
      return LogManager.getLogger(name, LCFactory);
    }

    public void action(Object message){
      //super.info(message);
      super.log(LCLevel.ACTION,message);
      //super.log(FQCN, LCLevel.ACTION, LCFactory);
    }
}


----------------------------
LCLoggerFactory.java
----------------------------

package com.lexi.adam.log4j;

import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerFactory;

class LCLoggerFactory implements LoggerFactory {
    public LCLoggerFactory(){
    }

    public Logger makeNewLoggerInstance(String name) {
      return new LCLogger(name);
    }
}

----------------------
LCLevelTest.java
----------------------

package com.lexi.adam.log4j;

//import org.apache.log4j.*;
import com.lexi.adam.log4j.LCLevel;
import org.apache.log4j.PropertyConfigurator;

class LCLevelTest {
    public static void main(String args[]){
        LCLogger log=LCLogger.getLogger("com.lexi.adam");
      PropertyConfigurator.configureAndWatch("log4j.properties",10);
      //log.log(LCLevel.ACTION,"TESTME");
      //log.info("TEST");
      log.action("REAL TEST");
    }
}
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Top Expert 2006
Commented:
in your LCLogger class:

   public static Logger getLogger(String name){
    return LogManager.getLogger(name, LCFactory);
   }

the method returns a "Logger" instance.
so when you do this:

   LCLogger log=LCLogger.getLogger("com.lexi.adam");

you are trying to assign a Logger to a variable declared as Logger
LCLogger extends Logger means that all LCLoggers are Loggers but not that all Loggers are LCLoggers.

so in your LCLogger class, the getLogger() method should return a LCLogger
   public static LCLogger getLogger(String name)


or you could try to cast the Logger to an LCLogger when you assign the value to the varible like this:

   LCLogger log=(LCLogger)LCLogger.getLogger("com.lexi.adam");

but you might get an cast exception.

Author

Commented:
thanks but I already tried that.

it wont let me override Log4j's getLogger function. using "public static LCLogger" gives me :

compile:
    [javac] Compiling 1 source file to C:\projects\LCLevel\build\WEB-INF\classes

    [javac] C:\projects\LCLevel\src\com\lexi\adam\log4j\LCLogger.java:19: getLog
ger(java.lang.String) in com.lexi.adam.log4j.LCLogger cannot override getLogger(
java.lang.String) in org.apache.log4j.Logger; attempting to use incompatible ret
urn type
    [javac] found   : com.lexi.adam.log4j.LCLogger
    [javac] required: org.apache.log4j.Logger
    [javac]     public static LCLogger getLogger(String name){
    [javac]                            ^
    [javac] C:\projects\LCLevel\src\com\lexi\adam\log4j\LCLogger.java:20: incomp
atible types
    [javac] found   : org.apache.log4j.Logger
    [javac] required: com.lexi.adam.log4j.LCLogger
    [javac]     return LogManager.getLogger(name, LCFactory);
    [javac]                                    ^
    [javac] 2 errors


And, as you said, casting the assignment in the test file gives me a cast exception when I try to run it.
Top Expert 2016

Commented:
Return a Logger type that holds an LCLogger reference. You would then have:

Logger log=LCLogger.getLogger("com.lexi.adam");
HTML5 and CSS3 Fundamentals

Build a website from the ground up by first learning the fundamentals of HTML5 and CSS3, the two popular programming languages used to present content online. HTML deals with fonts, colors, graphics, and hyperlinks, while CSS describes how HTML elements are to be displayed.

Author

Commented:
Thanks for the response.

For "Logger" to be used, I have to include vanilla log4j in the test file. Doing it that way ignores the changes I made in file LCLogger; it won't compile since it won't recognize "log.action" as a valid command

Perhaps I'm missing something here? Were you suggesting I do something besides change the LCLogger log statement to Logger log? If so then I misunderstood

Author

Commented:
doh! forget to include import com.lexi.adam.log4j.* in the test file. Once I did that, casting like GrandSchtroumpf suggested worked. Sometimes it's just the littlest things.

Sorry about the confusion, and thanks for the help!
Top Expert 2006

Commented:
Did you try the cast?
LCLogger log=(LCLogger)LCLogger.getLogger("com.lexi.adam");
Do you get a class cast exception?
I guess you do.

> it wont let me override Log4j's getLogger function.
This is normal.  Because your parent class (Logger) already defines the method to return a Logger, so java gets confused with the methods signatures.
But you can write your own method like
"LCLogger getLCLogger(String str)"
to return you LCLogger.

Ok, i wrote that post before reading yours Striker.
Happy to see that it's working.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial