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