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 }