Hi,


On Wed, Jun 18, 2014 at 12:20 PM, Norbert Hartl <norbert@hartl.name> wrote:
Sven,
Am 18.06.2014 um 11:15 schrieb Sven Van Caekenberghe <sven@stfx.eu>:

> Hi,
>
> I think we are all pretty much on the same page with how we think logging has to be done. In any case, here is the code (one, 1, line of code) that connects ZnLogEvent with either SystemLogger or Beacon - provided I understood everything correctly.
>
> ZnLogEvent announcer
> �� �� �� when: ZnLogEvent
> �� �� �� do: [ :each | BasicLog message: each ]
> �� �� �� for: #systemLogger.
>
You can do that. I���d prefer using ���each asLog��� instead of ���BasicLog message: each���. This way each can specify its desired wrapper class.

I like it that each Object can define its log event representation. In Beacon I have the same (asBeaconSignal), but I did not really considered the idea of using it for having other types of events choose the type of log events.

��
> ZnLogEvent announcer
> �� �� �� when: ZnLogEvent
> �� �� �� do: [ :each | WrapperSignal log: each ]
> �� �� �� for: #beacon.
>
> Now this is using a wrapper object, BasicLog and WrapperSignal respectively. It even seems to work without the wrapping as well.
>
> ZnLogEvent announcer
> �� �� �� when: ZnLogEvent
> �� �� �� do: [ :each | LogDispatcher current addLog: each ]
> �� �� �� for: #systemLogger.
>
> ZnLogEvent announcer
> �� �� �� when: ZnLogEvent
> �� �� �� do: [ :each | Beacon announce: each ]
> �� �� �� for: #beacon.
>
> Question is, is the wrapping needed ? For the implementation or for the user ? Right now, only a timestamp is added. As I indicated before, I don't think that even 'forcing' a particular timestamp is a good idea. Here is my reasoning.

The wrapping does two things. It adds additional state to form a log object and it adds the behaviour for simplifying the use of a log object (e.g. have a look at BasicLog>>#emit) . To me the timestamp in a log is mandatory. That is IMHO what it makes a log.


I agree that we should decide on a way to specify time. I also find it to be essential to the logging domain. I like the timestamp proposal. See below.

��
Without I would call it ���an object���.

Actually, I would call it an announcement because I consider logging to made of two things:
- announcing the event
- at a given moment in time

��
> Log events arrive in a certain order and that order should be maintained. Making log events sortable could be nice to have, but it is not 100% necessary. The same goes for uniquely identifying log events, nice to have but not necessary.

I was intrigued by this the first time Sven mentioned this, but I made peace with it in the meantime :).��
��

> A timestamp might seem like a good idea for both properties, but it is not.

I agree that the timestamp is not for ordering, but for managing time. Of course, we could see time as being relative, which in distributed systems makes even more sense, but log events are events in time, but I still consider that a time representation is an essential thing in this domain. I think the only disagreement is on how to model time (see below).

��
Consider:
>
> (Array streamContents: [ :set | 1000 timesRepeat: [ set nextPut: DateAndTime now ] ]) asSet.
>
> The set will contain only a couple of instances. And this is for the most precise timing that we currently have. It is also easy to think of alternatives for DateAndTime that some people might prefer: just Time, seconds, micro or milliseconds since a reference, ZTimestamp (which I use in other code), some class from Chronos, whatever. Features, abstraction, performance, precision, memory consumption are all different.

Agreed.

��
I don���t see a problem here. The timestamp is either a visual help here or if it is more important you need to make sure the precision does cope with your use case. A timestamp might be just a grouping thing to focus more easy on the entries of interest. I���m not sure it is definable for all use cases. If the order is important than we need to make sure the order is preserved. To pull out an edge case to proof it is of no value is nothing I can submit to.

That is indeed an interesting point of view, see below.

��
> But regardless of clock precision, I think an id is useful as a secondary sort or identity criterium, just in case. But again, I would not require it.
>
That is a good point. In the beginning there was only one Log class. It contained all the stuff like levels, tag and such. That is understandable because logging is done this way (expected by people) usually and we need to break free from that (what we do at the moment by introducing object oriented logging). In my mission to break free from (sys)log I divided the class in BasicLog and Log. BasicLog is what makes a Log: an object and a timestamp. The Log class resembles the other fields like level etc. You can argue that level, tag etc are not needed but a lot of people will need them so why not support them?
What if you don���t need level, tag etc. but you want to have an id and use another class for timestamp? That���s easy just subclass BasicLog, add an id instVar, initialize timestamp with your own class and then overwrite your business objects class side method logClass to return your own decorating class. That���s how we always do it, right? And still you could use the stuff from the workspace by doing

(SpecialEvent new
�� �� �� �� foo: ���bar���;
�� �� �� �� id: 10000 atRandom) asLog emit

> On the other hand, we need common protocol. What about the following: each log event object should implement #timestamp, which has to return a Magnitude compatible object so that increasing values conform with the order of the events (but not necessarily vice versa).

That���s basically how it is. We should define the protocol the logger needs internally. If there needs to be some access to #timestamp it is part of the interface. So that way we expect an log event object to respond to #timestamp. And the BasicLog is a wrapper that has a default implementation for it. I don���t understand what we need to define except the interface that is needed which is obvious?
So let���s take the three use cases: subclassing, wrapping and forced duck typing. If it works I would support all of them because people have different ideas how things should work. If that is too much we need to choose. I personally don���t like to have to subclass a framework class because I���d like to preserve the inheritance chain for my own stuff.

I think that this does not apply well here. I think that what applies for Exceptions and Announcements applies for logging as well. Subclassing makes sense there, and I think it makes sense here, too. You will be unlikely to want to mix events with your domain.
��
I also ��don���t like forced duck typing because a framework that forces me to implement a method in every class I want to log is cumbersome to me.

I agree as well.
��
So I like wrapping the most because I can add log specific stuff to any object and by being able to supply a wrapping class I���m free to adapt any object to be a log compatible object.

I would not favor wrapping.

Doru
��

Norbert







--
www.tudorgirba.com

"Every thing has its own flow"