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 }