00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <lestes/msg/logger.hh>
00029 #include <lestes/msg/logger_util.hh>
00030 #include <lestes/std/objectize_macros.hh>
00031 #include <stack>
00032 #include <iostream>
00033 #include <fstream>
00034
00035 #include <libxml/xmlmemory.h>
00036 #include <libxml/parser.h>
00037
00038 package(lestes);
00039 package(msg);
00040
00041 lstring logger2fullname( const ptr<logger> &l );
00042
00043
00044
00045
00046
00047
00048
00049
00050 ptr<logger> logger::the_root_instance = the_root_instance;
00051
00052
00053
00054
00055
00056
00057 ptr<ostream_wrapper> logger::null_ostream =
00058 ostream_wrapper::create( new ::std::ofstream(), true );
00059
00060 ptr<ostream_wrapper> logger::cerr_wrapper =
00061 ostream_wrapper::create( &::std::cerr, false );
00062 ptr<logger::files_map_type> logger::files_map = files_map_type::create();
00063
00064 ptr<logger> logger::create( const lstring & a_name, const ptr<logger> & a_parent )
00065 {
00066 return new logger( a_name, a_parent );
00067 }
00068
00069 ptr<logger> logger::root_instance()
00070 {
00071 if (!the_root_instance)
00072 the_root_instance = new logger();
00073 return the_root_instance;
00074 }
00075
00076 ptr<logger> logger::parent_get() const
00077 {
00078 return parent;
00079 }
00080 lstring logger::name_get() const
00081 {
00082 return name;
00083 }
00084 ptr<logger::children_map_type> logger::children_get() const
00085 {
00086 return children;
00087 }
00088
00089 ptr < logger_formatter > logger::formatter_get() const
00090 {
00091 return formatter;
00092 }
00093 void logger::formatter_set(ptr < logger_formatter > x)
00094 {
00095 lassert(x);
00096 formatter = x;
00097 }
00098 #ifdef ALL_LOGGER_GETTERS_NEEDED
00099 bool logger::logging_get() const
00100 {
00101 return logging;
00102 }
00103 bool logger::logging_changed_get() const
00104 {
00105 return logging_changed;
00106 }
00107 #endif
00108
00109 logger::logger()
00110 : logging(false), logging_changed(false), ostr(NULL),
00111 parent(this), children( children_map_type::create() ),
00112 formatter( plain_formatter::instance() )
00113 {}
00114
00115 logger::logger( const lstring & a_name, const ptr<logger> a_parent )
00116 : logging(false), logging_changed(false), ostr(NULL), name(a_name),
00117 parent( checked(a_parent) ), children( children_map_type::create() ),
00118 formatter( plain_formatter::instance() )
00119 {
00120 bool not_inserted_yet = parent->children->insert(
00121 *pair< lstring, srp<logger> >::create(name,this) ).second;
00122 lassert2( not_inserted_yet, "Trying to add a child logger with an already taken name." );
00123 }
00124
00125 #define cast_xml( str ) ((const xmlChar *)(str))
00126 #define cast_c( str ) ((const char *)(str))
00127
00128 static bool attr2bool( const xmlChar * value )
00129 {
00130 if (!strcmp(cast_c(value),"on"))
00131 return true;
00132 if (!strcmp(cast_c(value),"off"))
00133 return false;
00134
00135 ::std::cerr << "Invalid on/off value '" << value << "'. Using 'off'." << ::std::endl;
00136
00137 return false;
00138 }
00139
00140
00141 class logger_configurator {
00142
00143 friend class logger;
00144
00145 static void configure( xmlNode *node, bool inherited,
00146 const ptr<logger> & parent_logger,
00147 const ptr<ostream_wrapper> & parent_stream );
00148 };
00149
00150
00151
00152
00153
00154
00155
00156 void logger_configurator::configure( xmlNode *node, bool inherited,
00157 const ptr<logger> & parent_logger,
00158 const ptr<ostream_wrapper> & parent_stream )
00159 {
00160 lassert( node );
00161 lassert( parent_stream );
00162
00163
00164 lstring path = logger2fullname(parent_logger);
00165 if (path != "/")
00166 path += "/";
00167
00168 xmlChar *self_prop = NULL;
00169 xmlChar *children_prop = NULL;
00170 xmlChar *name_prop = NULL;
00171 xmlChar *file_prop = NULL;
00172 xmlChar * formatter_prop = NULL;
00173 xmlChar * formatter_param_prop = NULL;
00174
00175 for ( ; node; node = node->next ) {
00176
00177
00178 if (node->type != XML_ELEMENT_NODE)
00179 continue;
00180
00181 if (strcmp( cast_c(node->name), "logger" )) {
00182 ::std::cerr << "Ignoring unrecognized element '" <<
00183 path << node->name << "'." << ::std::endl;
00184 continue;
00185 }
00186
00187
00188 xmlFree( self_prop );
00189 xmlFree( children_prop );
00190 xmlFree( name_prop );
00191 xmlFree( file_prop );
00192 xmlFree( formatter_prop );
00193 xmlFree( formatter_param_prop );
00194 name_prop = xmlGetProp( node, cast_xml("name") );
00195 self_prop = xmlGetProp( node, cast_xml("self") );
00196 children_prop = xmlGetProp( node, cast_xml("children") );
00197 file_prop = xmlGetProp( node, cast_xml("file") );
00198 formatter_prop = xmlGetProp( node, cast_xml("formatter") );
00199 formatter_param_prop = xmlGetProp( node, cast_xml("parameter") );
00200
00201 if (!name_prop) {
00202 ::std::cerr << "Name attribute missing in element under '" <<
00203 path << "'." << ::std::endl;
00204 continue;
00205 }
00206 lstring name_attr(cast_c(name_prop));
00207
00208 bool self;
00209 if (!self_prop)
00210 self = inherited;
00211 else
00212 self = attr2bool(self_prop);
00213
00214 bool children;
00215 if (!children_prop)
00216 children = inherited;
00217 else
00218 children = attr2bool(children_prop);
00219
00220 if (parent_logger->children->find(name_attr)
00221 == parent_logger->children->end()) {
00222 ::std::cerr << "Trying to configure non-existing logger '" <<
00223 path << name_attr << "'." << ::std::endl;
00224 continue;
00225 }
00226
00227 ptr<ostream_wrapper> stream;
00228 if (file_prop && file_prop[0]) {
00229 lstring fn(cast_c(file_prop));
00230 if (logger::files_map->find(fn) == logger::files_map->end()) {
00231 stream = (*logger::files_map)[fn] =
00232 ostream_wrapper::create(
00233 new ::std::ofstream(fn.c_str()), true );
00234 } else
00235 stream = (*logger::files_map)[fn];
00236 } else if (file_prop) {
00237
00238 stream = logger::cerr_wrapper;
00239 } else {
00240
00241 stream = parent_stream;
00242 }
00243
00244 const srp<logger> & this_logger = (*(parent_logger->children))[name_attr];
00245 if (this_logger->logging_changed) {
00246 ::std::cerr << "Trying to configure logger '" <<
00247 path << name_attr <<
00248 "' for the second time, ignoring." << ::std::endl;
00249 continue;
00250 }
00251 this_logger->logging = self;
00252 this_logger->logging_changed = true;
00253 this_logger->ostr = stream;
00254
00255 this_logger->formatter = formatter_factory::create_formatter(
00256 formatter_prop ? cast_c(formatter_prop) : "",
00257 formatter_param_prop ? cast_c(formatter_param_prop) : "");
00258
00259
00260 if (node->children)
00261 configure( node->children, children, this_logger, stream );
00262 }
00263
00264
00265 ptr<logger::children_map_type> ch_map = parent_logger->children;
00266 for (logger::children_map_type::const_iterator it = ch_map->begin();
00267 it != ch_map->end(); ++it )
00268 if (!(it->second->logging_changed))
00269 ::std::cerr << "Logger '" << path << it->second->name <<
00270 "' not configured." << ::std::endl;
00271
00272 xmlFree( self_prop );
00273 xmlFree( children_prop );
00274 xmlFree( name_prop );
00275 xmlFree( file_prop );
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286 bool logger::init( const lstring & filename )
00287 {
00288 if (root_instance()->logging_changed) {
00289 ::std::cerr << "Trying to initialize loggers again, ignoring." << ::std::endl;
00290 return false;
00291 }
00292
00293
00294
00295
00296
00297
00298 LIBXML_TEST_VERSION
00299
00300 xmlDoc *doc = NULL;
00301 xmlNode *root_element = NULL;
00302 xmlChar *self_prop = NULL;
00303 xmlChar *children_prop = NULL;
00304 xmlChar *name_prop = NULL;
00305 xmlChar *file_prop = NULL;
00306
00307 ptr<ostream_wrapper> stream;
00308
00309 bool result = false;
00310 bool self;
00311 bool children;
00312
00313
00314 doc = xmlParseFile( filename.c_str() );
00315 if (!doc) {
00316 ::std::cerr << "Could not parse configuration file." << ::std::endl;
00317 goto err_out;
00318 }
00319
00320 root_element = xmlDocGetRootElement(doc);
00321 if (!root_element) {
00322 ::std::cerr << "Root element missing." << ::std::endl;
00323 goto err_out;
00324 }
00325 if (strcmp( cast_c(root_element->name), "logger" )) {
00326 ::std::cerr << "Invalid root element '" << root_element->name <<
00327 "'. Expected 'logger'." << ::std::endl;
00328 goto err_out;
00329 }
00330
00331 self_prop = xmlGetProp( root_element, cast_xml("self") );
00332 children_prop = xmlGetProp( root_element, cast_xml("children") );
00333
00334 if (!self_prop || !children_prop) {
00335 ::std::cerr << "Both 'self' and 'children' attributes have"
00336 " to be set in the root logger element." << ::std::endl;
00337 goto err_out;
00338 }
00339
00340 name_prop = xmlGetProp( root_element, cast_xml("name") );
00341 if (name_prop)
00342 ::std::cerr << "Name attribute ignored in the root logger element." << ::std::endl;
00343 file_prop = xmlGetProp( root_element, cast_xml("file") );
00344
00345 self = attr2bool(self_prop);
00346 children = attr2bool(children_prop);
00347
00348 if (file_prop && file_prop[0]) {
00349 lstring fn(cast_c(file_prop));
00350 stream = (*files_map)[fn] = ostream_wrapper::create(
00351 new ::std::ofstream(fn.c_str()), true );
00352 } else
00353 stream = cerr_wrapper;
00354
00355 root_instance()->logging = self;
00356 root_instance()->logging_changed = true;
00357 root_instance()->ostr = stream;
00358
00359 if (root_element->children)
00360 logger_configurator::configure( root_element->children, children,
00361 root_instance(), stream );
00362
00363 result = true;
00364 err_out:
00365 xmlFree( self_prop );
00366 xmlFree( children_prop );
00367 xmlFree( name_prop );
00368 xmlFree( file_prop );
00369 xmlFreeDoc( doc );
00370 xmlCleanupParser();
00371 return result;
00372 }
00373
00374
00375
00376
00377 void logger::finish()
00378 {
00379 for ( files_map_type::iterator it = files_map->begin(); it != files_map->end(); ++it )
00380 it->second->release();
00381 }
00382
00383 void logger::subtree_dump( const ptr<logger> & l, ::std::ostream & os )
00384 {
00385 children_map_type::const_iterator it = l->children->begin();
00386 children_map_type::const_iterator end_it = l->children->end();
00387
00388 for ( ; it != end_it; ++it ) {
00389 os << "<logger name=\"" << it->second->name << '"';
00390 if (it->second->children->empty()) {
00391 os << " />" << ::std::endl;
00392 } else {
00393 os << '>' << ::std::endl;
00394 subtree_dump( it->second, os );
00395 os << "</logger>" << ::std::endl;
00396 }
00397 }
00398 }
00399
00400 ::std::ostream & logger::dump_skeleton( ::std::ostream & os )
00401 {
00402 os << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
00403 "<logger self=\"off\" children=\"off\""
00404 " xmlns=\"http://lestes.jikos.cz/schemas/log-conf\">" << ::std::endl;
00405
00406 subtree_dump( root_instance(), os );
00407
00408 os << "</logger>" << ::std::endl;
00409 return os;
00410 }
00411
00412 ::std::ostream & logger::operator<<( const ptr<logger_formatter> & lf )
00413 {
00414 return lf->format( this, *((logging ? *ostr : *null_ostream).stream_get()) );
00415 }
00416
00417 void logger::gc_mark()
00418 {
00419 ostr.gc_mark();
00420 parent.gc_mark();
00421 children.gc_mark();
00422 formatter.gc_mark();
00423 object::gc_mark();
00424 }
00425
00426 end_package(msg);
00427 end_package(lestes);
00428