1 /**
2 *    Logging system designed to operate in concurrent application.
3 *
4 *    The system should be initialized with $(B initLoggingSystem) function.
5 *    There is no need to call shutdown function as it is happen in module
6 *    destructor.
7 *
8 *    Example:
9 *    ---------
10 *    void testThread()
11 *    {
12 *        foreach(j; 1 .. 50)
13 *        {
14 *            logInfo(to!string(j));
15 *            logError(to!string(j));
16 *        }
17 *    }    
18 *
19 *    foreach(i; 1 .. 50)
20 *    {
21 *        spawn(&testThread);
22 *    }
23 *    ---------
24 *
25 *   Copyright: © 2013-2014 Anton Gushcha
26 *   License: Subject to the terms of the MIT license, as written in the included LICENSE file.
27 *   Authors: NCrashed <ncrashed@gmail.com>
28 *
29 */
30 module dlogg.log;
31 @safe:
32 
33 public import std.conv;
34 
35 /**
36 *   Log levels defines style of the messages.
37 *   Printing in console can be controlled by
38 *   ILogger.minOutputLevel property.
39 */
40 enum LoggingLevel
41 {
42     Notice,
43     Warning,
44     Debug,
45     Fatal,
46     Muted // Used only to mute all writing to console
47 }
48 
49 /**
50 *   Default logger interface that uses $(B LoggingLevel) as
51 *   enum that describes ordering of logging levels.
52 */
53 alias ILogger = IStyledLogger!(LoggingLevel);
54 
55 // wrappers for easy logging
56 nothrow @trusted
57 {
58     /**
59     *   Wrapper for handy debug messages.
60     *   Warning: main purpose for debug messages, thus it is not lazy.
61     */
62     void logDebug(E...)(shared ILogger logger, E args)
63     {
64         debug
65         {
66             try logger.log(text(args), LoggingLevel.Debug);
67             catch(Exception e) {}
68         }
69     }
70     
71     /// Not lazy wrapper for multiple args messages
72     void logInfo(E...)(shared ILogger logger, E args)
73     {
74         try logger.log(text(args), LoggingLevel.Notice);
75         catch(Exception e) {}
76     }
77 
78     /// Lazy wrapper for one string message
79     void logInfo()(shared ILogger logger, lazy string message)
80     {
81     	try
82     	{
83     		if(message is null) return;
84     		logger.log(message, LoggingLevel.Notice);
85 		} 
86     	catch(Exception e) {}
87     }
88     
89     /// Not lazy wrapper for multiple args messages
90     void logWarning(E...)(shared ILogger logger, E args)
91     {
92         try logger.log(text(args), LoggingLevel.Warning);
93         catch(Exception e) {}
94     }
95     
96     /// Lazy wrapper for one string message
97     void logWarning()(shared ILogger logger, lazy string message)
98     {
99     	try
100     	{
101 	        if(message is null) return;
102 	        logger.log(message, LoggingLevel.Warning);
103 		} 
104     	catch(Exception e) {}
105     }
106     
107     /// Not lazy wrapper for multiple args messages
108     void logError(E...)(shared ILogger logger, E args)
109     {
110         try logger.log(text(args), LoggingLevel.Fatal);
111         catch(Exception e) {}
112     }
113     
114     /// Lazy wrapper for one string message
115     void logError()(shared ILogger logger, lazy string message)
116     {
117     	try
118     	{
119 	        if(message is null) return;
120 	        logger.log(message, LoggingLevel.Fatal);
121 		} 
122     	catch(Exception e) {}
123     }
124 }
125     
126 /**
127 *   Interface for lazy logging. Assumes to be nothrow.
128 *   Underlying realization should be concurrent safe.
129 *
130 *   $(B StyleEnum) is enum that used to distinct logging
131 *   levels and define ordering for verbosity muting.
132 */
133 shared interface IStyledLogger(StyleEnum)
134 {
135     /**
136     *   Setting new log file name. If the $(B value)
137     *   differs from old one, logger should close
138     *   old one and open new file.
139     */
140     void name(string value) @property;
141     
142     nothrow 
143     {
144         /**
145         *   Log file name.
146         */
147         string name() @property const;
148         
149         /**
150         *   Prints message into log. Displaying in the console
151         *   controlled by minOutputLevel property.
152         */
153         void log(lazy string message, StyleEnum level);
154 
155         /**
156         *   Returns: minimum log level,  will be printed in the console.
157         */
158         StyleEnum minOutputLevel() const @property;
159 
160         /**
161         *   Setups minimum message level that goes to console.
162         */
163         void minOutputLevel(StyleEnum level) @property;
164         
165         /**
166         *   Setups minimum message level that goes to file.
167         */
168         StyleEnum minLoggingLevel() @property;
169         
170         /**
171         *   Setups minimum message level that goes to file.
172         */
173         void minLoggingLevel(StyleEnum level) @property;
174         
175         /**
176         *   Used to manual shutdown protocols.
177         */
178         void finalize();
179     }
180 
181     /**
182     *   Unsafe write down the message without any meta information.
183     */
184     void rawInput(string message);
185     
186     /**
187     *   Format message with default logging style (etc. time and level string).
188     */
189     string formatConsoleOutput(string message, StyleEnum level);
190     
191     /**
192     *   Format message with default logging style (etc. time and level string).
193     */
194     string formatFileOutput(string message, StyleEnum level);
195     
196     /**
197     *   Checks if the log file is exists at specified $(B location) and
198     *   if can't find it, recreates the file and continues write into it.
199     *
200     *   Useful for $(B logrotate) utility. GNU/Linux system checks file identity by
201     *   inode, that doesn't change while renaming. Thus after renaming the file at 
202     *   $(B location) log continues write into the renamed file. The call to the
203     *   $(B reload) method force splitting log into two parts.
204     *
205     *   Note: The method is not nothrow!
206     */
207     void reload();
208 }