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 }