[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