// Copyright (c) 2019-2024, Zano Project // Copyright (c) 2019, anonimal // Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of the Andrey N. Sabelnikov nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // #ifndef _MISC_LOG_EX_H_ #define _MISC_LOG_EX_H_ //#include #include #include #include #include #include #include #include #include #include #include #include #ifndef Q_MOC_RUN #include #include #include #include #include #endif #if defined(WIN32) #include #else #include #endif #include "os_defenitions.h" #include "warnings.h" PUSH_VS_WARNINGS DISABLE_VS_WARNINGS(4100) #include "misc_helpers.h" #include "static_helpers.h" #include "string_tools.h" #include "time_helper.h" #include "misc_os_dependent.h" #include "syncobj.h" #include "sync_locked_object.h" #include "string_coding.h" #include "file_io_utils.h" #define LOG_LEVEL_SILENT -1 #define LOG_LEVEL_0 0 #define LOG_LEVEL_1 1 #define LOG_LEVEL_2 2 #define LOG_LEVEL_3 3 #define LOG_LEVEL_4 4 #define LOG_LEVEL_MIN LOG_LEVEL_SILENT #define LOG_LEVEL_MAX LOG_LEVEL_4 #define LOGGER_NULL 0 #define LOGGER_FILE 1 #define LOGGER_DEBUGGER 2 #define LOGGER_CONSOLE 3 #define LOGGER_DUMP 4 #define LOG_JOURNAL_MAX_ELEMENTS 100 #ifdef _DEBUG #define _ASSERTE__(expr) if(!(expr)) {__debugbreak();} #else #define _ASSERTE__(expr) #endif #ifndef LOCAL_ASSERT #include #if (defined _MSC_VER) #define LOCAL_ASSERT(expr) {if(epee::debug::get_set_enable_assert()){_ASSERTE__(expr);}} #define FORCE_ASSERT(expr) { _ASSERTE(expr); } #else #define LOCAL_ASSERT(expr) #define FORCE_ASSERT(expr) #endif #endif #if !defined(DISABLE_RELEASE_LOGGING) #define ENABLE_LOGGING_INTERNAL #endif #define LOG_DEFAULT_CHANNEL NULL #define ENABLE_CHANNEL_BY_DEFAULT(ch_name) \ static bool COMBINE(init_channel, __LINE__) UNUSED_ATTRIBUTE = epee::misc_utils::static_initializer([](){ \ epee::log_space::log_singletone::enable_channel(ch_name, false); return true; \ }); #if defined(ENABLE_LOGGING_INTERNAL) #define LOG_PRINT_CHANNEL_NO_PREFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str() , y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}} #define LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}} #define LOG_PRINT_CHANNEL_NO_POSTFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}} #define LOG_PRINT_CHANNEL2_CB(log_channel, log_name, x, y, cb) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);cb(ss________.str());CATCH_ALL_DO_NOTHING();}} #define LOG_PRINT_CHANNEL_COLOR2_CB(log_channel, log_name, x, y, color, cb) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, color, false, log_name); cb(ss________.str());CATCH_ALL_DO_NOTHING();}} #define LOG_PRINT_CHANNEL_2_JORNAL(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, true, log_name);CATCH_ALL_DO_NOTHING();}} #define LOG_ERROR2_CB(log_name, x, cb) { \ TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << "[ERROR] Location: " << std::endl << LOCATION_SS << epee::misc_utils::get_callstack() << " Message:" << std::endl << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str(), LOG_LEVEL_0, epee::log_space::console_color_red, true, log_name); LOCAL_ASSERT(0); epee::log_space::increase_error_count(LOG_DEFAULT_CHANNEL); cb(ss________.str()); CATCH_ALL_DO_NOTHING();} #define LOG_ERROR2(log_name, x) LOG_ERROR2_CB(log_name, x, epee::log_space::log_stub) #define LOG_PRINT_CHANNEL2(log_channel, log_name, x, y) LOG_PRINT_CHANNEL2_CB(log_channel, log_name, x, y, epee::log_space::log_stub) #define LOG_PRINT_CHANNEL_COLOR2(log_channel, log_name, x, y, color) LOG_PRINT_CHANNEL_COLOR2_CB(log_channel, log_name, x, y, color, epee::log_space::log_stub) #define LOG_FRAME2(log_name, x, y) epee::log_space::log_frame frame(x, y, log_name) #else // #if defined(ENABLE_LOGGING_INTERNAL) #define LOG_PRINT_NO_PREFIX2(log_name, x, y) #define LOG_PRINT_NO_PREFIX_NO_POSTFIX2(log_name, x, y) #define LOG_PRINT_NO_POSTFIX2(log_name, x, y) #define LOG_PRINT_COLOR2(log_name, x, y, color) #define LOG_PRINT2_JORNAL(log_name, x, y) #define LOG_PRINT2(log_name, x, y) #define LOG_ERROR2(log_name, x) #define LOG_FRAME2(log_name, x, y) #endif // #if defined(ENABLE_LOGGING_INTERNAL) #define LOG_PRINT_NO_PREFIX2(log_name, x, y) LOG_PRINT_CHANNEL_NO_PREFIX2(LOG_DEFAULT_CHANNEL, log_name, x, y) #define LOG_PRINT_NO_PREFIX_NO_POSTFIX2(log_name, x, y) LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(LOG_DEFAULT_CHANNEL, log_name, x, y) #define LOG_PRINT_NO_POSTFIX2(log_name, x, y) LOG_PRINT_CHANNEL_NO_POSTFIX2(LOG_DEFAULT_CHANNEL, log_name, x, y) #define LOG_PRINT2(log_name, x, y) LOG_PRINT_CHANNEL2(LOG_DEFAULT_CHANNEL, log_name, x, y) #define LOG_PRINT2_CB(log_name, x, y, cb) LOG_PRINT_CHANNEL2_CB(LOG_DEFAULT_CHANNEL, log_name, x, y, cb) #define LOG_PRINT_COLOR2(log_name, x, y, color) LOG_PRINT_CHANNEL_COLOR2(LOG_DEFAULT_CHANNEL, log_name, x, y, color) #define LOG_PRINT_COLOR2_CB(log_name, x, y, color, cb) LOG_PRINT_CHANNEL_COLOR2_CB(LOG_DEFAULT_CHANNEL, log_name, x, y, color, cb) #define LOG_PRINT2_JORNAL(log_name, x, y) LOG_PRINT_CHANNEL_2_JORNAL(LOG_DEFAULT_CHANNEL, log_name, x, y) #ifndef LOG_DEFAULT_TARGET #define LOG_DEFAULT_TARGET NULL #endif #define LOG_PRINT_NO_POSTFIX(mess, level) LOG_PRINT_NO_POSTFIX2(LOG_DEFAULT_TARGET, mess, level) #define LOG_PRINT_NO_PREFIX(mess, level) LOG_PRINT_NO_PREFIX2(LOG_DEFAULT_TARGET, mess, level) #define LOG_PRINT_NO_PREFIX_NO_POSTFIX(mess, level) LOG_PRINT_NO_PREFIX_NO_POSTFIX2(LOG_DEFAULT_TARGET, mess, level) #define LOG_PRINT(mess, level) LOG_PRINT2(LOG_DEFAULT_TARGET, mess, level) #define LOG_PRINT_CB(mess, level, cb) LOG_PRINT2_CB(LOG_DEFAULT_TARGET, mess, level, cb) #define LOG_PRINT_COLOR_CB(mess, level, color, cb) LOG_PRINT_COLOR2_CB(LOG_DEFAULT_TARGET, mess, level, color, cb) #define LOG_COLOR_RED epee::log_space::console_color_red #define LOG_COLOR_GREEN epee::log_space::console_color_green #define LOG_COLOR_BLUE epee::log_space::console_color_blue #define LOG_COLOR_YELLOW epee::log_space::console_color_yellow #define LOG_COLOR_CYAN epee::log_space::console_color_cyan #define LOG_COLOR_MAGENTA epee::log_space::console_color_magenta #define LOG_PRINT_COLOR(mess, level, color) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, color) #define LOG_PRINT_RED(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, LOG_COLOR_RED) #define LOG_PRINT_GREEN(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, LOG_COLOR_GREEN) #define LOG_PRINT_BLUE(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, LOG_COLOR_BLUE) #define LOG_PRINT_YELLOW(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, LOG_COLOR_YELLOW) #define LOG_PRINT_CYAN(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, LOG_COLOR_CYAN) #define LOG_PRINT_MAGENTA(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, LOG_COLOR_MAGENTA) #define LOG_PRINT_RED_L0(mess) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, LOG_LEVEL_0, epee::log_space::console_color_red) #define LOG_PRINT_GREEN_L0(mess) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, LOG_LEVEL_0, epee::log_space::console_color_green) #define LOG_PRINT_L0(mess) LOG_PRINT(mess, LOG_LEVEL_0) #define LOG_PRINT_L1(mess) LOG_PRINT(mess, LOG_LEVEL_1) #define LOG_PRINT_L2(mess) LOG_PRINT(mess, LOG_LEVEL_2) #define LOG_PRINT_L3(mess) LOG_PRINT(mess, LOG_LEVEL_3) #define LOG_PRINT_L4(mess) LOG_PRINT(mess, LOG_LEVEL_4) #define LOG_PRINT_J(mess, level) LOG_PRINT2_JORNAL(LOG_DEFAULT_TARGET, mess, level) #define LOG_ERROR(mess) LOG_ERROR2(LOG_DEFAULT_TARGET, mess) #define LOG_ERROR_CB(mess, cb) LOG_ERROR2_CB(LOG_DEFAULT_TARGET, mess, cb) #define LOG_FRAME(mess, level) LOG_FRAME2(LOG_DEFAULT_TARGET, mess, level) #define LOG_VALUE(mess, level) LOG_VALUE2(LOG_DEFAULT_TARGET, mess, level) #define LOG_ARRAY(mess, level) LOG_ARRAY2(LOG_DEFAULT_TARGET, mess, level) //#define LOGWIN_PLATFORM_ERROR(err_no) LOGWINDWOS_PLATFORM_ERROR2(LOG_DEFAULT_TARGET, err_no) #define LOG_SOCKET_ERROR(err_no) LOG_SOCKET_ERROR2(LOG_DEFAULT_TARGET, err_no) //#define LOGWIN_PLATFORM_ERROR_UNCRITICAL(mess) LOGWINDWOS_PLATFORM_ERROR_UNCRITICAL2(LOG_DEFAULT_TARGET, mess) #define ENDL std::endl #define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw std::runtime_error(ss.str());} #define CHECK_AND_ASSERT_THROW_MES(expr, message) {if(!(expr)) ASSERT_MES_AND_THROW(message << ENDL << "thrown from " << LOCATION_SS);} #define CHECK_AND_ASSERT_THROW(expr, exception_exp) {if(!(expr)) {LOG_ERROR("EXCEPTION is thrown from " << LOCATION_SS); throw exception_exp; };} #ifndef CHECK_AND_ASSERT #define CHECK_AND_ASSERT(expr, fail_ret_val) do{if(!(expr)){LOCAL_ASSERT(expr); return fail_ret_val;};}while(0) #endif #define NOTHING #ifndef CHECK_AND_ASSERT_MES #define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message) do{if(!(expr)) {LOG_ERROR(message); return fail_ret_val;};}while(0) #endif #ifndef CHECK_AND_FORCE_ASSERT_MES #define CHECK_AND_FORCE_ASSERT_MES(expr, fail_ret_val, message) do{if(!(expr)) {LOG_ERROR(message); FORCE_ASSERT(expr); return fail_ret_val;};}while(0) #endif #ifndef CHECK_AND_ASSERT_MES_CUSTOM #define CHECK_AND_ASSERT_MES_CUSTOM(expr, fail_ret_val, custom_code, message) do{if(!(expr)) {LOG_ERROR(message); custom_code; return fail_ret_val;};}while(0) #endif #ifndef CHECK_AND_NO_ASSERT_MES #define CHECK_AND_NO_ASSERT_MES(expr, fail_ret_val, message) do{if(!(expr)) {LOG_PRINT_MAGENTA(message, LOG_LEVEL_0); /*LOCAL_ASSERT(expr);*/ return fail_ret_val;};}while(0) #endif #ifndef CHECK_AND_NO_ASSERT_MES_LEVEL #define CHECK_AND_NO_ASSERT_MES_LEVEL(expr, fail_ret_val, message, log_level) do{if(!(expr)) {LOG_PRINT(message, log_level); return fail_ret_val;};}while(0) #endif #ifndef CHECK_AND_ASSERT_MES_NO_RET #define CHECK_AND_ASSERT_MES_NO_RET(expr, message) do{if(!(expr)) {LOG_ERROR(message);};}while(0) #endif #ifndef CHECK_AND_ASSERT_MES2 #define CHECK_AND_ASSERT_MES2(expr, message) do{if(!(expr)) {LOG_ERROR(message); };}while(0) #endif #ifndef CHECK_AND_ASSERT_EQ #define CHECK_AND_ASSERT_EQ(A, B) CHECK_AND_ASSERT_MES((A) == (B), false, STR(A) " != " STR(B) " because " << A << " != " << B) #endif #ifndef CHECK_AND_ASSERT_NEQ #define CHECK_AND_ASSERT_NEQ(A, B) CHECK_AND_ASSERT_MES((A) != (B), false, STR(A) " == " STR(B) " because " << A << " == " << B) #endif #ifndef CHECK_AND_ASSERT_LESS #define CHECK_AND_ASSERT_LESS(A, B) CHECK_AND_ASSERT_MES((A) < (B), false, STR(A) " >= " STR(B) " because " << A << " >= " << B) #endif #ifndef CHECK_AND_ASSERT_GREATER #define CHECK_AND_ASSERT_GREATER(A, B) CHECK_AND_ASSERT_MES((A) > (B), false, STR(A) " <= " STR(B) " because " << A << " <= " << B) #endif namespace epee { namespace debug { inline bool get_set_enable_assert(bool set = false, bool v = false) { static bool e = true; if(set) e = v; return e; } } namespace log_space { class logger; class log_message; class log_singletone; /************************************************************************/ /* */ /************************************************************************/ enum console_colors { console_color_default, console_color_white, console_color_red, console_color_green, console_color_blue, console_color_cyan, console_color_magenta, console_color_yellow }; struct ibase_log_stream { ibase_log_stream(){} virtual ~ibase_log_stream(){} virtual bool out_buffer( const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL)=0; virtual int get_type(){return 0;} virtual bool set_max_logfile_size(uint64_t max_size){return true;}; virtual bool set_log_rotate_cmd(const std::string& cmd){return true;}; virtual bool truncate_log_files() { return true; } virtual std::string copy_logs_to_buffer() { return ""; } }; /************************************************************************/ /* */ /************************************************************************/ /*struct ibase_log_value { public: virtual void debug_out( std::stringstream* p_stream)const = 0; };*/ /************************************************************************/ /* */ /************************************************************************/ /*class log_message: public std::stringstream { public: log_message(const log_message& lm): std::stringstream(), std::stringstream::basic_ios() {} log_message(){} template log_message& operator<< (T t) { std::stringstream* pstrstr = this; (*pstrstr) << t; return *this; } }; inline log_space::log_message& operator<<(log_space::log_message& sstream, const ibase_log_value& log_val) { log_val.debug_out(&sstream); return sstream; } */ /************************************************************************/ /* */ /************************************************************************/ #define CONSOLE_DEFAULT_STREAM std::cout inline void log_stub(const std::string& /**/) {} struct delete_ptr { template void operator() (P p) { delete p.first; } }; /************************************************************************/ /* */ /************************************************************************/ //------------------------------------------------------------------------ #define max_dbg_str_len 80 #ifdef _MSC_VER class debug_output_stream: public ibase_log_stream { virtual bool out_buffer( const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL) { for ( int i = 0; i < buffer_len; i = i + max_dbg_str_len ) { std::string s( buffer + i, buffer_len- i < max_dbg_str_len ? buffer_len - i : max_dbg_str_len ); ::OutputDebugStringA( s.c_str() ); } return true; } }; #endif inline bool is_stdout_a_tty() { #ifndef ANDROID_BUILD static std::atomic initialized(false); static std::atomic is_a_tty(false); if (!initialized.load(std::memory_order_acquire)) { #if defined(WIN32) is_a_tty.store(0 != _isatty(_fileno(stdout)), std::memory_order_relaxed); #else is_a_tty.store(0 != isatty(fileno(stdout)), std::memory_order_relaxed); #endif initialized.store(true, std::memory_order_release); } return is_a_tty.load(std::memory_order_relaxed); #else return false; #endif } inline void set_console_color(int color, bool bright) { if (!is_stdout_a_tty()) return; switch(color) { case console_color_default: { #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE| (bright ? FOREGROUND_INTENSITY:0)); #else if(bright) CONSOLE_DEFAULT_STREAM << "\033[1;37m"; else CONSOLE_DEFAULT_STREAM << "\033[0m"; #endif } break; case console_color_white: { #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0)); #else if(bright) CONSOLE_DEFAULT_STREAM << "\033[1;37m"; else CONSOLE_DEFAULT_STREAM << "\033[0;37m"; #endif } break; case console_color_red: { #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | (bright ? FOREGROUND_INTENSITY:0)); #else if(bright) CONSOLE_DEFAULT_STREAM << "\033[1;31m"; else CONSOLE_DEFAULT_STREAM << "\033[0;31m"; #endif } break; case console_color_green: { #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | (bright ? FOREGROUND_INTENSITY:0)); #else if(bright) CONSOLE_DEFAULT_STREAM << "\033[1;32m"; else CONSOLE_DEFAULT_STREAM << "\033[0;32m"; #endif } break; case console_color_blue: { #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE | FOREGROUND_INTENSITY);//(bright ? FOREGROUND_INTENSITY:0)); #else if(bright) CONSOLE_DEFAULT_STREAM << "\033[1;34m"; else CONSOLE_DEFAULT_STREAM << "\033[0;34m"; #endif } break; case console_color_cyan: { #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0)); #else if(bright) CONSOLE_DEFAULT_STREAM << "\033[1;36m"; else CONSOLE_DEFAULT_STREAM << "\033[0;36m"; #endif } break; case console_color_magenta: { #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE | FOREGROUND_RED | (bright ? FOREGROUND_INTENSITY:0)); #else if(bright) CONSOLE_DEFAULT_STREAM << "\033[1;35m"; else CONSOLE_DEFAULT_STREAM << "\033[0;35m"; #endif } break; case console_color_yellow: { #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | (bright ? FOREGROUND_INTENSITY:0)); #else if(bright) CONSOLE_DEFAULT_STREAM << "\033[1;33m"; else CONSOLE_DEFAULT_STREAM << "\033[0;33m"; #endif } break; } } inline void reset_console_color() { if (!is_stdout_a_tty()) return; #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); #else CONSOLE_DEFAULT_STREAM << "\033[0m"; CONSOLE_DEFAULT_STREAM.flush(); #endif } class console_output_stream: public ibase_log_stream { #ifdef _MSC_VER bool m_have_to_kill_console; #endif public: console_output_stream() { #ifdef _MSC_VER if(!::GetStdHandle(STD_OUTPUT_HANDLE)) m_have_to_kill_console = true; else m_have_to_kill_console = false; if (m_have_to_kill_console) { ::AllocConsole(); freopen("CONOUT$", "w", stdout); } std::cout.clear(); #endif } ~console_output_stream() { #ifdef _MSC_VER if(m_have_to_kill_console) ::FreeConsole(); #endif } int get_type(){return LOGGER_CONSOLE;} virtual bool out_buffer( const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL) { if(plog_name) return true; //skip alternative logs from console set_console_color(color, log_level < 1); #ifdef _MSC_VER const char* ptarget_buf = NULL; char* pallocated_buf = NULL; // int i = 0; for(; i < buffer_len; i++) if(buffer[i] == '\a') break; if(i == buffer_len) ptarget_buf = buffer; else { pallocated_buf = new char[buffer_len]; ptarget_buf = pallocated_buf; for(i = 0; i < buffer_len; i++) { if(buffer[i] == '\a') pallocated_buf[i] = '^'; else pallocated_buf[i] = buffer[i]; } } //uint32_t b = 0; //::WriteConsoleA(::GetStdHandle(STD_OUTPUT_HANDLE), ptarget_buf, buffer_len, (DWORD*)&b, 0); CONSOLE_DEFAULT_STREAM << ptarget_buf; if(pallocated_buf) delete [] pallocated_buf; #else std::string buf(buffer, buffer_len); for(size_t i = 0; i!= buf.size(); i++) { if(static_cast(buf[i]) == 0x7 || static_cast(buf[i]) == 0x95) buf[i] = '^'; } CONSOLE_DEFAULT_STREAM << buf; #endif reset_console_color(); return true; } }; inline bool rotate_log_file(const char* pfile_path) { #ifdef _MSC_VER if(!pfile_path) return false; std::string file_path = pfile_path; std::string::size_type a = file_path .rfind('.'); if ( a != std::string::npos ) file_path .erase( a, file_path .size()); ::DeleteFileA( (file_path + ".0").c_str() ); ::MoveFileA( (file_path + ".log").c_str(), (file_path + ".0").c_str() ); #else return false;//not implemented yet #endif return true; } //--------------------------------------------------------------------------// class file_output_stream : public ibase_log_stream { public: typedef std::map > named_log_streams; file_output_stream( const std::string& default_log_file_name, const std::string& log_path ) { m_default_log_filename = default_log_file_name; m_max_logfile_size = 0; m_default_log_path_w = epee::string_encoding::utf8_to_wstring(log_path); m_pdefault_file_stream = add_new_stream_and_open(default_log_file_name.c_str()); } ~file_output_stream() { for(named_log_streams::iterator it = m_log_file_names.begin(); it!=m_log_file_names.end(); it++) { if ( it->second.first->is_open() ) { it->second.first->flush(); it->second.first->close(); } delete it->second.first; } } private: named_log_streams m_log_file_names; std::wstring m_default_log_path_w; boost::filesystem::ofstream* m_pdefault_file_stream; std::string m_log_rotate_cmd; std::string m_default_log_filename; uint64_t m_max_logfile_size; // gets utf-8 encoded string boost::filesystem::ofstream* add_new_stream_and_open(const char* pstream_name) { //log_space::rotate_log_file((m_default_log_path + "\\" + pstream_name).c_str()); boost::system::error_code ec; boost::filesystem::create_directories(m_default_log_path_w, ec); boost::filesystem::ofstream* pstream = new boost::filesystem::ofstream; std::wstring target_path = epee::string_encoding::utf8_to_wstring(pstream_name); if (!m_default_log_path_w.empty()) target_path = m_default_log_path_w + L"/" + target_path; pstream->open( target_path.c_str(), std::ios_base::out | std::ios::app /*ios_base::trunc */); if(pstream->fail()) return NULL; m_log_file_names[pstream_name] = std::pair(pstream, target_path); return pstream; } bool set_max_logfile_size(uint64_t max_size) { m_max_logfile_size = max_size; return true; } bool set_log_rotate_cmd(const std::string& cmd) { m_log_rotate_cmd = cmd; return true; } bool truncate_log_files() { for (named_log_streams::iterator it = m_log_file_names.begin(); it != m_log_file_names.end(); it++) { std::wstring target_path = it->second.second; //close and delete current stream if (it->second.first->is_open()) { it->second.first->flush(); it->second.first->close(); } delete it->second.first; it->second.first = nullptr; //reopen it with truncate boost::filesystem::ofstream* pstream = new boost::filesystem::ofstream; pstream->open(target_path.c_str(), std::ios_base::out | std::ios::trunc ); if (pstream->fail()) { throw std::runtime_error("Unexpected error: failed to re-open log stream on truncate"); } it->second.first = pstream; } return true; } std::string copy_logs_to_buffer() { std::stringstream res; for (named_log_streams::iterator it = m_log_file_names.begin(); it != m_log_file_names.end(); it++) { std::wstring target_path = it->second.second; res << "[" << epee::string_encoding::convert_to_ansii(target_path) << "]" << ENDL; std::string res_buf; if (!epee::file_io_utils::load_file_to_string(target_path, res_buf)) { res << "ERROR"; } else { res << res_buf; } } return res.str(); } virtual bool out_buffer( const char* buffer, int buffer_len, int log_level, int color, const char* plog_name = NULL ) { boost::filesystem::ofstream* m_target_file_stream = m_pdefault_file_stream; if(plog_name) { //find named stream named_log_streams::iterator it = m_log_file_names.find(plog_name); if(it == m_log_file_names.end()) m_target_file_stream = add_new_stream_and_open(plog_name); else m_target_file_stream = it->second.first; } if(!m_target_file_stream || !m_target_file_stream->is_open()) return false;//TODO: add assert here m_target_file_stream->write(buffer, buffer_len ); m_target_file_stream->flush(); /* if(m_max_logfile_size) { boost::filesystem::ofstream::pos_type pt = m_target_file_stream->tellp(); uint64_t current_sz = pt; if(current_sz > m_max_logfile_size) { CONSOLE_DEFAULT_STREAM << "current_sz= " << current_sz << " m_max_logfile_size= " << m_max_logfile_size << std::endl; std::string log_file_name; if(!plog_name) log_file_name = m_default_log_filename; else log_file_name = plog_name; m_target_file_stream->close(); std::string new_log_file_name = log_file_name; time_t tm = 0; time(&tm); int err_count = 0; boost::system::error_code ec; do { new_log_file_name = string_tools::cut_off_extension(log_file_name); if(err_count) new_log_file_name += misc_utils::get_time_str_v2(tm) + "(" + boost::lexical_cast(err_count) + ")" + ".log"; else new_log_file_name += misc_utils::get_time_str_v2(tm) + ".log"; err_count++; }while(boost::filesystem::exists(m_default_log_path + "/" + new_log_file_name, ec)); std::string new_log_file_path = m_default_log_path + "/" + new_log_file_name; boost::filesystem::rename(m_default_log_path + "/" + log_file_name, new_log_file_path, ec); if(ec) { CONSOLE_DEFAULT_STREAM << "Filed to rename, ec = " << ec.message() << std::endl; } if(m_log_rotate_cmd.size()) { std::string m_log_rotate_cmd_local_copy = m_log_rotate_cmd; //boost::replace_all(m_log_rotate_cmd, "[*SOURCE*]", new_log_file_path); boost::replace_all(m_log_rotate_cmd_local_copy, "[*TARGET*]", new_log_file_path); misc_utils::call_sys_cmd(m_log_rotate_cmd_local_copy); } m_target_file_stream->open( (m_default_log_path + "/" + log_file_name).c_str(), std::ios_base::out | std::ios::app / * ios_base::trunc * /); if(m_target_file_stream->fail()) return false; } } */ return true; } int get_type(){return LOGGER_FILE;} }; /************************************************************************/ /* */ /************************************************************************/ class log_stream_splitter { public: typedef std::list > streams_container; log_stream_splitter(){} ~log_stream_splitter() { //free pointers std::for_each(m_log_streams.begin(), m_log_streams.end(), delete_ptr()); } bool set_max_logfile_size(uint64_t max_size) { for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++) it->first->set_max_logfile_size(max_size); return true; } bool set_log_rotate_cmd(const std::string& cmd) { for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++) it->first->set_log_rotate_cmd(cmd); return true; } bool truncate_log_files() { for (streams_container::iterator it = m_log_streams.begin(); it != m_log_streams.end(); it++) it->first->truncate_log_files(); return true; } std::string copy_logs_to_buffer() { std::string res; for (streams_container::iterator it = m_log_streams.begin(); it != m_log_streams.end(); it++) res += it->first->copy_logs_to_buffer(); return res; } bool do_log_message(const std::string& rlog_mes, int log_level, int color, const char* plog_name = NULL) { std::string str_mess = rlog_mes; size_t str_len = str_mess.size(); const char* pstr = str_mess.c_str(); for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++) if(it->second >= log_level) it->first->out_buffer(pstr, (int)str_len, log_level, color, plog_name); return true; } std::string get_log_file_path() { return m_default_log_file_path; } bool add_logger( int type, const char* pdefault_file_name, const char* pdefault_log_folder, int log_level_limit = LOG_LEVEL_4 ) { ibase_log_stream* ls = NULL; switch( type ) { case LOGGER_FILE: m_default_log_file_path = std::string(pdefault_log_folder) + "/" + pdefault_file_name; ls = new file_output_stream( pdefault_file_name, pdefault_log_folder ); break; case LOGGER_DEBUGGER: #ifdef _MSC_VER ls = new debug_output_stream( ); #else return false;//not implemented yet #endif break; case LOGGER_CONSOLE: ls = new console_output_stream( ); break; } if ( ls ) { m_log_streams.push_back(streams_container::value_type(ls, log_level_limit)); return true; } return false; } bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4 ) { m_log_streams.push_back(streams_container::value_type(pstream, log_level_limit) ); return true; } bool remove_logger(int type) { streams_container::iterator it = m_log_streams.begin(); for(;it!=m_log_streams.end(); it++) { if(it->first->get_type() == type) { delete it->first; m_log_streams.erase(it); return true; } } return false; } protected: private: streams_container m_log_streams; std::string m_default_log_file_path; }; /************************************************************************/ /* */ /************************************************************************/ inline int get_set_log_detalisation_level(bool is_need_set = false, int log_level_to_set = LOG_LEVEL_1); inline int get_set_time_level(bool is_need_set = false, int time_log_level = LOG_LEVEL_0); inline bool get_set_need_thread_id(bool is_need_set = false, bool is_need_val = false); inline bool get_set_need_proc_name(bool is_need_set = false, bool is_need_val = false); typedef std::map channels_err_stat_container_type; inline epee::locked_object_proxy get_channels_errors_stat_container() { static epee::static_helpers::wrapper cs; static epee::static_helpers::wrapper errors_by_channel; epee::locked_object_proxy res(errors_by_channel, cs); return res; } inline void increase_error_count(const char* channel) { auto ch_container = get_channels_errors_stat_container(); std::string ch_name = channel ? channel : ""; uint64_t& r = (*ch_container)[ch_name]; r++; } inline std::string get_daytime_string2() { boost::posix_time::ptime p = boost::posix_time::microsec_clock::local_time(); return misc_utils::get_time_str_v3(p); } inline std::string get_day_time_string() { return get_daytime_string2(); //time_t tm = 0; //time(&tm); //return misc_utils::get_time_str(tm); } inline std::string get_time_string() { return get_daytime_string2(); } #ifdef _MSC_VER inline std::string get_time_string_adv(SYSTEMTIME* pst = NULL) { SYSTEMTIME st = {0}; if(!pst) { pst = &st; GetSystemTime(&st); } std::stringstream str_str; str_str.fill('0'); str_str << std::setw(2) << pst->wHour << "_" << std::setw(2) << pst->wMinute << "_" << std::setw(2) << pst->wSecond << "_" << std::setw(3) << pst->wMilliseconds; return str_str.str(); } #endif class logger { public: friend class log_singletone; logger() { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); init(); FAST_CRITICAL_REGION_END(); } ~logger() { } bool set_max_logfile_size(uint64_t max_size) { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); m_log_target.set_max_logfile_size(max_size); FAST_CRITICAL_REGION_END(); return true; } bool set_log_rotate_cmd(const std::string& cmd) { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); m_log_target.set_log_rotate_cmd(cmd); FAST_CRITICAL_REGION_END(); return true; } std::string copy_logs_to_buffer() { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); return m_log_target.copy_logs_to_buffer(); FAST_CRITICAL_REGION_END(); } bool truncate_log_files() { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); return m_log_target.truncate_log_files(); FAST_CRITICAL_REGION_END(); } bool take_away_journal(std::list& journal) { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); m_journal.swap(journal); FAST_CRITICAL_REGION_END(); return true; } bool get_journal_items(std::list& journal, size_t count) { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); size_t i = 0; for (auto it = m_journal.rbegin(); it != m_journal.rend() && i!= count; it++, i++) { journal.push_front(*it); } FAST_CRITICAL_REGION_END(); return true; } bool do_log_message(const std::string& rlog_mes, int log_level, int color, bool add_to_journal = false, const char* plog_name = NULL) { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); m_log_target.do_log_message(rlog_mes, log_level, color, plog_name); if (add_to_journal) { m_journal.push_back(rlog_mes); if (m_journal.size() > m_journal_max_elements) m_journal.pop_front(); } return true; FAST_CRITICAL_REGION_END(); } bool add_logger( int type, const char* pdefault_file_name, const char* pdefault_log_folder , int log_level_limit = LOG_LEVEL_4) { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); return m_log_target.add_logger( type, pdefault_file_name, pdefault_log_folder, log_level_limit); FAST_CRITICAL_REGION_END(); } bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4) { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); return m_log_target.add_logger(pstream, log_level_limit); FAST_CRITICAL_REGION_END(); } bool remove_logger(int type) { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); return m_log_target.remove_logger(type); FAST_CRITICAL_REGION_END(); } bool set_thread_prefix(const std::string& prefix) { FAST_CRITICAL_REGION_BEGIN(m_critical_sec); m_thr_prefix_strings[misc_utils::get_thread_string_id()] = prefix; FAST_CRITICAL_REGION_END(); return true; } std::string get_thread_prefix() { FAST_CRITICAL_REGION_LOCAL(m_critical_sec); return m_thr_prefix_strings[misc_utils::get_thread_string_id()]; } std::string get_default_log_file() { return m_default_log_file; } std::string get_default_log_folder() { return m_default_log_folder; } void set_default_log_folder(const std::string& folder) { m_default_log_folder = folder; } std::string get_actual_log_file_path() { return m_log_target.get_log_file_path(); } protected: private: bool init() { // m_journal_max_elements = LOG_JOURNAL_MAX_ELEMENTS; m_process_name = string_tools::get_current_module_name(); init_log_path_by_default(); //this need ti initialize static critical section in get_channels_errors_stat_container() get_channels_errors_stat_container(); //init default set of loggers init_default_loggers(); std::stringstream ss; ss << get_time_string() << " Init logging. Level=" << get_set_log_detalisation_level() << "Default log path=" << m_default_log_folder << std::endl; this->do_log_message(ss.str(), console_color_white, LOG_LEVEL_0); return true; } bool init_default_loggers() { //TODO: return true; } bool init_log_path_by_default() { m_default_log_file = m_process_name; std::string::size_type a = m_default_log_file.rfind('.'); if (a != std::string::npos) m_default_log_file.erase(a, m_default_log_file.size()); //load process name m_default_log_folder = string_tools::get_current_module_folder(); m_default_log_file += ".log"; return true; } log_stream_splitter m_log_target; std::string m_default_log_folder; std::string m_default_log_file; std::string m_process_name; std::map m_thr_prefix_strings; std::list m_journal; size_t m_journal_max_elements; critical_section m_critical_sec; }; /************************************************************************/ /* */ /************************************************************************/ class log_singletone { public: friend class static_helpers::initializer; friend class logger; static int get_log_detalisation_level() { get_or_create_instance();//to initialize logger, if it not initialized return get_set_log_detalisation_level(); } //get_enabled_channels not thread-safe, at the moment leave it like this because it's configured in main, before other threads started static std::set& get_enabled_channels() { static epee::static_helpers::wrapper> genabled_channels; return genabled_channels; } static bool channel_enabled(const std::string& ch_name) { std::set& genabled_channels = get_enabled_channels(); return genabled_channels.find(ch_name) != genabled_channels.end(); } static void enable_channels(const std::string& channels_set, bool verbose = true) { std::set& genabled_channels = get_enabled_channels(); std::list list_of_channels; boost::split(list_of_channels, channels_set, boost::is_any_of(",;: "), boost::token_compress_on); if (verbose) std::cout << "log channels: "; for (const auto& ch : list_of_channels) { genabled_channels.insert(ch); if (verbose) std::cout << ch << " "; } if (verbose) std::cout << " enabled" << std::endl; } static void enable_channel(const std::string& ch_name, bool verbose = true) { std::set& genabled_channels = get_enabled_channels(); //lazy synchronization: just replace with modified copy of whole set std::set enabled_channels_local = genabled_channels; enabled_channels_local.insert(ch_name); genabled_channels.swap(enabled_channels_local); #ifndef ANDROID_BUILD if (verbose) std::cout << "log channel '" << ch_name << "' enabled" << std::endl; #endif } static void disable_channels(const std::string& channels_set) { std::set& genabled_channels = get_enabled_channels(); std::list list_of_channels; boost::split(list_of_channels, channels_set, boost::is_any_of(",;: "), boost::token_compress_on); std::cout << "log channels: "; for (const auto& ch : list_of_channels) { genabled_channels.erase(ch); std::cout << ch << " "; } std::cout << " disabled" << std::endl; } static void disable_channel(const std::string& ch_name) { std::set& genabled_channels = get_enabled_channels(); //lazy synchronization: just replace with modified copy of whole set std::set enabled_channels_local = genabled_channels; auto it = enabled_channels_local.find(ch_name); if (it != enabled_channels_local.end()) enabled_channels_local.erase(it); genabled_channels.swap(enabled_channels_local); std::cout << "log channel '" << ch_name << "' disabled" << std::endl; } static bool channel_enabled(const char* pch_name) { //null channel, enabled by default if (!pch_name) return true; return channel_enabled(std::string(pch_name)); } static bool is_filter_error(int error_code) { return false; } static bool do_log_message(const std::string& rlog_mes, int log_level, int color, bool keep_in_journal, const char* plog_name = NULL) { logger* plogger = get_or_create_instance(); bool res = false; if(plogger) res = plogger->do_log_message(rlog_mes, log_level, color, keep_in_journal, plog_name); else { //globally uninitialized, create new logger for each call of do_log_message() and then delete it plogger = new logger(); //TODO: some extra initialization res = plogger->do_log_message(rlog_mes, log_level, color, keep_in_journal, plog_name); delete plogger; plogger = NULL; } return res; } static bool take_away_journal(std::list& journal) { logger* plogger = get_or_create_instance(); bool res = false; if(plogger) res = plogger->take_away_journal(journal); return res; } static bool get_journal_items(std::list& journal, size_t count) { logger* plogger = get_or_create_instance(); bool res = false; if (plogger) res = plogger->get_journal_items(journal, count); return res; } static bool set_max_logfile_size(uint64_t file_size) { logger* plogger = get_or_create_instance(); if(!plogger) return false; return plogger->set_max_logfile_size(file_size); } static bool set_log_rotate_cmd(const std::string& cmd) { logger* plogger = get_or_create_instance(); if(!plogger) return false; return plogger->set_log_rotate_cmd(cmd); } static std::string copy_logs_to_buffer() { logger* plogger = get_or_create_instance(); if (!plogger) return ""; return plogger->copy_logs_to_buffer(); } static bool truncate_log_files() { logger* plogger = get_or_create_instance(); if (!plogger) return false; return plogger->truncate_log_files(); } static bool add_logger( int type, const char* pdefault_file_name, const char* pdefault_log_folder, int log_level_limit = LOG_LEVEL_4) { logger* plogger = get_or_create_instance(); if(!plogger) return false; return plogger->add_logger(type, pdefault_file_name, pdefault_log_folder, log_level_limit); } static std::string get_default_log_file() { logger* plogger = get_or_create_instance(); if(plogger) return plogger->get_default_log_file(); return ""; } static std::string get_actual_log_file_path() { logger* plogger = get_or_create_instance(); if (plogger) return plogger->get_actual_log_file_path(); return ""; } static std::string get_default_log_folder() { logger* plogger = get_or_create_instance(); if(plogger) return plogger->get_default_log_folder(); return ""; } static void set_default_log_folder(const std::string& folder) { logger* plogger = get_or_create_instance(); if (plogger) plogger->set_default_log_folder(folder); } static bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4 ) { logger* plogger = get_or_create_instance(); if(!plogger) return false; return plogger->add_logger(pstream, log_level_limit); } static bool remove_logger( int type ) { logger* plogger = get_or_create_instance(); if(!plogger) return false; return plogger->remove_logger(type); } PUSH_GCC_WARNINGS DISABLE_GCC_WARNING(maybe-uninitialized) static int get_set_log_detalisation_level(bool is_need_set = false, int log_level_to_set = LOG_LEVEL_1) { static int log_detalisation_level = LOG_LEVEL_1; if (is_need_set) { log_detalisation_level = log_level_to_set; } return log_detalisation_level; } POP_GCC_WARNINGS static int get_set_time_level(bool is_need_set = false, int time_log_level = LOG_LEVEL_0) { static int val_time_log_level = LOG_LEVEL_0; if(is_need_set) val_time_log_level = time_log_level; return val_time_log_level; } static int get_set_process_level(bool is_need_set = false, int process_log_level = LOG_LEVEL_0) { static int val_process_log_level = LOG_LEVEL_0; if(is_need_set) val_process_log_level = process_log_level; return val_process_log_level; } /*static int get_set_tid_level(bool is_need_set = false, int tid_log_level = LOG_LEVEL_0) { static int val_tid_log_level = LOG_LEVEL_0; if(is_need_set) val_tid_log_level = tid_log_level; return val_tid_log_level; }*/ static bool get_set_need_thread_id(bool is_need_set = false, bool is_need_val = false) { static bool is_need = false; if(is_need_set) is_need = is_need_val; return is_need; } static bool get_set_need_proc_name(bool is_need_set = false, bool is_need_val = false) { static bool is_need = true; if(is_need_set) is_need = is_need_val; return is_need; } #ifdef _MSC_VER static void SetThreadName( DWORD dwThreadID, const char* threadName) { #define MS_VC_EXCEPTION 0x406D1388 #pragma pack(push,8) typedef struct tagTHREADNAME_INFO { DWORD dwType; // Must be 0x1000. LPCSTR szName; // Pointer to name (in user addr space). DWORD dwThreadID; // Thread ID (-1=caller thread). DWORD dwFlags; // Reserved for future use, must be zero. } THREADNAME_INFO; #pragma pack(pop) Sleep(10); THREADNAME_INFO info; info.dwType = 0x1000; info.szName = (char*)threadName; info.dwThreadID = dwThreadID; info.dwFlags = 0; __try { RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); } __except(EXCEPTION_EXECUTE_HANDLER) { } } #endif static bool set_thread_log_prefix(const std::string& prefix) { #ifdef _MSC_VER SetThreadName(-1, prefix.c_str()); #endif logger* plogger = get_or_create_instance(); if(!plogger) return false; return plogger->set_thread_prefix(prefix); } static std::string get_thread_log_prefix() { logger* plogger = get_or_create_instance(); if (!plogger) return ""; return plogger->get_thread_prefix(); } static std::string get_prefix_entry() { std::stringstream str_prefix; //write time entry if ( get_set_time_level() <= get_set_log_detalisation_level() ) str_prefix << get_day_time_string() << " "; //write process info logger* plogger = get_or_create_instance(); //bool res = false; if(!plogger) { //globally uninitialized, create new logger for each call of get_prefix_entry() and then delete it plogger = new logger(); } //if ( get_set_need_proc_name() && get_set_process_level() <= get_set_log_detalisation_level() ) // str_prefix << "[" << plogger->m_process_name << " (id=" << GetCurrentProcessId() << ")] "; //#ifdef _MSC_VER_EX if ( get_set_need_thread_id() /*&& get_set_tid_level() <= get_set_log_detalisation_level()*/ ) str_prefix << "[tid:" << misc_utils::get_thread_string_id() << "] "; //#endif if(plogger->m_thr_prefix_strings.size()) { FAST_CRITICAL_REGION_LOCAL(plogger->m_critical_sec); std::string thr_str = misc_utils::get_thread_string_id(); std::map::iterator it = plogger->m_thr_prefix_strings.find(thr_str); if(it!=plogger->m_thr_prefix_strings.end()) { str_prefix << it->second; } } if(get_set_is_uninitialized()) delete plogger; return str_prefix.str(); } private: log_singletone(){}//restric to create an instance //static initializer m_log_initializer;//must be in one .cpp file (for example main.cpp) via DEFINE_LOGGING macro static bool init() { return true;/*do nothing here*/ } static bool un_init() { //delete object logger* plogger = get_set_instance_internal(); if(plogger) delete plogger; //set uninitialized get_set_is_uninitialized(true, true); get_set_instance_internal(true, NULL); return true; } static logger* get_or_create_instance() { logger* plogger = get_set_instance_internal(); if(!plogger) if(!get_set_is_uninitialized()) get_set_instance_internal(true, plogger = new logger); return plogger; } static logger* get_set_instance_internal(bool is_need_set = false, logger* pnew_logger_val = NULL) { static logger* val_plogger = NULL; if(is_need_set) val_plogger = pnew_logger_val; return val_plogger; } static bool get_set_is_uninitialized(bool is_need_set = false, bool is_uninitialized = false) { static bool val_is_uninitialized = false; if(is_need_set) val_is_uninitialized = is_uninitialized; return val_is_uninitialized; } //static int get_set_error_filter(bool is_need_set = false) }; const static static_helpers::initializer log_initializer; /************************************************************************/ /* */ // /************************************************************************/ // class log_array_value // { // int num; // log_message& m_ref_log_mes; // // public: // // log_array_value( log_message& log_mes ) : num(0), m_ref_log_mes(log_mes) {} // // void operator ( )( ibase_log_value *val ) { // m_ref_log_mes << "\n[" << num++ << "] "/* << val*/; } // // // template // void operator ()(T &value ) // { // m_ref_log_mes << "\n[" << num++ << "] " << value; // } // }; class log_frame { std::string m_name; int m_level; const char* m_plog_name; public: log_frame(const std::string& name, int dlevel = LOG_LEVEL_2 , const char* plog_name = NULL) { #ifdef _MSC_VER int lasterr=::GetLastError(); #endif m_plog_name = plog_name; if ( dlevel <= log_singletone::get_log_detalisation_level() ) { m_name = name; std::stringstream ss; ss << log_space::log_singletone::get_prefix_entry() << "-->>" << m_name << std::endl; log_singletone::do_log_message(ss.str(), dlevel, console_color_default, false, m_plog_name); } m_level = dlevel; #ifdef _MSC_VER ::SetLastError(lasterr); #endif } ~log_frame() { NESTED_TRY_ENTRY(); #ifdef _MSC_VER int lasterr=::GetLastError(); #endif if (m_level <= log_singletone::get_log_detalisation_level() ) { std::stringstream ss; ss << log_space::log_singletone::get_prefix_entry() << "<<--" << m_name << std::endl; log_singletone::do_log_message(ss.str(), m_level, console_color_default, false,m_plog_name); } #ifdef _MSC_VER ::SetLastError(lasterr); #endif NESTED_CATCH_ENTRY(__func__); } }; inline int get_set_time_level(bool is_need_set, int time_log_level) { return log_singletone::get_set_time_level(is_need_set, time_log_level); } inline int get_set_log_detalisation_level(bool is_need_set, int log_level_to_set) { return log_singletone::get_set_log_detalisation_level(is_need_set, log_level_to_set); } inline std::string get_prefix_entry() { return log_singletone::get_prefix_entry(); } inline bool get_set_need_thread_id(bool is_need_set, bool is_need_val) { return log_singletone::get_set_need_thread_id(is_need_set, is_need_val); } inline bool get_set_need_proc_name(bool is_need_set, bool is_need_val ) { return log_singletone::get_set_need_proc_name(is_need_set, is_need_val); } inline std::string get_win32_err_descr(int err_no) { #ifdef _MSC_VER LPVOID lpMsgBuf; FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err_no, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*) &lpMsgBuf, 0, NULL ); std::string fix_sys_message = "(null)"; if(lpMsgBuf) fix_sys_message = (char*)lpMsgBuf; std::string::size_type a; if ( (a = fix_sys_message.rfind( '\n' )) != std::string::npos ) fix_sys_message.erase(a); if ( (a = fix_sys_message.rfind( '\r' )) != std::string::npos ) fix_sys_message.erase(a); LocalFree(lpMsgBuf); return fix_sys_message; #else return "Not implemented yet"; #endif } inline bool getwin32_err_text(std::stringstream& ref_message, int error_no) { ref_message << "win32 error:" << get_win32_err_descr(error_no); return true; } } } // namespace epee POP_VS_WARNINGS #endif //_MISC_LOG_EX_H_