From 8def04f3411702d8d3538e9308ad26a6c285b728 Mon Sep 17 00:00:00 2001 From: Eric Frias Date: Thu, 25 Sep 2014 08:57:31 -0400 Subject: [PATCH] Add a path::preferred_string() function that generates a string in the platform's preferred format, using backslashes on win32 (uses boost::filesystem::path::make_preferred()). Modify the log file configuration and rotating code to call to_native_ansi_path() and do more paths manipulation in fc::path objects and less in std::strings, in an attempt to improve BitShares/bitshares_toolkit#791 --- include/fc/filesystem.hpp | 5 ++ include/fc/log/logger_config.hpp | 12 +++- src/compress/lzma.cpp | 4 +- src/filesystem.cpp | 10 +++ src/log/file_appender.cpp | 106 ++++++++++++++++++------------- 5 files changed, 87 insertions(+), 50 deletions(-) diff --git a/include/fc/filesystem.hpp b/include/fc/filesystem.hpp index d655d68..8e6bc7c 100644 --- a/include/fc/filesystem.hpp +++ b/include/fc/filesystem.hpp @@ -54,9 +54,14 @@ namespace fc { fc::path parent_path()const; fc::string string()const; fc::string generic_string()const; + /** On windows, returns a path where all path separators are '\' suitable for displaying + * to users. On other platforms, it does the same as generic_string() + */ + fc::string preferred_string() const; std::wstring wstring() const; std::wstring generic_wstring() const; + std::wstring preferred_wstring() const; /** Retrieves native string path representation and next converts it into ANSI UTF-8 representation. diff --git a/include/fc/log/logger_config.hpp b/include/fc/log/logger_config.hpp index b31fefe..f2fc1e2 100644 --- a/include/fc/log/logger_config.hpp +++ b/include/fc/log/logger_config.hpp @@ -4,8 +4,14 @@ namespace fc { class path; struct appender_config { - appender_config(const fc::string& n="",const fc::string& t="", variant a=variant()) - :name(n),type(t),args(fc::move(a)),enabled(true){} + appender_config(const string& name = "", + const string& type = "", + variant args = variant()) : + name(name), + type(type), + args(fc::move(args)), + enabled(true) + {} string name; string type; variant args; @@ -13,7 +19,7 @@ namespace fc { }; struct logger_config { - logger_config(const fc::string& n=""):name(n),enabled(true),additivity(false){} + logger_config(const fc::string& name = ""):name(name),enabled(true),additivity(false){} string name; ostring parent; /// if not set, then parents level is used. diff --git a/src/compress/lzma.cpp b/src/compress/lzma.cpp index fb669d0..0267dad 100644 --- a/src/compress/lzma.cpp +++ b/src/compress/lzma.cpp @@ -124,7 +124,7 @@ void lzma_compress_file( const path& src_path, FC_ASSERT( !exists( dst_path ) ); boost::iostreams::mapped_file_source src_file; - src_file.open( src_path.string() ); + src_file.open( src_path.to_native_ansi_path() ); FC_ASSERT( src_file.is_open() ); elzma_compress_handle handle = NULL; @@ -174,7 +174,7 @@ void lzma_decompress_file( const path& src_path, FC_ASSERT( !exists( dst_path ) ); boost::iostreams::mapped_file_source src_file; - src_file.open( src_path.string() ); + src_file.open( src_path.to_native_ansi_path() ); FC_ASSERT( src_file.is_open() ); elzma_decompress_handle handle = NULL; diff --git a/src/filesystem.cpp b/src/filesystem.cpp index e9066d6..2092dcc 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -91,6 +91,11 @@ namespace fc { return _p->generic_string(); } + fc::string path::preferred_string() const + { + return boost::filesystem::path(*_p).make_preferred().string(); + } + std::wstring path::wstring() const { return _p->wstring(); @@ -101,6 +106,11 @@ namespace fc { return _p->generic_wstring(); } + std::wstring path::preferred_wstring() const + { + return boost::filesystem::path(*_p).make_preferred().wstring(); + } + std::string path::to_native_ansi_path() const { std::wstring path = generic_wstring(); diff --git a/src/log/file_appender.cpp b/src/log/file_appender.cpp index e44d060..7ff69fb 100644 --- a/src/log/file_appender.cpp +++ b/src/log/file_appender.cpp @@ -13,9 +13,10 @@ namespace fc { - static const string compression_extension( ".lzma" ); + static const string compression_extension( ".lzma" ); - class file_appender::impl : public fc::retainable { + class file_appender::impl : public fc::retainable + { public: config cfg; ofstream out; @@ -43,7 +44,7 @@ namespace fc { return time_point::from_iso_string( str ); } - void compress_file( const string& filename ) + void compress_file( const fc::path& filename ) { FC_ASSERT( cfg.rotate && cfg.rotation_compression ); FC_ASSERT( _compression_thread ); @@ -55,7 +56,7 @@ namespace fc { try { - lzma_compress_file( filename, filename + compression_extension ); + lzma_compress_file( filename, filename.parent_path() / (filename.filename().string() + compression_extension) ); remove_all( filename ); } catch( ... ) @@ -101,11 +102,11 @@ namespace fc { void rotate_files( bool initializing = false ) { FC_ASSERT( cfg.rotate ); - const auto now = time_point::now(); - const auto start_time = get_file_start_time( now, cfg.rotation_interval ); - const auto timestamp_string = timestamp_to_string( start_time ); - const auto link_filename = cfg.filename.string(); - const auto log_filename = link_filename + "." + timestamp_string; + fc::time_point now = time_point::now(); + fc::time_point_sec start_time = get_file_start_time( now, cfg.rotation_interval ); + string timestamp_string = timestamp_to_string( start_time ); + fc::path link_filename = cfg.filename; + fc::path log_filename = link_filename.parent_path() / (link_filename.filename().string() + "." + timestamp_string); { fc::scoped_lock lock( slock ); @@ -114,7 +115,9 @@ namespace fc { { if( start_time <= _current_file_start_time ) { - _rotation_task = schedule( [this]() { rotate_files(); }, _current_file_start_time + cfg.rotation_interval.to_seconds(), "rotate_files(2)" ); + _rotation_task = schedule( [this]() { rotate_files(); }, + _current_file_start_time + cfg.rotation_interval.to_seconds(), + "rotate_files(2)" ); return; } @@ -122,36 +125,39 @@ namespace fc { out.close(); } - out.open( log_filename.c_str() ); + out.open( log_filename.to_native_ansi_path() ); } remove_all( link_filename ); create_hard_link( log_filename, link_filename ); /* Delete old log files */ - const auto limit_time = now - cfg.rotation_limit; - auto itr = directory_iterator( fc::path( link_filename ).parent_path() ); + fc::time_point limit_time = now - cfg.rotation_limit; + string link_filename_string = link_filename.filename().to_native_ansi_path(); + directory_iterator itr(link_filename.parent_path()); for( ; itr != directory_iterator(); itr++ ) { try { - const auto current_filename = itr->string(); - auto current_pos = current_filename.find( link_filename ); - if( current_pos != 0 ) continue; - current_pos = link_filename.size() + 1; - const auto current_timestamp_str = string( current_filename.begin() + current_pos, /* substr not working */ - current_filename.begin() + current_pos + timestamp_string.size() ); - const auto current_timestamp = string_to_timestamp( current_timestamp_str ); + string current_filename = itr->filename().string(); + if (current_filename.compare(0, link_filename_string.size(), link_filename_string) != 0 || + current_filename.size() <= link_filename_string.size() + 1) + continue; + string current_timestamp_str = current_filename.substr(link_filename_string.size() + 1, + timestamp_string.size()); + fc::time_point_sec current_timestamp = string_to_timestamp( current_timestamp_str ); if( current_timestamp < start_time ) { if( current_timestamp < limit_time || file_size( current_filename ) <= 0 ) { - remove_all( current_filename ); + remove_all( *itr ); continue; } - if( !cfg.rotation_compression ) continue; - if( current_filename.find( compression_extension ) != string::npos ) continue; - compress_file( current_filename ); + if( !cfg.rotation_compression ) + continue; + if( current_filename.find( compression_extension ) != string::npos ) + continue; + compress_file( *itr ); } } catch( ... ) @@ -160,30 +166,37 @@ namespace fc { } _current_file_start_time = start_time; - _rotation_task = schedule( [this]() { rotate_files(); }, _current_file_start_time + cfg.rotation_interval.to_seconds(), "rotate_files(3)" ); + _rotation_task = schedule( [this]() { rotate_files(); }, + _current_file_start_time + cfg.rotation_interval.to_seconds(), + "rotate_files(3)" ); } }; - file_appender::config::config( const fc::path& p ) - :format( "${timestamp} ${thread_name} ${context} ${file}:${line} ${method} ${level}] ${message}" ), - filename(p),flush(true),truncate(true),rotate(false),rotation_compression(true){} - file_appender::file_appender( const variant& args ) - :my( new impl( args.as() ) ) + file_appender::config::config(const fc::path& p) : + format( "${timestamp} ${thread_name} ${context} ${file}:${line} ${method} ${level}] ${message}" ), + filename(p), + flush(true), + truncate(true), + rotate(false), + rotation_compression(true) + {} + + file_appender::file_appender( const variant& args ) : + my( new impl( args.as() ) ) { - std::string log_filename; try { - log_filename = my->cfg.filename.string(); + fc::create_directories(my->cfg.filename.parent_path()); - fc::create_directories( fc::path( log_filename ).parent_path() ); - - if( !my->cfg.rotate ) my->out.open( log_filename.c_str() ); + if(!my->cfg.rotate) + my->out.open(my->cfg.filename.to_native_ansi_path().c_str()); } catch( ... ) { - std::cerr << "error opening log file: " << log_filename << "\n"; + std::cerr << "error opening log file: " << my->cfg.filename.string() << "\n"; } } + file_appender::~file_appender(){} // MS THREAD METHOD MESSAGE \t\t\t File:Line @@ -191,22 +204,24 @@ namespace fc { { std::stringstream line; //line << (m.get_context().get_timestamp().time_since_epoch().count() % (1000ll*1000ll*60ll*60))/1000 <<"ms "; - line << std::string(m.get_context().get_timestamp()) << " "; - line << std::setw( 21 ) << (m.get_context().get_thread_name().substr(0,9) + string(":") + m.get_context().get_task_name()).c_str() <<" "; + line << string(m.get_context().get_timestamp()) << " "; + line << std::setw( 21 ) << (m.get_context().get_thread_name().substr(0,9) + string(":") + m.get_context().get_task_name()).c_str() << " "; - auto me = m.get_context().get_method(); + string method_name = m.get_context().get_method(); // strip all leading scopes... - if( me.size() ) + if( method_name.size() ) { uint32_t p = 0; - for( uint32_t i = 0;i < me.size(); ++i ) + for( uint32_t i = 0;i < method_name.size(); ++i ) { - if( me[i] == ':' ) p = i; + if( method_name[i] == ':' ) p = i; } - if( me[p] == ':' ) ++p; + if( method_name[p] == ':' ) + ++p; line << std::setw( 20 ) << m.get_context().get_method().substr(p,20).c_str() <<" "; } + line << "] "; fc::string message = fc::format_string( m.get_format(), m.get_data() ); line << message.c_str(); @@ -217,8 +232,9 @@ namespace fc { { fc::scoped_lock lock( my->slock ); - my->out << line.str() << "\t\t\t" << m.get_context().get_file() <<":"<cfg.flush ) my->out.flush(); + my->out << line.str() << "\t\t\t" << m.get_context().get_file() << ":" << m.get_context().get_line_number() << "\n"; + if( my->cfg.flush ) + my->out.flush(); } }