44 return fwrite(str.data(), 1, str.size(), fp);
52 assert(m_fileout ==
nullptr);
61 setbuf(m_fileout,
nullptr);
70 while (!m_msgs_before_open.empty()) {
71 const std::string& s = m_msgs_before_open.front();
75 for (
const auto& cb : m_print_callbacks) {
79 m_msgs_before_open.pop_front();
90 if (m_fileout !=
nullptr) fclose(m_fileout);
92 m_print_callbacks.clear();
104 EnableCategory(flag);
110 m_categories &= ~flag;
117 DisableCategory(flag);
123 return (m_categories.load(std::memory_order_relaxed) & category) != 0;
132 if (!WillLogCategory(category))
return false;
135 const auto it{m_category_log_levels.find(category)};
136 return level >= (it == m_category_log_levels.end() ? LogLevel() : it->second);
171 #ifdef DEBUG_LOCKCONTENTION
184 [](
const std::map<std::string, BCLog::LogFlags>& in) {
185 std::unordered_map<BCLog::LogFlags, std::string>
out;
186 for (
const auto& [
k, v] : in) {
190 default:
out.emplace(v,
k);
235 static std::optional<BCLog::Level>
GetLogLevel(
const std::string& level_str)
237 if (level_str ==
"trace") {
239 }
else if (level_str ==
"debug") {
241 }
else if (level_str ==
"info") {
243 }
else if (level_str ==
"warning") {
245 }
else if (level_str ==
"error") {
254 std::vector<LogCategory>
ret;
272 return Join(std::vector<BCLog::Level>{levels.begin(), levels.end()},
", ", [](
BCLog::Level level) {
return LogLevelToStr(level); });
277 std::string strStamped;
279 if (!m_log_timestamps)
282 if (m_started_new_line) {
283 const auto now{SystemClock::now()};
284 const auto now_seconds{std::chrono::time_point_cast<std::chrono::seconds>(now)};
286 if (m_log_time_micros && !strStamped.empty()) {
287 strStamped.pop_back();
288 strStamped +=
strprintf(
".%06dZ", Ticks<std::chrono::microseconds>(now - now_seconds));
294 strStamped +=
' ' + str;
311 for (
char ch_in : str) {
312 uint8_t ch = (uint8_t)ch_in;
313 if ((ch >= 32 || ch ==
'\n') && ch !=
'\x7f') {
327 const bool has_category{m_always_print_category_level || category !=
LogFlags::ALL};
330 if (!has_category && level ==
Level::Info)
return {};
337 if (m_always_print_category_level || !has_category || level !=
Level::Debug) {
341 if (has_category) s +=
":";
354 if (m_started_new_line) {
355 str_prefixed.insert(0, GetLogPrefix(category, level));
358 if (m_log_sourcelocations && m_started_new_line) {
359 str_prefixed.insert(0,
"[" +
RemovePrefix(source_file,
"./") +
":" +
ToString(source_line) +
"] [" + logging_function +
"] ");
362 if (m_log_threadnames && m_started_new_line) {
364 str_prefixed.insert(0,
"[" + (threadname.empty() ?
"unknown" : threadname) +
"] ");
367 str_prefixed = LogTimestampStr(str_prefixed);
369 m_started_new_line = !str.empty() && str[str.size()-1] ==
'\n';
373 m_msgs_before_open.push_back(str_prefixed);
377 if (m_print_to_console) {
379 fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
382 for (
const auto& cb : m_print_callbacks) {
385 if (m_print_to_file) {
386 assert(m_fileout !=
nullptr);
390 m_reopen_file =
false;
393 setbuf(new_fileout,
nullptr);
395 m_fileout = new_fileout;
405 constexpr
size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
407 assert(!m_file_path.empty());
415 log_size = fs::file_size(m_file_path);
416 }
catch (
const fs::filesystem_error&) {}
420 if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
423 std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
424 if (fseek(file, -((
long)vch.size()), SEEK_END)) {
425 LogPrintf(
"Failed to shrink debug log file: fseek(...) failed\n");
429 int nBytes = fread(vch.data(), 1, vch.size(), file);
435 fwrite(vch.data(), 1, nBytes, file);
439 else if (file !=
nullptr)
447 m_log_level = level.value();
460 m_category_log_levels[flag] = level.value();
static std::string LogLevelToStr(BCLog::Level level)
Returns the string representation of a log level.
bool WillLogCategory(LogFlags category) const
std::string LogTimestampStr(const std::string &str)
void DisconnectTestLogger()
Only for testing.
bool DefaultShrinkDebugFile() const
void SetLogLevel(Level level)
bool WillLogCategoryLevel(LogFlags category, Level level) const
void LogPrintStr(const std::string &str, const std::string &logging_function, const std::string &source_file, int source_line, BCLog::LogFlags category, BCLog::Level level)
Send a string to the log output.
std::vector< LogCategory > LogCategoriesList() const
Returns a vector of the log categories in alphabetical order.
void EnableCategory(LogFlags flag)
bool StartLogging()
Start logging (and flush all buffered messages)
std::string GetLogPrefix(LogFlags category, Level level) const
std::string LogLevelsString() const
Returns a string with all user-selectable log levels.
void SetCategoryLogLevel(const std::unordered_map< LogFlags, Level > &levels)
void DisableCategory(LogFlags flag)
static constexpr std::array< BCLog::Level, 3 > LogLevelsList()
Log severity levels that can be selected by the user.
std::string LogCategoryToStr(BCLog::LogFlags category)
static int FileWriteStr(const std::string &str, FILE *fp)
bool GetLogCategory(BCLog::LogFlags &flag, const std::string &str)
Return true if str parses as a log category and set the flag.
static const std::unordered_map< BCLog::LogFlags, std::string > LOG_CATEGORIES_BY_FLAG
const char *const DEFAULT_DEBUGLOGFILE
static std::optional< BCLog::Level > GetLogLevel(const std::string &level_str)
static const std::map< std::string, BCLog::LogFlags > LOG_CATEGORIES_BY_STR
constexpr auto MAX_USER_SETABLE_SEVERITY_LEVEL
BCLog::Logger & LogInstance()
static const bool DEFAULT_LOGIPS
std::string LogEscapeMessage(const std::string &str)
Belts and suspenders: make sure outgoing log messages don't contain potentially suspicious characters...
FILE * fopen(const fs::path &p, const char *mode)
const std::string & ThreadGetInternalName()
Get the thread's internal (in-memory) name; used e.g.
std::string RemovePrefix(std::string_view str, std::string_view prefix)
std::string ToString(const T &t)
Locale-independent version of std::to_string.
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
std::chrono::seconds GetMockTime()
For testing.
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
constexpr int64_t count_seconds(std::chrono::seconds t)