Using string mixins for logging
This recipe uses string mixins for implementing a logging facility. The program code is given in the next section. ▶ Try it online
Program Code
import std.traits : PTT=ParameterTypeTuple;
import std.stdio : stderr;
import std.datetime : Clock;
template StringOf(TS...)
{
static if(TS.length == 0)
{
enum StringOf = "";
}
else static if(TS.length == 1)
{
enum StringOf = (TS[0]).stringof;
}
else
{
enum StringOf = (TS[0]).stringof ~ "," ~ StringOf!(TS[1..$]) ;
}
}
template ArgStringOf(TS...)
{
static if(TS.length == 0)
{
enum ArgStringOf = "";
}
else static if(TS.length == 1)
{
enum ArgStringOf = TS[0];
}
else
{
enum ArgStringOf = TS[0] ~ "," ~ ArgStringOf!(TS[1..$]);
}
}
template log(string level, PS...)
{
//pragma(msg, log);
const char[] log = `static if(!__traits(compiles, __FUNCTION__ == ""))` ~
`{ immutable string __FUNCTION__ = __traits(identifier, __traits(parent, {})) ~` ~
`"(" ~ StringOf!(PTT!(__traits(parent, {}))) ~ ")";` ~
`} stderr.writeln(Clock.currTime(), " [` ~ level ~ `] ", __FILE__, '(', __LINE__, "): ",` ~
`__FUNCTION__, ": ",` ~ ArgStringOf!(PS) ~ `);` ;
}
template info(PS...)
{
const char[] info = log!("INFO", PS);
}
template warn(PS...)
{
const char[] warn = log!("WARN", PS);
}
template error(PS...)
{
const char[] error = log!("ERROR", PS);
}
mixin template set_func_name(string fn)
{
immutable string __FUNCTION__ = fn;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
import std.exception;
auto foo(T)(in T val)
if(is(T==int) || is(T==string))
{
mixin set_func_name!("foo(" ~ T.stringof ~ ")"); //workaround for fwd ref issue
mixin (info!(`"starting"`));
scope(exit) { mixin (info!(`"stopping"`)); }
static if (is(T==int))
return 1.0123;
else static if(is(T==string))
return true;
else
static assert(false, "need int or string");
}
void baz()
{
mixin (info!(`"starting"`));
scope(exit) { mixin (info!(`"stopping"`)); }
scope(failure) { mixin (warn!(`"exception encountered"`)); }
throw new Exception("bazzzz");
}
void main(string[] args)
{
mixin (info!(`"starting"`));
scope(exit) { mixin (info!(`"stopping"`)); }
mixin (info!(`"foo(1) returned: "`, `foo(1)`));
mixin (info!(`"foo(\"bar\") returned: "`, `foo("bar")`));
mixin (info!(`"calling baz()"`));
try
{
baz();
}
catch(Exception e)
{
mixin (error!(`"Caught exception: "`, `e.toString()`));
}
}
Sample Output
2012-Dec-14 16:18:54.0343668 [INFO] /home/c748/c87.d(99): main(string[]): starting 2012-Dec-14 16:18:54.0344801 [INFO] /home/c748/c87.d(75): foo(int): starting 2012-Dec-14 16:18:54.0345128 [INFO] /home/c748/c87.d(77): foo(int): stopping 2012-Dec-14 16:18:54.034478 [INFO] /home/c748/c87.d(103): main(string[]): foo(1) returned: 1.0123 2012-Dec-14 16:18:54.0346471 [INFO] /home/c748/c87.d(75): foo(string): starting 2012-Dec-14 16:18:54.0346802 [INFO] /home/c748/c87.d(77): foo(string): stopping 2012-Dec-14 16:18:54.0346466 [INFO] /home/c748/c87.d(104): main(string[]): foo("bar") returned: true 2012-Dec-14 16:18:54.0347421 [INFO] /home/c748/c87.d(105): main(string[]): calling baz() 2012-Dec-14 16:18:54.0347725 [INFO] /home/c748/c87.d(89): baz(): starting 2012-Dec-14 16:18:54.0348131 [WARN] /home/c748/c87.d(92): baz(): exception encountered 2012-Dec-14 16:18:54.0348431 [INFO] /home/c748/c87.d(91): baz(): stopping 2012-Dec-14 16:18:54.0348695 [ERROR] /home/c748/c87.d(112): main(string[]): Caught exception: object.Exception@/home/c748/c87.d(94): bazzzz ---------------- 2012-Dec-14 16:18:54.0349043 [INFO] /home/c748/c87.d(101): main(string[]): stopping
[Semantic Metadata]
Novice Recipe Draft
10 min0.166 hr
D2