-
Notifications
You must be signed in to change notification settings - Fork 89
Logging macros
This package sits in the Nemerle.Logging
namespace. It is a mental shortcut for the following:
#define VERB
class A {
SomeMethod () : void
{
#if VERB
DoLog ("some stuff");
#endif
...
#if VERB
def previous_value = GetValue ();
#endif
...
UpdateValue ();
...
#if VERB
DoLog ($ "value $(GetValue ()) --> $previous_value");
#endif
}
}
The above is replaced by:
using Nemerle.Logging;
[assembly: LogFunction (DoLog)]
[assembly: LogFlag (VERB, true)]
class A {
SomeMethod () : void
{
log (VERB, "some stuff");
...
whenlogging (VERB)
def previous_value = GetValue ();
...
UpdateValue ();
...
log (VERB, $ "value change $previous_value --> $(GetValue ())");
}
}
The flags set with LogFlag
are global to the current compilation.
Same goes to the LogFunction
. It is an error to use log
(or whenlogging
) with an unknown flag (use
LogFlag (FOO, false)
to disable given flag). This should save
you from typos.
Setting a flag or printing function several times is also an error.
Enabling given logging is a compile time operation -- without the flag the logging code is not compiled in. However, when some boolean expression are used instead of literal true/false, logging code is preceeded by check of whether this expression is true.
You can use 0/1 instead of true/false as an argument to LogFlag
. This saves typing (I tend to disable/enable lots of debug flags during debuging ;-)
It is also allowed to pass several arguments to the logging function, provided it supports such overload. So the code like below is OK:
[LogFunction (DoLog)]
[LogFlag (SOME_FLAG, 1)]
...
DoLog (color : int, s : string) : void { ... }
...
log (SOME_FLAG, 12, "ble bla");
...
If you want to customize which logging function is used for every
flag, you can specify mapping from each flag name to logging function.
It is done by listing expressions of form FLAG => func_expr
as arguments of
LogFunction
.
For example you may want to use log4net's functions for Debug and Info, so you specify:
using Nemerle.Logging;
[assembly: LogFunction (DEBUG => log4net_category.Debug, TRACE => log4net_category.Info)]
and then
log (DEBUG, "I'm here");
log (TRACE, "enter business functionality");
will use log4net_category.debug
in first expression and log4net_category.info
in second.
It is sometimes needed to restrict logging to some particular case
(for example when -d flag is passed to the program). This can be done
with LogCondition
macro. When you specify it, each call to the
logging function is preceeded by check of the condition.
[assembly: LogCondition (EnableLogging),
LogFlag (DEBUG, true)]
...
EnableLogging = true;
log (DEBUG, "i'm visible");
EnableLogging = false;
log (DEBUG, "and i'm not");
You could also check all the condition you want in the log printing function, but this way you can avoid computations needed for producing the log message (this is not high cost in most cases, but it is very significant in some).
You can prepend logging flag to each message by using:
[assembly: LogFormat (PrependFlag)]
There are no other options controling format right now.
There already was an example of using log4net's framework for logging. This article will demonstate integration with log4net in more particular. Let's imagine that we have a class library with logging based on log4net. The library has an aux module MyLib. This module has a property to assign logger from outside:
public module MyLib
{
[Accessor(flags = WantSetter)]
mutable _logger : ILog;
}
[assembly: LogFunction (Debug => MyLib.Logger.Debug,
Info => MyLib.Logger.Info,
Warn => MyLib.Logger.Warn,
Error => MyLib.Logger.Error,
Fatal => MyLib.Logger.Fatal)]
...
log (Debug, $"nothing serious, just debug variable value: $var");
...
log (Fatal, $"oh my god! unhandled exception: $ex; additional info: $addInfo");
[assembly: LogCondition (MyLib.Logger != null)]
<logger name="SomeLogger">
<level value="INFO"/> <!-- only logs with INFO level and higher will be saved -->
<appender-ref ref="LogFileAppender" />
...
</logger>
[assembly: LogFlag (Debug, MyLib.Logger.IsDebugEnabled)]
[assembly: LogFlag (Info, MyLib.Logger.IsInfoEnabled )]
[assembly: LogFlag (Warn, MyLib.Logger.IsWarnEnabled )]
[assembly: LogFlag (Error, MyLib.Logger.IsErrorEnabled)]
[assembly: LogFlag (Fatal, MyLib.Logger.IsFatalEnabled)]
log (Debug, $"nothing serious, just debug variable value: $var");
// Equivalent
when (MyLib.Logger != null && MyLib.Logger.IsDebugEnabled)
MyLib.Logger.Debug($"nothing serious, just debug variable value: $var");
In the following example x and y will be local to the scope:
whenlogging (FOO) {
def x = ...;
def y = ...;
}
Source is available at https://github.com/rsdn/nemerle/tree/master/macros/Logging.n