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