xxxxxxxxxx
import std.datetime : Clock;
import std.stdio;
enum LogLevel { INFO, WARN, ERROR }
// Nested template to allow aliasing LogLevels.
// This makes it easily possible to create wrapper aliases without creating new
// wrapper functions which would alter the FILE, LINE and FUNCTION constants.
template log(LogLevel level)
{
void log(Args...)(
Args args,
string fn = __FUNCTION__, // fully qualified function name of the caller
string file = __FILE__, // filename of the caller as specified in the compilation
size_t line = __LINE__ // line number of the caller
)
{
// Instead of using the default string conversion of Clock.currTime()
// we could use Clock.currTime().toISOExtString() for a machine parsable
// format or have a static constructor initializing a global MonoTime
// variable at program startup and subtract from it here to have a time
// offset from the start of the program being logged which is guaranteed
// to only increase. (as opposed to the clock, which could change with
// leap days, leap seconds or system clock manipulation)
writeln(Clock.currTime(), // dump date & time with default format
" [", level, "] ", // automatically converts enum member name to string
file,
'(', line, "): ",
fn, ": ",
args // actual log arguments, all dumped using writeln
);
}
}
// convenience aliases, uses nested templates to allow easily doing this
alias info = log!(LogLevel.INFO);
alias warn = log!(LogLevel.WARN);
alias error = log!(LogLevel.ERROR);
void main(string[] args)
{
// nested templates of functions call like any function
info("hello ", "world");
warn("we are", " number ", 1);
log!(LogLevel.INFO)("manual call");
error(true);
}