$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
From: John Torjo (john.groups_at_[hidden])
Date: 2008-01-14 13:23:30
Hi Benjamin,
Sorry for that. It's because I introduced a breaking change: after you 
initialize the log, call:
g_logger->turn_cache_off();
That should do the trick.
Best,
John
> Hi John,
>
> I'm working on integrating your last modifications about flushing 
> rolling files, but I encounter some problems.
>
> With version V0.11.7, I change rolling_file.hpp (see attached file) to 
> flush logs each time. It works fine.
>
>    /destination::rolling_file_settings settings;
>    settings.file_count( 10 );
>    settings.max_size_bytes( 5242880 );
>    destination::rolling_file loggerFile( logFile.GetPath(), settings );
>    g_logger->writer().add_destination( loggerFile );
>    /
>
> With last version (revision 42765), I just add one line. /
> /
>
>    /destination::rolling_file_settings settings;/
>    /settings.file_count( 10 );/
>    /settings.max_size_bytes( 5242880 ); /
>    */=> settings.flush_each_time(true); // add this line/*
>    /destination::rolling_file loggerFile( logFile.GetPath(), settings );/
>    /g_logger->writer().add_destination( loggerFile );/
>
> Then it doesn't work.
> I put a break point in rolling_file_info#write but my program does not 
> enter in it anymore !
> I think that rolling file objects are not instanciated because output 
> files are MY_FILE.txt and not MY_FILE.txt.1
>
> Even if it will not compile alone, I give you my class Logger to see 
> my implementation.
>
> Regards,
> Benjamin
>
>
> ------------------------------------------------------------------------
>
> // destination_rolling_file.hpp
>
> // Boost Logging library
> //
> // Author: John Torjo, www.torjo.com
> //
> // Copyright (C) 2007 John Torjo (see www.torjo.com for email)
> //
> // Distributed under the Boost Software License, Version 1.0.
> //    (See accompanying file LICENSE_1_0.txt or copy at
> //          http://www.boost.org/LICENSE_1_0.txt)
> //
> // See http://www.boost.org for updates, documentation, and revision history.
> // See http://www.torjo.com/log2/ for more details
>
>
> #ifndef JT28092007_destination_rolling_file_HPP_DEFINED
> #define JT28092007_destination_rolling_file_HPP_DEFINED
>
> #if defined(_MSC_VER) && (_MSC_VER >= 1020)
> # pragma once
> #endif
>
> #if defined(_MSC_VER) 
> #pragma warning ( disable : 4355)
> #endif 
>
> #include <boost/logging/detail/fwd.hpp>
> #include <boost/logging/detail/manipulator.hpp>
> #include <boost/logging/format/destination/convert_destination.hpp>
> #include <fstream>
> #include <string>
> #include <sstream>
> #include <boost/filesystem/path.hpp>
> #include <boost/filesystem/operations.hpp>
>
> namespace boost { namespace logging { namespace destination {
>
>
> /** 
>     @brief Settings you can pass to the rolling file. To see how it's used, see @ref dealing_with_flags.
> */
> struct rolling_file_settings {
>     typedef boost::logging::detail::flag<rolling_file_settings> flag;
>
>     rolling_file_settings() 
>         : max_size_bytes(this, 1024 * 1024)
>         , file_count(this, 10)
>         , initial_erase(this, false)
>         , start_where_size_not_exceeded(this, true) 
>     {}
>
>     /// maximum size in bytes, by default 1Mb
>     flag::t<int> max_size_bytes;
>     /// how many files has a rolling file, by default, 10
>     flag::t<int> file_count;
>     /// if true, it initially erases all files from the rolling file (by default, false)
>     flag::t<bool> initial_erase;
>     /// if true, it starts with the first file that hasn't exceeded the max size;
>     /// otherwise, it starts with the first file (default = true)
>     flag::t<bool> start_where_size_not_exceeded;
> };
>
> namespace detail {
>     template<class convert_dest > 
>     struct rolling_file_info {
>         
>         rolling_file_info (const std::string& name_prefix, rolling_file_settings flags ) 
>                 // many thanks to Martin Bauer
>                 : m_name_prefix(name_prefix), m_flags(flags), m_cur_idx(0) {
>             namespace fs = boost::filesystem;
>             
>             if ( m_flags.initial_erase()) {
>                 for ( int idx = 0; idx < m_flags.file_count(); ++idx)
>                     if ( fs::exists( file_name(idx) ))
>                         fs::remove( file_name(idx) );
>             }
>
>             // see what file to start from
>             if ( m_flags.start_where_size_not_exceeded() ) {
>                 for ( m_cur_idx = 0; m_cur_idx < m_flags.file_count(); ++m_cur_idx )
>                     if ( fs::exists( file_name(m_cur_idx) )) {
>                         if ( fs::file_size( file_name(m_cur_idx))  < m_flags.max_size_bytes() )
>                             // file hasn't reached max size
>                             break;
>                     }
>                     else
>                         // file not found, we'll create it now
>                         break;
>
>             }
>
>             recreate_file();
>         }
>
>         std::string file_name(int idx) {
>             std::ostringstream out; 
>             out << m_name_prefix << "." << (idx+1);
>             return out.str();
>         }
>
>         void recreate_file() {
>             m_out = boost::shared_ptr< std::basic_ofstream<char_type> >(new std::basic_ofstream<char_type>( file_name(m_cur_idx).c_str(),
>                 std::ios_base::out | std::ios_base::app));
>             m_cur_size = 0;
>         }
>
>         template<class msg_type> void write( const msg_type& msg) {
>             convert_dest::write(msg, (*m_out) );
>
>             // bdd 2007-12-10 : flush each time
>             m_cur_size += static_cast<int>( msg.size() );
>             m_out->flush();
>
>             // bdd
>             //if ( m_out->tellp() > m_flags.max_size_bytes()) {
>             if ( m_cur_size > m_flags.max_size_bytes()) {
>                 m_cur_idx = (m_cur_idx + 1) % m_flags.file_count();
>                 recreate_file();
>             }    
>         }
>
>         boost::shared_ptr< std::basic_ofstream<char_type> > m_out;
>         std::string m_name_prefix;
>         rolling_file_settings m_flags;
>         // the index of the current file
>         int m_cur_idx;
>
>         // bdd 2007-12-10 : flush each time
>         //size_t m_cur_size;
>         int m_cur_size;
>     };
> }
>
> /** 
>     @brief Writes to multiple files: name_prefix.1, name_prefix.2, ... name_prefix.N, and then restarts from 1.
>
>     We first write to name_prefix.1.
>
>     The log has a max_size. When max_size is reached, we start writing to name_prefix.2. When max_size is reached, we start writing to name_prefix.3.
>     And so on, until we reach name_prefix.N (N = file_count). When that gets fool, we start over, with name_prefix.1.
> */
> template<class convert_dest = do_convert_destination > struct rolling_file_t : is_generic, non_const_context<detail::rolling_file_info<convert_dest> > {
>     typedef non_const_context<detail::rolling_file_info<convert_dest> > non_const_context_base;
>
>     /** 
>         Constructs a rolling file
>
>         @param name_prefix the name to be used as prefix for the files
>         
>         @param flags [optional] extra settings to pass to the rolling file. See rolling_file_settings and @ref dealing_with_flags.
>     */
>     rolling_file_t(const std::string & name_prefix, rolling_file_settings flags = rolling_file_settings() ) : non_const_context_base(name_prefix, flags) {}
>
>     template<class msg_type> void operator()( const msg_type & msg) const {
>         non_const_context_base::context().write(msg);
>     }
>
>     bool operator==(const rolling_file_t & other) const {
>         return non_const_context_base::context().m_name_prefix == other.context().m_name_prefix;
>     }
> };
>
> /** @brief rolling_file_t with default values. See rolling_file_t
>
> @copydoc rolling_file_t
> */
> typedef rolling_file_t<> rolling_file;
>
>
>
>
> }}}
>
> #endif
>
>   
> ------------------------------------------------------------------------
>
>
>
> //=============================================================================
> // Includes
> //=============================================================================
> #include "StdAfx.h"
> #include "common/log/Logger.h"
>
> //----- MEDCommon -----
> #include "common/system/ApplicationHelper.h"
> #include "common/io/Directory.h"
> #include "common/system/Time.h"
>
> //----- boost -----
> #pragma warning(disable: 4541) 
>
> #include "boost/logging/tags.hpp"
> #include "boost/logging/defaults.hpp"
> #include "boost/logging/format.hpp"
> #include "boost/logging/format_all.hpp"
> #include "boost/logging/format_fwd.hpp"
> #include "boost/logging/format_ts.hpp"
> #include "boost/logging/logging.hpp"
> #include "boost/logging/detail/error.hpp"
> #include "boost/logging/detail/filter.hpp"
> #include "boost/logging/detail/find_gather.hpp"
> #include "boost/logging/detail/format_msg_type.hpp"
> #include "boost/logging/detail/format_write_detail.hpp"
> #include "boost/logging/detail/forward_constructor.hpp"
> #include "boost/logging/detail/fwd.hpp"
> #include "boost/logging/detail/level.hpp"
> #include "boost/logging/detail/log_keeper.hpp"
> #include "boost/logging/detail/logger.hpp"
> #include "boost/logging/detail/macros.hpp"
> #include "boost/logging/detail/manipulator.hpp"
> #include "boost/logging/detail/scenario.hpp"
> #include "boost/logging/detail/template.hpp"
> #include "boost/logging/detail/use_format_write.hpp"
> // raw_doc ?
> #include "boost/logging/detail/ts/ts.hpp"
> #include "boost/logging/detail/ts/ts_boost.hpp"
> #include "boost/logging/detail/ts/ts_none.hpp"
> //#include "boost/logging/detail/ts/ts_posix.hpp"
> #include "boost/logging/detail/ts/ts_resource.hpp"
> #include "boost/logging/detail/ts/ts_win32.hpp"
> #include "boost/logging/detail/tss/tss.hpp"
> #include "boost/logging/detail/tss/tss_ensure_proper_delete.hpp"
> #include "boost/logging/detail/tss/tss_impl.hpp"
> //#include "boost/logging/detail/tss/tss_impl_pthread.hpp"
> #include "boost/logging/detail/tss/tss_impl_win32.hpp"
> #include "boost/logging/format/array.hpp"
> #include "boost/logging/format/op_equal.hpp"
> #include "boost/logging/format/optimize.hpp"
> #include "boost/logging/format/destination/convert_destination.hpp"
> #include "boost/logging/format/destination/defaults.hpp"
> #include "boost/logging/format/destination/file.hpp"
> #include "boost/logging/format/destination/rolling_file.hpp"
> #include "boost/logging/format/destination/shared_memory.hpp"
> #include "boost/logging/format/formatter/convert_format.hpp"
> #include "boost/logging/format/formatter/defaults.hpp"
> #include "boost/logging/format/formatter/tags.hpp"
> #include "boost/logging/format/formatter/thread_id.hpp"
> #include "boost/logging/format/formatter/time.hpp"
> #include "boost/logging/gather/ostream_like.hpp"
> #include "boost/logging/tag/defaults.hpp"
> #include "boost/logging/writer/format_write.hpp"
> #include "boost/logging/writer/on_dedicated_thread.hpp"
> #include "boost/logging/writer/ts_write.hpp"
>
> using namespace boost::logging;
>
> //----- Step 3 : Specify your logging class(es) -----
> //typedef logger_format_write< > log_type;
> // thread safe
> typedef logger_format_write< default_, default_, writer::threading::ts_write > log_type;
> //typedef logger_format_write< default_, default_, writer::threading::on_dedicated_thread > log_type;
>
> //----- Step 4: declare which filters and loggers you'll use (usually in a header file) -----
> // filter
> BOOST_DECLARE_LOG_FILTER(g_log_level, level::holder )
> BOOST_DECLARE_LOG_FILTER(g_audit_filter, filter::ts )
>
> // logger
> BOOST_DECLARE_LOG(g_logger, log_type)
> BOOST_DECLARE_LOG(g_audit, log_type)
> BOOST_DECLARE_LOG(g_debug, log_type)
>
> //----- Step 5: define the macros through which you'll log -----
>
> //----- Step 6: Define the filters and loggers you'll use (usually in a source file) -----
> // filter
> BOOST_DEFINE_LOG_FILTER(g_log_level, level::holder ) // holds the application log level
> BOOST_DEFINE_LOG_FILTER(g_audit_filter, filter::ts )
> BOOST_DEFINE_LOG_FILTER(g_debug_filter, filter::ts )
> //BOOST_DEFINE_LOG_FILTER(g_audit_filter, filter::no_ts )
> // logger
> BOOST_DEFINE_LOG(g_logger, log_type)
> BOOST_DEFINE_LOG(g_audit, log_type)
> BOOST_DEFINE_LOG(g_debug, log_type)
>
> using namespace common::log;
>
> //=============================================================================
> // Global functions
> //=============================================================================
> void
> Audit( const std::ostringstream & msg )
> {
>     Info( msg );
>     BOOST_LOG_USE_LOG_IF_FILTER(g_audit, g_audit_filter->is_enabled() ) << "\t[AUDIT]\t" << msg.str();
> }
>
> void
> Debug( const std::ostringstream & msg )
> {
>     BOOST_LOG_USE_LOG_IF_FILTER(g_debug, g_debug_filter->is_enabled() ) << "\t[DEBUG]\t" << msg.str();
> }
>
> void
> Trace2( const std::ostringstream & msg )
> {
>     Debug( msg );
>     common::log::Logger::s_traces.Push( msg.str() );
> }
>
> void
> Info( const std::ostringstream & msg )
> {
>     BOOST_LOG_USE_LOG_IF_LEVEL(g_logger, g_log_level, info ) << "\t[INFO]\t" << msg.str();
>     BOOST_LOG_USE_LOG_IF_FILTER(g_debug, g_debug_filter->is_enabled() ) << "\t[INFO]\t" << msg.str();
> }
>
> void
> Warning( const std::ostringstream & msg )
> {
>     BOOST_LOG_USE_LOG_IF_LEVEL(g_logger, g_log_level, warning ) << "\t[WARN]\t" << msg.str();
>     BOOST_LOG_USE_LOG_IF_FILTER(g_debug, g_debug_filter->is_enabled() ) << "\t[WARN]\t" << msg.str();
> }
>
> void
> Error( const std::ostringstream & msg )
> {
>     if ( ! common::log::Logger::IsInitialized() )
>     {
>         common::log::Logger::Init( "INIT" );
>     }
>     if ( ! common::log::Logger::s_traces.IsEmpty() )
>     {
>         //
>         vector<string> traces = common::log::Logger::s_traces.ToArray();
>         for ( size_t i=0; i < traces.size(); i++ )
>         {
>             BOOST_LOG_USE_LOG_IF_LEVEL(g_logger, g_log_level, error ) << "\t[TRACE]\t" << traces[i];
>         }
>     }    
>     BOOST_LOG_USE_LOG_IF_LEVEL(g_logger, g_log_level, error ) << "\t[ERROR]\t" << msg.str();
>     BOOST_LOG_USE_LOG_IF_FILTER(g_debug, g_debug_filter->is_enabled() ) << "\t[ERROR]\t" << msg.str();
> }
>
> void
> Exception( const std::ostringstream & msg )
> {
>     if ( ! common::log::Logger::IsInitialized() )
>     {
>         common::log::Logger::Init( "INIT" );
>     }
>     if ( ! common::log::Logger::s_traces.IsEmpty() )
>     {
>         //
>         vector<string> traces = common::log::Logger::s_traces.ToArray();
>         for ( size_t i=0; i < traces.size(); i++ )
>         {
>             BOOST_LOG_USE_LOG_IF_LEVEL(g_logger, g_log_level, fatal ) << "\t[TRACE]\t" << traces[i];
>         }
>     } 
>     BOOST_LOG_USE_LOG_IF_LEVEL(g_logger, g_log_level, fatal ) << "\t[FATAL]\t" << msg.str();
>     BOOST_LOG_USE_LOG_IF_FILTER(g_debug, g_debug_filter->is_enabled() ) << "\t[FATAL]\t" << msg.str();
> }
>
>
>
> //=============================================================================
> // Class attributs
> //=============================================================================
> bool Logger::s_isInitialized = false;
> bool Logger::MODE_DEBUG = false;
> common::container::RollingStack<string> Logger::s_traces( 15 );
>
> //=============================================================================
> // Class methods
> //============================================================================= 
> void 
> Logger::SetLevel( LEVEL level )
> {
>     g_audit_filter->set_enabled(true);
>     g_debug_filter->set_enabled(false);
>     switch ( level )
>     {   
>     case LEVEL_DEBUG :
>         Logger::MODE_DEBUG = true;
>         g_debug_filter->set_enabled(true);
>         g_log_level->set_enabled(level::debug); // debug        
>         break;
>     case LEVEL_INFO :
>         g_log_level->set_enabled(level::info); // info + warning + ...
>         break;
>     case LEVEL_ERROR :
>         g_log_level->set_enabled(level::error); // error + fatal + ...
>         break;
>     default:
>         g_log_level->set_enabled(level::info);
>         break;
>     } 
>     
> }               
>
> bool
> Logger::IsInitialized()
> {
>     return s_isInitialized;
> }
>
> void 
> Logger::Init( const string & product )
> {
>     if ( s_isInitialized )
>     {
>         return;
>     }
>     
>     // check log dir
>     common::system::ApplicationHelper ah;
>     common::io::Directory dir( ah.GetPath() + "logfiles" );
>     dir.CheckAndCreate();
>
>     // init file names
>     //string date = common::system::Time::GetTime( common::system::Time::FORMAT_AAAA_MM_JJ );
>     //common::io::File logFile( dir.GetPath() + date + "_" + product + ".txt" );
>     //common::io::File auditFile( dir.GetPath() + date + "_AUDIT_" + product + ".txt" );
>     common::io::File logFile( dir.GetPath() + product + ".txt" );
>     common::io::File auditFile( dir.GetPath() + "AUDIT_" + product + ".txt" );
>     common::io::File debugFile( dir.GetPath() + "DEBUG_" + product + ".txt" );
>
>     // Step 7: add formatters and destinations
>     //         That is, how the message is to be formatted...
>     g_logger->writer().add_formatter( formatter::time("$dd/$MM/$yyyy - $hh:$mm.$ss ") );
>     g_logger->writer().add_formatter( formatter::idx() );    
>     g_logger->writer().add_formatter( formatter::append_newline() );
>     //g_log_err->writer().add_formatter( formatter::tag::module() ); // tag::file_line() );
>     //g_log_err->writer().add_formatter( formatter::tag::level() );
>
>     g_audit->writer().add_formatter( formatter::time("$dd/$MM/$yyyy - $hh:$mm.$ss ") );
>     g_audit->writer().add_formatter( formatter::idx() );    
>     g_audit->writer().add_formatter( formatter::append_newline() );
>
>     g_debug->writer().add_formatter( formatter::time("$dd/$MM/$yyyy - $hh:$mm.$ss ") );
>     g_debug->writer().add_formatter( formatter::idx() );    
>     g_debug->writer().add_formatter( formatter::append_newline() );
>
>     g_logger->writer().add_destination( destination::cout() );
>
>     // bdd : rolling file : pb de flush (garde les donnees en cache)
>     destination::rolling_file_settings settings;
>     settings.file_count( 10 );
>     settings.max_size_bytes( 5242880 ); // bytes = 5M
>     //settings.flush_each_time(true);
>     destination::rolling_file loggerFile( logFile.GetPath(), settings );
>     g_logger->writer().add_destination( loggerFile );
>
>     g_debug->writer().add_destination( destination::dbg_window() );  
>
>     destination::rolling_file_settings settingsD;
>     settingsD.file_count( 30 );
>     settingsD.max_size_bytes( 10000000 ); // ~10M
>     //settingsD.flush_each_time(true);
>     g_debug->writer().add_destination( destination::rolling_file( debugFile.GetPath(), settingsD ) );
>
>     // bdd xml : en attente
>     //g_log_err->writer().add_destination( as_xml("logerror.xml") );
>
>     g_audit->writer().add_destination( destination::file( auditFile.GetPath() ) );
>
> #ifdef _DEBUG
>     SetLevel( Logger::LEVEL_DEBUG );
> #else
>     SetLevel( Logger::LEVEL_INFO ); 
> #endif
>     s_isInitialized = true;
>     // Step 9 : Enjoy!
> }
>
>
> //=============================================================================
> // Constructor and destructor
> //=============================================================================
> Logger::Logger(void)
> : common::app::Object("common::log::Logger")
> {   
> }
>
> Logger::~Logger(void)
> {
> }
>
> //=============================================================================
> // Public methods
> //=============================================================================    
>
>   
> ------------------------------------------------------------------------
>
> //* Step 1: (optional) Specify your format message class and/or destination message class. By default, it's std::(w)string. You'll use this when you want a optimize string class.
> //* Step 2: (optional) Specify your formatter & destination base classes
> //* Step 3: Specify your logger class(es)
> //* Step 4: Declare the filters and loggers you'll use (in a header file)
> //* Step 5: Define the macros through which you'll do logging
> //* Step 6: Define the loggers and the filters you'll use (in a source file). We need this separation (into declaring and defining the logs/filters), in order to make compilation times fast.
> //* Step 7: Add formatters and destinations. That is, how the message is to be formatted...
> //* Step 8: Use it
> //* Step 9: Enjoy the results! 
>
> //* debug (smallest level),
> //* info,
> //* warning ,
> //* error ,
> //* fatal (highest level)
>
> #ifndef _COMMON_LOG_LOGGER_H_
> #define _COMMON_LOG_LOGGER_H_
> #pragma once
>
> //=============================================================================
> // Includes
> //=============================================================================
> //----- MEDCommon -----
> #include "../commonIncludes.h"
> #include "../app/Object.h"
> #include "StackLog.h"
> #include "common/txt/StringHelper.h"
> #include "common/container/RollingStack.h"
>
> void MEDCOMMON_API Audit( const std::ostringstream & msg );
> void MEDCOMMON_API Debug( const std::ostringstream & msg );
> void MEDCOMMON_API Trace2( const std::ostringstream & msg );
> void MEDCOMMON_API Info( const std::ostringstream & msg );
> void MEDCOMMON_API Warning( const std::ostringstream & msg );
> void MEDCOMMON_API Error( const std::ostringstream & msg );
> void MEDCOMMON_API Exception( const std::ostringstream & msg );
>
> #define MED_FUNCTION \
>     common::log::StackLog log( __FUNCTION__ );
>
> #define MED_FUNCTION2( msg ) \
>     ostringstream s; \
>     s << msg; \
>     common::log::StackLog log( __FUNCTION__, s );    
>
> #define MED_METHOD( object ) \
>     common::log::StackLog log( object,__FUNCTION__ );
>
> #define MED_METHOD2( object, params ) \
>     ostringstream s; \
>     s << params; \
>     common::log::StackLog log( object,__FUNCTION__, s );
>
> #define MED_AUDIT( module, msg ) \
> { \
>     ostringstream s; \
>     s << "[" << module << "]\t" \
>     << msg; \
>     Audit( s ); \
> }
>
> #define MED_DBG2( module, msg ) \
> { \
>     if ( common::log::Logger::MODE_DEBUG ) \
>     { \
>         string file = __FILE__; \
>         string fileName = common::txt::StringHelper::LastToken(file,"\\"); \
>         ostringstream s; \
>         s << "[" << module << "]\t" \
>         << msg \
>         << " (" \
>         << fileName \
>         << "#" \
>         << __FUNCTION__ \
>         << " L." \
>         << __LINE__ \
>         <<  ")"; \
>         Debug( s ); \
>     } \
> }
>
> #define MED_TRC2( module, msg ) \
> { \
>     string file = __FILE__; \
>     string fileName = common::txt::StringHelper::LastToken(file,"\\"); \
>     ostringstream s; \
>     s << "[" << module << "]\t" \
>     << msg \
>     << " (" \
>     << fileName \
>     << "#" \
>     << __FUNCTION__ \
>     << " L." \
>     << __LINE__ \
>     <<  ")"; \
>     Trace2( s ); \
> }
>
> #define MED_INF2( module, msg ) \
> { \
>     ostringstream s; \
>     s << "[" << module << "]\t" \
>     << msg; \
>     Info( s ); \
> }
>
> #define MED_WARN2( module, msg ) \
> { \
>     string file = __FILE__; \
>     string fileName = common::txt::StringHelper::LastToken(file,"\\"); \
>     ostringstream s; \
>     s << "[" << module << "]\t" \
>     << msg \
>     << " (" \
>     << fileName \
>     << "#" \
>     << __FUNCTION__ \
>     << " L." \
>     << __LINE__ \
>     <<  ")"; \
>     Warning( s ); \
> }
>
> #define MED_ERR2( module, msg ) \
> { \
>     string file = __FILE__; \
>     string fileName = common::txt::StringHelper::LastToken(file,"\\"); \
>     ostringstream s; \
>     s << "[" << module << "]\t" \
>     << msg \
>     << " (" \
>     << fileName \
>     << "#" \
>     << __FUNCTION__ \
>     << " L." \
>     << __LINE__ \
>     <<  ")"; \
>     Error( s ); \
> }
>
> #define MED_EXC2( module, msg ) \
> { \
>     string file = __FILE__; \
>     string fileName = common::txt::StringHelper::LastToken(file,"\\"); \
>     ostringstream s; \
>     s << "[" << module << "]\t" \
>     << msg \
>     << " (" \
>     << fileName \
>     << "#" \
>     << __FUNCTION__ \
>     << " L." \
>     << __LINE__ \
>     <<  ")"; \
>     Exception( s ); \
> }
>
> namespace common
> {
>     namespace log
>     {
>         class MEDCOMMON_API Logger : public common::app::Object
>         {
>
>
>
> //=============================================================================
> // Constants
> //=============================================================================
>         public:
>             enum LEVEL { 
>                 LEVEL_DEBUG , 
>                 LEVEL_INFO ,                 
>                 LEVEL_ERROR };
>
> //=============================================================================
> // Class attributs
> //=============================================================================
>         public:
>             static bool MODE_DEBUG;
>             // traces
>             static common::container::RollingStack<string> s_traces;
>
>         private:
>             static bool s_isInitialized;  
>
> //=============================================================================
> // Class methods
> //=============================================================================
>         public:
>             static void SetProduct( const string & product ); 
>             static bool IsInitialized();
>             static void Init( const string & product );
>             static void SetLevel( LEVEL level );     
>
> //=============================================================================
> // Attributs
> //=============================================================================
>         private:
>             
>
> //=============================================================================
> // Constructor and destructor
> //=============================================================================
>         private:
>     	    Logger();
> 		    virtual ~Logger();
>             
> //=============================================================================
> // Public methods
> //=============================================================================    
>         public:    
>
> //=============================================================================
> // Other methods
> //=============================================================================      
>         protected:
>
>         };
>     } // namespace log
> } // namespace common 
>
> #endif // _COMMON_LOG_LOGGER_H_ 
>
>   
-- http://John.Torjo.com -- C++ expert ... call me only if you want things done right