I'm refactoring a large application and have the following problem :
The application consists of minimally 6 and maximally 40 VB DLLs (and
OCXes). This is because the is a main application which dynamically loads
subsystems (country-specific payment modules). If only one subsystem is
installed, the application will load only that subsystem. If more are
installed on the PC, other subsystems will get loaded as well. This
explains the strange DLL numbers.
All subsystems, as well as the main application, share references to 6
common DLLs. There are six because of practical problems (less would mean a
+4Mb DLL, more would mean more possible update problems). Now all
subsystems and the main application, as well as shared services inside the
system DLL, need to log once in a while. Since this is a huge application
logging tends to be a reliable means to 'debug' problems detected on client
installations.
The question I have is what you think of my approach for logging, which I'll
explain below.
Since there are many ways to log, I decided to capture a logservice
functionality inside an interface (this is VB, but the problem is in fact
language -independent):
interface iTBXLogService
Public Enum eLogType
eltFirstLogType = 1
eltFatalError = 1
eltError = 2
eltWarning = 3
eltHint = 4
eltLastLogType = 4
End Enum
Public Sub LogString(ByVal eType As eLogType, _
ByVal strModuleName As String, _
ByVal strMessage As String)
End Sub
Now for this there a some basic implementations : FileLogger, NTLogLogger,
MsgBoxLogger, FilteredLogger, TreeViewLogger, TextBoxLogger...
There is one logger (NoLogger) that implements the NullObject design pattern
(do nothing but fully implement the interface) and another (MultiLogger),
which implements a Composite for Loggers (Log to multiple loggers at once).
Now this is tedious to use :
CreateFileLogger ("mylog.txt").LogString eltWarning,
"WvddCore.Sorting.clsSortableCollection.Get Item", "Index out of bounds"
Since a logger is used in many, many places, it makes sense to define a
Singleton to access THE logger. The main application sets up THE logger,
and all clients use it.
The client code becomes slightly easier :
LogServiceSingleton.LogString eltWarning,
"WvddCore.Sorting.clsSortableCollection.Get Item", "Index out of bounds"
There are now two global methods (in a Global multi use in VB, public class
methods in most other languages)
public function LogServiceSingleton as iTBXLogservice
public sub setLogServiceSingleton (byval objNew as iTBXLogservice)
There is one catch : if you want to log before the global logger is
installed (at startup) then there is a possibility of an uninitialized
singleton. We solve this by returning a MsgBoxLogger if there is no logger
installed. That way, at least the message doesn't disappear and the user
can say something when he reports a problem.
Now since a logservice is called a lot, I decided to put a facade on top of
it.
I defined the following global routines :
Sub LogFatalError (ByVal strModuleName As String, ByVal strMessage As
String)
...
Sub LogHint(ByVal strModuleName As String, ByVal strMessage As String)
They all work on the singleton and make client logging easy :
LogWarning, "WvddCore.Sorting.clsSortableCollection.Get Item", "Index out of
bounds"
Now what is your opinion on this. What else do I need for a LogService ?
Is the design sound ? How did YOU do it ?
Thanks in advance
--
Van den Driessche Willy
07-06-2001, 08:37 AM
Thomas Eyde
Re: Logging
Nice work, I learned something new here. I have two suggestions:
1. Why do you ask us for more? You do know your logging needs, don't you?
Why invent more than you need?
2. If practical, why not use a module as your facade/singleton? If you
prefix the methods with the module name, it looks like you're using an
object. The benefit is that a module is always there.
/Thomas
07-09-2001, 02:47 AM
Willy Van den Driessche
Re: Logging
"Thomas Eyde" <thomas.eyde@eunet.no> wrote in message
news:3b48cd95@news.devx.com...
> Nice work, I learned something new here. I have two suggestions:
>
> 1. Why do you ask us for more? You do know your logging needs, don't you?
> Why invent more than you need?
You have a very good point there. I am hoping to create a 'final' component
for something as 'simple' as logging. It always pays off to listen to
others, so that's why I launched the question in the first place.
>
> 2. If practical, why not use a module as your facade/singleton? If you
> prefix the methods with the module name, it looks like you're using an
> object. The benefit is that a module is always there.
The logging component will go inside a separate ActiveX DLL. (The idea is
to reuse it for other projects). The façade and singleton are allready in a
module. The problem however is that I need a GlobalMultiUse class to be
able to export this functionality out of the DLL. The GMU class just calls
the methods inside the module. I always use this module/GMU approach,
because it let's me move my components between DLLs. That is to say : in
one project this component will go by itself in a DLL, in another we might
choose to put several components together in one big DLL. The other
components inside the big DLL will use the module directly. Components
outside that border will pass via a GMU class right into the same code.
>
> /Thomas
>
>
>