1 module geario.logging.appender; 2 3 @system: 4 package: 5 6 import geario.logging.config; 7 8 /** 9 * Appender Creating interface 10 * 11 * Use by Logger for create new Appender 12 * 13 * ==================================================================================== 14 */ 15 interface AppenderFactory 16 { 17 Appender factory(LoggerConfig config); 18 } 19 20 21 /** 22 * Accept messages and publicate it in target 23 */ 24 abstract class Appender 25 { 26 /** 27 * Append new message 28 */ 29 void append(Level level, string message); 30 } 31 32 33 /** 34 * Factory for NullAppender 35 * 36 * ==================================================================================== 37 */ 38 class NullAppenderFactory:AppenderFactory 39 { 40 override Appender factory(LoggerConfig config) 41 { 42 return new NullAppender(); 43 } 44 } 45 46 47 /** 48 * Only Accept messages 49 */ 50 class NullAppender:Appender 51 { 52 /** 53 * Append new message and do nothing 54 */ 55 override void append(Level level, string message) nothrow pure {} 56 } 57 58 59 /** 60 * Factory for ConsoleAppender 61 * 62 * ==================================================================================== 63 */ 64 class ConsoleAppenderFactory:AppenderFactory 65 { 66 override Appender factory(LoggerConfig config) 67 { 68 return new ConsoleAppender(); 69 } 70 } 71 72 73 /** 74 * Accept messages and publicate it on console 75 */ 76 class ConsoleAppender:Appender 77 { 78 /** 79 * Append new message and print it to console 80 */ 81 @trusted /* writefln is system */ 82 override void append(Level level, string message) 83 { 84 import colorize : fg, color, cwriteln, cwritefln; 85 86 fg c; 87 88 switch (level) 89 { 90 case level.Warn: 91 c = fg.yellow; 92 break; 93 case Level.Error: 94 case Level.Fatal: 95 c = fg.red; 96 break; 97 case Level.Info: 98 c = fg.green; 99 break; 100 default: 101 c = fg.init; 102 } 103 104 cwriteln(message.color(c)); 105 } 106 } 107 108 109 /** 110 * Factory for FileAppender 111 * 112 * ==================================================================================== 113 */ 114 class FileAppenderFactory:AppenderFactory 115 { 116 override Appender factory(LoggerConfig config) 117 { 118 return new FileAppender(config); 119 } 120 } 121 122 123 /** 124 * Accept messages and publicate it in file 125 */ 126 class FileAppender:Appender 127 { 128 import std.concurrency; 129 130 /* Tid for appender activity */ 131 Tid activity; 132 133 /** 134 * Create Appender 135 */ 136 @trusted 137 this(LoggerConfig config) 138 { 139 activity = spawn(&fileAppenderActivityStart, config); 140 } 141 142 /** 143 * Append new message and send it to file 144 */ 145 @trusted 146 override void append(Level level, string message) 147 { 148 activity.send(message); 149 } 150 } 151 152 153 /** 154 * Start new thread for file log activity 155 */ 156 @system 157 void fileAppenderActivityStart(LoggerConfig config) nothrow 158 { 159 try 160 { 161 new FileAppenderActivity(config).run(); 162 } 163 catch (Exception e) 164 { 165 try 166 { 167 import std.stdio; 168 writeln("FileAppenderActivity exception: " ~ e.msg); 169 } 170 catch (Exception ioe){} 171 } 172 } 173 174 175 /** 176 * Logger FileAppender activity 177 * 178 * Write log message to file from one thread 179 */ 180 class FileAppenderActivity 181 { 182 import geario.logging.storage; 183 import std.concurrency; 184 import std.datetime; 185 186 /* Max flush period to write to file */ 187 enum logFileWriteFlushPeriod = 100; // ms 188 189 /* Activity working status */ 190 enum AppenderWorkStatus {WORKING, STOPPING} 191 private auto workStatus = AppenderWorkStatus.WORKING; 192 193 long startFlushTime; 194 195 /* Max flush period to write to file */ 196 FileStorage storage; 197 198 /** 199 * Primary constructor 200 * 201 * Save config path and name 202 */ 203 this(LoggerConfig config) 204 { 205 storage = FileStorage(config); 206 startFlushTime = Clock.currStdTime(); 207 } 208 209 /** 210 * Entry point for start module work 211 */ 212 @system 213 void run() 214 { 215 /** 216 * Main activity cycle 217 */ 218 while (workStatus == AppenderWorkStatus.WORKING) 219 { 220 try 221 { 222 workCycle(); 223 } 224 catch (Exception e) 225 { 226 import std.stdio; 227 writeln("FileAppenderActivity workcycle exception: " ~ e.msg); 228 } 229 } 230 } 231 232 /** 233 * Activity main cycle 234 */ 235 @trusted 236 private void workCycle() 237 { 238 receiveTimeout( 239 100.msecs, 240 (string msg) 241 { 242 storage.saveMsg(msg); 243 }, 244 (OwnerTerminated e){workStatus = AppenderWorkStatus.STOPPING;}, 245 (Variant any){} 246 ); 247 248 if (logFileWriteFlushPeriod <= (Clock.currStdTime() - startFlushTime)/(1000*10)) 249 { 250 storage.flush; 251 startFlushTime = Clock.currStdTime(); 252 } 253 } 254 }