Re: [boost] [boost::logging] using rolling files failed

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
participants (1)
-
John Torjo