Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2019-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <init/common.h>6#include <logging.h>7#include <logging/timer.h>8#include <scheduler.h>9#include <test/util/common.h>10#include <test/util/logging.h>11#include <test/util/setup_common.h>12#include <tinyformat.h>13#include <util/fs.h>14#include <util/fs_helpers.h>15#include <util/string.h>17#include <chrono>18#include <fstream>19#include <future>20#include <ios>21#include <iostream>22#include <source_location>23#include <string>24#include <unordered_map>25#include <utility>26#include <vector>28#include <boost/test/unit_test.hpp>30using util::SplitString;31using util::TrimString;33BOOST_FIXTURE_TEST_SUITE(logging_tests, BasicTestingSetup)35static void ResetLogger()36{37LogInstance().SetLogLevel(BCLog::DEFAULT_LOG_LEVEL);38LogInstance().SetCategoryLogLevel({});39}41static std::vector<std::string> ReadDebugLogLines()42{43std::vector<std::string> lines;44std::ifstream ifs{LogInstance().m_file_path.std_path()};45for (std::string line; std::getline(ifs, line);) {46lines.push_back(std::move(line));47}48return lines;49}51struct LogSetup : public BasicTestingSetup {52fs::path prev_log_path;53fs::path tmp_log_path;54bool prev_reopen_file;55bool prev_print_to_file;56bool prev_log_timestamps;57bool prev_log_threadnames;58bool prev_log_sourcelocations;59std::unordered_map<BCLog::LogFlags, BCLog::Level> prev_category_levels;60BCLog::Level prev_log_level;61BCLog::CategoryMask prev_category_mask;63LogSetup() : prev_log_path{LogInstance().m_file_path},64tmp_log_path{m_args.GetDataDirBase() / "tmp_debug.log"},65prev_reopen_file{LogInstance().m_reopen_file},66prev_print_to_file{LogInstance().m_print_to_file},67prev_log_timestamps{LogInstance().m_log_timestamps},68prev_log_threadnames{LogInstance().m_log_threadnames},69prev_log_sourcelocations{LogInstance().m_log_sourcelocations},70prev_category_levels{LogInstance().CategoryLevels()},71prev_log_level{LogInstance().LogLevel()},72prev_category_mask{LogInstance().GetCategoryMask()}73{74LogInstance().m_file_path = tmp_log_path;75LogInstance().m_reopen_file = true;76LogInstance().m_print_to_file = true;77LogInstance().m_log_timestamps = false;78LogInstance().m_log_threadnames = false;80// Prevent tests from failing when the line number of the logs changes.81LogInstance().m_log_sourcelocations = false;83LogInstance().SetLogLevel(BCLog::Level::Debug);84LogInstance().DisableCategory(BCLog::LogFlags::ALL);85LogInstance().SetCategoryLogLevel({});86LogInstance().SetRateLimiting(nullptr);87}89~LogSetup()90{91LogInstance().m_file_path = prev_log_path;92LogInfo("Sentinel log to reopen log file");93LogInstance().m_print_to_file = prev_print_to_file;94LogInstance().m_reopen_file = prev_reopen_file;95LogInstance().m_log_timestamps = prev_log_timestamps;96LogInstance().m_log_threadnames = prev_log_threadnames;97LogInstance().m_log_sourcelocations = prev_log_sourcelocations;98LogInstance().SetLogLevel(prev_log_level);99LogInstance().SetCategoryLogLevel(prev_category_levels);100LogInstance().SetRateLimiting(nullptr);101LogInstance().DisableCategory(BCLog::LogFlags::ALL);102LogInstance().EnableCategory(BCLog::LogFlags{prev_category_mask});103}104};106BOOST_AUTO_TEST_CASE(logging_timer)107{108auto micro_timer = BCLog::Timer<std::chrono::microseconds>("tests", "end_msg");109const std::string_view result_prefix{"tests: msg ("};110BOOST_CHECK_EQUAL(micro_timer.LogMsg("msg").substr(0, result_prefix.size()), result_prefix);111}113BOOST_FIXTURE_TEST_CASE(logging_LogPrint, LogSetup)114{115LogInstance().m_log_sourcelocations = true;117struct Case {118std::string msg;119BCLog::LogFlags category;120BCLog::Level level;121std::string prefix;122SourceLocation loc;123};125std::vector<Case> cases = {126{"foo1: bar1", BCLog::NET, BCLog::Level::Debug, "[net] ", SourceLocation{__func__}},127{"foo2: bar2", BCLog::NET, BCLog::Level::Info, "[net:info] ", SourceLocation{__func__}},128{"foo3: bar3", BCLog::ALL, BCLog::Level::Debug, "[debug] ", SourceLocation{__func__}},129{"foo4: bar4", BCLog::ALL, BCLog::Level::Info, "", SourceLocation{__func__}},130{"foo5: bar5", BCLog::NONE, BCLog::Level::Debug, "[debug] ", SourceLocation{__func__}},131{"foo6: bar6", BCLog::NONE, BCLog::Level::Info, "", SourceLocation{__func__}},132};134std::vector<std::string> expected;135for (auto& [msg, category, level, prefix, loc] : cases) {136expected.push_back(tfm::format("[%s:%s] [%s] %s%s", util::RemovePrefix(loc.file_name(), "./"), loc.line(), loc.function_name_short(), prefix, msg));137LogInstance().LogPrint({.category = category, .level = level, .should_ratelimit = false, .source_loc = std::move(loc), .message = msg});138}139std::vector<std::string> log_lines{ReadDebugLogLines()};140BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());141}143BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros, LogSetup)144{145LogInstance().EnableCategory(BCLog::NET);146LogTrace(BCLog::NET, "foo6: %s", "bar6"); // not logged147LogDebug(BCLog::NET, "foo7: %s", "bar7");148LogInfo("foo8: %s", "bar8");149LogWarning("foo9: %s", "bar9");150LogError("foo10: %s", "bar10");151std::vector<std::string> log_lines{ReadDebugLogLines()};152std::vector<std::string> expected = {153"[net] foo7: bar7",154"foo8: bar8",155"[warning] foo9: bar9",156"[error] foo10: bar10",157};158BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());159}161BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros_CategoryName, LogSetup)162{163LogInstance().EnableCategory(BCLog::LogFlags::ALL);164const auto concatenated_category_names = LogInstance().LogCategoriesString();165std::vector<std::pair<BCLog::LogFlags, std::string>> expected_category_names;166const auto category_names = SplitString(concatenated_category_names, ',');167for (const auto& category_name : category_names) {168const auto trimmed_category_name = TrimString(category_name);169const auto category{*Assert(BCLog::Logger::GetLogCategory(trimmed_category_name))};170expected_category_names.emplace_back(category, trimmed_category_name);171}173std::vector<std::string> expected;174for (const auto& [category, name] : expected_category_names) {175LogDebug(category, "foo: %s\n", "bar");176std::string expected_log = "[";177expected_log += name;178expected_log += "] foo: bar";179expected.push_back(expected_log);180}182std::vector<std::string> log_lines{ReadDebugLogLines()};183BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());184}186BOOST_FIXTURE_TEST_CASE(logging_SeverityLevels, LogSetup)187{188LogInstance().SetLogLevel(BCLog::Level::Debug);189LogInstance().EnableCategory(BCLog::LogFlags::ALL);190LogInstance().SetCategoryLogLevel(/*category_str=*/"net", /*level_str=*/"info");192// Global log level193LogInfo("info_%s", 1);194LogTrace(BCLog::HTTP, "trace_%s. This log level is lower than the global one.", 2);195LogDebug(BCLog::HTTP, "debug_%s", 3);196LogWarning("warn_%s", 4);197LogError("err_%s", 5);199// Category-specific log level200LogDebug(BCLog::NET, "debug_%s. This log level is the same as the global one but lower than the category-specific one, which takes precedence.", 6);202std::vector<std::string> expected = {203"info_1",204"[http] debug_3",205"[warning] warn_4",206"[error] err_5",207};208std::vector<std::string> log_lines{ReadDebugLogLines()};209BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());210}212BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)213{214// Set global log level215{216ResetLogger();217ArgsManager args;218args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);219const char* argv_test[] = {"bitcoind", "-loglevel=debug"};220std::string err;221BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));223auto result = init::SetLoggingLevel(args);224BOOST_REQUIRE(result);225BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::Level::Debug);226}228// Set category-specific log level229{230ResetLogger();231ArgsManager args;232args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);233const char* argv_test[] = {"bitcoind", "-loglevel=net:trace"};234std::string err;235BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));237auto result = init::SetLoggingLevel(args);238BOOST_REQUIRE(result);239BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::DEFAULT_LOG_LEVEL);241const auto& category_levels{LogInstance().CategoryLevels()};242const auto net_it{category_levels.find(BCLog::LogFlags::NET)};243BOOST_REQUIRE(net_it != category_levels.end());244BOOST_CHECK_EQUAL(net_it->second, BCLog::Level::Trace);245}247// Set both global log level and category-specific log level248{249ResetLogger();250ArgsManager args;
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.