I have previously written about kbmMW’s rather advanced logging framework in a whitepaper from 2017, found here, in the blogpost “REST easy with kbmMW #5 – Logging” and the blogpost “REST easy with kbmMW #10 – Logging to a database”
However the logging framework really deserves an updated blogpost because it has, as with most kbmMW evolved, and is a central and important set of features for every application being written.
This blog will reiterate some of the things from previous posts, surface the old whitepaper, written when the logging framework was introduced in kbmMW v. 4.82, and bring it up to date with the latest bells and whistles, of which next release of kbmMW (shortly after this whitepapers release), will contain even more.
Why logging?
Reasons to log includes but are not limited to
- For debugging while developing
- For debugging after deployment
- For keeping track of resources
- For keeping track of usage (perhaps even relates to later invoicing)
- For proving reasons for user complaints
- Of security reasons to track who is doing what
As you can tell, there seems to be various log requirements for various stages of the lifetime of the application:
- During development
- During usage
- Early warning
- Post incident investigation
A good log system should handle all the above scenarios, while making it simple to use for the developer, and allow the administrator to tune on the amount of information needed.
kbmMW’s log system handles these scenarios, and can be late fine tuned for the required log level and scenarios.
In addition the log system should be able to output the log in relevant formats, that match the application’s purpose.
Web server applications, might want to output some log data in a format generally accepted by web servers, and thus also by web server log file analyzer software, while other server applications may have other requirements for output, like JSON or XML in a format easily digestible by external log analyzers.
kbmMW supports several output formats, and also allows adding additional formats, without having to make changes in the developer’s logging statements.
Contents
Log, debug and audit the kbmMW way
One annoying thing in Delphi during the years has been the lack of a centralized, customizable, single style
logging and auditing mechanism with enough flexibility and high enough performance that it also works for bug hunting in live applications.
Various 3rdparty products has taken that lack of functionality up, but no one of them is as flexible and fast as the one kbmMW is equipped with.
In the later years, the problem has worsened, because Delphi supports new platforms, which themselves have their own (not always so great) way of logging, and none of the platforms has any way to
register audit data, which is crucial for many systems, especially the ones handling person critical data.
Most of the features mentioned in this blog post are available for kbmMW Enterprise, Professional and Community Edition
Log entries are always initiated via one of the many methods of the Log (TkbmMWLog) instance.
There are methods for doing an informative log, a warning log, an error log, an audit log and several more types, and there are methods which can be used for selecting what type of log to make at runtime, because the type is provided as one of the arguments.
And kbmMW even provides the ability to output a stack trace for your logs if desired.
So let us get on with it.
First add the kbmMWLog unit to the units in which you expect to do some logging or where you setup your logging scheme.
uses
... kbmMWLog;
By simply adding this unit, we can already log by calling one of the methods of the public default available Log singleton instance. Eg.
Log.Debug('some debug information');
Log.Info('2 + 2 = %d',[2+2]);
These calls introduces log entries into the logging framework.
If we have done nothing else, then the log will automatically end up on your OS preferred output. In case of Windows, the logs can be seen if you run the application in debug mode in Delphi, or if you use an external Debug viewer. Is the application running on Android, IOS og Linux the output will be directed elsewhere.
See TkbmMWSystemLogManager later for more information.
As you can see there are several methods that can be used for logging. These methods controls what type of logging you are doing. In the above cases debug log and ordinary informative log.
In the next part we will look at the various log types.
Log entry types
kbmMW’s log system amongst others, supports these easy to use methods in the TkbmMWLog class to produce a log entry:
- Debug – typically used during development purposes
- Info – inform about some non critical and non error like information
- Warn – inform about some non critical anormal situation
- Error – inform about some error, like an exception or something else which still allow the application to continue to operate.
- Fatal – inform about an error of such magnitude that the application no longer can run.
- Audit – inform about some information that you want to be used as evidence in a post analysis scenario.
- Alert – inform about some significant type of information that needs to be handled by someone. Eg. alarm from a radiation detector.
- Log – specify the type of log by an argument.
- TimeStart/TimeEnd/TimeClear/TimeLapse – Used for logging timing information.
Some of them exists in more variants, to easily log XML or JSON data, or key/value type data, or contents of a stream or other binary data.
kbmMW supports the following log types (the set TkbmMWLogTypes) which the above functions represent:
- mwltDebug
- mwltInfo
- mwltWarning
- mwltError
- mwltFatal
- mwltAudit
- mwltAlert
Log entry levels
For each log entry you choose to make, you can optionally specify the log level which this entry belongs to. The purpose is to allow log managers to handle only those log levels that are of interest, while the developer can choose to put log statements anywhere in the code where it makes sense, categorizing the log entries into various levels of detail.
kbmMW supports the following log levels which will only be handled by a log manager if LogLevelFilter contains the relevant log levels:
- mwllOff – Usually not to be used. Will typically result in the log entry never being handled by a log manager.
- mwllBasic – Typically to be used for start and stop of application / service. This is included in the default log level for log managers.
- mwllNormal – Typically to be used for additional info during start of the application, like information about where the logfile is to be found, where the configuration file may be, which database is being used or other such general information. This is included in the default log level for log managers.
- mwllDetailed – Will typically output more detailed log info, which is normally not of interest when running the application under normal production. Is the next higher step from Normal.
- mwllAdvanced – Will typically output even more detailed log info which is typically only of interest in some debug scenarios. Is the next higher step from Detailed.
- mwllHighest – Will output the most detailed log info which will usually only rarely be used even for debugging except for specific cases, because of the amount of output generated. It is the highest possible log level.
Notice that log levels are applicable for most of the log types. So it is entirely possible to log info for example at a basic, normal and detailed level, depending on configuration of the log manager, while also supporting debug log entries at normal, detailed, advanced and highest levels.
Basically it is up to the developer to make the choice of what a log level actually means for the application. The above comments for each log level is only a good rule of thumb.
Log entry data types
As mentioned before, there are many different variations of log entry methods available in the TkbmMWLog class. Example Debug and DebugXML.
The variations often control which log entry data type is used. Eg. using Debug will produce a log entry of log type mwltDebug, at the given log level, using the log data type mwldtString, while DebugXML will produce a log entry of type mwltDebug, at the given log level, using the log data type mwldtXML.
This way, log managers will know how to best store or present the log entry.
The following log data types are supported:
- mwldtString – The log entry is a string (optionally a format like string with arguments)
- mwldtException – The log entry is an exception that is being handled by some exception handler.
- mwldtUnhandledException – The log entry is an exception that was not being handled by any exception handler.
- mwldtXML – The log entry data is XML (Log.LogXML, Log.DebugXML).
- mwldtJSON – The log entry data is JSON (Log.LogJSON, Log.DebugJSON).
- mwldtYAML – The log entry data is YAML (Log.LogYAML, Log.DebugYAML).
- mwldtStream – The log entry data is coming from a stream (typically understood as a binary stream) (Log.LogStream, Log.Debug, Log.Warn, Log.Error, Log.Fatal).
- mwldtBytes – The log entry data is coming from a binary byte array. (Log.LogBytes, Log.Debug, Log.Warn, Log.Error, Log.Fatal).
- mwldtStack – The log entry data is a stack trace. (Log.LogStack).
- mwldtWeb – The log entry is specifically something to be handled as a web server like logging (Log.LogWeb).
- mwldtAllocation – The log entry is related to allocation info, like leaks. Usually only used via the kbmMWDebugMemory unit, which can be enabled for debugging leaks and allocation statistics.
- mwldtRaw – The log entry is supposed to be handled by outputting its data to a raw file (Log.LogRaw).
- mwldtValues – The log entry contains data as a list of name/value pairs (Log.Log and Log.Audit).
Logs with data type mwldtException and mwldtAllocation will usually also contain a stack trace, as part of the log entry. This happens automatically within kbmMW. Compile your application with debug information and output a TDS and/or a detailed MAP file which you distribute with the application to get full stack info including source references.
Logging process overview

The “frontend” and the “backend”
The kbmMW logging framework consists of two parts, the “frontend” towards the developer which produce a new log entry, and the “backend” which we call the log manager that handles the produced log entry.
The frontend (producer of a new log entry)
The “frontend” is provided to the developer through an interfaced (IkbmMWLog) instance of TkbmMWLog. kbmMW comes with a singleton already defined, named Log, of type IkbmMWLog which is defined in the unit kbmMWLog.pas, which usually serves all needs for you, but you can choose to instantiate your own instances, although I have personally not really seen a need for that yet.
All examples in this blog will use that singleton.
As the singleton Log is an interface, it is automatically reference counted, and can be used wherever you find a need for logging, timing or auditing something.
It is also thread safe, so it can be used in threads as you see fit.
The “frontend” always communicates directly with the “backend” (the log manager).
The backend (log manager)
It is the log manager (backend) that determines how the log entry is processed.
A log manager can be the end station for the log entry. The one responsible for putting the entry in a file, or a native system log, or it can be an intermediate that handles forwarding it to other log managers or to another server.
Default, if one does nothing, the backend log manager is TkbmMWSystemLogManager.
It will be shown later how to change the log systems log manager to another.
Log managers
Each log manager contain a number of properties, that are of interest. Some are special for the particular log manager, but there are a number of properties that are common to all.
A set of them are used to filter out, exactly which log entries, this particular log manager is supposed to handle.
The filters are set via these properties:
- LogTypeFilter – Specifies which types of log entries this log manager will handle.
Default it is mwltDebug,mwltInfo,mwltWarning,mwltError,mwltFatal,mwltAudit - LogLevelFilter – Specifies which levels of log this log manager will handle.
Default it is mwllBasic,mwllNormal - LogDataTypeFilter – Specifies which log data types will be handled by this log manager.
Default is mwldtString,mwldtException,mwldtUnhandledException,mwldtXML,mwldtJSON,
mwldtYAML,mwldtStream,mwldtBytes,mwldtStack,mwldtWeb,mwldtAllocation,mwldtRaw,
mwldtValues
Thus by fine tuning the log managers filter settings, you can make sure it will only handle those types, levels and datatypes you find relevant for the particular log manager. And since you can register multiple log managers (see the tee log manager), you can choose different output formats for various filter settings.
Another property is Options which currently only can have the value nothing or mwloAutoLogExceptions, which is default and means that exceptions will be logged automatically. If there are exceptions you do not want a log manager to handle, you can specify the specific exception classes with the IgnoreException and IgnoreExceptions methods.
The property LogFormatter describes an interfaced class that should do any log entry to output string conversion. Default is TkbmMWStandardLogFormatter. See later for the various types of log formatters and the resulting output.
Finally you can choose to subscribe for specific log entries, so your own code is getting called whenever a log entry is accepted by the log manager, using the Subscribe and Unsubscribe methods.
Make sure your code is quick and thread safe and generally do not try to synchronize with the main GUI thread within the code.
End station log manager
When it is an end station log manager, it uses a configurable log formatter, to determine exactly the textual look of the log entry will look. It includes, which type of, already gathered, information to include and how data like binary data should be formatted.
The end station log manager then outputs (or in case of the null log manager, forgets) the log entry to some sort of storage.
A number of end station log managers exists:
- TkbmMWSystemLogManager which implements IkbmMWSystemLogManager.
The default system log manager.
It will output the formatted log string to the system default log system. - TkbmMWStringsLogManager which implements IkbmMWStringsLogManager
A log manager that will append the handled and formatted log into a TStrings descendant, and be friendly to visual controls like TMemo if needed, by updating the TStrings synchronously with the main GUI thread (which is required if you want the log to automatically end up in your TMemo or TList (VCL) instance), or asynchronously. - TkbmMWStreamLogManager which implements IkbmMWStreamLogManager
A log manager that will append the handled and formatted log to a TStreams based storage. The storage needs to be thread safe. - TkbmMWLocalFileLogManager which implements IkbmMWLocalFileLogManager
A log manager that stores the handled and formatted log in one single file, but maintains file roll over and backups. - TkbmMWVirtualLogManager which implements IkbmMWVirtualLogManager
A log manager for which you can provide an anonymous procedure that should handle the log entry. Depending on the arguments of the procedure, you can get the formatted log entry, or only the base values for the log entry. - TkbmMWNullLogManager which just implements IkbmMWLogManager
A log manager that simply ignores the log entry.
Forwarding log manager
A forwarding log manager typically do not itself, produce any textual log entries, but instead forwards a copy of the log entry to one or more other log managers. The log managers can be within the same process or handle communication with another remote process, that will then handle the log.
The log entry is typically forwarded as is, without any attempt to format it.
- TkbmMWTeeLogManager which implements IkbmMWTeeLogManager
A log manager that forwards log data to one or more other log managers. This is useful for example when you want debug log in one file, and system log in another file, or want to send logs away to a remote system, while also logging it locally etc. It is possible to define any number of log managers handled by the tee manager, and you can define the conditions for each of the log managers what to log. - TkbmMWProxyLogManager which implements IkbmMWProxyLogManager
A log manager that forwards log data to another log manager. It is in itself not terribly interesting, however it can be used for creating a custom log manager that intercepts the log process, and do something with it before sending it off to another log manager. The IkbmMWServerLogManager is a proxy log manager. - TkbmMWClientLogManager which implements IkbmMWClientLogManager
Enterprise Edition and Community Edition only.
It forwards log via a designated WIB client or server side transport as WIB LOG events. - TkbmMWServerLogManager which implements IkbmMWServerLogManager
Enterprise Edition and Community Edition only.
It receives log entries from a client or server WIB where it has subscribed for the subject WIB LOG.
It forwards the resulting log entries to another log manager.
You can derive your own custom log manager from TkbmMWCustomLogManager or implement the interface IkbmMWLogManager in a class hierarchy of your own.
TkbmMWSystemLogManager
The system log manager use the systems default logging mechanism (OutputDebugString on Windows, NSLog on IOS, android_log_write on Android and syslog on Linux/Unix like systems).
It is default set up to only output the first n bytes of the log message and snip the rest. n depends on the system.
The reason is that various native logging methods often will choke if stuffed with too much info.
You can disable the snipping by setting the property Snip to false on the system log manager’s interface.
- Windows – 768 bytes
- Linux – 1024 bytes
- IOS – 512 bytes
- Android – 512 bytes
- Mac – no limit.
TkbmMWStringsLogManager
This log manager is great for updating classes, components or controls descending from or having properties descending from TStrings. It is very useful when you have an application which you want to run with a visual form, and want to see the log entries as they happen.
The log manager have the following properties:
- Strings:TStrings – point to the TStrings descendant you want to receive the formatted log entries.
- Synchronized:boolean – set to True, if the TStrings is part of a component or control currently put on a form/frame and thus governed by the main GUI thread.
- AutoSplitLines:boolean – Default True. Will automatically check the formatted log string and split it into multiple strings entries if there are line feed characters as part of the data.
TkbmMWStreamLogManager
This log manager is designed to output nicely formatted log strings to a stream of any kind. The stream class must however be thread safe.
The log manager have the following properties:
LogStream:TStream – The actual stream that will receive the stringified log entries. It must be thread safe.
FlushInterval:integer – Default 0 secs. The interval in seconds, between flushing the contents of the stream to whatever storage that the stream may link to. It is useful when the stream may cache the writings and only write persist the contents when asked to, or when the cache runs full. When set to 0, the stream will always be flushed on every log entry.
LastWriteTime:TkbmMWDateTime – Timestamp of last log entry being written to the stream.
LastFlushTime:TkbmMWDateTime – Timestamp of last time the stream was flushed.
TkbmMWLocalFileLogManager
A descendant of the TkbmMWStreamLogManager, which persists the log entries to a file. It contain plenty features, like the ability to cache the log entries for performance reasons (default FlushInterval is 0 and thus it writes the log entry each time to the file).
Further it handles automatic roll over of a log file when it reaches a certain size or age. Roll over means that it renames the original log file to include a timestamp, and creates a new log file. While doing that, it also checks if there are old roll over files that needs to be cleaned up.
Further this log manager handles the concept of raw files. Each time you choose to use the LogRaw method of the TkbmMWLog class, this log manager (if triggered) will create a new binary file to dump the raw data into and instead log the name of the newly generated file. The number of raw files that can exist, can also be controlled automatically so older files will be removed.
The log manager have the following properties:
- LogFile:string – The path and base file name of the file to log into. If you create a TkbmMWLocalFileLogManager and do not provide a file name, one will automatically be generated for you. It will be named kbmMW_xxxxxxxxxxxxxxxxxx.log and be placed in the current users temporary directory. The x’s will be a short GUID which essentially is a random globally unique identifier without formatting characters.
- MaxLogFileSize:integer – Default 1024 kB. The size the log file is allowed to get before being rolled over. If set to 0, no rollover will happen and the file will grow to an unlimited size.
- MaxLogFileAge:TkbmMWDuration – Default not set. The age the log file can have before being rolled over. Can be used to create a new log file each day for example.
- FileOptions:TkbmMWLocalFileOptions – Default [mwlfoBackup,mwlfoTimestampBackup].
It is a set of:- mwlfoDeleteOldLog – If in set, any existing log file will be deleted upon first attempt to write to the log.
- mwlfoBackup – If in set, the existing log file will be rolled over when reaching size or age.
- mwlfoTimestampBackup – If in set, the rolled over backup file will be timestamped.
- mblfoBackupIfEmpty – If in set, an empty over age log file will be rolled over despite being empty.
- BackupExt:string – Default ‘.bak’. The extension (including preceding dot) to be used for the rolled over file.
- BackupPath:string – Default empty. The path where rolled over log files should be placed. If empty, they will be placed in the same directory as the log file itself.
- LogFileCreation:TkbmMWDateTime – Timestamp of when the last log file was created.
- MaxBackupCount:integer – Default 0. Max number of rolled over log files to keep. If 0 will keep all.
- MaxBackupAgeSecs:integer – Default 0. Max number of seconds old that a log file can be before it will be rolled over. If 0 it will not be rolled over due to age.
- MaxRawFileCount:integer – Default 0. Max number of raw files to keep when used with the LogRaw method.
TkbmMWVirtualLogManager
This log manager provides an easy way to put developer defined code into the logging chain.
It could for example be useful if you want to put the log entries into a database or thru another 3rdparty logging mechanism.
You instantiate an instance of TkbmMWVirtualLogManager with one of 3 variants of anonymous methods as argument.
The most complex variant:
mylogmgr := TkbmMWVirtualLogManager.Create(
procedure(Sender:TObject;
const AContext:IkbmMWLogContext;
const AType:TkbmMWLogType;
const ALevel:TkbmMWLogLevel;
const ADataType:TkbmMWLogDataType;
const AOrigin:string;
const AThread:TThread;
const AProcessID:TkbmNativeUInt;
const AThreadID:TkbmNativeUInt;
const AString:string;
const AData:TkbmMWBytes;
const ADateTime:TkbmMWDateTime;
const AExceptionClass:string;
const AValues:IkbmMWLogKeyValues)
begin
// do something.
// You have access to all the data for the log entry.
// If you want a nicely formatted string you can use, you can use the
// GenerateLogEntry method of the log formatter. It takes a TkbmMWStringBuilder
// instance which receives the formatted log entry as a string.
end
);
A simpler variant:
mylogmgr := TkbmMWVirtualLogManager.Create(
procedure(const AContext:IkbmMWLogContext;
const AType:TkbmMWLogType;
const ALevel:TkbmMWLogLevel;
const AOrigin:string;
const ADateTime:TkbmMWDateTime;
const AString:string)
begin
// do something.
// You have access to some of the data for the log entry.
// If you want a nicely formatted string you can use, you can use the
// GenerateLogEntry method of the log formatter. It takes a TkbmMWStringBuilder
// instance which receives the formatted log entry as a string.
end
);
The simplest variant:
mylogmgr := TkbmMWVirtualLogManager.Create(
procedure(const AString:string)
begin
// do something.
// You have access to least of the data for the log entry.
end
);
TkbmMWNullLogManager
This log manager is a simple bit shredder in the sense that any log entries getting into this, will not be output. Only code that has subscribed for log info using the Subscribe method of the log manager, will be triggered.
TkbmMWTeeLogManager
This log managers job is to forward the log entries to other log managers, that has been registered with it.
As with any log manager, it still adheres to the filter setup, and thus prevents unwanted log entries to pass thru to log managers attached to it.
It is an important log manager, when you want to have multiple end stations for your log entries. Perhaps you will want to ensure that log entries ends up in a system log, while also in a TMemo instance while you run your application, or you might want to forward the log to another server that then deals with it, but still need to have access to the local version of the log entries etc.
You can attach any number and types of log managers to a tee log manager, and you can put an overall filter on the tee log manager, and more specialized filters on the attached log managers.
You can instantiate the tee log manager with a between 0 and 4 other log manager instances via the overloaded constructors, or you can add or remove log managers as you wish. Make sure not to add or remove log managers while logging is happening from other threads.
The log manager have the following properties:
- Count:integer – Returns the number of attached log managers.
- LogManager[const AIndex:integer]:IkbmMWLogManager – Returns the specific indexed log manager.
- ForwardFilterSettings:boolean – Default true. Controls if changes of filter settings on the tee log manager, should be used as settings for all attached log managers.
- ForwardLogTypeSettings:boolean – Default true. If ForwardFilterSettings is true, then controls if log type filter settings should be used as settings for all attached log managers.
- ForwardLogDataTypeSettings:boolean – Default true. If ForwardFilterSettings is true, then controls if log data type filter settings should be used as settings for all attached log managers.
- ForwardLogLevelSettings:boolean – Default true. If ForwardFilterSettings is true, then controls if log level filter settings should be used as settings for all attached log managers.
TkbmMWProxyLogManager
This log manager is a simple proxy where every log entry, that is passing its filters, will be forwarded to another log manager.
It however, as all other log managers have the ability for the application to subscribe for log entry events.
You must instantiate the proxy log manager with 1 other log manager instance in the constructors arguments.
The log manager have the following properties:
- LogManager:IkbmMWLogManager – Getter for the currently attached log manager.
TkbmMWClientLogManager
This particular log manager and its sibling, the TkbmMWServerLogManager resides in separate unit, named kbmMWRemoteLog, which is only available if you have a license for Community Edition or Enterprise Edition, includes access to the WIB (Wide Information Bus).
The purpose of this log manager is to forward the log entry via the WIB (Wide Information Bus messaging system) typically to another process, typically on another computer.
The log manager have the following properties:
- Transport:TkbmMWCustomTransport – Must be set to either an instance of a TkbmMWCustomMessagingClientTransport descendant or an instance of a TkbmMWCustomMessagingServerTransport. The connected transport will be used for sending the log entries along to some other subscriber on the WIB.
- ClientIdentity:TkbmMWClientIdentity – Can be set to a TkbmMWClientIdentity which properties will then be copied into the client log managers local client identity instance. The purpose is to provide relevant username/password/tokens etc. that may be required in the other end to expedite the log entry.
TkbmMWServerLogManager
This particular log manager and its sibling, the TkbmMWClientLogManager resides in separate unit, named kbmMWRemoteLog, which is only available if you have a license for Community Edition or Enterprise Edition, includes access to the WIB (Wide Information Bus).
The purpose of this log manager is to receive log entries already being forwarded on the WIB and forward those to another log manager that will in turn take care of the log entries.
The log manager have the following properties:
- Transport:TkbmMWCustomTransport – Must be set to either an instance of a TkbmMWCustomMessagingClientTransport descendant or an instance of a TkbmMWCustomMessagingServerTransport. The connected transport will be used for subscribing for and receiving being forwarded from other log entry publishers on the WIB.
Log formatters
The end station log managers usually converts the log entry to a nicely formatted string that can be put into the relevant output media (file, strings, stream etc.).
This conversion happens via a log formatter, and kbmMW comes with several:
- TkbmMWStandardLogFormatter – Good all round textual log formatter that is the default for all log managers.
- TkbmMWCSVLogFormatter – A standard CSV formatter producing comma separated values formatted log entries.
- TkbmMWJSONLogFormatter – A complex JSON formatter, that will provide arrays of JSON objects, that may contain further objects for additional info for each log entry. This and the XML log formatter are the only ones able to represent all log data types in a structured format.
- TkbmMWXMLLogFormatter – A complex XML formatter, that will provide sequences of XML elements, that may contain further sub elements for each log entry.
All kbmMW log formatters descend from TkbmMWCustomLogFormatter which implements the IkbmMWLogFormatter interface. You can make your own log formatter by implementing the same interface.
You specify which log formatter to use, on each log manager by setting its LogFormatter property to an instance of a log formatter. It is recommended to use a new instance for each log manager. The log formatter should apart from its initial settings, be stateless and thread safe.
The log formatter have the following properties:
- Columns:TkbmMWLogFormatterColumns – You can, by setting this property, choose which elements or columns to include in the stringified version of a log entry. Default is [mwlfcLogDateTime, mwlfcLogType, mwlfcLogDataType, mwlfcLogProcessThreadInfo, mwlfcLogThreadName, mwlfcLogString, mwlfcLogData]
- BinaryPrettyMode:TkbmMWLogBinaryPrettyMode – Default mwlbpmDefault. Defines how binary data should be represented in the string or if it should be output to a separate raw binary file.
- ColumnSeparator:string – Default ‘ : ‘. Used by the standard log formatter to separate columns visually.
- LineSeparator:string – Default #10#13. Used by the standard log formatter to separate lines in the stringified log.
- FixedColumnWidth:boolean – Default false. Currently not in use.
- AddFinalLineSeparator:boolean – Default true. Adds a final line separator after the stringified log entry.
- PrettyChar[const APrettyChar:TkbmMWPrettyChar]:string – An array of strings for each of a large number of special characters in the ASCII character set. Default indicates that for example ASCII 03 should be output as ‘<ETX>’ when pretty stringifying binary data.
- PrettyOptions:TkbmMWPrettyHexOptions – Default [mwphoIncludeOffset,mwphoIncludeHex,mwphoIncludePretty,mwphoPrettySimple,mwphoSpaceEvery8Bytes,mwphoIncludeCRLF]. Defines how prettified binary data should look like.
- UseStackMap:boolean – Default true. Determines if stack traces should try to be converted to line info in source code. It require the presence of an up to date TDS or MAP file.
Setting up the log ouput the easy way
As have been shown, the log output consist of two parts, the end “storage” and the look of the stringified log.
kbmMW contains a few easy methods for this:
- function OutputToDefaultAndFile(const AFileName:string=”; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWTeeLogManager;
- function OutputToFile(const AFileName:string=”; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWLocalFileLogManager;
- function OutputToDefault(const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWSystemLogManager;
- function OutputToStrings(const AStrings:TStrings; const ASynchronized:boolean = true; const ASimpleStrings:boolean = true; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWStringsLogManager;
- function OutputToStringsAndFile(const AStrings:TStrings; const ASynchronized:boolean = true; const ASimpleStrings:boolean = true; const AFileName:string=”; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWTeeLogManager;
- function OutputToDefaultAndStringsAndFile(const AStrings:TStrings; const ASynchronized:boolean = true; const ASimpleStrings:boolean = true; const AFileName:string=”; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWTeeLogManager;
- function OutputToTee(const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWTeeLogManager;
- procedure OutputToNull;
- function OutputToSystemAndAuditFile(const ASystemFileName:string=”; const AAuditFileName:string=”; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWTeeLogManager;
- function OutputToJSONSystemAndAuditFile(const ASystemFileName:string=”; const AAuditFileName:string=”; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWTeeLogManager;
- function OutputToXMLSystemAndAuditFile(const ASystemFileName:string=”; const AAuditFileName:string=”; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWTeeLogManager;
- function OutputToDebugAndSystemAndAuditFile(const ADebugFileName:string=”; const ASystemFileName:string=”; const AAuditFileName:string=”; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWTeeLogManager;
- function OutputToJSONDebugAndSystemAndAuditFile(const ADebugFileName:string=”; const ASystemFileName:string=”; const AAuditFileName:string=”; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWTeeLogManager;
- function OutputToXMLDebugAndSystemAndAuditFile(const ADebugFileName:string=”; const ASystemFileName:string=”; const AAuditFileName:string=”; const ATypes:TkbmMWLogTypes = [mwltInfo,mwltWarning,mwltError,mwltFatal]; const ALevel:TkbmMWLogLevel = mwllNormal):IkbmMWTeeLogManager;
As you can see the methods can be used without providing any arguments, in which case some default assumptions about file naming and other configurations are made.
The methods will instantiate one or more log manager. Typically a tee log manager will be returned, which in turn handles other log managers specialized for the task at hand, like outputting a file in a specific format like JSON.
So by simply calling one of the output methods early on, before attempting logging anything, you can configure the framework in a simple way for even quite complex logging scenarios.
If you have not used any of the output methods, the logging framework is default setup to output via a system log manager.
If the returned log manager instance is a tee log manager, you can access any of the sub log managers by name. The name will typically be “system”, “audit”, “file”, “strings”, and makes it possible for you to do additional specialized configuration on those, like changing the default used log formatter.
Or you can choose to define the log manager tree yourself, by allocating an instance of the log manager, optionally the tee log manager, and add other log managers to it.
Just remember to set the Log.LogManager property to the root log manager you want to use.
Ekample to log to both system log and a file the easy way:
Log.OutputToDefaultAndFIle;
Or to do it the harder way:
var
tm:IkbmMWTeeLogManager;
fm:IkbmMWLocalFileLogManager;
sym:IkbmMWSystemLogManager;
begin
tm:=TkbmMWTeeLogManager.Create;
tm.LogLevelFilter:=Result.LogLevel2LogLevels(mwllNormal);
tm.LogTypeFilter:=kbmMWLogDefaultTypes;
sym:=TkbmMWSystemLogManager.Create;
sym.LogLevelFilter:=Result.LogLevel2LogLevels(mwllNormal);
sym.LogTypeFilter:=kbmMWLogDefaultTypes;
tm.AddLogManager('system',sym);
fm:=TkbmMWLocalFileLogManager.Create('somefilename.log');
fm.LogLevelFilter:=Result.LogLevel2LogLevels(mwllNormal);
fm.LogTypeFilter:=kbmMWLogDefaultTypes;
tm.AddLogManager('file',fm);
LogManager:=tm;
end;
Obviously you could also just usea simple file log manager if that is all you need:
Log.LogManager:=TkbmMWLocalFileLogManager.Create('c:\temp\mylogfile.log');
Happy logging.
![]()









