Jump to content

Architecture Question for Observer Pattern


Recommended Posts

Ok, so here goes.

Basically I have set up an observer pattern and I have a few questions about how I should handle a few things, most notably logging.

Here's how my pattern basically works.

I have a variety of independant processes running. Each one has it's own Message Interface Object. Through the Message Interface Object (really just a sophisticated queue based system with a "global" registry) it can send any messages that are descendants of "Message Parent". When any message is sent, the parent class captures the sending process and a time stamp and then sends it out to whoever is registered for it. I also have a hook so that any child class cna execute a specific piece of code right before the message is sent for error-checking or whatever. So any process can send any message and then it can also register to recieve specific messages. I also worked in an inheritance scheme, so if you register for a particular class you get all its children as well. One of the main design considerations though is that is a broadcast type system. That means when a process sends a message, it doesn't care if it gets a response or if anyone is listening. The only time it cares is when it is waiting to recieve a message. Even then it shouldn't care who sends it, it should just care about the message itself.

So far I have the messaging scheme all worked out as far as sending and recieving messages. I'm trying to build a nice demo program to demonstrate it (I don't have an actual project to use this on at the moment).

So I have nice debugging tool that is registered for the parent class, so it recieves every message that is sent out and it pulls out the timestamp and sending process etc. And I have a few dummy processes just sending data out.

Now I'm trying to work on a logger. Something that would run in the background and just log important events. I'd like to make it as generic as possible, but I also want to have my other modules not care about the logger (ie. I don't like the idea of them determining what gets logged.) My question is what is the best way to log things? I guess my real question is whose responsibility should it be to determine what text gets logged?

As I see it I have 3 options:

1. Add a logtext field to the parent class and allow children to update it. Then when a child can update that when its private data is changed. In this case the responsibility would belong to each message child class.

2. Add a loggable message class and have it contain a logtext field, which its children can update. This is nice because then I can just register my logger for the loggable message parent class and get all loggable messages.

3. Have the logger itself determine what text to put in the file for each type of message. I think I am ok with this. My main concern is that the sending process be unaware of what is out there. THe recieving process kind of has to know what's out there or what to expect, or do I have this all wrong?

Anybody have any thoughts?

Link to comment

Why not have the parent message class implement a dynamic method that logs some default information. Override methods can override/extend/extinguish as needed?

I've done a few variants of this. Some parent method defines an interface, maybe it's supplied with a byte stream refnum, maybe it's as simple as providing a ToString() method that returns a log friendly form of the object. Regardless of the exact interface, the parent method ultimately logs some basics such as the timestamp, fully qualified class name, whatever is relevant. Some extending classes override this with other information entirely, other implementations call the parent then concatenate extra information, and others in turn override the method only to not do anything and therefore keep the messages entirely silent from a log perspective.

This model of course depends on the message itself being able to define what needs to be logged and what doesn't, which is what I think you mean by your modules being unaware? That is the observer doesn't decide what gets logged, and the signalling process doesn't have direct control over the logs, except by virtue of what messages it sends.

Link to comment

Why not have the parent message class implement a dynamic method that logs some default information. Override methods can override/extend/extinguish as needed?

I've done a few variants of this. Some parent method defines an interface, maybe it's supplied with a byte stream refnum, maybe it's as simple as providing a ToString() method that returns a log friendly form of the object. Regardless of the exact interface, the parent method ultimately logs some basics such as the timestamp, fully qualified class name, whatever is relevant. Some extending classes override this with other information entirely, other implementations call the parent then concatenate extra information, and others in turn override the method only to not do anything and therefore keep the messages entirely silent from a log perspective.

This model of course depends on the message itself being able to define what needs to be logged and what doesn't, which is what I think you mean by your modules being unaware? That is the observer doesn't decide what gets logged, and the signalling process doesn't have direct control over the logs, except by virtue of what messages it sends.

That was my initial though.

I had some misgivings and things got a little hazy when I started thinking about who was responsible for what.

But I think that idea might work after all.

Link to comment

Now I'm trying to work on a logger. Something that would run in the background and just log important events. I'd like to make it as generic as possible, but I also want to have my other modules not care about the logger (ie. I don't like the idea of them determining what gets logged.) My question is what is the best way to log things? I guess my real question is whose responsibility should it be to determine what text gets logged?

First, since you want to make this a generic messaging framework, I assume you're planning on adding it to your reuse library. Second, I know you mean "which bit of code should define the log text," but let's take a step back and read it a bit differently. Which developer--the library designer or the library user--should define what messages and text are logged? To me the answer is clearly the library user. (Maybe the user wants to log message data along with the message name... maybe the message contains a queue and the user wants to log the number of items on the queue... the possibilities are endless.) What part of the system is customized by the user on a per-application basis? If I'm understanding your system correctly, it's the messages. Therefore, the decision about what text to log should be left up to each message--option 1 from your list.

As I see it I have 3 options:

1. Add a logtext field to the parent class and allow children to update it. Then when a child can update that when its private data is changed. In this case the responsibility would belong to each message child class.

2. Add a loggable message class and have it contain a logtext field, which its children can update. This is nice because then I can just register my logger for the loggable message parent class and get all loggable messages.

3. Have the logger itself determine what text to put in the file for each type of message. I think I am ok with this. My main concern is that the sending process be unaware of what is out there. THe recieving process kind of has to know what's out there or what to expect, or do I have this all wrong?

What if I want the log file in xml format instead of text format? What if I need the log file stored on a server instead of the local computer? What if I just want the log messages to appear in a window instead of on disk? In other words, how can I, as the user, change the logger behavior without editing the distributed reuse code?

4. Create an abstract MessageLogger class that can be injected into the Message Interface Object by the library user. If no MessageLogger is injected, no messages are logged and you don't suffer any performance penalties. You can supply a simple text file logger with the distribution. If users need different behavior, they can create their own MessageLogger child class that does exactly what they want it to do and inject it into the Message Interface Object.

Link to comment

First, since you want to make this a generic messaging framework, I assume you're planning on adding it to your reuse library. Second, I know you mean "which bit of code should define the log text," but let's take a step back and read it a bit differently. Which developer--the library designer or the library user--should define what messages and text are logged? To me the answer is clearly the library user. (Maybe the user wants to log message data along with the message name... maybe the message contains a queue and the user wants to log the number of items on the queue... the possibilities are endless.) What part of the system is customized by the user on a per-application basis? If I'm understanding your system correctly, it's the messages. Therefore, the decision about what text to log should be left up to each message--option 1 from your list.

What if I want the log file in xml format instead of text format? What if I need the log file stored on a server instead of the local computer? What if I just want the log messages to appear in a window instead of on disk? In other words, how can I, as the user, change the logger behavior without editing the distributed reuse code?

4. Create an abstract MessageLogger class that can be injected into the Message Interface Object by the library user. If no MessageLogger is injected, no messages are logged and you don't suffer any performance penalties. You can supply a simple text file logger with the distribution. If users need different behavior, they can create their own MessageLogger child class that does exactly what they want it to do and inject it into the Message Interface Object.

Those are some good thoughts.

I really like #4, although I'm not entirely sure if that fits into my paradigm.

If I was going to do something like that I would like some way to implement it "globally" within a specific application, rather than having each process specify which Logger to use. I already have a "Master Table" that records what process is registered for what messages. Perhaps I just define the logger there.

Which developer--the library designer or the library user--should define what messages and text are logged?

Obviously I am thinking the end-user (who in this case happens to be me as well). My end goal is to develop a framework where when I start a new project I can just grab a copy of this framework and I already have certain tools built in (ie. I already have a debugging window that lets me view who is registered for what message, and I can view all the message traffic.) I'm trying to include some kind of logging and basic error handling in that. Then I can take that basic library and I can start building my application from there. Obviously I should be able to customize the logger or error handler, etc. as needed, but I'm hoping that I can design something that will cover 90% of my uses cases.

Right now I've got the messaging framework built up pretty well and I'm very happy with it. It's just a matter now of how to extend it.

I'm kind of new to this whole object oriented thing. I'm just trying to make sure I get the design right.

Also I was kind of thinking of the logger as more of a template.

When you get a new copy of the framework, you get a copy of this logger and then you edit it to suit the needs of your specific application. In most cases it would already do 90% of what you need.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.