Difference between revisions of "Using string mixins for logging"

From D Wiki
Jump to: navigation, search
(Adding code and dpaste link)
 
(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 ~ ( (TS.length == 1)? "" : ("," ~ StringOf!(TS[1..$])) );
+
         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] ~ ( (TS.length == 1)? "" : ("," ~ ArgStringOf!(TS[1..$])) );
+
         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...)
 
{
 
{
     //pragma(msg, info);
+
     enum info = log!("INFO", PS);   
    const char[] info = `static if(!__traits(compiles, __FUNCTION__ == ""))` ~
+
}
                        `{ immutable string __FUNCTION__ = __traits(identifier, __traits(parent, {})) ~` ~
+
                                                          `"(" ~ StringOf!(PTT!(__traits(parent, {}))) ~ ")";` ~
+
template warn(PS...)
                        `} stderr.writeln(Clock.currTime(), " [INFO] ", __FILE__, '(', __LINE__, "): ",` ~
+
{
                                          `__FUNCTION__, ": ",` ~ ArgStringOf!(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)
{
+
{  
     immutable string __FUNCTION__ = 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!(`"started"`));
+
     mixin (info!(`"starting"`));
     mixin (info!(`"stopped"`));
+
+
     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!(`"started"`));
+
     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 (info!(`"stopped"`));
+
     try
 +
    {
 +
        baz();
 +
    }
 +
    catch(Exception e)
 +
    {
 +
        mixin (error!(`"Caught exception: "`, `e.toString()`));
 +
    }   
 
}
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
+
==Sample Output==
[http://dpaste.dzfl.pl/e67958e5 &#9654; Run code]
+
<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

Level: Novice
Cookbook Type: Recipe
Cookbook Status: Deprecated
Approximate reading time: 10 min
0.166 hr
D Version: D2


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