21#include <source_location>
23#include <unordered_map>
27#include <boost/test/unit_test.hpp>
42 std::vector<std::string> lines;
44 for (std::string line; std::getline(ifs, line);) {
45 lines.push_back(std::move(line));
91 LogInfo(
"Sentinel log to reopen log file");
108 const std::string_view result_prefix{
"tests: msg ("};
109 BOOST_CHECK_EQUAL(micro_timer.LogMsg(
"msg").substr(0, result_prefix.size()), result_prefix);
121 std::source_location loc;
124 std::vector<Case> cases = {
133 std::vector<std::string> expected;
134 for (
auto& [
msg, category, level,
prefix, loc] : cases) {
139 BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());
152 std::vector<std::string> expected = {
155 "[net:info] foo8: bar8",
156 "[net:warning] foo9: bar9",
157 "[net:error] foo10: bar10",
159 BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());
171 std::vector<std::string> expected = {
174 "[warning] foo9: bar9",
175 "[error] foo10: bar10",
177 BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());
184 std::vector<std::pair<BCLog::LogFlags, std::string>> expected_category_names;
185 const auto category_names =
SplitString(concatenated_category_names,
',');
186 for (
const auto& category_name : category_names) {
188 const auto trimmed_category_name =
TrimString(category_name);
190 expected_category_names.emplace_back(category, trimmed_category_name);
193 std::vector<std::string> expected;
194 for (
const auto& [category,
name] : expected_category_names) {
195 LogDebug(category,
"foo: %s\n",
"bar");
196 std::string expected_log =
"[";
197 expected_log +=
name;
198 expected_log +=
"] foo: bar";
199 expected.push_back(expected_log);
203 BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());
222 std::vector<std::string> expected = {
223 "[http:info] foo1: bar1",
224 "[validation:warning] foo3: bar3",
225 "[rpc:error] foo4: bar4",
226 "[net:warning] foo5: bar5",
227 "[net:error] foo7: bar7",
230 BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());
240 const char* argv_test[] = {
"bitcoind",
"-loglevel=debug"};
245 BOOST_REQUIRE(result);
254 const char* argv_test[] = {
"bitcoind",
"-loglevel=net:trace"};
259 BOOST_REQUIRE(result);
264 BOOST_REQUIRE(net_it != category_levels.end());
273 const char* argv_test[] = {
"bitcoind",
"-loglevel=debug",
"-loglevel=net:trace",
"-loglevel=http:info"};
278 BOOST_REQUIRE(result);
308 std::promise<void> promise;
310 promise.get_future().wait();
312 std::shared_ptr<BCLog::LogRateLimiter>
GetLimiter(
size_t max_bytes, std::chrono::seconds window)
314 auto sched_func = [
this](
auto func,
auto w) {
323 uint64_t max_bytes{1024};
324 auto reset_window{1min};
326 auto limiter_{scheduler.
GetLimiter(max_bytes, reset_window)};
327 auto& limiter{*
Assert(limiter_)};
330 auto source_loc_1{std::source_location::current()};
331 auto source_loc_2{std::source_location::current()};
341 BOOST_CHECK_EQUAL(limiter.Consume(source_loc_1, std::string(max_bytes - 1,
'a')), Status::UNSUPPRESSED);
350 BOOST_CHECK_EQUAL(limiter.Consume(source_loc_2, std::string(max_bytes,
'a')), Status::UNSUPPRESSED);
355 scheduler.MockForwardAndSync(reset_window);
358 BOOST_CHECK_EQUAL(limiter.Consume(source_loc_1, std::string(max_bytes,
'a')), Status::UNSUPPRESSED);
359 BOOST_CHECK_EQUAL(limiter.Consume(source_loc_2, std::string(max_bytes,
'a')), Status::UNSUPPRESSED);
394void LogFromLocation(Location location,
const std::string& message) {
396 case Location::INFO_1:
399 case Location::INFO_2:
402 case Location::DEBUG_LOG:
405 case Location::INFO_NOLIMIT:
416void TestLogFromLocation(Location location,
const std::string& message,
418 std::source_location
source = std::source_location::current())
420 BOOST_TEST_INFO_SCOPE(
"TestLogFromLocation called from " <<
source.file_name() <<
":" <<
source.line());
422 if (!suppressions_active)
assert(status == Status::UNSUPPRESSED);
425 LogFromLocation(location, message);
427 BOOST_TEST_INFO_SCOPE(log_lines.size() <<
" log_lines read: \n" <<
util::Join(log_lines,
"\n"));
429 if (status == Status::STILL_SUPPRESSED) {
434 if (status == Status::NEWLY_SUPPRESSED) {
435 BOOST_REQUIRE_EQUAL(log_lines.size(), 2);
436 BOOST_CHECK(log_lines[0].starts_with(
"[*] [warning] Excessive logging detected"));
437 log_lines.erase(log_lines.begin());
439 BOOST_REQUIRE_EQUAL(log_lines.size(), 1);
440 auto& payload{log_lines.back()};
455 constexpr int64_t line_length{1024};
456 constexpr int64_t num_lines{10};
457 constexpr int64_t bytes_quota{line_length * num_lines};
458 constexpr auto time_window{1h};
461 auto limiter{scheduler.
GetLimiter(bytes_quota, time_window)};
464 const std::string log_message(line_length - 1,
'a');
466 for (
int i = 0; i < num_lines; ++i) {
467 TestLogFromLocation(Location::INFO_1, log_message, Status::UNSUPPRESSED,
false);
469 TestLogFromLocation(Location::INFO_1,
"a", Status::NEWLY_SUPPRESSED,
true);
470 TestLogFromLocation(Location::INFO_1,
"b", Status::STILL_SUPPRESSED,
true);
471 TestLogFromLocation(Location::INFO_2,
"c", Status::UNSUPPRESSED,
true);
473 scheduler.MockForwardAndSync(time_window);
477 TestLogFromLocation(Location::INFO_1, log_message, Status::UNSUPPRESSED,
false);
480 for (Location location : {Location::DEBUG_LOG, Location::INFO_NOLIMIT}) {
481 for (
int i = 0; i < num_lines + 2; ++i) {
482 TestLogFromLocation(location, log_message, Status::UNSUPPRESSED,
false);
#define Assert(val)
Identity function.
@ ALLOW_ANY
disable validation
bool ParseParameters(int argc, const char *const argv[], std::string &error)
void AddArg(const std::string &name, const std::string &help, unsigned int flags, const OptionsCategory &cat)
Add argument.
static std::shared_ptr< LogRateLimiter > Create(SchedulerFunction &&scheduler_func, uint64_t max_bytes, std::chrono::seconds reset_window)
Status
Suppression status of a source log location.
void LogPrintStr(std::string_view str, std::source_location &&source_loc, BCLog::LogFlags category, BCLog::Level level, bool should_ratelimit) EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
Send a string to the log output.
bool m_log_sourcelocations
void SetCategoryLogLevel(const std::unordered_map< LogFlags, Level > &levels) EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
void SetLogLevel(Level level)
void SetRateLimiting(std::shared_ptr< LogRateLimiter > limiter) EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
void EnableCategory(LogFlags flag)
std::atomic< bool > m_reopen_file
std::unordered_map< LogFlags, Level > CategoryLevels() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
std::string LogCategoriesString() const
Returns a string with the log categories in alphabetical order.
void DisableCategory(LogFlags flag)
RAII-style object that outputs timing information to logs.
Simple class for background tasks that should be run periodically or once "after a while".
void MockForward(std::chrono::seconds delta_seconds) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Mock the scheduler to fast forward in time.
void serviceQueue() EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Services the queue 'forever'.
void scheduleEvery(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Repeat f until the scheduler is stopped.
std::thread m_service_thread
void stop() EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Tell any threads running serviceQueue to stop as soon as the current task is done.
void scheduleFromNow(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Call f once after the delta has passed.
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
Common init functions shared by bitcoin-node, bitcoin-wallet, etc.
bool GetLogCategory(BCLog::LogFlags &flag, std::string_view str)
Return true if str parses as a log category and set the flag.
BCLog::Logger & LogInstance()
#define LogPrintLevel(category, level,...)
#define LogPrintLevel_(category, level, should_ratelimit,...)
#define LogTrace(category,...)
#define LogDebug(category,...)
static std::vector< std::string > ReadDebugLogLines()
BOOST_FIXTURE_TEST_CASE(logging_LogPrintStr, LogSetup)
BOOST_AUTO_TEST_CASE(logging_timer)
static void ResetLogger()
constexpr uint64_t RATELIMIT_MAX_BYTES
constexpr auto DEFAULT_LOG_LEVEL
util::Result< void > SetLoggingLevel(const ArgsManager &args)
std::vector< std::string > SplitString(std::string_view str, char sep)
std::string TrimString(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
std::string RemovePrefix(std::string_view str, std::string_view prefix)
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
Keeps track of an individual source location and how many available bytes are left for logging from i...
uint64_t m_available_bytes
Remaining bytes.
bool Consume(uint64_t bytes)
Updates internal accounting and returns true if enough available_bytes were remaining.
uint64_t m_dropped_bytes
Number of bytes that were consumed but didn't fit in the available bytes.
ArgsManager m_args
Test-specific arguments and settings.
std::unordered_map< BCLog::LogFlags, BCLog::Level > prev_category_levels
BCLog::Level prev_log_level
bool prev_log_threadnames
bool prev_log_sourcelocations
BCLog::CategoryMask prev_category_mask
std::shared_ptr< BCLog::LogRateLimiter > GetLimiter(size_t max_bytes, std::chrono::seconds window)
void MockForwardAndSync(std::chrono::seconds duration)