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