1 /******************************************************************************* 2 3 Application extension to parse configuration for the stats output. 4 5 This extension writes to a file the list of value and identifier in 6 an easily parseable way. It also has the option to send metrics 7 directly to a Collectd unix socket. 8 9 Should one want to use the Collectd socket, several additional configuration 10 values need to be provided: 11 - path to the unix socket (which enables the option); 12 - application name: If not provided, default to the name passed to the 13 application framework; 14 - application instance: Optional, no default value 15 - hostname: If not provided, the value of `gethostname` (2) will be used; 16 - default type: A convention on the type of the 'application stats', 17 which will be used when calling `StatsLog.add`. 18 Defaults to `application_name ~ "_stats"`. 19 20 Copyright: 21 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 22 All rights reserved. 23 24 License: 25 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 26 Alternatively, this file may be distributed under the terms of the Tango 27 3-Clause BSD License (see LICENSE_BSD.txt for details). 28 29 *******************************************************************************/ 30 31 module ocean.util.app.ext.StatsExt; 32 33 34 35 36 import core.sys.posix.unistd : gethostname; 37 38 import ocean.core.Enforce; 39 import ocean.core.TypeConvert; 40 import ocean.sys.ErrnoException; 41 42 import ocean.util.app.model.ExtensibleClassMixin; 43 import ocean.util.app.Application; 44 import ocean.util.app.ext.model.IConfigExtExtension; 45 import ocean.util.app.ext.model.ILogExtExtension; 46 import ocean.util.app.ext.ConfigExt; 47 48 import ocean.util.app.ext.ReopenableFilesExt; 49 50 import ocean.util.config.ConfigParser; 51 import ocean.util.log.Appender; 52 import ocean.util.log.Stats; 53 import ConfigFiller = ocean.util.config.ConfigFiller; 54 55 import ocean.transition; 56 import ocean.core.Verify; 57 import ocean.io.device.File; 58 59 60 /******************************************************************************* 61 62 Application extension to parse configuration files for the stats output. 63 64 *******************************************************************************/ 65 66 class StatsExt : IConfigExtExtension 67 { 68 /*************************************************************************** 69 70 Stats Log instance 71 72 ***************************************************************************/ 73 74 public StatsLog stats_log; 75 76 77 /// Config instance for creating the default StatsLog. 78 public StatsLog.Config config; 79 80 81 /*************************************************************************** 82 83 Extension order. This extension uses -500 because it should be 84 called early, but after the LogExt extension. 85 86 Returns: 87 the extension order 88 89 ***************************************************************************/ 90 91 public override int order ( ) 92 { 93 return -500; 94 } 95 96 97 /*************************************************************************** 98 99 Parse the configuration file options to set up the stats log. 100 101 Params: 102 app = the application instance 103 parser = configuration instance 104 105 ***************************************************************************/ 106 107 public override void processConfig ( IApplication app, ConfigParser parser ) 108 { 109 ConfigFiller.fill!(StatsLog.Config)("STATS", this.config, parser); 110 111 if (!this.config.app_name.length) 112 this.config.app_name = app.name; 113 if (!this.config.hostname.length) 114 this.config.hostname = getHostName(); 115 if (!this.config.default_type.length) 116 this.config.default_type = this.config.app_name ~ "_stats"; 117 118 verify(this.config.app_name.length != 0); 119 120 this.stats_log = this.newStatsLog(app, this.config); 121 } 122 123 124 /*************************************************************************** 125 126 Creates a new stats log instance according to the provided config 127 settings. If the reopenable files extension exists, the log file is 128 registered with it. 129 130 Params: 131 app = the application instance 132 stats_config = stats log configuration instance 133 134 Returns: 135 new, configured StatsLog instance 136 137 ***************************************************************************/ 138 139 static public StatsLog newStatsLog ( IApplication app, 140 StatsLog.Config stats_config ) 141 { 142 Appender newAppender ( istring file, Appender.Layout layout ) 143 { 144 auto stream = new File(file, File.WriteAppending); 145 146 if ( auto reopenable_files_ext = 147 (cast(Application)app).getExtension!(ReopenableFilesExt) ) 148 { 149 reopenable_files_ext.register(stream); 150 } 151 152 return new AppendStream(stream, true, layout); 153 } 154 155 return new StatsLog(stats_config, &newAppender, stats_config.file_name); 156 } 157 158 /*************************************************************************** 159 160 Unused IConfigExtExtension method. 161 162 We just need to provide an "empty" implementation to satisfy the 163 interface. 164 165 Params: 166 app = the application instance 167 config = configuration instance 168 169 ***************************************************************************/ 170 171 public override void preParseConfig ( IApplication app, ConfigParser config ) 172 { 173 // Unused 174 } 175 176 177 /*************************************************************************** 178 179 Unused IConfigExtExtension method. 180 181 We just need to provide an "empty" implementation to satisfy the 182 interface. 183 184 Params: 185 app = the application instance 186 config = configuration instance 187 files = current list of configuration files to parse 188 189 Returns: 190 new list of configuration files to parse 191 192 ***************************************************************************/ 193 194 public override istring[] filterConfigFiles ( IApplication app, 195 ConfigParser config, 196 istring[] files ) 197 { 198 // Unused 199 return files; 200 } 201 } 202 203 204 /******************************************************************************* 205 206 An helper function to get the hostname, used by Collectd 207 208 Returns: 209 A string representing the hostname 210 211 *******************************************************************************/ 212 213 private istring getHostName () 214 { 215 // SuSv2 ensure that hostname are <= 255 bytes 216 // On Linux, they are <= HOST_MAX_NAME which has been 64 bytes 217 // for almost all of Linux lifetime 218 char[256] buffer; 219 enforce!(ErrnoException)(gethostname(buffer.ptr, buffer.length) == 0); 220 return idup(buffer[0 .. strnlen(buffer.ptr, buffer.length)]); 221 222 } 223 224 private extern(C) size_t strnlen(Const!(char)* s, size_t maxlen);