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