| 298 | |
| 299 | //! This class stores a details that will be logged to a logger |
| 300 | template<class T> class log_level_template : public log_level_base { |
| 301 | //! this is necessary to allow logger to set ids vector appropriately and also to set registered_logger |
| 302 | friend class logger; |
| 303 | |
| 304 | //! vector of log IDs - one element for each entry |
| 305 | ivec ids; |
| 306 | |
| 307 | //! internal pointer to the logger to which this log_level is registered |
| 308 | //! |
| 309 | //! it is set to NULL at the beginning |
| 310 | logger * registered_logger; |
| 311 | |
| 312 | public: |
| 313 | //! default constructor |
| 314 | log_level_template() { |
| 315 | registered_logger = NULL; |
| 316 | ids.set_size( T::log_level_names().length() ); |
| 317 | ids = -1; |
| 318 | } |
| 319 | |
| 320 | //! This method stores a vector to the proper place in registered logger |
| 321 | void store( const enum T::log_level_enums log_level_enum, const vec &vect ) const |
| 322 | { |
| 323 | bdm_assert_debug( registered_logger != NULL, "You have to register instance to a logger first! Use root::log_register(...) method."); |
| 324 | bdm_assert_debug( ids( log_level_enum ) >= 0, "This particular vector was not added to logger! Use logger::add_vector(...) method."); |
| 325 | registered_logger->log_vector( ids( log_level_enum ), vect ); |
| 326 | } |
| 327 | |
| 328 | //! This method stores a double to the proper place in registered logger |
| 329 | void store( const enum T::log_level_enums log_level_enum, const double &dbl ) const |
| 330 | { |
| 331 | bdm_assert_debug( registered_logger != NULL, "You have to register instance to a logger first! See root::log_register(...) method."); |
| 332 | bdm_assert_debug( ids( log_level_enum ) >= 0, "This particular double was not added to logger! Use logger::add_vector(...) method."); |
| 333 | registered_logger->log_double( ids( log_level_enum ), dbl ); |
| 334 | } |
| 335 | |
| 336 | //! This method stores a Setting obtained by call of UI::save( data, .. ) to the proper place in registered logger |
| 337 | template<class U> void store( const enum T::log_level_enums log_level_enum, const U data ) const |
| 338 | { |
| 339 | bdm_assert_debug( registered_logger != NULL, "You have to register instance to a logger first! See root::log_register(...) method."); |
| 340 | bdm_assert_debug( ids( log_level_enum ) >= 0, "This particular vector was not added to logger! Use logger::add_setting(...) method."); |
| 341 | registered_logger->log_setting( ids( log_level_enum ), data); |
| 342 | } |
| 343 | |
| 344 | |
| 345 | //! string equivalents of the used enumerations which are filled with a help of #LOG_LEVEL macro within class T |
| 346 | const Array<string> &names() const |
| 347 | { |
| 348 | return T::log_level_names(); |
| 349 | } |
| 350 | |
| 351 | //! read only operator for testing individual fields of log_level |
| 352 | //! |
| 353 | //! it is necessary to acces it with a proper enumeration type, thus this approach is type-safe |
| 354 | bool operator [] (const enum T::log_level_enums &log_level_enum ) const |
| 355 | { |
| 356 | return values[log_level_enum]; |
| 357 | } |
| 358 | |
| 359 | //! operator for setting an individual field of log_level |
| 360 | //! |
| 361 | //! it is necessary to acces it with a proper enumeration type, thus this approach is type-safe |
| 362 | bitset<32>::reference operator [] (const enum T::log_level_enums &log_level_enum ) |
| 363 | { |
| 364 | return values[log_level_enum]; |
| 365 | } |
| 366 | }; |
| 367 | |
| 368 | /*! |
| 369 | \def LOG_LEVEL(classname,...) |
| 370 | \brief Macro for defining a log_level attribute with a specific set of enumerations related to a specific class |
| 371 | |
| 372 | This macro has to be called within a class declaration. Its argument \a classname has to correspond to that wrapping class. |
| 373 | This macro defines a log_level instance which can be modified either directly or by the means of #UI class. |
| 374 | |
| 375 | One of the main purposes of this macro is to allow variability in using enumerations. By relating them to their names through |
| 376 | an array of strings, we are no more dependant on their precise ordering. What is more, we can add or remove any without harming |
| 377 | any applications which are using this library. |
| 378 | |
| 379 | \todo Write a more detailed explanation including also examples |
| 380 | |
| 381 | \ref ui |
| 382 | */ |
| 383 | #define LOG_LEVEL(classname,...) public: enum log_level_enums { __VA_ARGS__ }; log_level_template<classname> log_level; private: friend class log_level_template<classname>; static const Array<string> &log_level_names() { static const Array<string> log_level_names = log_level_base::string2Array( #__VA_ARGS__ ); return log_level_names; } |
| 384 | |
| 385 | |
312 | | public: |
313 | | //!Default constructor |
314 | | logger ( const string separator0 ) : entries ( 0 ), names ( 0 ), separator ( separator0 ) {} |
315 | | |
| 406 | |
| 407 | //! log this instance to Setting |
| 408 | //! |
| 409 | //! this method has to be called only through \c log_level class to assure the validity of the passed id |
| 410 | template<class U> void log_setting ( int id, const U data ) { |
| 411 | UI::save(data, *settings ( id ) ); |
| 412 | } |
| 413 | |
| 414 | //! log this vector |
| 415 | //! |
| 416 | //! this method has to be called only through \c log_level class to assure the validity of the passed id |
| 417 | virtual void log_vector ( int id, const vec &v ) NOT_IMPLEMENTED_VOID; |
| 418 | |
| 419 | //! log this double |
| 420 | //! |
| 421 | //! this method has to be called only through \c log_level class to assure the validity of the passed id |
| 422 | virtual void log_double ( int id, const double &d ) NOT_IMPLEMENTED_VOID; |
| 423 | |
| 424 | //! it is necessary to allow log_levels to call log_setting, log_vector and log_double methods |
| 425 | template<class T> friend class log_level_template; |
| 426 | public: |
321 | | |
322 | | //! returns an identifier which will be later needed for calling the \c logit() function |
323 | | //! For empty RV it returns -1, this entry will be ignored by \c logit(). |
324 | | virtual int add_vector ( const RV &rv, const string &prefix, const string &name = "" ); |
325 | | |
326 | | virtual int add_setting ( const string &prefix ); |
327 | | |
328 | | //! log this vector |
329 | | virtual void log_vector ( int id, const vec &v ) = 0; |
330 | | |
331 | | virtual Setting & log_to_setting ( int id ) { |
332 | | return settings ( id )->add ( Setting::TypeGroup ); |
333 | | } |
334 | | //! log this double |
335 | | virtual void logit ( int id, const double &d ) = 0; |
| 432 | //!Default constructor |
| 433 | logger ( const string separator ) : entries ( 0 ), names ( 0 ), separator ( separator ) {} |
| 434 | |
| 435 | //!Destructor calls the finalize method |
| 436 | ~logger() { |
| 437 | finalize(); |
| 438 | } |
| 439 | |
| 440 | //! sets up the ids identifier in the passed log_level instance to permit future calls of the log_level_template<T>::store(...) method |
| 441 | //! |
| 442 | //! It also sets a pointer to logger or justify it is correctly assigned from previous call to this procedure |
| 443 | //! Entries with empty RV will be ignored |
| 444 | template<class T> void add_vector ( log_level_template<T> &log_level, enum T::log_level_enums const log_level_enum, const RV &rv, const string &prefix ) |
| 445 | { |
| 446 | if( !log_level.registered_logger ) |
| 447 | log_level.registered_logger = this; |
| 448 | else |
| 449 | bdm_assert_debug ( log_level.registered_logger == this, "This log_level is already registered to another logger!"); |
| 450 | |
| 451 | |
| 452 | if ( rv._dsize() == 0 ) |
| 453 | return; |
| 454 | |
| 455 | int id = entries.length(); |
| 456 | string adjusted_name = remove_log_prefix_if_possible( log_level.names()(log_level_enum) ); |
| 457 | names = concat ( names, prefix + separator + adjusted_name ); // diff |
| 458 | entries.set_length ( id + 1, true ); |
| 459 | entries ( id ) = rv; |
| 460 | log_level.ids(log_level_enum) = id; |
| 461 | } |
| 462 | |
| 463 | //! sets up the ids identifier in the passed log_level instance to permit future calls of the log_level_template<T>::store(...) method |
| 464 | //! |
| 465 | //! It also sets a pointer to logger or justify it is correctly assigned from previous call to this procedure |
| 466 | template<class T> void add_setting ( log_level_template<T> &log_level, enum T::log_level_enums const log_level_enum, const string &prefix ) { |
| 467 | if( !log_level.registered_logger ) |
| 468 | log_level.registered_logger = this; |
| 469 | else |
| 470 | bdm_assert_debug ( log_level.registered_logger == this, "This log_level is already registered to another logger!"); |
| 471 | |
| 472 | Setting &root = setting_conf.getRoot(); |
| 473 | int id = root.getLength(); //root must be group!! |
| 474 | settings.set_length ( id + 1, true ); |
| 475 | string adjusted_name = remove_log_prefix_if_possible( log_level.names()(log_level_enum) ); |
| 476 | settings ( id ) = &root.add ( prefix + separator + adjusted_name, Setting::TypeList ); |
| 477 | log_level.ids(log_level_enum) = id; |
| 478 | } |