1 module appbase.utils.log; 2 3 import core.sync.mutex; 4 import std.path : buildPath; 5 import std.conv : to; 6 import std.experimental.logger.core : LogLevel; 7 import std.experimental.logger.filelogger : FileLogger, CreateFolder; 8 import std.datetime; 9 import std.stdio : writeln; 10 11 import appbase.utils.utility; 12 13 /// file logger. 14 struct Logger 15 { 16 private __gshared Date today; 17 private __gshared FileLogger fl; 18 19 private __gshared Mutex _mutex; 20 21 private static this() 22 { 23 _mutex = new Mutex(); 24 } 25 26 /// write log to file. 27 static void write(string file = __FILE__, size_t line = __LINE__, 28 string funcName = __FUNCTION__, 29 string prettyFuncName = __PRETTY_FUNCTION__, 30 string moduleName = __MODULE__, 31 Args...)(Args args) 32 { 33 if (args.length == 0) 34 { 35 return; 36 } 37 38 DateTime dt = now; 39 if ((dt.date != today) || (fl is null)) 40 { 41 synchronized (_mutex) 42 { 43 if ((dt.date != today) || (fl is null)) 44 { 45 if (fl !is null) 46 { 47 fl.file.flush(); 48 fl.file.close(); 49 } 50 51 today = dt.date; 52 const auto filename = buildPath(getExePath(), "log", dt.year.to!string, dt.date.toISOString() ~ ".log"); 53 fl = new FileLogger(filename, LogLevel.all, CreateFolder.yes); 54 } 55 } 56 } 57 58 fl.log!(line, file, funcName, prettyFuncName, moduleName)(getExeName, ": ", args); 59 } 60 61 static void flush(const bool closeFile = false) 62 { 63 synchronized (_mutex) 64 { 65 fl.file.flush(); 66 67 if (closeFile) 68 { 69 fl.file.close(); 70 fl = null; 71 } 72 } 73 } 74 } 75 alias logger = Logger; 76 77 78 /// classification file logger. 79 struct LoggerEx 80 { 81 private __gshared Date today; 82 private __gshared FileLogger[size_t] fl; 83 84 private __gshared Mutex _mutex; 85 86 private static this() 87 { 88 _mutex = new Mutex(); 89 } 90 91 /// write log to file. 92 static void write(string file = __FILE__, size_t line = __LINE__, 93 string funcName = __FUNCTION__, 94 string prettyFuncName = __PRETTY_FUNCTION__, 95 string moduleName = __MODULE__, 96 T = size_t, 97 Args...)(T classification, Args args) 98 { 99 if (args.length == 0) 100 { 101 return; 102 } 103 104 const size_t _class = cast(size_t) classification; 105 DateTime dt = now; 106 107 if ((dt.date != today) || (_class !in fl) || (fl[_class] is null)) 108 { 109 synchronized (_mutex) 110 { 111 if ((dt.date != today) || (_class !in fl) || (fl[_class] is null)) 112 { 113 if ((_class in fl) && (fl[_class] !is null)) 114 { 115 fl[_class].file.flush(); 116 fl[_class].file.close(); 117 } 118 119 today = dt.date; 120 const auto filename = buildPath(getExePath(), "log", dt.year.to!string, dt.date.toISOString(), _class.to!string ~ ".log"); 121 fl[_class] = new FileLogger(filename, LogLevel.all, CreateFolder.yes); 122 } 123 } 124 } 125 126 fl[_class].log!(line, file, funcName, prettyFuncName, moduleName)(getExeName, ": ", args); 127 } 128 129 static void flush(const bool closeFile = false) 130 { 131 synchronized (_mutex) 132 { 133 foreach (ref f; fl) 134 { 135 f.file.flush(); 136 137 if (closeFile) 138 { 139 f.file.close(); 140 f = null; 141 } 142 } 143 } 144 } 145 } 146 alias loggerEx = LoggerEx; 147 148 149 void writelnEx(string file = __FILE__, size_t line = __LINE__, 150 string funcName = __FUNCTION__, 151 string prettyFuncName = __PRETTY_FUNCTION__, 152 string moduleName = __MODULE__, 153 Args...)(Args args) 154 { 155 writeln(appbase.utils.now, " ", file, ":", line, ":", funcName, ": ", args); 156 }