[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14055663#comment-14055663 ] Remko Popma commented on LOG4J2-519: Tool to be added to the {{org.apache.logging.log4j.core.tools}} package in the log4j-core module as discussed on the mailing list. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma >Assignee: Remko Popma > Attachments: Generate.java, GenerateCustomLoggerTest.java, > GenerateExtendedLoggerTest.java > > > Please try out the attached [^Generate.java] tool that provides the > functionality described below and give feedback if you notice any issues. > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class t
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14050071#comment-14050071 ] Remko Popma commented on LOG4J2-519: I am working on JUnit tests for both the Generate CustomLogger and Generate ExtendedLogger use cases. The JUnit test generates source code, compiles it, asserts that the generated class has the expected methods, and finally executes some simple logging using the generated class and validates the result. This ensures that any future API changes, if they occur, will break the JUnit tests and give us a heads-up that the tool needs to be updated too. Once I have this working I would like to commit the tool to the {{org.apache.logging.log4j.util}} package in the log4j-api module. Since the tool only has dependencies on log4j-api and not on log4j-core, I think the api module is the best place for it. About the class name: usually class names are nouns, and method names are verbs, so that when the class is used it will follow the noun.verb() pattern (e.g. car.move(), bird.fly()). This class is only used from the command line, and there are two use cases: {{java Generate$CustomLogger}} and {{java Generate$ExtendedLogger}}. This follows the verb + noun pattern. If we were to rename the class to Generator or some other noun, we would end up with {{java Generator$CustomLogger}}, giving us a noun + noun pattern, like car.wheel(), or bird.beak(). This does not look right to me. Because of this command line-only usage I think it is appropriate to not follow Java conventions and keep the class name a verb. Thoughts? > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > Please try out the attached [^Generate.java] tool that provides the > functionality described below and give feedback if you notice any issues. > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. Thi
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14049618#comment-14049618 ] Remko Popma commented on LOG4J2-519: Update for RC2: {code} static final String METHODS = "" // + "%n" // + "/**%n" // + " * Logs a message with the specific Marker at the {@code CUSTOM_LEVEL} level.%n" // + " * %n" // + " * @param marker the marker data specific to this log statement%n" // + " * @param msg the message string to be logged%n" // + " */%n" // + "public void methodName(final Marker marker, final Message msg) {%n" // + "logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msg, (Throwable) null);%n" // + "}%n" // + "%n" // + "/**%n" // + " * Logs a message with the specific Marker at the {@code CUSTOM_LEVEL} level.%n" // + " * %n" // + " * @param marker the marker data specific to this log statement%n" // + " * @param msg the message string to be logged%n" // + " * @param t A Throwable or null.%n" // + " */%n" // + "public void methodName(final Marker marker, final Message msg, final Throwable t) {%n" // + "logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msg, t);%n" // + "}%n" // + "%n" // + "/**%n" // + " * Logs a message object with the {@code CUSTOM_LEVEL} level.%n" // + " * %n" // + " * @param marker the marker data specific to this log statement%n" // + " * @param message the message object to log.%n" // + " */%n" // + "public void methodName(final Marker marker, final Object message) {%n" // + "logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, (Throwable) null);%n" // + "}%n" // + "%n" // + "/**%n" // + " * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n" // + " * the {@link Throwable} {@code t} passed as parameter.%n" // + " * %n" // + " * @param marker the marker data specific to this log statement%n" // + " * @param message the message to log.%n" // + " * @param t the exception to log, including its stack trace.%n" // + " */%n" // + "public void methodName(final Marker marker, final Object message, final Throwable t) {%n" // + "logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, t);%n" // + "}%n" // + "%n" // + "/**%n" // + " * Logs a message object with the {@code CUSTOM_LEVEL} level.%n" // + " * %n" // + " * @param marker the marker data specific to this log statement%n" // + " * @param message the message object to log.%n" // + " */%n" // + "public void methodName(final Marker marker, final String message) {%n" // + "logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, (Throwable) null);%n" // + "}%n" // + "%n" // + "/**%n" // + " * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n" // + " * %n" // + " * @param marker the marker data specific to this log statement%n" // + " * @param message the message to log; the format depends on the message factory.%n" // + " * @param params parameters to the message.%n" // + " * @see #getMessageFactory()%n" // + " */%n" // + "public void methodName(final Marker marker, final String message, final Object... params) {%n" // + "logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, params);%n" // + "}%n" // + "%n" // + "/**%n" // + " * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n" // + " * the {@link Throwable} {@code t} passed as parameter.%n" // + " * %n" // + " * @param marker the marker data specific to this log statement%n" // + " * @param message the message to log.%n" // + " * @param t the exception to log, including its stack trace.%n" // + " */%n" // + "public void methodName(final Marker marker, final String message, final Throwable t) {%n" // + "logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, t);%
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13935960#comment-13935960 ] Remko Popma commented on LOG4J2-519: This weekend I won't have time (one more push for an exam I have next week), but after that I'll look at the patch for LOG4J2-555 and also update the generator tool. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java, Generate_old_20140130.java > > > Please try out the attached [^Generate.java] tool that provides the > functionality described below and give feedback if you notice any issues. > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class to generate > * the list of custom leve
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13935894#comment-13935894 ] Bruce Brouwer commented on LOG4J2-519: -- I'm abandoning the idea I had in LOG4J2-562 in favor of what I proposed in LOG4J-555. I think there is one aspect of LOG4J-562 that still has merit and could potentially effect this, but I'm going to leave that discussion for inside LOG4J-562. Here is what I think this code would look like in light of my patch provided in LOG4J2-555 {code} package com.bhb.log4j; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.spi.AbstractLoggerWrapper; import org.apache.logging.log4j.spi.LoggerProvider; public final class ExtLogger extends AbstractLoggerWrapper { private static final long serialVersionUID = 1L; private static final ConcurrentMap loggers = new ConcurrentHashMap(); private static final String FQCN = ExtLogger.class.getName(); public static final Level DIAG = Level.forName("DIAG", 350); public static final Level NOTICE = Level.forName("NOTICE", 450); public static final Level VERBOSE = Level.forName("VERBOSE", 550); private ExtLogger(Logger logger) { super((LoggerProvider) logger, logger.getName(), logger.getMessageFactory()); } /** * Returns a custom Logger with the name of the calling class. * * @return The custom Logger for the calling class. */ public static ExtLogger getLogger() { return getLogger(getClassName(2)); } /** * Returns a custom Logger using the fully qualified name of the Class as the Logger name. * * @param loggerName The Class whose name should be used as the Logger name. If null it will *default to the calling class. * @return The custom Logger. */ public static ExtLogger getLogger(final Class clazz) { return getLogger(clazz != null ? clazz.getName() : getClassName(2)); } /** * Returns a custom Logger using the fully qualified name of the Class as the Logger name. * * @param loggerName The Class whose name should be used as the Logger name. If null it will *default to the calling class. * @param messageFactory The message factory is used only when creating a logger, subsequent use *does not change the logger but will log a warning if mismatched. * @return The custom Logger. */ public static ExtLogger getLogger(final Class clazz, final MessageFactory factory) { return getLogger(clazz != null ? clazz.getName() : getClassName(2), factory); } /** * Returns a custom Logger using the fully qualified class name of the value as the Logger name. * * @param value The value whose class name should be used as the Logger name. If null the name *of the calling class will be used as the logger name. * @return The custom Logger. */ public static ExtLogger getLogger(final Object value) { return getLogger(value != null ? value.getClass().getName() : getClassName(2)); } /** * Returns a custom Logger using the fully qualified class name of the value as the Logger name. * * @param value The value whose class name should be used as the Logger name. If null the name *of the calling class will be used as the logger name. * @param messageFactory The message factory is used only when creating a logger, subsequent use *does not change the logger but will log a warning if mismatched. * @return The custom Logger. */ public static ExtLogger getLogger(final Object value, final MessageFactory factory) { return getLogger(value != null ? value.getClass().getName() : getClassName(2), factory); } /** * Returns a custom Logger with the specified name. * * @param name The logger name. If null the name of the calling class will be used. * @return The custom Logger. */ public static ExtLogger getLogger(final String name) { return getLogger(name != null ? name : getClassName(2), null); } /** * Returns a custom Logger with the specified name. * * @param name The logger name. If null the name of the calling class will be used. * @param messageFactory The message factory is used only when creating a logger, subsequent use *does not change the logger but will log a warning if mismatched. * @return The custom Logger. */ public static ExtLogg
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13923170#comment-13923170 ] Bruce Brouwer commented on LOG4J2-519: -- Sorry, I wasn't clear in what my code represents. I neglected to remove FQCN from the code I posted as in the last getLogger method, you'll see that my example is passing in the ExtLogger.class and AbstractLogger.class. Basically, what would have been two separate FQCN. I don't particularly need to pass in actual classes. They could be FQCN strings. Also, this is is just code that demonstrates where we could take it if we moved forward with what I am suggesting in LOG4J2-562 and influenced by the discussion in LOG4J2-555. The code as I provided does not actually work currently with the trunk on log4j2. It is important to note that I'm giving 2 FQCNs. Because some of the implemented methods are on AbstractLogger and others on ExtLogger, we need to tell the extended logger about both classes. I imagine we would want to allow any number of FQCNs if we pursued this approach. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java, Generate_old_20140130.java > > > Please try out the attached [^Generate.java] tool that provides the > functionality described below and give feedback if you notice any issues. > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13923148#comment-13923148 ] Remko Popma commented on LOG4J2-519: Bruce, it looks like the FQCN is declared, but never used in your example ExtLogger. This means that the FQCN of AbstractLogger will be used and the caller location in the log file will be listed as ExtLogger (because ExtLogger calls a method in AbstractLogger) but we want to list MyApp (the class calling ExtLogger) - this is basically the issue vibin reported above... Note that I've only looked at the code, not tried to run it. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java, Generate_old_20140130.java > > > Please try out the attached [^Generate.java] tool that provides the > functionality described below and give feedback if you notice any issues. > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one wou
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13922497#comment-13922497 ] Bruce Brouwer commented on LOG4J2-519: -- With my work in LOG4J-547, this example would turn into something like this: {code} package com.bhb.log4j; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.simple.SimpleLogger; import org.apache.logging.log4j.spi.AbstractLogger; import org.apache.logging.log4j.spi.LoggerExtension; public final class ExtLogger extends AbstractLogger { private static final long serialVersionUID = 26876940739430L; private static final ConcurrentMap loggers = new ConcurrentHashMap(); private final LoggerExtension logger; private static final String FQCN = ExtLogger.class.getName(); private static final Level DIAG = Level.forName("DIAG", 350); private static final Level NOTICE = Level.forName("NOTICE", 450); private static final Level VERBOSE = Level.forName("VERBOSE", 550); private ExtLogger(LoggerExtension logger) { super(logger.getName()); this.logger = logger; } /** * Returns a custom Logger with the name of the calling class. * * @return The custom Logger for the calling class. */ public static ExtLogger getLogger() { return getLogger(getClassName(2)); } /** * Returns a custom Logger using the fully qualified name of the Class as the Logger name. * * @param loggerName The Class whose name should be used as the Logger name. If null it will *default to the calling class. * @return The custom Logger. */ public static ExtLogger getLogger(final Class clazz) { return getLogger(clazz != null ? clazz.getName() : getClassName(2)); } /** * Returns a custom Logger using the fully qualified name of the Class as the Logger name. * * @param loggerName The Class whose name should be used as the Logger name. If null it will *default to the calling class. * @param messageFactory The message factory is used only when creating a logger, subsequent use *does not change the logger but will log a warning if mismatched. * @return The custom Logger. */ public static ExtLogger getLogger(final Class clazz, final MessageFactory factory) { return getLogger(clazz != null ? clazz.getName() : getClassName(2), factory); } /** * Returns a custom Logger using the fully qualified class name of the value as the Logger name. * * @param value The value whose class name should be used as the Logger name. If null the name *of the calling class will be used as the logger name. * @return The custom Logger. */ public static ExtLogger getLogger(final Object value) { return getLogger(value != null ? value.getClass().getName() : getClassName(2)); } /** * Returns a custom Logger using the fully qualified class name of the value as the Logger name. * * @param value The value whose class name should be used as the Logger name. If null the name *of the calling class will be used as the logger name. * @param messageFactory The message factory is used only when creating a logger, subsequent use *does not change the logger but will log a warning if mismatched. * @return The custom Logger. */ public static ExtLogger getLogger(final Object value, final MessageFactory factory) { return getLogger(value != null ? value.getClass().getName() : getClassName(2), factory); } /** * Returns a custom Logger with the specified name. * * @param name The logger name. If null the name of the calling class will be used. * @return The custom Logger. */ public static ExtLogger getLogger(final String name) { return getLogger(name != null ? name : getClassName(2), null); } /** * Returns a custom Logger with the specified name. * * @param name The logger name. If null the name of the calling class will be used. * @param messageFactory The message factory is used only when creating a logger, subsequent use *does not change the logger but will log a warning if mismatched. * @return The custom Logger. */ public static ExtLogger getLogger(final String name, final MessageFactory factory) { final String actualName = name != null ? name : getClassName(2); if (loggers.containsKey(actualNa
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13918826#comment-13918826 ] Bruce Brouwer commented on LOG4J2-519: -- Definitely it would go in spi. It would allow flexibility in implementations that might not directly extend AbstractLogger and I think it might help me out with LOG4J2-547 where my logger needs to extend Writer and OutputStream. I could extend Writer and still implement ExtensibleLogger. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java, Generate_old_20140130.java > > > Please try out the attached [^Generate.java] tool that provides the > functionality described below and give feedback if you notice any issues. > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > c
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13918768#comment-13918768 ] Ralph Goers commented on LOG4J2-519: Logger is the interface end users can code to. It should only contain methods they should call. If you want to create an interface and add it to the spi directory I guess I don't have a problem with it. But if it just declares all the additional methods in AbstractLogger than I'm not sure I see the point. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java, Generate_old_20140130.java > > > Please try out the attached [^Generate.java] tool that provides the > functionality described below and give feedback if you notice any issues. > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13918741#comment-13918741 ] Bruce Brouwer commented on LOG4J2-519: -- I've been wondering about the need here to cast to AbstractLogger. This ties us to the implementation of Loggers originally conceived in core. What if we had an interface that has the .log(...) methods defined on AbstractLogger that take the FQCN. Perhaps we could call this interface ExtensibleLogger or something like that. I would feel better about casting to an interface that any logging implementation could implement. I'm kind of looking at this for LOG4J2-547 which I am working on. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java, Generate_old_20140130.java > > > Please try out the attached [^Generate.java] tool that provides the > functionality described below and give feedback if you notice any issues. > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To p
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917670#comment-13917670 ] Gary Gregory commented on LOG4J2-519: - [~rem...@yahoo.com] Why don't you commit the generator (needs a better name than "Generate") in core's test code base. At least that will give a place to look at it, play with it and make sure it always compiles and is part of any refactorings. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java, Generate_old_20140130.java > > > Please try out the attached [^Generate.java] tool that provides the > functionality described below and give feedback if you notice any issues. > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify:
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917378#comment-13917378 ] vibin commented on LOG4J2-519: -- Thanks,I tried test again with latest generated code, it worked. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java, Generate_old_20140130.java > > > Please try out the attached [^Generate.java] tool that provides the > functionality described below and give feedback if you notice any issues. > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class to generate > * the list of custom levels to support and their {{intLevel}} relative > strength > * whether to extend {{Logger}} (and keep the existing b
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917298#comment-13917298 ] Remko Popma commented on LOG4J2-519: vibin, the quick fix may be to use %c (lowercase) in your pattern layout instead of %C (upper case). This will use the logger _name_ instead of its class and as a side-effect will be about [ten times faster|http://logging.apache.org/log4j/2.x/manual/async.html#Throughput_of_Logging_With_Location_includeLocationtrue] because it doesn't use reflection. Ralph, this looks like a bug: it basically means that any location-based logic is broken for loggers that subclass AbstractLoggerWrapper. I've raised LOG4J2-555 for this. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to s
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917192#comment-13917192 ] vibin commented on LOG4J2-519: -- Is there a quick solution to fix this issue ..? i tried setting FQCN in the wrapper calss , did not work.. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class to generate > * the list of custom levels to support and their {{intLevel}} relative > strength > * whether to extend {{Logger}} (and keep the existing built-in methods) or > have only methods for the custom log levels > and the tool generates the source code for the wrapper class th
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917141#comment-13917141 ] Ralph Goers commented on LOG4J2-519: logger.fatal, logger.error, etc all go straight to AbstractLogger, which is why you get the correct class name - the methods in AbstractLogger all use AbstractLogger as the FQCN. However, the logger.diag and logger.notice methods in Remko's example are all calling a logger.log method that does not contain an FQCN, which is why the caller info is wrong. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class to generate > * the lis
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917137#comment-13917137 ] Ralph Goers commented on LOG4J2-519: in AbstractLoggerWrapper you will notice that the log method contains an fqcn parameter. This value must contain the fully qualified class name of the class that implements your logging. In this case I would guess that to be LoggerWrapper. Log4j uses this to determine the caller information - it traverses the stack until it finds the entry prior to the class named as the fqcn. So if the fqcn is incorrect then the caller information will be incorrect. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917136#comment-13917136 ] vibin commented on LOG4J2-519: -- Here is the code : Wrapper class: * public final class DPLogger extends AbstractLoggerWrapper { private static final long serialVersionUID = 216489351472874L; private static final Level NOTICE = Level.forName("NOTICE", 450); private DPLogger(final Logger logger) { super((AbstractLogger) logger, logger.getName(), logger.getMessageFactory()); } /** * Returns a custom Logger with the name of the calling class. * * @return The custom Logger for the calling class. */ public static DPLogger create() { final Logger wrapped = LogManager.getLogger(); return new DPLogger(wrapped); } /** * Returns a custom Logger using the fully qualified name of the Class as * the Logger name. * * @param loggerName The Class whose name should be used as the Logger name. * If null it will default to the calling class. * @return The custom Logger. */ public static DPLogger create(final Class loggerName) { final Logger wrapped = LogManager.getLogger(loggerName); return new DPLogger(wrapped); } ... } Test App: * public class DPTestLogger { public static void main(String[] args) { // TODO Auto-generated method stub final DPLogger logger = DPLogger.create(DPTestLogger.class); //DPLog logger = new DPLog(DPTestLogger.class); try { logger.fatal("test"); logger.error("test"); logger.warn("test"); logger.info("test"); logger.debug("test"); logger.trace("test"); logger.notice("Notice"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } Printed log 2014-03-01 12:45:22,300 FATAL c.h.i.d.t.DPTestLogger [main] test 2014-03-01 12:45:22,301 ERROR c.h.i.d.t.DPTestLogger [main] test 2014-03-01 12:45:22,301 WARN c.h.i.d.t.DPTestLogger [main] test 2014-03-01 12:45:22,301 INFO c.h.i.d.t.DPTestLogger [main] test 2014-03-01 12:45:22,301 DEBUG c.h.i.d.t.DPTestLogger [main] test 2014-03-01 12:45:22,301 TRACE c.h.i.d.t.DPTestLogger [main] test 2014-03-01 12:45:22,302 NOTICE c.h.i.d.l.w.DPLogger [main] Notice > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{i
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917134#comment-13917134 ] vibin commented on LOG4J2-519: -- The example generated code given in this article doesn't contain FQCN properly,I just followed the same. If it is required can you explain how to set FQCN property ? > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class to generate > * the list of custom levels to support and their {{intLevel}} relative > strength > * whether to extend {{Logger}} (and keep the existing built-in methods) or > have only methods for the custom log levels > an
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917131#comment-13917131 ] Ralph Goers commented on LOG4J2-519: Can you provide some sample code to demonstrate this? > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class to generate > * the list of custom levels to support and their {{intLevel}} relative > strength > * whether to extend {{Logger}} (and keep the existing built-in methods) or > have only methods for the custom log levels > and the tool generates the source code for the wrapper class that has exactly > the required methods. Us
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917126#comment-13917126 ] Ralph Goers commented on LOG4J2-519: I don't see how the log level would affect the class name. In your custom logger did you set the FQCN properly? > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class to generate > * the list of custom levels to support and their {{intLevel}} relative > strength > * whether to extend {{Logger}} (and keep the existing built-in methods) or > have only methods for the custom log levels > and the tool generates the source code for th
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13917071#comment-13917071 ] vibin commented on LOG4J2-519: -- Fund an issue while using a custom log level, it does print incorrect Class name, it prints WrapperClass name instead actual class where the logs are originated. Find example below: The NOTICE level prints incorrect class name in the log file, it prints WrapperClass name instead of "TestApp", any solution to this issue ? 2014-03-01 08:19:16,551 ERROR c.h.i.d.t.TesApp [main] test message 2014-03-01 08:19:16,551 WARN c.h.i.d.t.TestApp [main] test message 2014-03-01 08:19:16,551 INFO c.h.i.d.t.TestApp [main] test message 2014-03-01 08:19:16,551 DEBUG c.h.i.d.t.TestApp [main] test message 2014-03-01 08:19:16,551 TRACE c.h.i.d.t.TestApp [main] test message 2014-03-01 08:19:16,551 NOTICE c.h.i.d.l.w.LoggerWrapper [main] test message Thanks. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > er
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13893026#comment-13893026 ] Remko Popma commented on LOG4J2-519: Bruce, interesting point, I hadn't thought of that. I think {{LogManager.getLogger()}} does return the same instance. {{Custom/ExtendedLogger.getLogger()}} would need to do its own caching if we want to provide the same guarantees. Hmm, food for thought... Anyway, consensus on the mailing list was to leave this for the time being until after the 2.0 GA release. Help with other issues is of course always welcome! :-) > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13892953#comment-13892953 ] Bruce Brouwer commented on LOG4J2-519: -- If we call it {{.getLogger(...)}}, I as a user might expect to get the exact same instance back from repeated calls. So in this sense, {{.create(...)}} would be a better fit. I like the idea of {{.getLogger(..)}} best, but would like it to return the same instance each time. I didn't yet dig deeper into {{LogManager.getLogger(...)}} to determine if I get the exact same instance, but I would assume it is the same instance for each call given the same class name. Perhaps there is some way to use the {{LoggerContext}} to retrieve the exact same instance of this custom logger. Or maybe stuff the custom logger into some property on the logger retrieved from {{LogManager.getLogger(...)}}. I'm just throwing out ideas. I honestly just started poking around looking to see how I could help get log4j2 out the door because my company is not terribly interested in using beta software in production. So I actually have very little need for this feature. I personally would rather see this wait until later so we can release 2.0 sooner. I'll check out the mailing lists to see if there is somewhere else that I could better help. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_r
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13891687#comment-13891687 ] Remko Popma commented on LOG4J2-519: Gary, I agree, naming the factory method {{getLogger(Class)}} is probably better. Yes, this tool can generate a logger that does not extend from {{AbstractLogger}}. There is a [section|https://issues.apache.org/jira/browse/LOG4J2-519#Customizing] on this in the description above. (The command is briefly mentioned in my first comment above, but it is easy to overlook.) The command to generate a wrapper that _only_ provides convenience methods for the specified custom levels (and hides the convenience methods for the built-in levels) is: {{java org.apache.logging.log4j.util.Generate$CustomLogger com.mycomp.MyLogger DEFCON1=350 DEFCON2=450 DEFCON3=550}} The generated {{MyLogger}} class only has {{defcon1()}}, {{defcon2()}}, ... methods, no {{info()}}, {{debug()}}, {{warn()}}, etc. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13891678#comment-13891678 ] Remko Popma commented on LOG4J2-519: Bruce, there is still discussion going on on the mailing list (currently pending as we are all focusing on the upcoming 2.0 GA release), about which approach to take. Your argument to automatically benefit from bugfixes/enhancements was mentioned on the ML as an argument to have a generated or hand-coded interface instead of an implementation class. The log4j library would then generate an implementation at runtime. Personally, I like the simplicity of the concrete class approach, but there are many trade-offs here and I am sure that the discussion is not finished yet. :-) > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > m
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13891654#comment-13891654 ] Gary Gregory commented on LOG4J2-519: - Can this tool generate a logger class that does _not_ extend the stock logger? If you have not read about my DEFCON example on the ML, the idea is to have a logger that _only_ implements defcon1(), defcon2(), ..., defcon5(). No warn, info and so on. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class to generate > * the list of custom levels to support and their {{intLevel}} relative > strength > * whether to extend {{Logger
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13891650#comment-13891650 ] Gary Gregory commented on LOG4J2-519: - {code:java} final ExtendedLogger logger = ExtendedLogger.create(MyClass.class); {code} Why is the factory method _not_ called {{getLogger(Class)}}? That would make it like {{LogManager.getLogger(Class)}} > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class to generate > * the list of custom levels to support and their {{intLevel}} relative > strength > * whether to extend {{Logger}} (and keep the existing built-in methods) or
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13891628#comment-13891628 ] Bruce Brouwer commented on LOG4J2-519: -- Thanks for that explanation. What I was trying to get at, though, is that there are good tools available that can tie code generation such as this into your build tool, so wouldn't that be a better place for this? And speaking of a place, where exactly would you recommend this Generate code be placed? log4j-core seem kind of arbitrary to me. And if it went into a new artifact, then why not make it a maven plugin? (You can probably tell that I'm a fan of Maven). And if this code generation was tied into the Maven build lifecycle, upgrading the Maven plugin would get me enhancements and bug fixes automatically without requiring me to remember that now I need to update this generated wrapper. If you like the idea of this Maven approach, I could contribute a patch. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-cod
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13891404#comment-13891404 ] Remko Popma commented on LOG4J2-519: *How to use the Generate tool* Please follow the steps below. _You only need to do this once._ # Suppose you decide you want to use custom log levels, e.g. WARN > *DIAG* > INFO > *NOTICE* > DEBUG > *VERBOSE* > TRACE, and you want a convenient API # Download the attached file {{Generate.java}} and compile with {{javac -d org/apache/logging/log4j/util Generate.java}} # Generate an extended logger with {{java org.apache.logging.log4j.util.Generate$ExtendedLogger com.mycomp.myproject.util.ExtendedLogger DIAG=350 NOTICE=450 VERBOSE=550 > ExtendedLogger.java}} # Copy the generated ExtendedLogger.java to the {{com.mycomp.myproject.util}} package of your project. That's it. You're done. Now in your project you can write: {code} import com.mycomp.myproject.util.ExtendedLogger; final ExtendedLogger logger = ExtendedLogger.create(MyClass.class); logger.warn("This is a warning"); logger.diag("This is a diagnostic message"); logger.info("This is an info message"); logger.notice("This is a notice message"); logger.debug("This is a debug message"); {code} There is no need for Maven or APT to take some additional action at compile time or runtime. Once you've generated the ExtendedLogger class you just use it in your project like any other class. > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could
[jira] [Commented] (LOG4J2-519) Custom/Extended Loggers
[ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13890837#comment-13890837 ] Bruce Brouwer commented on LOG4J2-519: -- So how would this actually get used? Would you use this with APT, or maybe a Maven plugin? > Custom/Extended Loggers > --- > > Key: LOG4J2-519 > URL: https://issues.apache.org/jira/browse/LOG4J2-519 > Project: Log4j 2 > Issue Type: New Feature > Components: API >Affects Versions: 2.0-rc1 >Reporter: Remko Popma > Attachments: Generate.java > > > {anchor:Extending} > *[#Extending] the Logger interface* > LOG4J2-41 added support for custom log Levels. Users can now log messages at > the new custom level by passing the custom level to the {{Logger.log()}} > method: > {code} > final Logger logger = LogManager.getLogger(); > final Level VERBOSE = Level.forName("VERBOSE", 550); > logger.log(VERBOSE, "a verbose message"); > logger.log(VERBOSE, "another message"); > {code} > However, custom levels are not as easy to use as the built-in levels: one > needs to call the generic {{log()}} method and pass a {{Level}} parameter. > Built-in levels on the other hand have a set of convenience methods on the > Logger interface. For example, the Logger interface has 14 debug methods that > support the DEBUG level: > {code} > debug(Marker, Message) > debug(Marker, Message, Throwable) > debug(Marker, Object) > debug(Marker, Object, Throwable) > debug(Marker, String) > debug(Marker, String, Object...) > debug(Marker, String, Throwable) > debug(Message) > debug(Message, Throwable) > debug(Object) > debug(Object, Throwable) > debug(String) > debug(String, Object...) > debug(String, Throwable) > {code} > Similar method sets exist for the other built-in levels. > Several people have expressed the desire to have the same ease of use with > custom levels, so after declaring a custom VERBOSE level, we would like to be > able to use code like this: > {code} > logger.verbose("a verbose message"); // no need to pass the VERBOSE level as > a parameter > logger.verbose("another message"); > {code} > {anchor:Customizing} > *[#Customizing] the Logger interface* > In the above use case, convenience methods were _added_ to the Logger > interface, in addition to the existing {{trace()}}, {{debug()}}, {{info()}}, > ... methods for the built-in log levels. > There is another use case, Domain Specific Language loggers, where we want to > _replace_ the existing {{trace()}}, {{debug()}}, {{info()}}, ... methods with > all-custom methods. > For example, for medical devices we could have only {{critical()}}, > {{warning()}}, and {{advisory()}} methods. Another example could be a game > that has only {{defcon1()}}, {{defcon2()}}, and {{defcon3()}} levels. > Finally, if it were possible to hide existing log levels, users could > customize the Logger interface to match their requirements. Some people may > not want to have a {{FATAL}} or a {{TRACE}} level, for example. They would > like to be able to create a custom Logger that only has {{debug()}}, > {{info()}}, {{warn()}} and {{error()}} methods. > {anchor:wrapper} > *Proposal: Generate source code for a Logger [#wrapper]* > Common log4j usage is to get an instance of the {{Logger}} interface from the > {{LogManager}} and call the methods on this interface. This makes it hard to > achieve the above customization; especially taking away existing methods is > not possible. > An alternative is for the user to create a wrapper class that exposes only > the convenience methods for the desired log levels. When _extending_ the > {{Logger}} API (_adding_ methods), this wrapper class could subclass > {{org.apache.logging.log4j.spi.AbstractLoggerWrapper}}. When _customizing_ > the {{Logger}} API (_removing_ built-in methods), the wrapper class would > simply not extend AbstractLoggerWrapper, so the only public methods would be > the methods for the custom log levels. > As the custom log Levels are not known in advance, Log4J cannot provide > pre-built wrapper classes for these custom log Levels. However, we don't want > to ask the users to hand-code such a wrapper class: this is cumbersome and > error-prone: there are 14 methods for each built-in level. To provide > comparable functionality for custom log Levels one would need to provide 14 > methods for each custom log Level. > The proposal is to solve this by providing a tool that generates the source > code for a wrapper class. The user can specify: > * the fully qualified name of the class to generate > * the list of custom levels to support and their {{intLevel}} relative > strength > * whether to extend {{Logger}} (and keep the existing built-in methods) or > have only methods for the custom log levels > and the tool generates the source code for the wrapper class th