On 08.09.2011, at 21:11, John Vasileff wrote:

> I put together the following examples to help net out benefits of supporting 
> "Map supplementalData" arguments in Logger methods in addition to Message 
> object support.
> 
> Support for supplementalData does not replace Message objects, but is perhaps 
> more of a shortcut for common usage scenarios.  In the end, a Message object 
> is always created by either the application writer or SLF4J.
> 
> 
> Scenario #1: Working with a domain object "posting" that implements 
> java.util.Map.  A 1.6.2 error log may look like:
> 
> logger.error("error parsing markdown '{}'", badString, e);
> 
> but we want to add all details of the "posting" domain object without 
> including them in the message.  Using the supplementalData log methods:
> 
> // just add the data
> Logger logger = LoggerFactory.getLogger(MyClass.class);
> logger.error(posting, "error parsing markdown '{}'", badString, e);
> 
> // add the data, but also allow named parameter formatting
> Logger logger = 
> LoggerFactory.getLogger(MyClass.class).formatWith(NamedParamFormatter.getInstance());
> logger.error(posting, "error parsing markdown for posting {id} '{}'", 
> badString, e);
> 
> // just add the data, and format using java.util.formatter
> Logger logger = 
> LoggerFactory.getLogger(MyClass.class).formatWith(JavaUtilFormatter.getInstance());
> logger.error(posting, "error parsing markdown '%s'", badString, e);

One huge problem with this approach is that Logger, for a given name/class, has 
to be a singleton. You absolutely must not change its state, otherwise chaos 
will happen.

I'll give you just one example:
Suppose ThreadA is changing the Logger with formatWith. Then, before ThreadA 
executes its log statement, ThreadB is changing the same instance with a 
different formatWith call. This will cause ThreadA to log with a wrong 
formatting. A mutable Logger would automatically make it non-threadsafe.

I firmly believe that default formatting must not be configurable. Doing so 
would just introduce a big pile of problems.

> 
> If we used Message objects:
> 
> Logger logger = LoggerFactory.getLogger(MyClass.class);
> 
> // just add the data
> logger.error(new DefaultMessage(posting, "error parsing markdown '{}'", 
> badString, e));
> 
> // add the data, but also allow named parameter formatting
> logger.error(new NamedParamFormattingMessage(posting, "error parsing markdown 
> for posting {id} {}", badString, e));
> 
> // just add the data, and format using java.util.formatter
> logger.error(new JavaUtilFormatterMessage(posting, "error parsing markdown 
> for posting %s", badString, e));
> 
> 
> Scenario #2: Support for StructuredData.  The StructuredData object may 
> augment a log message, or both augment the message and provide the message 
> with toString().
> 
> Using SupplementalData methods, where SD implements Map
> 
> StructuredData sd = new StructuredData(...);
> logger.error(sd);
> logger.error(sd, "some log message"); 
> 
> Using Message object methods, where SD implements Message
> 
> StructuredData sd = new StructuredDataMessage(...);
> logger.error(sd);
> StructuredData sd = new StructuredDataMessage(..., "some log message");
> logger.error(sd);
> 

The idea was to put both the internal structure and the formatting in the 
respective Message implementation, with ParameterizedMessage being the 
implementation for the default SLF4J formatting. A shortcut exists for this 
type of messages, namely the foo(String pattern, Object... args) methods, since 
this is the message type encouraged by the logging framework.

It is encouraged since it is a perfect mix of features (placeholder 
replacement) and speed (it is *much* faster than JUL and likely faster than 
most other implementation). It is also the type of formatting already 
documented by the API and accepted by its users.

The 99% of the users will just keep on using the "normal" logging methods and 
ignore the newly defined ones. This is the main target we are developing for.

The foo(Message message) type of methods, however, enable the 1% "pro users" to 
implement specific features they need - and the logging framework will be able 
to (optionally, you could filter on the Message class) cope with those 
arbitrary Message types in a default way or implement specialized handling if 
that is required.

Take the StructuredDataMessage ( http://bugzilla.slf4j.org/show_bug.cgi?id=148 
) as an example. It does not just define a Message with key-value pairs in a 
Map<String, String>. Instead, it is more specific. It is used to create 
messages that conform to ( http://tools.ietf.org/html/rfc5424 ). This involves 
making sure that the keys must have a maximum length of 32 characters. Such a 
requirement can't be met by the abstract logging interface. It is an 
implementation detail of RFC5424 Syslog messages.
In addition to the Map<String, String>, such a StructuredDataMessage could 
implement the whole range of the specification, e.g. it could bypass the normal 
logging levels and make use of the Syslog severities instead.

One should not forget that someone implementing his own message type could also 
define a wrapper around the SLF4J Logger to support efficient creation of his 
handcrafted Messages. A special SyslogLogger implementation could automatically 
match the Syslog severity to a proper SLF4J level, for example, while still 
using the whole logging backend without any wheel-reinvention.

Another example for specific needs would be end-user-facing localized messages. 
Why should I reinvent my own logging layer if I could just use SLF4J/<insert 
backend here> for that?

Audit logging is another use case.
See http://audit.qos.ch/manual/index.html and 
http://audit.qos.ch/apidocs/ch/qos/logback/audit/AuditEvent.html 
This could be implemented using a AuditMessage instead while still being able 
to use the full range of Logback-Classic appenders but with the ability to add 
specific appenders handcrafted for specific tasks like writing them into a 
special audit database.

One small, additional thing is the possibility of immutable Message instances 
that could be kept and reused if there are no variables involved.

Concerning "COMPATIBILITY #1" in your previous message:
It is absolutely crucial that the original interface is left unchanged so that 
both use and implementations of that interface will keep on working as 
expected. It also needs to stay 1.4 compatible and logging frameworks that do 
not require 1.5 should still just implement the old SLF4J interface. The new 
interfaces will be available automatically via wrapper in that case.

If the logging implementation requires Java >= 1.5 anyway (e.g. Logback) then 
it would be a good idea to implement the new interface instead, providing 
backwards-compatibility by means of a wrapper in the other direction.

Concerning your Entry interface:
The main idea of the very minimal Message interface is the absolute freedom it 
gives to the developer. A message does not have to have a pattern and 
parameters. Why should it? And why should I create an abstract base-class that 
returns null for all methods that are not applicable to that specific 
message/entry type? Isn't that enough evidence that the interface would be too 
specific?
I did consider to add Throwable to the Message interface but ultimately decided 
against it for exactly that reason. It just doesn't make sense for every type 
of message imaginable.
I'm also not a big fan of including either MDC or NDC in the Message since 
those belong to the LoggingEvent, similarly to the call-stack or the timestamp 
of the event. Neither of them are visible at the SLF4J interface level.

To finish this wall of text:
I can not stress enough that the Message interface would enable us to *filter* 
on the specific type of Message in the logging configuration and/or appender 
implementation. Granted, a better place for this argument would be the Logback 
mailing list but it IS a major feature and does indeed open a huge door of 
possibilities for future enhancements, all without touching the logging 
interfaces again.

Joern
_______________________________________________
slf4j-dev mailing list
[email protected]
http://qos.ch/mailman/listinfo/slf4j-dev

Reply via email to