1 /******************************************************************************* 2 3 Application extension to parse configuration files for the logging system. 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.app.ext.LogExt; 17 18 19 20 21 import ocean.core.TypeConvert; 22 23 import ocean.util.app.model.ExtensibleClassMixin; 24 import ocean.util.app.Application; 25 import ocean.util.app.ext.model.IConfigExtExtension; 26 import ocean.util.app.ext.model.ILogExtExtension; 27 import ocean.util.app.ext.ConfigExt; 28 29 import ocean.util.app.ext.ReopenableFilesExt; 30 31 import ocean.util.config.ConfigFiller; 32 import ocean.util.config.ConfigParser; 33 import LogUtil = ocean.util.log.Config; 34 import ConfigFiller = ocean.util.config.ConfigFiller; 35 36 import ocean.meta.types.Qualifiers; 37 import ocean.io.device.File; 38 39 import ocean.util.log.Appender; 40 41 42 /******************************************************************************* 43 44 Application extension to parse configuration files for the logging system. 45 46 This extension is an extension itself, providing new hooks via 47 ILogExtExtension. 48 49 *******************************************************************************/ 50 51 class LogExt : IConfigExtExtension 52 { 53 /*************************************************************************** 54 55 Adds a list of extensions (this.extensions) and methods to handle them. 56 See ExtensibleClassMixin documentation for details. 57 58 ***************************************************************************/ 59 60 mixin ExtensibleClassMixin!(ILogExtExtension); 61 62 63 /*************************************************************************** 64 65 True if the InsertConsole appender should be used instead of the regular 66 one. The InsertConsole appender is needed when using the AppStatus 67 module. 68 69 ***************************************************************************/ 70 71 public bool use_insert_appender; 72 73 74 /// If set, will be used by `makeLayout` to map a name to a `Layout` 75 private Appender.Layout delegate (cstring name) layout_maker; 76 77 78 /*************************************************************************** 79 80 Constructor. 81 82 Params: 83 use_insert_appender = true if the InsertConsole appender should be 84 used (needed when using the AppStatus module) 85 86 ***************************************************************************/ 87 88 this ( bool use_insert_appender ) 89 { 90 this(null, use_insert_appender); 91 } 92 93 94 /*************************************************************************** 95 96 Constructor. 97 98 Params: 99 make_layout = A delegate that instantiates an 100 `Appender.Layout` from a name. If null, 101 defaults to `ocean.util.Config: newLayout`. 102 use_insert_appender = true if the InsertConsole appender should be 103 used (needed when using the AppStatus module) 104 105 ***************************************************************************/ 106 107 public this ( scope Appender.Layout delegate (cstring name) make_layout = null, 108 bool use_insert_appender = false ) 109 { 110 this.layout_maker = make_layout is null ? &this.makeLayoutDefault 111 : make_layout; 112 113 this.use_insert_appender = use_insert_appender; 114 } 115 116 /*************************************************************************** 117 118 Extension order. This extension uses -1_000 because it should be 119 called early, but after the ConfigExt extension. 120 121 Returns: 122 the extension order 123 124 ***************************************************************************/ 125 126 public override int order ( ) 127 { 128 return -1_000; 129 } 130 131 132 /*************************************************************************** 133 134 Parse the configuration file options to set up the loggers. 135 136 Params: 137 app = the application instance 138 config = configuration instance 139 140 ***************************************************************************/ 141 142 public override void processConfig ( IApplication app, ConfigParser config ) 143 { 144 auto conf_ext = (cast(Application)app).getExtension!(ConfigExt); 145 146 foreach (ext; this.extensions) 147 { 148 ext.preConfigureLoggers(app, config, conf_ext.loose_config_parsing, 149 this.use_insert_appender); 150 } 151 152 auto log_config = ConfigFiller.iterate!(LogUtil.Config)("LOG", config); 153 auto log_meta_config = ConfigFiller.fill!(LogUtil.MetaConfig)("LOG", config); 154 155 enable_loose_parsing(conf_ext.loose_config_parsing); 156 157 // tracks already registered files to prevent double registration 158 File[cstring] registered_files; 159 160 Appender appender ( istring file, LogUtil.Layout layout ) 161 { 162 if (!(file in registered_files)) 163 { 164 auto stream = new File(file, File.WriteAppending); 165 if ( auto reopenable_files_ext = 166 (cast(Application)app).getExtension!(ReopenableFilesExt) ) 167 { 168 reopenable_files_ext.register(stream); 169 } 170 registered_files[file] = stream; 171 } 172 173 return new AppendStream(registered_files[file], true, layout); 174 } 175 176 LogUtil.configureNewLoggers(log_config, log_meta_config, &appender, 177 this.layout_maker, this.use_insert_appender); 178 179 foreach (ext; this.extensions) 180 { 181 ext.postConfigureLoggers(app, config, conf_ext.loose_config_parsing, 182 this.use_insert_appender); 183 } 184 } 185 186 187 /*************************************************************************** 188 189 Unused IConfigExtExtension methods. 190 191 We just need to provide an "empty" implementation to satisfy the 192 interface. 193 194 Params: 195 app = the application instance 196 config = configuration instance 197 198 ***************************************************************************/ 199 200 public override void preParseConfig ( IApplication app, ConfigParser config ) 201 { 202 // Unused 203 } 204 205 206 /*************************************************************************** 207 208 Function to filter the list of configuration files to parse. 209 Only present to satisfy the interface 210 211 Params: 212 app = the application instance 213 config = configuration instance 214 files = current list of configuration files to parse 215 216 Returns: 217 new list of configuration files to parse 218 219 ***************************************************************************/ 220 221 public override istring[] filterConfigFiles ( IApplication app, 222 ConfigParser config, 223 istring[] files ) 224 { 225 // Unused 226 return files; 227 } 228 229 230 /*************************************************************************** 231 232 Default for layout_maker. DMD complains because `LogUtil.newLayout` 233 is a function, not a delegate. 234 235 Params: 236 name = name of the Layout to instantiate. 237 238 Throws: 239 `Exception` if it cannot match the name 240 241 Returns: 242 A new Layout instance matching name 243 244 ***************************************************************************/ 245 246 private Appender.Layout makeLayoutDefault ( cstring name ) 247 { 248 return LogUtil.newLayout(name); 249 } 250 }