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 40 { 41 /// 42 Trace = 0, 43 /// 44 Info, 45 /// 46 Warn, 47 /// 48 Error, 49 /// 50 Fatal, 51 /// 52 None 53 }; 54 55 /// Internal struct to associate a `Level` with its name 56 private struct Pair 57 { 58 /// The name associated with `value` 59 istring name; 60 /// An `ILogger.Level` value 61 Level value; 62 } 63 64 /*************************************************************************** 65 66 Poor man's SmartEnum: We don't use SmartEnum directly because 67 it would change the public interface, and we accept any case anyway. 68 69 This can be fixed when we drop D1 support. 70 71 ***************************************************************************/ 72 73 private static immutable Pair[Level.max + 1] Pairs = 74 [ 75 { "Trace", Level.Trace }, 76 { "Info", Level.Info }, 77 { "Warn", Level.Warn }, 78 { "Error", Level.Error }, 79 { "Fatal", Level.Fatal }, 80 { "None", Level.None } 81 ]; 82 83 /*************************************************************************** 84 85 Return the enum value associated with `name`, or a default value 86 87 Params: 88 name = Case-independent string representation of an `ILogger.Level` 89 If the name is not one of the logger, `def` is returned. 90 def = Default value to return if no match is found for `name` 91 92 Returns: 93 The `Level` value for `name`, or `def` 94 95 ***************************************************************************/ 96 97 public static Level convert (cstring name, Level def = Level.Trace) 98 { 99 foreach (field; ILogger.Pairs) 100 { 101 if (field.name.length == name.length 102 && !strncasecmp(name.ptr, field.name.ptr, name.length)) 103 return field.value; 104 } 105 return def; 106 } 107 108 /*************************************************************************** 109 110 Return the name associated with level 111 112 Params: 113 level = The `Level` to get the name for 114 115 Returns: 116 The name associated with `level`. 117 118 ***************************************************************************/ 119 120 public static istring convert (Level level) 121 { 122 return ILogger.Pairs[level].name; 123 } 124 125 126 /*************************************************************************** 127 128 Context for a hierarchy, used for customizing behaviour of log 129 hierarchies. You can use this to implement dynamic log-levels, 130 based upon filtering or some other mechanism 131 132 ***************************************************************************/ 133 134 public interface Context 135 { 136 /// return a label for this context 137 public istring label (); 138 139 /// first arg is the setting of the logger itself, and 140 /// the second arg is what kind of message we're being 141 /// asked to produce 142 public bool enabled (Level setting, Level target); 143 } 144 145 146 /*************************************************************************** 147 148 Returns: 149 `true` if this logger is enabed for the specified `Level` 150 151 Params: 152 `Level` to test for, defaults to `Level.Fatal`. 153 154 ***************************************************************************/ 155 156 public bool enabled (Level level = Level.Fatal); 157 158 /*************************************************************************** 159 160 Returns: 161 The name of this `ILogger` (without the appended dot). 162 163 ***************************************************************************/ 164 165 public cstring name (); 166 167 168 /*************************************************************************** 169 170 Returns: 171 The `Level` this `ILogger` is set to 172 173 ***************************************************************************/ 174 175 public Level level (); 176 177 /*************************************************************************** 178 179 Set the current `Level` for this logger (and only this logger). 180 181 Params: 182 l = New `Level` value to set this logger to. 183 184 Returns: 185 `this` for easy chaining 186 187 ***************************************************************************/ 188 189 public ILogger level (Level l); 190 191 /*************************************************************************** 192 193 Returns: 194 `true` if the logger is additive. 195 Additive loggers walk through ancestors looking for more appenders 196 197 ***************************************************************************/ 198 199 public bool additive (); 200 201 /*************************************************************************** 202 203 Set the additive status of this logger 204 205 Additive loggers walk through ancestors looking for more appenders 206 207 Params: 208 enabled = Whereas this logger is additive. 209 210 Returns: 211 `this` for easy chaining 212 213 ***************************************************************************/ 214 215 public ILogger additive (bool enabled); 216 217 /*************************************************************************** 218 219 Send a message to this logger. 220 221 Params: 222 level = Level at which to log the message 223 exp = Lazily evaluated message string 224 If the `level` is not enabled for this logger, it won't 225 be evaluated. 226 227 Returns: 228 `this` for easy chaining 229 230 ***************************************************************************/ 231 232 public ILogger append (Level level, lazy cstring exp); 233 } 234 235 unittest 236 { 237 test!("==")(ILogger.convert(ILogger.Level.Trace), "Trace"); 238 test!("==")(ILogger.convert(ILogger.Level.Info), "Info"); 239 test!("==")(ILogger.convert(ILogger.Level.Warn), "Warn"); 240 test!("==")(ILogger.convert(ILogger.Level.Error), "Error"); 241 test!("==")(ILogger.convert(ILogger.Level.Fatal), "Fatal"); 242 test!("==")(ILogger.convert(ILogger.Level.None), "None"); 243 } 244 245 unittest 246 { 247 test!("==")(ILogger.convert("info"), ILogger.Level.Info); 248 test!("==")(ILogger.convert("Info"), ILogger.Level.Info); 249 test!("==")(ILogger.convert("INFO"), ILogger.Level.Info); 250 test!("==")(ILogger.convert("FATAL"), ILogger.Level.Fatal); 251 // Use the default value 252 test!("==")(ILogger.convert("Info!"), ILogger.Level.Trace); 253 test!("==")(ILogger.convert("Baguette", ILogger.Level.Warn), 254 ILogger.Level.Warn); 255 // The first entry in the array 256 test!("==")(ILogger.convert("trace", ILogger.Level.Error), 257 ILogger.Level.Trace); 258 }