1 module mage.log; 2 import mage; 3 4 import io = std.stdio; 5 6 7 struct Block 8 { 9 string message; 10 int indentation; 11 bool isPrinted = false; 12 13 @disable this(); 14 15 this(Args...)(string message, Args fmtargs) 16 { 17 static if(Args.length) { 18 this.message = message.format(fmtargs); 19 } 20 else { 21 this.message = message; 22 } 23 this.indentation = blocks.length; 24 blocks ~= &this; 25 } 26 27 ~this() 28 { 29 assert(blocks[$-1] == &this, "Popping log Blocks in wrong order."); 30 blocks.length--; 31 if(this.isPrinted) { 32 print("<<<| ", "<<< ", ""); 33 } 34 } 35 36 void print(string linePrefix, string messagePrefix, string messageSuffix) 37 { 38 io.writef("%-*s", 2 * this.indentation + linePrefix.length, linePrefix); 39 io.writefln("%s%s%s", messagePrefix, this.message, messageSuffix); 40 this.isPrinted = true; 41 } 42 } 43 44 auto forcedBlock(Args...)(Args args) 45 { 46 auto b = Block(args); 47 printBlocks(); 48 return b; 49 } 50 51 package 52 { 53 Block*[] blocks; 54 55 void printBlocks() 56 { 57 foreach(block; blocks) { 58 if(!block.isPrinted) { 59 block.print(">>>| ", ">>> ", ""); 60 assert(block.isPrinted); 61 } 62 } 63 } 64 65 void doLog(string prefix, Args...)(string message, Args fmtargs) 66 { 67 printBlocks(); 68 io.write(indentString(prefix)); 69 io.writefln(message, fmtargs); 70 } 71 } 72 73 @property int indentSize() { return blocks.length; } 74 string indentString(string prefix = "") { return "%-*s".format(2 * indentSize + prefix.length, prefix); } 75 76 void info (Args...)(string fmt, Args fmtargs) { doLog!"Ifo| "(fmt, fmtargs); } 77 void trace (Args...)(string fmt, Args fmtargs) { doLog!"Trc| "(fmt, fmtargs); } 78 void error (Args...)(string fmt, Args fmtargs) { doLog!"Err| "(fmt, fmtargs); } 79 void warning(Args...)(string fmt, Args fmtargs) { doLog!"Wrn| "(fmt, fmtargs); } 80 81 unittest 82 { 83 info("Hello testing world"); 84 with(Block("Block 0")) 85 { 86 info("Inner message"); 87 with(Block("Block 1")) 88 { 89 info("Going deeper..."); 90 } 91 info("Backing out again."); 92 } 93 info("Back to the top-level"); 94 }