Details

    • Type: New Feature New Feature
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.0-rc2
    • Fix Version/s: 0.1, 2.3
    • Component/s: API
    • Labels:
      None

      Description

      The Log4j API should support using annotations as provided in Java 6 so applications can use them instead of calls to logger APIs. This is especially useful for entering & exiting type of events, but could be used wherever annotations are allowed.

        Activity

        Hide
        Paul D Johe added a comment -

        I believe Spring's org.springframework.aop.interceptor.CustomizableTraceInterceptor does exactly what you are looking for.

        Show
        Paul D Johe added a comment - I believe Spring's org.springframework.aop.interceptor.CustomizableTraceInterceptor does exactly what you are looking for.
        Hide
        Ralph Goers added a comment -

        The reason I've never done anything with this issue is that I am not sure I really see the value in doing

        @Log

        vs

        @Log Logger logger;

        vs

        Logger logger = LogManager.getLogger(this.getClass());

        except that the latter allows you to specify a different logger name.

        I like the idea of @LogEntryExit as that really does save some coding, especially if you can add it to the class and have it apply to all methods.

        Show
        Ralph Goers added a comment - The reason I've never done anything with this issue is that I am not sure I really see the value in doing @Log vs @Log Logger logger; vs Logger logger = LogManager.getLogger(this.getClass()); except that the latter allows you to specify a different logger name. I like the idea of @LogEntryExit as that really does save some coding, especially if you can add it to the class and have it apply to all methods.
        Hide
        Matt Sicker added a comment -

        The best way I think that it can be auto-initialized while keeping compatibility with everything is to allow an uninitialized Logger instance in the class, then let the annotation processor inject the proper code to instantiate the Logger.

        Show
        Matt Sicker added a comment - The best way I think that it can be auto-initialized while keeping compatibility with everything is to allow an uninitialized Logger instance in the class, then let the annotation processor inject the proper code to instantiate the Logger.
        Hide
        Ralph Goers added a comment -

        Yes, I've seen that. What I had hoped was that all the logger calls could be annotations, but Java 6 & 7 don't provide support for that. In Java 8 annotations aren't allowed everywhere but it may be possible to do a lot more. I originally thought it would be cool if the annotations did nothing if logging was disabled but then would inject code if it was. However, that doesn't seem realistic the more I think about it.

        Show
        Ralph Goers added a comment - Yes, I've seen that. What I had hoped was that all the logger calls could be annotations, but Java 6 & 7 don't provide support for that. In Java 8 annotations aren't allowed everywhere but it may be possible to do a lot more. I originally thought it would be cool if the annotations did nothing if logging was disabled but then would inject code if it was. However, that doesn't seem realistic the more I think about it.
        Hide
        Bruce Brouwer added a comment -

        You should check out Project Lombok. It uses Java's built in annotation processing features to make your code look like this:

        @Log
        public class LogExample {
          public static void main(String... args) {
            log.error("Something's wrong here");
          }
        }
        

        And no, that code did not neglect to extend another class, nor did it neglect to define the log field. You could probably take the concepts from Lombok to do stuff like this as well:

        public class LogExample {
          @LogEntryExit
          public void doStuff() {
            // do stuff
          }
        }
        

        Basically, it uses byte code manipulation to make this all work. From what I can tell, there is no need to setup anything special with javac or maven; it just works. It looks like there are some issues with some IDEs, which Project Lombok has solved. I haven't used it yet myself, but it might be fun to try it out in Log4j 2 (maybe after 2.0 is released)

        Show
        Bruce Brouwer added a comment - You should check out Project Lombok . It uses Java's built in annotation processing features to make your code look like this: @Log public class LogExample { public static void main( String ... args) { log.error( "Something's wrong here" ); } } And no, that code did not neglect to extend another class, nor did it neglect to define the log field. You could probably take the concepts from Lombok to do stuff like this as well: public class LogExample { @LogEntryExit public void doStuff() { // do stuff } } Basically, it uses byte code manipulation to make this all work. From what I can tell, there is no need to setup anything special with javac or maven; it just works. It looks like there are some issues with some IDEs, which Project Lombok has solved. I haven't used it yet myself, but it might be fun to try it out in Log4j 2 (maybe after 2.0 is released)
        Hide
        Matt Sicker added a comment -

        I've got a better idea on how to implement this. Two particular ways to do it, both are essentially injecting a Logger into a declared (but not defined) Logger field of the class. One way to use it would be to mark the class or field with an annotation that an annotation processor would be able to statically inject the proper Logger (which could use annotation attributes to specify any default settings to override). The other way would be similar to how Mockito uses MockitoAnnotations.injectMocks(this) (or whatever the actual method is called; I forget thanks to autocomplete). A class wishing to inject a logger could add a line of code to each class like:

        static { LogManager.inject(); }
        

        Or a special-purpose abuse of class names could be made like:

        public class Foo {
          static { L4J.inject(); }
          private static Logger LOGGER;
        }
        

        I'd specify using @Inject on a Logger field, but last time I tried looking into that, CDI has several different candidates for injection and I'm not very experienced with it.

        I'd prefer the annotation route myself as doing it the other way is practically the same thing as the usual initialization. It could be done as an actual annotation processor, or it could be done with reflection somehow. I may have to think more in regard to the reflective version.

        Show
        Matt Sicker added a comment - I've got a better idea on how to implement this. Two particular ways to do it, both are essentially injecting a Logger into a declared (but not defined) Logger field of the class. One way to use it would be to mark the class or field with an annotation that an annotation processor would be able to statically inject the proper Logger (which could use annotation attributes to specify any default settings to override). The other way would be similar to how Mockito uses MockitoAnnotations.injectMocks(this) (or whatever the actual method is called; I forget thanks to autocomplete). A class wishing to inject a logger could add a line of code to each class like: static { LogManager.inject(); } Or a special-purpose abuse of class names could be made like: public class Foo { static { L4J.inject(); } private static Logger LOGGER; } I'd specify using @Inject on a Logger field, but last time I tried looking into that, CDI has several different candidates for injection and I'm not very experienced with it. I'd prefer the annotation route myself as doing it the other way is practically the same thing as the usual initialization. It could be done as an actual annotation processor, or it could be done with reflection somehow. I may have to think more in regard to the reflective version.
        Hide
        Matt Sicker added a comment -

        No, you're perfectly correct. I'm not sure how to go about getting that data otherwise. This particular style might not be feasible. I'm working on an example using aspects for logging field access and method/constructor calls, so that might be more promising or useful. The thing is, though, we can't just add AOP as a dependency for log4j-api, so I'm not sure where the best place to put it would be. Perhaps a module/bundle?

        Show
        Matt Sicker added a comment - No, you're perfectly correct. I'm not sure how to go about getting that data otherwise. This particular style might not be feasible. I'm working on an example using aspects for logging field access and method/constructor calls, so that might be more promising or useful. The thing is, though, we can't just add AOP as a dependency for log4j-api, so I'm not sure where the best place to put it would be. Perhaps a module/bundle?
        Hide
        Gary Gregory added a comment - - edited

        What I do not like about the patch is that it creates a stack trace for every single logging call. And the usual pattern makes x2 worse:

        if (Log.get().isDebugEnabled()) {
           Log.get().debug(...);
        }
        

        So I would want to say:

        Logger logger = Log.get();
        if (logger.isDebugEnabled()) {
           logger.debug(...);
        }
        

        Which is not pretty. Which make me want to save the Logger in an ivar, and that's the same as having a wrapper.

        Am I missing something?

        Show
        Gary Gregory added a comment - - edited What I do not like about the patch is that it creates a stack trace for every single logging call. And the usual pattern makes x2 worse: if (Log.get().isDebugEnabled()) { Log.get().debug(...); } So I would want to say: Logger logger = Log.get(); if (logger.isDebugEnabled()) { logger.debug(...); } Which is not pretty. Which make me want to save the Logger in an ivar, and that's the same as having a wrapper. Am I missing something?
        Hide
        Matt Sicker added a comment -

        Here's a patch that's inspired by the Loggable meta-library. I'm not too sure on the benefits of this yet, but the @Loggable annotation can be beefed up to support more things and such.

        Show
        Matt Sicker added a comment - Here's a patch that's inspired by the Loggable meta-library. I'm not too sure on the benefits of this yet, but the @Loggable annotation can be beefed up to support more things and such.
        Hide
        Ralph Goers added a comment -

        Yes. Something like http://javakane.blogspot.ro/2012/07/automate-log4j-logging-with-aop-and.html. The thought was to provide more than just injecting a logger but to mark methods to automatically log entry and exit.

        Show
        Ralph Goers added a comment - Yes. Something like http://javakane.blogspot.ro/2012/07/automate-log4j-logging-with-aop-and.html . The thought was to provide more than just injecting a logger but to mark methods to automatically log entry and exit.
        Hide
        Matt Sicker added a comment -

        So like support CDI and @Inject and such?

        Show
        Matt Sicker added a comment - So like support CDI and @Inject and such?
        Hide
        Daniele Di Bernardo added a comment -

        An implementation via Java annotations can be found in my meta-library called Loggable. You can find more info at this web page: http://www.marzapower.com/loggable/

        I hope that such an implementation could help in the development of log4j v. 2, with full support for Java annotations.

        Show
        Daniele Di Bernardo added a comment - An implementation via Java annotations can be found in my meta-library called Loggable. You can find more info at this web page: http://www.marzapower.com/loggable/ I hope that such an implementation could help in the development of log4j v. 2, with full support for Java annotations.
        Hide
        Ralph Goers added a comment -

        My experimental branch uses annotations for Logj components, but still does not address my desire to allow applications to inject logging.

        Show
        Ralph Goers added a comment - My experimental branch uses annotations for Logj components, but still does not address my desire to allow applications to inject logging.

          People

          • Assignee:
            Unassigned
            Reporter:
            Ralph Goers
          • Votes:
            1 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

            • Created:
              Updated:

              Development