json Serializer::serializeLogMessage(const LogMessagePtr& aMessageData) noexcept { return{ { "id", aMessageData->getId() }, { "text", aMessageData->getText() }, { "time", aMessageData->getTime() }, { "severity", getSeverity(aMessageData->getSeverity()) }, { "is_read", aMessageData->getRead() } }; }
/** explicits copy of all input. This is makes it possibly to use g3log across dynamically loaded libraries * i.e. (dlopen + dlsym) */ void saveMessage(const char *entry, const char *file, int line, const char *function, const LEVELS &level, const char *boolean_expression, int fatal_signal, const char *stack_trace) { LEVELS msgLevel {level}; LogMessagePtr message {std2::make_unique<LogMessage>(file, line, function, msgLevel)}; message.get()->write().append(entry); message.get()->setExpression(boolean_expression); if (internal::wasFatal(level)) { auto fatalhook = g_fatal_pre_logging_hook; // In case the fatal_pre logging actually will cause a crash in its turn // let's not do recursive crashing! setFatalPreLoggingHook(g_pre_fatal_hook_that_does_nothing); ++g_fatal_hook_recursive_counter; // thread safe counter // "benign" race here. If two threads crashes, with recursive crashes // then it's possible that the "other" fatal stack trace will be shown // that's OK since it was anyhow the first crash detected static const std::string first_stack_trace = stack_trace; fatalhook(); message.get()->write().append(stack_trace); if (g_fatal_hook_recursive_counter.load() > 1) { message.get()->write() .append("\n\n\nWARNING\n" "A recursive crash detected. It is likely the hook set with 'setFatalPreLoggingHook(...)' is responsible\n\n") .append("---First crash stacktrace: ").append(first_stack_trace).append("\n---End of first stacktrace\n"); } FatalMessagePtr fatal_message { std2::make_unique<FatalMessage>(*(message._move_only.get()), fatal_signal) }; // At destruction, flushes fatal message to g3LogWorker // either we will stay here until the background worker has received the fatal // message, flushed the crash message to the sinks and exits with the same fatal signal //..... OR it's in unit-test mode then we throw a std::runtime_error (and never hit sleep) fatalCall(fatal_message); } else { pushMessageToLogger(message); } }
/** * save the message to the logger. In case of called before the logger is instantiated * the first message will be saved. Any following subsequent unitnialized log calls * will be ignored. * * The first initialized log entry will also save the first uninitialized log message, if any * @param log_entry to save to logger */ void pushMessageToLogger(LogMessagePtr incoming) { // todo rename to Push SavedMessage To Worker // Uninitialized messages are ignored but does not CHECK/crash the logger if (!internal::isLoggingInitialized()) { std::call_once(g_set_first_uninitialized_flag, [&] { g_first_unintialized_msg = incoming.release(); std::string err = {"LOGGER NOT INITIALIZED:\n\t\t"}; err.append(g_first_unintialized_msg->message()); std::string& str = g_first_unintialized_msg->write(); str.clear(); str.append(err); // replace content std::cerr << str << std::endl; }); return; } // logger is initialized g_logger_instance->save(incoming); }
//----------------------------------------------------------------------------- void Logger::run( const bool& shutdown ) { LogMessagePtr message; std::string path = path_; std::string suffix = suffix_; std::ofstream log_file; while ( shutdown == false ) { if ( messages_.pop( message ) && message ) { if( message->is_flush_marker_ ) { message->signalFlushed(); } else { if ( message->log_level_ <= log_level_ ) { std::cout << message->toString( console_log_options_ ); } if ( log_file_enabled_ ) { { boost::mutex::scoped_lock guard( file_attribute_lock_ ); path = path_; suffix = suffix_; } if ( log_file.is_open() == false ) { log_file.close(); // openLogFile( path, suffix ); std::string full_log_filename = generateLogName( path, suffix ); log_file.open( full_log_filename.c_str(), std::ofstream::out ); } if ( log_file.is_open() ) { std::string log_message = message->toString( log::DisplayAll ); current_log_file_size_ += log_message.size(); log_file << log_message; } } else { if ( log_file.is_open() ) { log_file.close(); } } } } } // Make sure the log file is closed. log_file.close(); }
void SystemFrame::addLine(const LogMessagePtr& aMessageData) { ctrlPad.SetRedraw(FALSE); POINT pt = { 0 }; bool scroll = !lButtonDown && scrollIsAtEnd(); ctrlPad.GetScrollPos(&pt); int curPos = ctrlPad.CharFromPos(pt); //current scroll position by character pos LONG SavedBegin, SavedEnd; LONG Begin = 0; LONG End = 0; ctrlPad.GetSel(SavedBegin, SavedEnd); End = Begin = ctrlPad.GetTextLengthEx(GTL_NUMCHARS); tstring Text = Text::toT(aMessageData->getText()) + _T(" \r\n"); tstring time = Text::toT(" [" + Util::getTimeStamp(aMessageData->getTime()) + "] "); tstring line = time + Text; LONG limitText = ctrlPad.GetLimitText(); LONG TextLength = End + line.size(); if((TextLength +1) > limitText) { dcdebug("textlength %s \n", Util::toString(TextLength).c_str()); LONG RemoveEnd = 0; RemoveEnd = ctrlPad.LineIndex(ctrlPad.LineFromChar(2000)); End = Begin -=RemoveEnd; SavedBegin -= RemoveEnd; SavedEnd -= RemoveEnd; //fix the scroll position if text was removed from the start POINT p = { 0 }; curPos -= RemoveEnd; p = ctrlPad.PosFromChar(curPos); pt.y = p.y; ctrlPad.SetSel(0, RemoveEnd); ctrlPad.ReplaceSel(_T("")); } ctrlPad.AppendText(line.c_str()); End += time.size() -1; ctrlPad.SetSel(Begin, End); ctrlPad.SetSelectionCharFormat(WinUtil::m_TextStyleTimestamp); if (aMessageData->getSeverity() == LogMessage::SEV_ERROR) { ctrlPad.SetSel(End, End+Text.length()-1); CHARFORMAT2 ec = WinUtil::m_ChatTextGeneral; ec.crTextColor = SETTING(ERROR_COLOR); ctrlPad.SetSelectionCharFormat(ec); } Colorize(Text, End+1); //timestamps should always be timestamps right? ctrlPad.SetSel(Begin, Begin); switch(aMessageData->getSeverity()) { case LogMessage::SEV_INFO: CImageDataObject::InsertBitmap(ctrlPad.GetOleInterface(),hbInfo, false); break; case LogMessage::SEV_WARNING: CImageDataObject::InsertBitmap(ctrlPad.GetOleInterface(), hbWarning, false); break; case LogMessage::SEV_ERROR: CImageDataObject::InsertBitmap(ctrlPad.GetOleInterface(), hbError, false); if(!errorNotified && !getActive()) { setIcon(tabError); errorNotified = true; } break; default: break; } ctrlPad.SetSel(SavedBegin, SavedEnd); //restore the user selection if(scroll/* && (SavedBegin == SavedEnd)*/) { scrollToEnd(); } else { ctrlPad.SetScrollPos(&pt); } ctrlPad.SetRedraw(TRUE); ctrlPad.InvalidateRect(NULL); }