Pantheios Architecture
Pantheios is comprised of four separate parts:
-
Application Layer - The
functions that application code uses in log statements, e.g.
log_DEBUG(),
log_INFORMATIONAL(), and so on.
-
Core - Prepares the statement by efficiently
concatenating the elements (often without any memory allocation whatsoever).
-
Front-end - Provides the process identity and
determines whether a given severity level is currently to be emitted.
Note: the front-end library must be implemented by the user, or one of
the stock front-ends linked in.
-
Back-end - Transports the prepared log
statement to an output stream (such as console, COM Error Object, syslog,
Windows Event Log, and many more).
Note: the back-end library must be implemented by the user, or one of
the stock back-ends linked in.
Together, these four parts interact with the body of the application as
shown in the following figure:
Application-Layer
The Pantheios application layer consists of:
-
One suite of (32) log() functions,
catering for between 1 and 32 parameters.
- Eight suites of 32 severity-specific functions
(log_DEBUG(),
log_INFORMATIONAL(),
log_NOTICE(),
log_WARNING(),
log_ERROR(),
log_CRITICAL(),
log_ALERT()
and
log_EMERGENCY(). Each of these is
equivalent to a call to the requisite
log() with an explicit severity
level.)
-
Two inserter classes for handling numeric types:
integer,
and
real.
-
One inserter class for handling pointers:
pointer.
-
One inserter class for representing untyped areas of memory:
blob.
(Note: there's also an extension class,
b64, that represents untyped areas
of memory as Base-64. This requires the headers and libraries
from the
b64
library, which is not part of the Pantheios distribution.)
With these functions and inserter classes diagnostic logging statements can be
written into application code in a simple and succinct manner, as
shown in the follow examples:
- Log an exception (with the ERROR severity):
. . .
}
catch(std::exception& x)
{
pantheios::log_ERROR("Exception encountered: ", x);
}
- Log the parameters to a function call (with the INFORMATIONAL severity):
void func(std::string const& s1, char const* s2, struct tm const* t)
{
pantheios::log(pantheios::informational, "func(", s1, ", ", s2, ", ", t, ")");
. . .
}
- Log a mix of types (with severity NOTICE and a custom severity level of 99):
int i;
float f;
HWND hwnd;
GUID guid;
pantheios::log( pantheios::notice(99)
, "int=", pantheios::integer(i)
, " float=", pantheios::real(f)
, " HWND=", hwnd
, " GUID=", guid);
The application layer is entirely header-only, accessed via the
pantheios/pantheios.hpp and, if the
inserter classes are required,
pantheios/inserters.hpp.
#include <pantheios/pantheios.hpp> // Pantheios log and log_XXX functions
#include <pantheios/inserters.hpp> // Pantheios inserter classes
Core
The Pantheios core API is invoked by the
application layer to implement its
functionality. Elements of the core API may also be useful to
application layer code in some circumstances.
For example, the core API function
pantheios_isSeverityLogged() may be used
to determine whether logging of a given severity level is enabled
before doing any significant amount of log statement preparation.
PANTHEIOS_CALL(int) pantheios_isSeverityLogged(pan_sev_t severity);
Furthermore, Pantheios may be used from C client code via the core
API directly, via the pantheios_printf()
and pantheios_vprintf() functions:
int i;
float f;
pantheios_printf( PANTHEIOS_SEV_INFORMATIONAL, "int=%d, float=%g"
, i, f);
But it should be noted that the C functions in the core API do not
offer either the type-safety or the genericity of the
application layer.
Front-end
The Pantheios front-end is a library of four functions that
together provide the process identity used in the log statements
and determine, at runtime, whether a given severity level is to
be logged:
PANTHEIOS_CALL(int) pantheios_fe_init( int reserved
, void** ptoken);
PANTHEIOS_CALL(void) pantheios_fe_uninit( void* token);
PANTHEIOS_CALL(char const*) pantheios_fe_processIdentity( void* token);
PANTHEIOS_CALL(int) pantheios_fe_isSeverityLogged(void* token
, int severity
, int backEndId);
pantheios_fe_init(),
pantheios_fe_uninit() and
pantheios_fe_processIdentity() are invoked
at most once, during library initialisation. (See the documentation included
with the library for more details.)
pantheios_fe_isSeverityLogged() is invoked each
time an application layer log statement is invoked, and determines whether
the statement is to be emitted to the back end
based on the statement's severity level. In this way, the Pantheios core
may be married to any application scheme for filtering log statements based
on severity level.
The front-end is selected at link time. Pantheios comes with one stock
front-end called fe.simple.
A tutorial on using fe.simple and writing custom front-ends is
available here.
Back-end
The Pantheios back-end is a library of three functions that together
provide the back-end transport:
PANTHEIOS_CALL(int) pantheios_be_init( char const* processIdentity
, int reserved
, void** ptoken);
PANTHEIOS_CALL(void) pantheios_be_uninit( void* token);
PANTHEIOS_CALL(int) pantheios_be_logEntry(void* feToken
, void* beToken
, int severity
, char const* entry
, size_t cchEntry);
pantheios_be_init() and
pantheios_be_uninit() are invoked
at most once, during library initialisation. (See the documentation included
with the library for more details.)
pantheios_be_logEntry() is invoked each
time an application layer log statement is invoked, as long as
pantheios_fe_isSeverityLogged() returned
non-zero.
The back-end is selected at link time. Pantheios comes with several
stock back-ends:
- be.ACE - output is via the ACE diagnostic logging infrastructure.
- be.COMErrorObject - output is written to the COM Error Object.
- be.fprintf - output is to the console via fprintf().
- be.null - output is stubbed (the Null Object pattern).
- be.syslog - output is via the Syslog protocol, using the native UNIX SysLog API.
- be.Win32Console - output is via the Windows console, with severity-dependent statement colouring.
- be.Win32Debugger - output is via the Windows debugger.
- be.Win32syslog - output is via the SysLog protocol, using a
custom implementation. This is a useful library independent of Pantheios.
- be.WindowsEventLog - output is via the Windows Event Log.
There is also a back-end, be.lrsplit, that implements the
Composite Pattern by splitting output into local and remote
streams using any of the stock (or custom) back-ends.
A tutorial on using the stock back-ends and writing custom back-ends is
available here.
|