[slf4j-dev] Release of SLF4J version 1.6.0-RC0

Ceki Gülcü ceki at qos.ch
Fri Apr 30 15:15:37 CEST 2010


Should the lack of response to my LoggingEvent proposal be interpreted 
as approval or as resignation?

On 27/04/2010 1:04 PM, Ceki Gülcü wrote:
> Ralph,
>
> Thanks for sharing these different use cases. I agree with you that
> adding a throwable or a marker to a message does not necessarily make
> sense. And yes, we could do
>
> LogEvent event = new LogEvent(Level.ERROR,msg).addParam("p0").add(t);
> logger.log(event);
>
> I also understand that the point of the Message interface is to provide
> a bit more structure around the message, not encapsulate all the logging
> attributes such as the Marker, Level, etc into it.
>
> There are two distinct problems here. One is the encapsulation of
> various logging attributes (Marker, Level etc) and the other is the
> structure of messages.
>
> The encapsulation problem is important because I don't want to add 5x4
> new methods to the Logger interface multiplied by the 6 implementations.
> We can't just keep adding methods to the Logger interface. Hence the
> idea of LoggingEvent. Given that a Message is data point in
> LoggingEvent, you can still write:
>
> LoggingEvent event =
> new LoggingEvent(new AuditMessage("msg0", "type0"))).add(t);
> logger.error(event);
>
> or
>
> LoggingEvent event =
> new LoggingEvent(Level.ERROR,
> new AuditMessage("msg0", "type0"))).add(t);
> logger.error(event);
>
>
> On 27/04/2010 6:38 AM, Ralph Goers wrote:
>> Adding a throwable to an event with structured data makes no sense.
>> The throwable, or components of it, would be part of the structured
>> data. To do what you are suggesting you might as well do:
>>
>> LogEvent event = new LogEvent(Level.ERROR,
>> msg).addParam("parm1").addThrowable(t);
>> logger.log(event);
>>
>> The point of the Message interface is to provide a bit more structure
>> around the message, not encapsulate all the logging attributes such as
>> the Marker, Level, etc into it. For example, for auditing I can do:
>>
>> public class AuditMessage extends StructuredDataMessage {
>> public AuditMessage(String msg, String type) {
>> super("Audit at 12345", msg);
>> }
>> }
>>
>> public class LogiinMessage extends AuditMessage {
>> public LoginMessage(String userId) {
>> super("Login Succeeded", "Login");
>> put("userid", userid);
>> }
>> }
>>
>> For an Object such as a HashMap I could do:
>>
>> public HashMapMessage<K,V> implements Message {
>> private Map<K,V> map;
>>
>> public HashMapMessage(Map<K,V> map) {
>> this.map = map;
>> }
>>
>> public String getFormattedMessage() {
>> StringBuilder sb = new StringBuidler();
>> for (Map.Entry<K,V> entry : map.entrySet()) {
>> if (sb.size()> 0) {
>> insertPad(sb);
>> }
>> formatEntry(Map.Entry<K,V> entry, sb);
>> }
>> }
>> protected void insertPad(StringBuilder sb) {
>> sb.append(" ");
>> }
>> protected void formatEntry(Map.Entry<K,V> entry, StringBuilder sb) {
>> sb.append(entry.getKey()).append("="),append(entry.getValue());
>> }
>> }
>>
>> which now allows me to easily override this if I just want to change
>> how each entry is formatted.
>>
>> And so on.
>>
>> Ralph
>>
>> On Apr 26, 2010, at 1:08 PM, Ceki Gülcü wrote:
>>
>>>
>>> OK. Instead of passing a Message, one would pass an Event which would
>>> contain a Message as well as optionally other data.
>>>
>>> Example 1)
>>>
>>> Event event = new Event("hello {}").addParam("world").add(marker);
>>> logger.error(event);
>>>
>>> Example 2)
>>>
>>> Event event = new Event(structredData).add(throwable);
>>> logger.error(event);
>>>
>>>
>>> On 26/04/2010 3:38 PM, Ralph Goers wrote:
>>>> In general, I agree with Joern. The point of the Message interface
>>>> is to make it easy to create all different kinds of Messages. A
>>>> StructuredData message really has no good way to implement
>>>> addParam() or event addThrowable.
>>>>
>>>> Ralph
>>>>
>>>> On Apr 26, 2010, at 5:09 AM, Joern Huxhorn wrote:
>>>>
>>>>>
>>>>> On 26.04.2010, at 10:58, Ceki Gülcü wrote:
>>>>>
>>>>>> On 24/04/2010 3:55 PM, Joern Huxhorn wrote:
>>>>>>
>>>>>>> One of my goals in slf4j-n was to reduce the number of methods in
>>>>>>> the
>>>>>>> Logger interface.
>>>>>>> This was seemingly a bad idea since it would have a performance
>>>>>>> impact,
>>>>>>> in the case where a message isn't actually logged, as Ralph
>>>>>>> reported.
>>>>>>>
>>>>>>> Because of this, it would be very wise to keep all the methods
>>>>>>> that are
>>>>>>> already present in the Logger interface and simply add
>>>>>>> debug(Message)
>>>>>>> debug(Message, Throwable)
>>>>>>> debug(Marker, Message)
>>>>>>> debug(Marker, Message, Throwable)
>>>>>>> [same for other levels plus generic log(Level, ...)-methods]
>>>>>>>
>>>>>>> The designer in me doesn't like the "bloated" (in the sense that
>>>>>>> some
>>>>>>> methods could be dropped without losing functionality) interface,
>>>>>>> but
>>>>>>> the realist in me accepts that performance is more important than
>>>>>>> aesthetics ;)
>>>>>>
>>>>>> Can't we coalesce debug(Message), debug(Message, Throwable),
>>>>>> debug(Marker, Message) and debug(Marker, Message, Throwable) into
>>>>>> a single variant?
>>>>>>
>>>>>> Here is an idea:
>>>>>>
>>>>>> try {
>>>>>> ...
>>>>>> } catch(Throwable t) {
>>>>>> Message m = new
>>>>>> Message("hello{}").addParam("word").add(marker).add(t);
>>>>>> logger.error(m);
>>>>>> }
>>>>>>
>>>>>> This approach incurs the cost of creating and building the Message
>>>>>> object regardless of whether the request will be logged or not. I
>>>>>> suspect that the bulk of the cost is due to the object creation
>>>>>> incurred by new Message(...) and not due to the addition of extra
>>>>>> data incurred in calling addParam() and the other add() methods.
>>>>>> Thus, performance-wise we are in the same position as the original
>>>>>> Message proposal but now we can get rid of all the overloaded
>>>>>> variants dealing with Marker and throwable.
>>>>>>
>>>>>
>>>>> Well, the idea of the Message interface (!) was to enable lazy
>>>>> initialization (in contrast to a simply toString) without adding
>>>>> too many additional requirements to it.
>>>>>
>>>>> http://github.com/huxi/slf4j/blob/slf4j-redesign/slf4j-n-api/src/main/java/org/slf4j/core/Message.java
>>>>>
>>>>>
>>>>> It would be much more work to implement a custom Message with the
>>>>> suggestion above. More work implies more chances of faulty
>>>>> implementation, for example in case of Marker support. The
>>>>> addParam() method would be quite a mistake, too, since a different
>>>>> implementation of Message might use key/value-pairs as parameters.
>>>>> (This is something that I'd really like to do since it would also
>>>>> enable easier translations)
>>>>>
>>>>> I see that interface as the main extension point of SLF4J& Logback.
>>>>> The Message instance is supposed to end up in the appenders in case
>>>>> of Logback, so custom appenders could handle custom Message
>>>>> implementations in arbitrary ways without having to parse anything.
>>>>>
>>>>> We could, however, add the Throwable to the Message interface. I
>>>>> left it out of the interface and added it only to the
>>>>> ParameterizedMessage implementation to keep the interface as clean
>>>>> as possible.
>>>>>
>>>>> This would reduce the interface to debug(Message) and debug(Marker,
>>>>> Message), at least.
>>>>>
>>>>> How about
>>>>>
>>>>> interface Message
>>>>> {
>>>>> Message set(Throwable); // instead of setThrowable to be more concise?
>>>>> Throwable getThrowable();
>>>>> }
>>>>>
>>>>> in addition?
>>>>>
>>>>> My problem is: I'm not really sure if I'll like this while using it ;)
>>>>> Regardless of the way we'll implement it in the Message, it will
>>>>> always be less concise (concerning both brevity and readability)
>>>>> than code using the four methods...
>>>>>
>>>>> Joern.



More information about the slf4j-dev mailing list