1 /*******************************************************************************
2
3 Log appender which writes to syslog
4
5 Copyright:
6 Copyright (c) 2009-2016 dunnhumby Germany GmbH.
7 All rights reserved.
8
9 License:
10 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
11 Alternatively, this file may be distributed under the terms of the Tango
12 3-Clause BSD License (see LICENSE_BSD.txt for details).
13
14 *******************************************************************************/
15
16 module ocean.util.log.AppendSysLog;
17
18
19 import ocean.meta.types.Qualifiers;
20 import ocean.core.Verify;
21 import ocean.util.log.Appender;
22 import ocean.util.log.Event;
23 import ocean.util.log.ILogger;
24
25 import core.sys.posix.syslog;
26
27
28 /*******************************************************************************
29
30 syslog priority levels
31
32 *******************************************************************************/
33
34 private enum Priority
35 {
36 LOG_EMERG = 0, /* system is unusable */
37 LOG_ALERT = 1, /* action must be taken immediately */
38 LOG_CRIT = 2, /* critical conditions */
39 LOG_ERR = 3, /* error conditions */
40 LOG_WARNING = 4, /* warning conditions */
41 LOG_NOTICE = 5, /* normal but significant condition */
42 LOG_INFO = 6, /* informational */
43 LOG_DEBUG = 7, /* debug-level messages */
44 }
45
46 /*******************************************************************************
47
48 syslog appender class
49
50 *******************************************************************************/
51
52 public class AppendSysLog : Appender
53 {
54 import ocean.core.Array : concat;
55 import ocean.core.TypeConvert : castFrom;
56
57 /***************************************************************************
58
59 Layout class for syslog output. Outputs the logger name followed by the
60 log message.
61
62 ***************************************************************************/
63
64 private static class SysLogLayout : Layout
65 {
66 override public void format ( LogEvent event, scope FormatterSink dg )
67 {
68 dg("[");
69 dg(event.name);
70 dg("] - ");
71 dg(event.toString);
72 }
73 }
74
75 /***************************************************************************
76
77 Alias for this type.
78
79 ***************************************************************************/
80
81 private alias typeof(this) This;
82
83 /***************************************************************************
84
85 Static instance of SysLogLayout, shared by all AppendSysLog instances.
86
87 ***************************************************************************/
88
89 static private SysLogLayout syslog_layout;
90
91 /***************************************************************************
92
93 Static constructor. Initialises the shared SysLogLayout instance.
94
95 ***************************************************************************/
96
97 static this ( )
98 {
99 This.syslog_layout = new SysLogLayout;
100 }
101
102 /***************************************************************************
103
104 Internal formatting buffer.
105
106 ***************************************************************************/
107
108 private mstring buf;
109
110 /***************************************************************************
111
112 Mask used to identify this Appender. The mask is used to figure out
113 whether an appender has already been invoked for a particular logger.
114
115 ***************************************************************************/
116
117 private Mask mask_;
118
119 /***************************************************************************
120
121 Global ID string used by syslog to identify this program's log messages.
122 Set by setId().
123
124 ***************************************************************************/
125
126 static private mstring id;
127
128 /***************************************************************************
129
130 Sets the global syslog ID string for this program. Calling this function
131 is optional; if it is not called, the program's name is used as the ID.
132
133 Params:
134 id = ID string to set (copied internally)
135
136 ***************************************************************************/
137
138 static public void setId ( cstring id )
139 {
140 This.id.concat(id, "\0");
141 int option = 0; // no options
142 int facility = 0; // default facility
143 openlog(This.id.ptr, option, facility);
144 }
145
146 /***************************************************************************
147
148 Constructor. Sets the layout to the static SysLogLayout instance.
149
150 ***************************************************************************/
151
152 public this ( )
153 {
154 this.layout = This.syslog_layout;
155 }
156
157 /***************************************************************************
158
159 Return:
160 the fingerprint for this class
161
162 ***************************************************************************/
163
164 override public Mask mask ( )
165 {
166 return this.mask_;
167 }
168
169 /***************************************************************************
170
171 Returns:
172 the name of this class
173
174 ***************************************************************************/
175
176 override public istring name ( )
177 {
178 return this.classinfo.name;
179 }
180
181 /***************************************************************************
182
183 Append an event to the output.
184
185 Params:
186 event = log event to be appended
187
188 ***************************************************************************/
189
190 override public void append ( LogEvent event )
191 {
192 if ( event.level != event.level.None )
193 syslog(this.priority(event), "%s".ptr, this.format(event));
194 }
195
196 /***************************************************************************
197
198 Gets the syslog priority for the specified log event.
199
200 Params:
201 event = log event to get the priority for
202
203 Returns:
204 syslog priority of the log event
205
206 In:
207 as level None is a non-value, events of this level are not valid
208 input to the function
209
210 ***************************************************************************/
211
212 private int priority ( LogEvent event )
213 {
214 verify(event.level != event.level.None);
215
216 with (ILogger.Level) switch (event.level)
217 {
218 case Trace:
219 return Priority.LOG_DEBUG;
220 case Info:
221 return Priority.LOG_INFO;
222 case Warn:
223 return Priority.LOG_WARNING;
224 case Error:
225 return Priority.LOG_ERR;
226 case Fatal:
227 return Priority.LOG_CRIT;
228 default:
229 assert(false);
230 // Note that there is no mapping to LOG_NOTICE, LOG_ALERT, LOG_EMERG
231 }
232 }
233
234 /***************************************************************************
235
236 Gets a pointer to the formatted, null-terminated string for the
237 specified log event.
238
239 Params:
240 event = log event to get the formatted string for
241
242 Returns:
243 pointer to the formatted string for the log event
244
245 ***************************************************************************/
246
247 private char* format ( LogEvent event )
248 {
249 void sink ( cstring data )
250 {
251 this.buf ~= data;
252 }
253
254 this.buf.length = 0;
255 assumeSafeAppend(this.buf);
256 this.layout.format(event, &sink);
257 this.buf ~= '\0';
258
259 return this.buf.ptr;
260 }
261 }