You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by "Remko Popma (JIRA)" <ji...@apache.org> on 2014/07/02 17:26:25 UTC

[jira] [Issue Comment Deleted] (LOG4J2-519) Custom/Extended Loggers

     [ https://issues.apache.org/jira/browse/LOG4J2-519?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Remko Popma updated LOG4J2-519:
-------------------------------

    Comment: was deleted

(was: 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);%n" //
            + "    }%n" //
            + "%n" //
            + "    /**%n" //
            + "     * Logs the specified Message at the {@code CUSTOM_LEVEL} level.%n" //
            + "     * %n" //
            + "     * @param msg the message string to be logged%n" //
            + "     */%n" //
            + "    public void methodName(final Message msg) {%n" //
            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msg, (Throwable) null);%n" //
            + "    }%n" //
            + "%n" //
            + "    /**%n" //
            + "     * Logs the specified Message at the {@code CUSTOM_LEVEL} level.%n" //
            + "     * %n" //
            + "     * @param msg the message string to be logged%n" //
            + "     * @param t A Throwable or null.%n" //
            + "     */%n" //
            + "    public void methodName(final Message msg, final Throwable t) {%n" //
            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msg, t);%n" //
            + "    }%n" //
            + "%n" //
            + "    /**%n" //
            + "     * Logs a message object with the {@code CUSTOM_LEVEL} level.%n" //
            + "     * %n" //
            + "     * @param message the message object to log.%n" //
            + "     */%n" //
            + "    public void methodName(final Object message) {%n" //
            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, 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 message the message to log.%n" //
            + "     * @param t the exception to log, including its stack trace.%n" //
            + "     */%n" //
            + "    public void methodName(final Object message, final Throwable t) {%n" //
            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, t);%n" //
            + "    }%n" //
            + "%n" //
            + "    /**%n" //
            + "     * Logs a message object with the {@code CUSTOM_LEVEL} level.%n" //
            + "     * %n" //
            + "     * @param message the message object to log.%n" //
            + "     */%n" //
            + "    public void methodName(final String message) {%n" //
            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, (Throwable) null);%n" //
            + "    }%n" //
            + "%n" //
            + "    /**%n" //
            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n" //
            + "     * %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 String message, final Object... params) {%n" //
            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, 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 message the message to log.%n" //
            + "     * @param t the exception to log, including its stack trace.%n" //
            + "     */%n" //
            + "    public void methodName(final String message, final Throwable t) {%n" //
            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, t);%n" //
            + "    }%n" //
    ;
{code})

> 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. 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. Users would include this source code in the project where they want to use custom log levels.
> {anchor:GeneratedWrapperUsage}
> Note that no Log4J API changes are required to support this functionality.
> Users would create instances of the wrapper by calling a factory method on the wrapper class, instead of calling the {{LogManager.getLogger()}} methods.
> For example, instead of writing:
> {code}
> import org.apache.logging.log4j.Level;
> import org.apache.logging.log4j.LogManager;
> import org.apache.logging.log4j.Logger;
> final Logger logger = LogManager.getLogger(MyClass.class); // standard log4j logger
> final Level VERBOSE = Level.forName("VERBOSE", 550);
> logger.log(VERBOSE, "a verbose message");
> {code}
> users would instead write:
> {code}
> // MyLogger is a generated customized logger wrapper
> import com.mycompany.myproject.MyLogger;
> final MyLogger logger = MyLogger.create(MyClass.class);
> logger.verbose("a verbose message");
> {code}
> Creating an extended or customized Logger is as easy as creating a standard Logger (one line of code). Extended Loggers are drop-in replacements for standard Loggers - they only add more convenience methods.



--
This message was sent by Atlassian JIRA
(v6.2#6252)

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org