Implement logging abstraction (#371)

Fixes #290
This commit is contained in:
Alex Kremer
2022-11-17 23:02:16 +01:00
committed by GitHub
parent 4b8dd7b981
commit a47bf2e8fe
38 changed files with 1441 additions and 1003 deletions

View File

@@ -1,17 +1,23 @@
#include <algorithm>
#include <backend/BackendFactory.h>
#include <backend/BackendInterface.h>
#include <backend/DBHelpers.h>
#include <config/Config.h>
#include <etl/ReportingETL.h>
#include <gtest/gtest.h>
#include <log/Logger.h>
#include <rpc/RPCHelpers.h>
#include <util/Fixtures.h>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/trivial.hpp>
#include <backend/BackendFactory.h>
#include <backend/BackendInterface.h>
#include <config/Config.h>
#include <gtest/gtest.h>
TEST(BackendTest, Basic)
#include <algorithm>
class BackendTest : public NoLoggerFixture
{
};
TEST_F(BackendTest, Basic)
{
boost::asio::io_context ioc;
std::optional<boost::asio::io_context::work> work;
@@ -21,7 +27,7 @@ TEST(BackendTest, Basic)
boost::asio::spawn(
ioc, [&done, &work, &ioc](boost::asio::yield_context yield) {
boost::log::core::get()->set_filter(
boost::log::trivial::severity >= boost::log::trivial::warning);
clio::log_severity >= clio::Severity::WARNING);
std::string keyspace = "clio_test_" +
std::to_string(std::chrono::system_clock::now()
.time_since_epoch()
@@ -41,7 +47,6 @@ TEST(BackendTest, Basic)
std::vector<boost::json::object> configs = {cassandraConfig};
for (auto& config : configs)
{
std::cout << keyspace << std::endl;
auto backend = Backend::make_Backend(ioc, clio::Config{config});
std::string rawHeader =
@@ -107,10 +112,8 @@ TEST(BackendTest, Basic)
}
{
std::cout << "fetching ledger by sequence" << std::endl;
auto retLgr =
backend->fetchLedgerBySequence(lgrInfo.seq, yield);
std::cout << "fetched ledger by sequence" << std::endl;
ASSERT_TRUE(retLgr.has_value());
EXPECT_EQ(retLgr->seq, lgrInfo.seq);
EXPECT_EQ(
@@ -147,10 +150,8 @@ TEST(BackendTest, Basic)
EXPECT_EQ(seq, lgrInfoNext.seq);
}
{
std::cout << "fetching ledger by sequence" << std::endl;
auto retLgr =
backend->fetchLedgerBySequence(lgrInfoNext.seq, yield);
std::cout << "fetched ledger by sequence" << std::endl;
EXPECT_TRUE(retLgr.has_value());
EXPECT_EQ(retLgr->seq, lgrInfoNext.seq);
EXPECT_EQ(
@@ -802,9 +803,6 @@ TEST(BackendTest, Basic)
auto objs,
auto accountTx,
auto state) {
std::cout
<< "writing ledger = " << std::to_string(lgrInfo.seq)
<< std::endl;
backend->startWrites();
backend->writeLedger(
@@ -978,11 +976,6 @@ TEST(BackendTest, Basic)
uint32_t limit = 10;
page = backend->fetchLedgerPage(
page.cursor, seq, limit, false, yield);
std::cout << "fetched a page " << page.objects.size()
<< std::endl;
if (page.cursor)
std::cout << ripple::strHex(*page.cursor)
<< std::endl;
// if (page.cursor)
// EXPECT_EQ(page.objects.size(), limit);
retObjs.insert(
@@ -1007,8 +1000,7 @@ TEST(BackendTest, Basic)
}
}
if (found != (obj.second.size() != 0))
std::cout << ripple::strHex(obj.first) << std::endl;
ASSERT_EQ(found, obj.second.size() != 0);
ASSERT_EQ(found, obj.second.size() != 0);
}
};
@@ -1148,15 +1140,12 @@ TEST(BackendTest, Basic)
for (auto [seq, diff] : state)
{
std::cout << "flatteneing" << std::endl;
auto flat = flatten(seq);
std::cout << "flattened" << std::endl;
checkLedger(
lgrInfos[seq],
allTxns[seq],
flat,
flattenAccountTx(seq));
std::cout << "checked" << std::endl;
}
}
@@ -1168,11 +1157,11 @@ TEST(BackendTest, Basic)
EXPECT_EQ(done, true);
}
TEST(Backend, cache)
TEST_F(BackendTest, cache)
{
using namespace Backend;
boost::log::core::get()->set_filter(
boost::log::trivial::severity >= boost::log::trivial::warning);
clio::log_severity >= clio::Severity::WARNING);
SimpleCache cache;
ASSERT_FALSE(cache.isFull());
cache.setFull();
@@ -1410,11 +1399,11 @@ TEST(Backend, cache)
}
}
TEST(Backend, cacheBackground)
TEST_F(BackendTest, cacheBackground)
{
using namespace Backend;
boost::log::core::get()->set_filter(
boost::log::trivial::severity >= boost::log::trivial::warning);
clio::log_severity >= clio::Severity::WARNING);
SimpleCache cache;
ASSERT_FALSE(cache.isFull());
ASSERT_EQ(cache.size(), 0);
@@ -1814,7 +1803,7 @@ TEST(Backend, cacheBackground)
ASSERT_EQ(idx, allObjs.size());
}
TEST(Backend, cacheIntegration)
TEST_F(BackendTest, cacheIntegration)
{
boost::asio::io_context ioc;
std::optional<boost::asio::io_context::work> work;
@@ -1824,7 +1813,7 @@ TEST(Backend, cacheIntegration)
boost::asio::spawn(
ioc, [&ioc, &done, &work](boost::asio::yield_context yield) {
boost::log::core::get()->set_filter(
boost::log::trivial::severity >= boost::log::trivial::warning);
clio::log_severity >= clio::Severity::WARNING);
std::string keyspace = "clio_test_" +
std::to_string(std::chrono::system_clock::now()
.time_since_epoch()
@@ -1844,7 +1833,6 @@ TEST(Backend, cacheIntegration)
std::vector<boost::json::object> configs = {cassandraConfig};
for (auto& config : configs)
{
std::cout << keyspace << std::endl;
auto backend = Backend::make_Backend(ioc, clio::Config{config});
backend->cache().setFull();
@@ -1927,10 +1915,8 @@ TEST(Backend, cacheIntegration)
}
{
std::cout << "fetching ledger by sequence" << std::endl;
auto retLgr =
backend->fetchLedgerBySequence(lgrInfo.seq, yield);
std::cout << "fetched ledger by sequence" << std::endl;
ASSERT_TRUE(retLgr.has_value());
EXPECT_EQ(retLgr->seq, lgrInfo.seq);
EXPECT_EQ(
@@ -1967,10 +1953,8 @@ TEST(Backend, cacheIntegration)
EXPECT_EQ(seq, lgrInfoNext.seq);
}
{
std::cout << "fetching ledger by sequence" << std::endl;
auto retLgr =
backend->fetchLedgerBySequence(lgrInfoNext.seq, yield);
std::cout << "fetched ledger by sequence" << std::endl;
EXPECT_TRUE(retLgr.has_value());
EXPECT_EQ(retLgr->seq, lgrInfoNext.seq);
EXPECT_EQ(
@@ -2226,8 +2210,6 @@ TEST(Backend, cacheIntegration)
return lgrInfo;
};
auto writeLedger = [&](auto lgrInfo, auto objs, auto state) {
std::cout << "writing ledger = "
<< std::to_string(lgrInfo.seq);
backend->startWrites();
backend->writeLedger(
@@ -2344,11 +2326,6 @@ TEST(Backend, cacheIntegration)
uint32_t limit = 10;
page = backend->fetchLedgerPage(
page.cursor, seq, limit, false, yield);
std::cout << "fetched a page " << page.objects.size()
<< std::endl;
if (page.cursor)
std::cout << ripple::strHex(*page.cursor)
<< std::endl;
// if (page.cursor)
// EXPECT_EQ(page.objects.size(), limit);
retObjs.insert(
@@ -2372,8 +2349,7 @@ TEST(Backend, cacheIntegration)
}
}
if (found != (obj.second.size() != 0))
std::cout << ripple::strHex(obj.first) << std::endl;
ASSERT_EQ(found, obj.second.size() != 0);
ASSERT_EQ(found, obj.second.size() != 0);
}
};
@@ -2437,11 +2413,8 @@ TEST(Backend, cacheIntegration)
for (auto [seq, diff] : state)
{
std::cout << "flatteneing" << std::endl;
auto flat = flatten(seq);
std::cout << "flattened" << std::endl;
checkLedger(lgrInfos[seq], flat);
std::cout << "checked" << std::endl;
}
}

View File

@@ -1,9 +1,8 @@
#include <config/Config.h>
#include <util/Fixtures.h>
#include <boost/filesystem.hpp>
#include <boost/json/parse.hpp>
#include <boost/log/core.hpp>
#include <gtest/gtest.h>
#include <cstdio>
#include <exception>
@@ -34,17 +33,10 @@ constexpr static auto JSONData = R"JSON(
}
)JSON";
class ConfigTest : public ::testing::Test
class ConfigTest : public NoLoggerFixture
{
protected:
Config cfg{json::parse(JSONData)};
void
SetUp() override
{
// disable logging in test
core::get()->set_logging_enabled(false);
}
};
TEST_F(ConfigTest, SanityCheck)

49
unittests/Logger.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include <util/Fixtures.h>
using namespace clio;
// Used as a fixture for tests with enabled logging
class LoggerTest : public LoggerFixture
{
};
// Used as a fixture for tests with disabled logging
class NoLoggerTest : public NoLoggerFixture
{
};
TEST_F(LoggerTest, Basic)
{
Logger log{"General"};
log.info() << "Info line logged";
checkEqual("General:NFO Info line logged");
LogService::debug() << "Debug line with numbers " << 12345;
checkEqual("General:DBG Debug line with numbers 12345");
LogService::warn() << "Warning is logged";
checkEqual("General:WRN Warning is logged");
}
TEST_F(LoggerTest, Filtering)
{
Logger log{"General"};
log.trace() << "Should not be logged";
checkEmpty();
log.warn() << "Warning is logged";
checkEqual("General:WRN Warning is logged");
Logger tlog{"Trace"};
tlog.trace() << "Trace line logged for 'Trace' component";
checkEqual("Trace:TRC Trace line logged for 'Trace' component");
}
TEST_F(NoLoggerTest, Basic)
{
Logger log{"Trace"};
log.trace() << "Nothing";
checkEmpty();
LogService::fatal() << "Still nothing";
checkEmpty();
}

93
unittests/util/Fixtures.h Normal file
View File

@@ -0,0 +1,93 @@
#ifndef CLIO_UNITTEST_FIXTURES_H
#define CLIO_UNITTEST_FIXTURES_H
#include <ios>
#include <mutex>
#include <gtest/gtest.h>
#include <log/Logger.h>
/**
* @brief Fixture with LogService support.
*/
class LoggerFixture : public ::testing::Test
{
/**
* @brief A simple string buffer that can be used to mock std::cout for
* console logging.
*/
class FakeBuffer final : public std::stringbuf
{
public:
std::string
getStrAndReset()
{
auto value = str();
str("");
return value;
}
};
FakeBuffer buffer_;
std::ostream stream_ = std::ostream{&buffer_};
protected:
// Simulates the `LogService::init(config)` call
void
SetUp() override
{
static std::once_flag once_;
std::call_once(once_, [] {
boost::log::add_common_attributes();
boost::log::register_simple_formatter_factory<clio::Severity, char>(
"Severity");
});
namespace src = boost::log::sources;
namespace keywords = boost::log::keywords;
namespace sinks = boost::log::sinks;
namespace expr = boost::log::expressions;
auto core = boost::log::core::get();
core->remove_all_sinks();
boost::log::add_console_log(
stream_, keywords::format = "%Channel%:%Severity% %Message%");
auto min_severity = expr::channel_severity_filter(
clio::log_channel, clio::log_severity);
min_severity["General"] = clio::Severity::DEBUG;
min_severity["Trace"] = clio::Severity::TRACE;
core->set_filter(min_severity);
core->set_logging_enabled(true);
}
void
checkEqual(std::string expected)
{
auto value = buffer_.getStrAndReset();
ASSERT_EQ(value, expected + '\n');
}
void
checkEmpty()
{
ASSERT_TRUE(buffer_.getStrAndReset().empty());
}
};
/**
* @brief Fixture with LogService support but completely disabled logging.
*
* This is meant to be used as a base for other fixtures.
*/
class NoLoggerFixture : public LoggerFixture
{
protected:
void
SetUp() override
{
LoggerFixture::SetUp();
boost::log::core::get()->set_logging_enabled(false);
}
};
#endif // CLIO_UNITTEST_FIXTURES_H