Difference between revisions of "Using string mixins for logging"
(Adding code and dpaste link) |
WebFreak001 (talk | contribs) (deprecate this page) |
||
(10 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
+ | {{Cookbook | ||
+ | |category=Meta Programming | ||
+ | |level=Novice | ||
+ | |type=Recipe | ||
+ | |status=Deprecated | ||
+ | |time=10 min | ||
+ | |dversion=D2 | ||
+ | |display=none | ||
+ | }} | ||
+ | |||
+ | '''This code manually defines __FUNCTION__ which break as of D 2.063 and uses a few now obsolete workarounds. To view more up-to-date examples visit [[Logging mechanisms]]''' | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | |||
+ | This recipe uses string mixins for implementing a logging facility. | ||
+ | The program code is given in the next section. [http://dpaste.dzfl.pl/cdacef45 ▶ Try it online] | ||
+ | |||
+ | ==Program Code== | ||
<syntaxhighlight lang="D"> | <syntaxhighlight lang="D"> | ||
import std.traits : PTT=ParameterTypeTuple; | import std.traits : PTT=ParameterTypeTuple; | ||
import std.stdio : stderr; | import std.stdio : stderr; | ||
import std.datetime : Clock; | import std.datetime : Clock; | ||
− | + | ||
template StringOf(TS...) | template StringOf(TS...) | ||
{ | { | ||
Line 9: | Line 29: | ||
{ | { | ||
enum StringOf = ""; | enum StringOf = ""; | ||
+ | } | ||
+ | else static if(TS.length == 1) | ||
+ | { | ||
+ | enum StringOf = (TS[0]).stringof; | ||
} | } | ||
else | else | ||
{ | { | ||
− | enum StringOf = (TS[0]).stringof ~ | + | enum StringOf = (TS[0]).stringof ~ "," ~ StringOf!(TS[1..$]) ; |
} | } | ||
} | } | ||
− | + | ||
template ArgStringOf(TS...) | template ArgStringOf(TS...) | ||
{ | { | ||
Line 21: | Line 45: | ||
{ | { | ||
enum ArgStringOf = ""; | enum ArgStringOf = ""; | ||
+ | } | ||
+ | else static if(TS.length == 1) | ||
+ | { | ||
+ | enum ArgStringOf = TS[0]; | ||
} | } | ||
else | else | ||
{ | { | ||
− | enum ArgStringOf = TS[0] ~ | + | enum ArgStringOf = TS[0] ~ "," ~ ArgStringOf!(TS[1..$]); |
} | } | ||
} | } | ||
− | + | ||
+ | template log(string level, PS...) | ||
+ | { | ||
+ | //pragma(msg, log); | ||
+ | enum log = `static if(!__traits(compiles, __FUNCTION__ == ""))` ~ | ||
+ | `{ enum __FUNCTION__ = __traits(identifier, __traits(parent, {})) ~` ~ | ||
+ | `"(" ~ StringOf!(PTT!(__traits(parent, {}))) ~ ")";` ~ | ||
+ | `} stderr.writeln(Clock.currTime(), " [` ~ level ~ `] ", __FILE__, '(', __LINE__, "): ",` ~ | ||
+ | `__FUNCTION__, ": ",` ~ ArgStringOf!(PS) ~ `);` ; | ||
+ | } | ||
+ | |||
template info(PS...) | template info(PS...) | ||
{ | { | ||
− | + | enum info = log!("INFO", PS); | |
− | + | } | |
− | + | ||
− | + | template warn(PS...) | |
− | + | { | |
− | + | enum warn = log!("WARN", PS); | |
} | } | ||
− | + | ||
+ | template error(PS...) | ||
+ | { | ||
+ | enum error = log!("ERROR", PS); | ||
+ | } | ||
+ | |||
mixin template set_func_name(string fn) | mixin template set_func_name(string fn) | ||
− | { | + | { |
− | + | enum __FUNCTION__ = fn; | |
} | } | ||
− | + | ||
+ | ///////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | import std.exception; | ||
+ | |||
auto foo(T)(in T val) | auto foo(T)(in T val) | ||
if(is(T==int) || is(T==string)) | if(is(T==int) || is(T==string)) | ||
{ | { | ||
mixin set_func_name!("foo(" ~ T.stringof ~ ")"); //workaround for fwd ref issue | mixin set_func_name!("foo(" ~ T.stringof ~ ")"); //workaround for fwd ref issue | ||
− | mixin (info!(`" | + | mixin (info!(`"starting"`)); |
− | mixin (info!(`" | + | |
− | + | scope(exit) { mixin (info!(`"stopping"`)); } | |
+ | |||
static if (is(T==int)) | static if (is(T==int)) | ||
return 1.0123; | return 1.0123; | ||
Line 55: | Line 103: | ||
return true; | return true; | ||
else | else | ||
− | static assert(false, "need int or string"); | + | 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) | void main(string[] args) | ||
{ | { | ||
− | mixin (info!(`" | + | mixin (info!(`"starting"`)); |
− | + | ||
+ | scope(exit) { mixin (info!(`"stopping"`)); } | ||
+ | |||
mixin (info!(`"foo(1) returned: "`, `foo(1)`)); | mixin (info!(`"foo(1) returned: "`, `foo(1)`)); | ||
mixin (info!(`"foo(\"bar\") returned: "`, `foo("bar")`)); | mixin (info!(`"foo(\"bar\") returned: "`, `foo("bar")`)); | ||
− | + | mixin (info!(`"calling baz()"`)); | |
− | mixin ( | + | try |
+ | { | ||
+ | baz(); | ||
+ | } | ||
+ | catch(Exception e) | ||
+ | { | ||
+ | mixin (error!(`"Caught exception: "`, `e.toString()`)); | ||
+ | } | ||
} | } | ||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | ==Sample Output== | |
− | [ | + | <pre> |
+ | 2012-Dec-14 19:12:58.5092108 [INFO] /home/c706/c392.d(99): main(string[]): starting | ||
+ | 2012-Dec-14 19:12:58.5093317 [INFO] /home/c706/c392.d(75): foo(int): starting | ||
+ | 2012-Dec-14 19:12:58.5094113 [INFO] /home/c706/c392.d(77): foo(int): stopping | ||
+ | 2012-Dec-14 19:12:58.5093314 [INFO] /home/c706/c392.d(103): main(string[]): foo(1) returned: 1.0123 | ||
+ | 2012-Dec-14 19:12:58.509528 [INFO] /home/c706/c392.d(75): foo(string): starting | ||
+ | 2012-Dec-14 19:12:58.5095605 [INFO] /home/c706/c392.d(77): foo(string): stopping | ||
+ | 2012-Dec-14 19:12:58.5095276 [INFO] /home/c706/c392.d(104): main(string[]): foo("bar") returned: true | ||
+ | 2012-Dec-14 19:12:58.5096157 [INFO] /home/c706/c392.d(105): main(string[]): calling baz() | ||
+ | 2012-Dec-14 19:12:58.5096436 [INFO] /home/c706/c392.d(89): baz(): starting | ||
+ | 2012-Dec-14 19:12:58.5096851 [WARN] /home/c706/c392.d(92): baz(): exception encountered | ||
+ | 2012-Dec-14 19:12:58.5097154 [INFO] /home/c706/c392.d(91): baz(): stopping | ||
+ | 2012-Dec-14 19:12:58.5097433 [ERROR] /home/c706/c392.d(112): main(string[]): Caught exception: object.Exception@/home/c706/c392.d(94): bazzzz | ||
+ | ---------------- | ||
+ | 2012-Dec-14 19:12:58.5097807 [INFO] /home/c706/c392.d(101): main(string[]): stopping | ||
+ | </pre> |
Latest revision as of 11:55, 16 July 2020
This code manually defines __FUNCTION__ which break as of D 2.063 and uses a few now obsolete workarounds. To view more up-to-date examples visit Logging mechanisms
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);
enum log = `static if(!__traits(compiles, __FUNCTION__ == ""))` ~
`{ enum __FUNCTION__ = __traits(identifier, __traits(parent, {})) ~` ~
`"(" ~ StringOf!(PTT!(__traits(parent, {}))) ~ ")";` ~
`} stderr.writeln(Clock.currTime(), " [` ~ level ~ `] ", __FILE__, '(', __LINE__, "): ",` ~
`__FUNCTION__, ": ",` ~ ArgStringOf!(PS) ~ `);` ;
}
template info(PS...)
{
enum info = log!("INFO", PS);
}
template warn(PS...)
{
enum warn = log!("WARN", PS);
}
template error(PS...)
{
enum error = log!("ERROR", PS);
}
mixin template set_func_name(string fn)
{
enum __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 19:12:58.5092108 [INFO] /home/c706/c392.d(99): main(string[]): starting 2012-Dec-14 19:12:58.5093317 [INFO] /home/c706/c392.d(75): foo(int): starting 2012-Dec-14 19:12:58.5094113 [INFO] /home/c706/c392.d(77): foo(int): stopping 2012-Dec-14 19:12:58.5093314 [INFO] /home/c706/c392.d(103): main(string[]): foo(1) returned: 1.0123 2012-Dec-14 19:12:58.509528 [INFO] /home/c706/c392.d(75): foo(string): starting 2012-Dec-14 19:12:58.5095605 [INFO] /home/c706/c392.d(77): foo(string): stopping 2012-Dec-14 19:12:58.5095276 [INFO] /home/c706/c392.d(104): main(string[]): foo("bar") returned: true 2012-Dec-14 19:12:58.5096157 [INFO] /home/c706/c392.d(105): main(string[]): calling baz() 2012-Dec-14 19:12:58.5096436 [INFO] /home/c706/c392.d(89): baz(): starting 2012-Dec-14 19:12:58.5096851 [WARN] /home/c706/c392.d(92): baz(): exception encountered 2012-Dec-14 19:12:58.5097154 [INFO] /home/c706/c392.d(91): baz(): stopping 2012-Dec-14 19:12:58.5097433 [ERROR] /home/c706/c392.d(112): main(string[]): Caught exception: object.Exception@/home/c706/c392.d(94): bazzzz ---------------- 2012-Dec-14 19:12:58.5097807 [INFO] /home/c706/c392.d(101): main(string[]): stopping