[slf4j-dev] Re: TRACE level
Greg Wilkins
gregw at mortbay.com
Tue Jul 5 16:43:10 CEST 2005
Ceki,
I'm a bit both ways about the marker mechanism.
On one level I see that it is cool and flexible - I specially like the nested
marker bit. Markers are a bit like log levels - except a hierarchical name
space is easier to manage than a numeric space.
But then I see some problems....
Firstly - I can see how it applies to debug, but I don't think it
applies well to info, warn, error, etc.
I would never say:
logger.warn(HEADER,"msg",e);
So do markers only apply to debug?
This is the same problem with nested loggers. I want a multiple levels
of debug - but I have no use-case for multiple levels of warn, info etc.
Markers seam a little heavy weight just to have multiple levels between
info and nothing.
Also it is important to be able to do:
if (logger.isDebugEnabled(HEADER))
{
logger.debug(HEADER, "Headers follow.");
for(int i = 0; i < header.length; i++)
logger.debug(HEADER, "{}: {}", header[i].getName(), header[i].getValue());
}
But I'm not clear if that will be possible?
Also I do like the simplicity and clarity of
try
{
Object answer = theQuestion();
log.debug("got the answer.");
log.verbose("answer = {}",answer);
}
catch(Exception e)
{
log.ignore(e);
}
It is not quiet the same to have
class LogSupport
{
static final String IGNORED_MSG="Ignored {}";
static final String IGNORED="Ignored";
static final Marker STACK_TRACE=Marker.getMarker("stack trace");
static final Marker VERBOSE=Marker.getMarker("verbose");
}
and then do
try
{
Object answer = theQuestion();
log.debug("got the answer.");
log.debug(LogSupport.VERBOSE,"answer = {}",answer);
}
catch(Exception e)
{
log.debug(LogSupport.IGNORED_MSG,e.toString());
log.debug(LogSupport.STACK_TRACE,LogSupport.IGNORED,e);
}
Ceki Gülcü wrote:
> Greg, thank you for your input.
>
> In response to the discussions here and previously identified use
> cases, I've just committed the Marker, StarMarker and CompositeMarker
> classes to the experimental branch [1] of SLF4J. A Marker is
> basically a name. Here is a basic (simplified) implementation.
>
> package org.slf4j;
>
> public class Marker {
>
> static Map markerMap = new Hashtable();
> String name;
>
> private Marker(String name) {
> this.name = name;
> }
>
> public static final Marker getMarker(String name) {
> if (name == null) {
> throw new IllegalArgumentException("Marker name cannot be null");
> }
>
> Marker marker = (Marker) markerMap.get(name);
> if (marker == null) {
> marker = new Marker(name);
> markerMap.put(name, marker);
> }
>
> return marker;
> }
>
> public String getName() {
> return name;
> }
>
> public boolean matches(Marker marker) {
> if ((this == marker)) {
> return true;
> }
>
> return false;
> }
>
> public boolean matches(String name) {
> if (this.name.equals(name)) {
> return true;
> }
> return false;
> }
> }
>
>
> Markers allow log statements to be marked in user-chosen ways.
>
> For example, for the HttpRequest class you mentioned, we can now
> write:
>
>
> package org.mortbay.jetty;
>
> import org.slf4j.Marker;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
>
> class HttpRequest {
>
> Logger logger = LoggerFactory.getLogger(HttpRequest.class);
>
> static final Marker HEADER = Marker.getMarker("header");
>
> void doRequest() {
> logger.debug("Request URI is {}", uri);
>
> logger.debug(HEADER, "Headers follow.");
> for(int i = 0; i < header.length; i++) {
> logger.debug(HEADER, "{}: {}", header[i].getName(),
> header[i].getValue());
> }
>
> ... do real work
> }
> }
>
> If the org.mortbay.jetty.HttpRequest is enabled for the DEBUG level,
> than all log statements in doRequest() will be printed. However, the
> user can chose to instruct the logging system to those disable log
> statements of level DEBUG marked with the HEADER marker.
>
> This approach has the advantage of allowing multiple markings to
> co-exist without interference. Nothing prevents the developer from
> writing log statements with different markings.
>
> As for the ignore() method, the logging system can be instructed to
> ignore the stack traces for a given exception using a special
> marking. For example,
>
> try {
> access some IOStream
> } catch(IOException e) {
> logger.debug(NO_STACK_TRACE, "Exception while talking to peer", e);
> }
>
>
> One of challenges in the design is to allow for markers to contain child
> markers. For example,
>
> Marker blue = Marker.getMarker("blue");
> Marker red = Marker.getMarker("red");
> Marker colors = Marker.getCompositeMarker("colors");
> colors.add(blue);
> colors.add(red);
>
> blue.matches("blue"); // this is true
> red.matches("red"); // also true
> red.matches("blue"); // false
> colors.matches("colors"); // true
> colors.matches("red"); // also true
> colors.matches("blue"); // true
>
>
> I am tempted to use the Composite pattern from the Go4 book although it
> is not totally clear whether the pattern could be judiciously applied
> here.
>
> In the HttpRequest example above, some headers could be marked with an
> additional marker, say IMPORTANT_HEADER. Thus, the user could chose
> between printing all headers, no headers, or only important headers.
>
>
> So, wdyt?
>
> [1] http://svn.slf4j.org/viewcvs/slf4j/branches/marker-experiment/
>
> At 12:44 AM 7/3/2005, Greg Wilkins wrote:
>
>> Ceki Gülcü wrote:
>>
>> > <request>
>> >
>> > Can anyone think of a class which makes uses of both trace() and
>> > debug()? If so, could you please provide a URL?
>> >
>> > </request>
>>
>> The use case I have for trace (or I prefer to call it verbose) is
>> the case when I have an object that I wish to log, but that I have
>> a choice of the amount of detail that can be logged.
>>
>> Examples include:
>>
>> HttpRequest: log just the method and URI or all the headers.
>> Document: log just the URI of the document or dump all of the XML.
>>
>> I see this as quiet related to ignore, where the developer has
>> an exception object to log, but has to choose between clogging the
>> log with excess information or hiding something valuable.
>>
>> With the case of ignore, the developer has a clear intent that
>> can be signalled in the signature - to assist a later decision on
>> how much detail to display. This can be done because the
>> logging system has the ability to expand the Exception statck trace or
>> just call toString on it.
>>
>> With other objects, the logging system will only call toString on
>> them, so if the developer wants to report an object in detail then
>> they must do so explicitly - it would be good if they could protect
>> that with an if(log.isVerboseEnabled()) or an if(log.isTraceEnabled())
>>
>> But then another solution would be to have a logger that supports
>> customizable object formatters....
>>
>> cheers
>
>
More information about the slf4j-dev
mailing list