1 /******************************************************************************* 2 3 Base interface for Loggers implementation 4 5 Note: 6 The formatting primitives (error, info, warn...) are not part of the 7 interface anymore, as they can be templated functions. 8 9 Copyright: 10 Copyright (c) 2004 Kris Bell. 11 Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH. 12 All rights reserved. 13 14 License: 15 Tango Dual License: 3-Clause BSD License / Academic Free License v3.0. 16 See LICENSE_TANGO.txt for details. 17 18 Version: Initial release: May 2004 19 20 Authors: Kris 21 22 *******************************************************************************/ 23 24 module ocean.util.log.ILogger; 25 26 import ocean.meta.types.Qualifiers; 27 import core.sys.posix.strings; 28 29 version (unittest) 30 { 31 import ocean.core.Test; 32 } 33 34 35 /// Ditto 36 interface ILogger 37 { 38 /// Defines the level at which a message can be logged 39 public enum Level : ubyte 40 { 41 /// The lowest level: Used for programming debug statement 42 Debug, 43 /// Trace messages let the user "trace" the program behavior, 44 /// e.g. what function calls are made (or when they exit) 45 Trace, 46 /// Verbose message provide extra informations about the program 47 Verbose, 48 /// Informative message, this is the "default" value for the user 49 Info, 50 /// Warnings about potential issues 51 Warn, 52 /// Notify the user of a hard error 53 Error, 54 /// A Fatal error, which could lead to the program termination 55 Fatal, 56 /// No message should be output 57 None, 58 }; 59 60 /// Internal struct to associate a `Level` with its name 61 private struct Pair 62 { 63 /// The name associated with `value` 64 istring name; 65 /// An `ILogger.Level` value 66 Level value; 67 } 68 69 /*************************************************************************** 70 71 Poor man's SmartEnum: We don't use SmartEnum directly because 72 it would change the public interface, and we accept any case anyway. 73 74 This can be fixed when we drop D1 support. 75 76 ***************************************************************************/ 77 78 private static immutable Pair[Level.max + 1] Pairs = 79 [ 80 { "Debug", Level.Debug }, 81 { "Trace", Level.Trace }, 82 { "Verbose", Level.Verbose }, 83 { "Info", Level.Info }, 84 { "Warn", Level.Warn }, 85 { "Error", Level.Error }, 86 { "Fatal", Level.Fatal }, 87 { "None", Level.None }, 88 ]; 89 90 /*************************************************************************** 91 92 Return the enum value associated with `name`, or a default value 93 94 Params: 95 name = Case-independent string representation of an `ILogger.Level` 96 If the name is not one of the logger, `def` is returned. 97 def = Default value to return if no match is found for `name` 98 99 Returns: 100 The `Level` value for `name`, or `def` 101 102 ***************************************************************************/ 103 104 public static Level convert (cstring name, Level def = Level.Trace) 105 { 106 foreach (field; ILogger.Pairs) 107 { 108 if (field.name.length == name.length 109 && !strncasecmp(name.ptr, field.name.ptr, name.length)) 110 return field.value; 111 } 112 return def; 113 } 114 115 /*************************************************************************** 116 117 Return the name associated with level 118 119 Params: 120 level = The `Level` to get the name for 121 122 Returns: 123 The name associated with `level`. 124 125 ***************************************************************************/ 126 127 public static istring convert (Level level) 128 { 129 return ILogger.Pairs[level].name; 130 } 131 132 133 /*************************************************************************** 134 135 Context for a hierarchy, used for customizing behaviour of log 136 hierarchies. You can use this to implement dynamic log-levels, 137 based upon filtering or some other mechanism 138 139 ***************************************************************************/ 140 141 public interface Context 142 { 143 /// return a label for this context 144 public istring label (); 145 146 /// first arg is the setting of the logger itself, and 147 /// the second arg is what kind of message we're being 148 /// asked to produce 149 public bool enabled (Level setting, Level target); 150 } 151 152 153 /*************************************************************************** 154 155 Returns: 156 `true` if this logger is enabed for the specified `Level` 157 158 Params: 159 `Level` to test for, defaults to `Level.Fatal`. 160 161 ***************************************************************************/ 162 163 public bool enabled (Level level = Level.Fatal); 164 165 /*************************************************************************** 166 167 Returns: 168 The name of this `ILogger` (without the appended dot). 169 170 ***************************************************************************/ 171 172 public cstring name (); 173 174 175 /*************************************************************************** 176 177 Returns: 178 The `Level` this `ILogger` is set to 179 180 ***************************************************************************/ 181 182 public Level level (); 183 184 /*************************************************************************** 185 186 Set the current `Level` for this logger (and only this logger). 187 188 Params: 189 l = New `Level` value to set this logger to. 190 191 Returns: 192 `this` for easy chaining 193 194 ***************************************************************************/ 195 196 public ILogger level (Level l); 197 198 /*************************************************************************** 199 200 Returns: 201 `true` if the logger is additive. 202 Additive loggers walk through ancestors looking for more appenders 203 204 ***************************************************************************/ 205 206 public bool additive (); 207 208 /*************************************************************************** 209 210 Set the additive status of this logger 211 212 Additive loggers walk through ancestors looking for more appenders 213 214 Params: 215 enabled = Whereas this logger is additive. 216 217 Returns: 218 `this` for easy chaining 219 220 ***************************************************************************/ 221 222 public ILogger additive (bool enabled); 223 224 /*************************************************************************** 225 226 Send a message to this logger. 227 228 Params: 229 level = Level at which to log the message 230 exp = Lazily evaluated message string 231 If the `level` is not enabled for this logger, it won't 232 be evaluated. 233 234 Returns: 235 `this` for easy chaining 236 237 ***************************************************************************/ 238 239 public ILogger append (Level level, lazy cstring exp); 240 } 241 242 unittest 243 { 244 test!("==")(ILogger.convert(ILogger.Level.Trace), "Trace"); 245 test!("==")(ILogger.convert(ILogger.Level.Info), "Info"); 246 test!("==")(ILogger.convert(ILogger.Level.Warn), "Warn"); 247 test!("==")(ILogger.convert(ILogger.Level.Error), "Error"); 248 test!("==")(ILogger.convert(ILogger.Level.Fatal), "Fatal"); 249 test!("==")(ILogger.convert(ILogger.Level.None), "None"); 250 } 251 252 unittest 253 { 254 test!("==")(ILogger.convert("info"), ILogger.Level.Info); 255 test!("==")(ILogger.convert("Info"), ILogger.Level.Info); 256 test!("==")(ILogger.convert("INFO"), ILogger.Level.Info); 257 test!("==")(ILogger.convert("FATAL"), ILogger.Level.Fatal); 258 // Use the default value 259 test!("==")(ILogger.convert("Info!"), ILogger.Level.Trace); 260 test!("==")(ILogger.convert("Baguette", ILogger.Level.Warn), 261 ILogger.Level.Warn); 262 // The first entry in the array 263 test!("==")(ILogger.convert("trace", ILogger.Level.Error), 264 ILogger.Level.Trace); 265 }