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/system.h> | |||||
#include <util/time.h> | #include <util/time.h> | ||||
bool fLogIPs = DEFAULT_LOGIPS; | bool fLogIPs = DEFAULT_LOGIPS; | ||||
const char *const DEFAULT_DEBUGLOGFILE = "debug.log"; | 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 | ||||
Show All 11 Lines | 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); | ||||
} | } | ||||
fs::path BCLog::Logger::GetDebugLogPath() { | |||||
fs::path logfile(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); | |||||
return AbsPathForConfigVal(logfile); | |||||
} | |||||
bool BCLog::Logger::OpenDebugLog() { | 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 = GetDebugLogPath(); | assert(!m_file_path.empty()); | ||||
m_fileout = fsbridge::fopen(pathDebug, "a"); | m_fileout = fsbridge::fopen(m_file_path, "a"); | ||||
if (!m_fileout) { | if (!m_fileout) { | ||||
return false; | 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()) { | ||||
▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | if (m_print_to_file) { | ||||
// 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) { | ||||
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 = GetDebugLogPath(); | FILE *new_fileout = fsbridge::fopen(m_file_path, "a"); | ||||
FILE *new_fileout = fsbridge::fopen(pathDebug, "a"); | |||||
if (new_fileout) { | if (new_fileout) { | ||||
// unbuffered. | // unbuffered. | ||||
setbuf(m_fileout, nullptr); | setbuf(m_fileout, nullptr); | ||||
fclose(m_fileout); | fclose(m_fileout); | ||||
m_fileout = new_fileout; | m_fileout = new_fileout; | ||||
} | } | ||||
} | } | ||||
FileWriteStr(strTimestamped, m_fileout); | FileWriteStr(strTimestamped, m_fileout); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
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; | ||||
assert(!m_file_path.empty()); | |||||
// Scroll debug.log if it's getting too big. | // Scroll debug.log if it's getting too big. | ||||
fs::path pathLog = GetDebugLogPath(); | FILE *file = fsbridge::fopen(m_file_path, "r"); | ||||
FILE *file = fsbridge::fopen(pathLog, "r"); | |||||
// Special files (e.g. device nodes) may not have a size. | // Special files (e.g. device nodes) may not have a size. | ||||
size_t log_size = 0; | size_t log_size = 0; | ||||
try { | try { | ||||
log_size = fs::file_size(pathLog); | log_size = fs::file_size(m_file_path); | ||||
} catch (boost::filesystem::filesystem_error &) { | } catch (boost::filesystem::filesystem_error &) { | ||||
} | } | ||||
// 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 && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10)) { | if (file && log_size > 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); | ||||
if (fseek(file, -((long)vch.size()), SEEK_END)) { | if (fseek(file, -((long)vch.size()), SEEK_END)) { | ||||
LogPrintf("Failed to shrink debug log file: fseek(...) failed\n"); | LogPrintf("Failed to shrink debug log file: fseek(...) failed\n"); | ||||
fclose(file); | fclose(file); | ||||
return; | return; | ||||
} | } | ||||
int nBytes = fread(vch.data(), 1, vch.size(), file); | int nBytes = fread(vch.data(), 1, vch.size(), file); | ||||
fclose(file); | fclose(file); | ||||
file = fsbridge::fopen(pathLog, "w"); | file = fsbridge::fopen(m_file_path, "w"); | ||||
if (file) { | if (file) { | ||||
fwrite(vch.data(), 1, nBytes, file); | fwrite(vch.data(), 1, nBytes, file); | ||||
fclose(file); | fclose(file); | ||||
} | } | ||||
} else if (file != nullptr) { | } else if (file != nullptr) { | ||||
fclose(file); | fclose(file); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |