Changeset View
Changeset View
Standalone View
Standalone View
src/logging.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Copyright (c) 2017-2018 The Bitcoin developers | // Copyright (c) 2017-2018 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "logging.h" | #include "logging.h" | ||||
#include "util.h" | #include "util.h" | ||||
#include "utiltime.h" | #include "utiltime.h" | ||||
bool fLogIPs = DEFAULT_LOGIPS; | bool fLogIPs = DEFAULT_LOGIPS; | ||||
const char *const DEFAULT_DEBUGLOGFILE = "debug.log"; | |||||
/** | /** | ||||
* NOTE: the logger instance is leaked on exit. This is ugly, but will be | * NOTE: the logger instance is leaked on exit. This is ugly, but will be | ||||
* cleaned up by the OS/libc. Defining a logger as a global object doesn't work | * cleaned up by the OS/libc. Defining a logger as a global object doesn't work | ||||
* since the order of destruction of static/global objects is undefined. | * since the order of destruction of static/global objects is undefined. | ||||
* Consider if the logger gets destroyed, and then some later destructor calls | * Consider if the logger gets destroyed, and then some later destructor calls | ||||
* LogPrintf, maybe indirectly, and you get a core dump at shutdown trying to | * LogPrintf, maybe indirectly, and you get a core dump at shutdown trying to | ||||
* access the logger. When the shutdown sequence is fully audited and tested, | * access the logger. When the shutdown sequence is fully audited and tested, | ||||
* explicit destruction of these objects can be implemented by changing this | * explicit destruction of these objects can be implemented by changing this | ||||
* from a raw pointer to a std::unique_ptr. | * from a raw pointer to a std::unique_ptr. | ||||
* | * | ||||
* This method of initialization was originally introduced in | * This method of initialization was originally introduced in | ||||
* ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c. | * ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c. | ||||
*/ | */ | ||||
BCLog::Logger &GetLogger() { | BCLog::Logger &GetLogger() { | ||||
static BCLog::Logger *const logger = new BCLog::Logger(); | static BCLog::Logger *const logger = new BCLog::Logger(); | ||||
return *logger; | return *logger; | ||||
} | } | ||||
static int FileWriteStr(const std::string &str, FILE *fp) { | static int FileWriteStr(const std::string &str, FILE *fp) { | ||||
return fwrite(str.data(), 1, str.size(), fp); | return fwrite(str.data(), 1, str.size(), fp); | ||||
} | } | ||||
void BCLog::Logger::OpenDebugLog() { | fs::path BCLog::Logger::GetDebugLogPath() { | ||||
fs::path logfile(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); | |||||
if (logfile.is_absolute()) { | |||||
return logfile; | |||||
} else { | |||||
return GetDataDir() / logfile; | |||||
} | |||||
} | |||||
bool BCLog::Logger::OpenDebugLog() { | |||||
std::lock_guard<std::mutex> scoped_lock(m_file_mutex); | std::lock_guard<std::mutex> scoped_lock(m_file_mutex); | ||||
assert(m_fileout == nullptr); | assert(m_fileout == nullptr); | ||||
fs::path pathDebug = GetDataDir() / "debug.log"; | fs::path pathDebug = GetDebugLogPath(); | ||||
m_fileout = fsbridge::fopen(pathDebug, "a"); | m_fileout = fsbridge::fopen(pathDebug, "a"); | ||||
if (m_fileout) { | if (!m_fileout) { | ||||
return false; | |||||
} | |||||
// Unbuffered. | // Unbuffered. | ||||
setbuf(m_fileout, nullptr); | setbuf(m_fileout, nullptr); | ||||
// Dump buffered messages from before we opened the log. | // Dump buffered messages from before we opened the log. | ||||
while (!m_msgs_before_open.empty()) { | while (!m_msgs_before_open.empty()) { | ||||
FileWriteStr(m_msgs_before_open.front(), m_fileout); | FileWriteStr(m_msgs_before_open.front(), m_fileout); | ||||
m_msgs_before_open.pop_front(); | m_msgs_before_open.pop_front(); | ||||
} | } | ||||
} | |||||
return true; | |||||
} | } | ||||
struct CLogCategoryDesc { | struct CLogCategoryDesc { | ||||
BCLog::LogFlags flag; | BCLog::LogFlags flag; | ||||
std::string category; | std::string category; | ||||
}; | }; | ||||
const CLogCategoryDesc LogCategories[] = { | const CLogCategoryDesc LogCategories[] = { | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | if (m_print_to_console) { | ||||
// Buffer if we haven't opened the log yet. | // Buffer if we haven't opened the log yet. | ||||
if (m_fileout == nullptr) { | if (m_fileout == nullptr) { | ||||
ret = strTimestamped.length(); | ret = strTimestamped.length(); | ||||
m_msgs_before_open.push_back(strTimestamped); | m_msgs_before_open.push_back(strTimestamped); | ||||
} else { | } else { | ||||
// Reopen the log file, if requested. | // Reopen the log file, if requested. | ||||
if (m_reopen_file) { | if (m_reopen_file) { | ||||
m_reopen_file = false; | m_reopen_file = false; | ||||
fs::path pathDebug = GetDataDir() / "debug.log"; | fs::path pathDebug = GetDebugLogPath(); | ||||
if (fsbridge::freopen(pathDebug, "a", m_fileout) != nullptr) { | if (fsbridge::freopen(pathDebug, "a", m_fileout) != nullptr) { | ||||
// unbuffered. | // unbuffered. | ||||
setbuf(m_fileout, nullptr); | setbuf(m_fileout, nullptr); | ||||
} | } | ||||
} | } | ||||
ret = FileWriteStr(strTimestamped, m_fileout); | ret = FileWriteStr(strTimestamped, m_fileout); | ||||
} | } | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
void BCLog::Logger::ShrinkDebugFile() { | void BCLog::Logger::ShrinkDebugFile() { | ||||
// Amount of debug.log to save at end when shrinking (must fit in memory) | // Amount of debug.log to save at end when shrinking (must fit in memory) | ||||
constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000; | constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000; | ||||
// Scroll debug.log if it's getting too big. | // Scroll debug.log if it's getting too big. | ||||
fs::path pathLog = GetDataDir() / "debug.log"; | fs::path pathLog = GetDebugLogPath(); | ||||
FILE *file = fsbridge::fopen(pathLog, "r"); | FILE *file = fsbridge::fopen(pathLog, "r"); | ||||
// If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE | // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE | ||||
// trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes. | // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes. | ||||
if (file && | if (file && | ||||
fs::file_size(pathLog) > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10)) { | fs::file_size(pathLog) > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10)) { | ||||
// Restart the file with some of the end. | // Restart the file with some of the end. | ||||
std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0); | std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0); | ||||
fseek(file, -((long)vch.size()), SEEK_END); | fseek(file, -((long)vch.size()), SEEK_END); | ||||
▲ Show 20 Lines • Show All 49 Lines • Show Last 20 Lines |