1 /*
2  *  BSD 3-Clause License
3  *  
4  *  Copyright (c) 2016, Mango-Engine Team
5  *  All rights reserved.
6  *  
7  *  Redistribution and use in source and binary forms, with or without
8  *  modification, are permitted provided that the following conditions are met:
9  *  
10  *  * Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *  
13  *  * Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  *  
17  *  * Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from
19  *    this software without specific prior written permission.
20  *  
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 module mango_engine.logging;
33 
34 import mango_engine.mango : VERSION;
35 import mango_engine.util : getTimestamp, getOSString, SyncLock;
36 
37 import consoled : writecln, FontStyle, Fg, resetColors, resetFontStyle;
38 
39 import std.stdio : write, writeln, File;
40 import std.system : os;
41 import std.conv : to;
42 
43 import core.thread : Thread;
44 import core.cpuid : coresPerCPU, processor, vendor;
45 
46 private shared SyncLock consoleLock;
47 
48 shared static this() {
49     consoleLock = new SyncLock();
50 }
51 
52 abstract class Logger {
53     /// The name of the logger.
54     immutable string name;
55 
56     this(in string name) @safe nothrow {
57         this.name = name;
58     }
59 
60     void logDebug(in string message) @safe {
61         debug {
62             logDebug_(message);
63         }
64     }
65 
66     abstract void logDebug_(in string message) @safe;
67 
68     abstract void logInfo(in string message) @safe;
69 
70     abstract void logWarn(in string message) @safe;
71 
72     abstract void logError(in string message) @safe;
73 
74     abstract void logException(in string messageInfo, Exception e) @safe;
75 }
76 
77 class ConsoleLogger : Logger {
78 
79     this(in string name) @safe nothrow {
80         super(name);
81     }
82 
83     override {
84         void logDebug_(in string message) @trusted {
85             synchronized(consoleLock) {
86                 writecln(FontStyle.bold, Fg.cyan, "[", name, Fg.magenta, "|", Thread.getThis().name, "|", Fg.cyan, "/", Fg.lightBlue, "DEBUG", Fg.cyan, "]: ", FontStyle.none, Fg.white, message);
87 
88                 resetColors();
89                 resetFontStyle();
90             }
91         }
92 
93         void logInfo(in string message) @trusted {
94             synchronized(consoleLock) {
95                 writecln(FontStyle.bold, Fg.cyan, "[", name, "/", Fg.lightGreen, "INFO", Fg.cyan, "]: ", FontStyle.none, Fg.white, message);
96 
97                 resetColors();
98                 resetFontStyle();
99             }
100         }
101 
102         void logWarn(in string message) @trusted {
103             synchronized(consoleLock) {
104                 writecln(FontStyle.bold, Fg.cyan, "[", name, "/", Fg.lightYellow, "WARN", Fg.cyan, "]: ", FontStyle.none, Fg.white, message);
105 
106                 resetColors();
107                 resetFontStyle();
108             }
109         }
110 
111         void logError(in string message) @trusted {
112             synchronized(consoleLock) {
113                 writecln(FontStyle.bold, Fg.cyan, "[", name, Fg.magenta, "|", Thread.getThis().name, "|", Fg.cyan, "/", Fg.lightRed, "ERROR", Fg.cyan, "]: ", Fg.white, message);
114 
115                 resetColors();
116                 resetFontStyle();
117             }
118         }
119 
120         void logException(in string messageInfo, Exception e) @trusted {
121             string filename = "exceptionDump_" ~ getTimestamp() ~ ".txt";
122             debug {
123                 logError(e.toString());
124             }
125             logError("An exception report has been saved to " ~ filename);
126 
127             File file = File(filename, "w");
128             file.writeln("Mango-Engine exception dump at " ~ getTimestamp());
129             file.writeln("Mango-Engine version: " ~ VERSION);
130             file.writeln("Compiler: " ~ __VENDOR__ ~ ", compiled at: " ~ __TIMESTAMP__);
131             file.writeln("------------------------------------------");
132             file.writeln("System Information:");
133             file.writeln("Operating System: " ~ getOSString());
134             file.writeln("size_t length: " ~ to!string(size_t.sizeof));
135             file.writeln("CPU: " ~ vendor ~ " " ~ processor ~ " with " ~ to!string(coresPerCPU()) ~ " cores");
136             file.writeln("------------------------------------------");
137             file.writeln("Additional Information: " ~ messageInfo);
138             file.writeln("In Thread: " ~ Thread.getThis().name);
139             file.writeln("Exception: \n");
140             file.write(e.toString());
141             file.close();
142         }
143     }
144 }