Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions core/utest/include/userver/utest/logging_fixture.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#pragma once
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this file into universal/utest/include/userver/utest/ directory (or even merge into universal/utest/include/userver/utest/default_logger_fixture.hpp)


#include <userver/utest/utest.hpp>
#include <userver/logging/log.hpp>
#include <userver/logging/null_logger.hpp>
#include <userver/logging/impl/logger_base.hpp>

#include <atomic>
#include <concepts>
#include <iostream>
#include <mutex>
#include <string_view>
#include <thread>

USERVER_NAMESPACE_BEGIN

namespace utest {

namespace detail {

class CoutLogger final : public logging::impl::TextLogger {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think, is it decent to propose logger change: get TextLogger out of the impl namespace?
The assumed downside: might be there would be a client which would use the class on a regular basis..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave it in impl for now.

We have an asynchronous logger TpLogger, and it should be used in applications. Any other public logger confuses our users

public:
CoutLogger() : TextLogger(logging::Format::kTskv)
{
SetLevel(logging::GetDefaultLoggerLevel()); // consider gtest_hooks.hpp usage
}

void Log(logging::Level level, logging::impl::formatters::LoggerItemRef item) override
{
UASSERT(dynamic_cast<logging::impl::TextLogItem*>(&item));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure here also: may be it's enough to check via static_cast on the next line.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave the UASSERT as is. Looks right

auto& str = static_cast<logging::impl::TextLogItem&>(item);
std::lock_guard lock(m_mutex);
std::cout << std::this_thread::get_id()
<< "\t" << logging::ToString(level)
<< "\t" << std::string_view(str.log_line.begin(), str.log_line.end())
<< std::endl;
}
private:
std::mutex m_mutex;
};

class LoggingFixtureEnvironment
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to public, rename to CoutLoggingFixture and inherit from:

template <class Base>
class DefaultLoggerFixture : public Base {

Something like:

namespace detail {

logging::LoggerPtr MakeCoutLogger() {
    static CoutLogger g_cout;
    return std::shared_ptr<logging::Logger>(nullptr, &g_cout);
}

}

template <class Base>
class CoutLoggingFixtureBase: public DefaultLogginFixture<Base> {
    LoggingFixtureEnvironment()
    {
        SetDefaultLoggerRef(detail::MakeCoutLogger()); 
    }
};

using CoutLoggingFixture = CoutLoggingFixtureBase<::testing::Test>;

{
CoutLogger m_logger;

static auto& NonOwningNullLogger() noexcept
{
static std::atomic<logging::impl::LoggerBase*> nullLoggerPtr(&logging::GetNullLogger());
return nullLoggerPtr;
}

public:
LoggingFixtureEnvironment()
{
logging::impl::SetDefaultLoggerRef(m_logger);
}

~LoggingFixtureEnvironment()
{
logging::impl::SetDefaultLoggerRef(*NonOwningNullLogger());
}
};

} // namespace detail
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw I'm not sure, but may be if we provide LoggingFixtureEx along with, we'd better get LoggingFixtureEnvironment outta detail namespace?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The the above comment, it places the Fixture to public


/// @ingroup userver_utest
///
/// @brief Fixture for logger usage due to unit tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, also add references to

class DefaultLoggerFixture : public Base {
and in
class DefaultLoggerFixture : public Base {
add reference to this class

struct LoggingFixture : ::testing::Test, detail::LoggingFixtureEnvironment {};

template<typename DerivedEnvironment>
struct LoggingFixtureEx : ::testing::Test, DerivedEnvironment
{
static_assert(std::derived_from<DerivedEnvironment, detail::LoggingFixtureEnvironment>);
};

} // namespace utest

USERVER_NAMESPACE_END

21 changes: 21 additions & 0 deletions core/utest/src/utest/logging_fixture_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <userver/utest/logging_fixture.hpp>
#include <userver/utest/utest.hpp>

USERVER_NAMESPACE_BEGIN

namespace utest
{

UTEST_F(LoggingFixture, DebugMessage)
{
LOG_DEBUG() << "Test message";
}

UTEST_F(LoggingFixture, InfoMessage)
{
LOG_INFO() << "Test message";
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we provide an example on DerivedEnvironment or the usage is obvious?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to have more examples than less %)

Also use @snippet core/utest/src/utest/logging_fixture_test.cpp Sample Name to make nice samples that are visible in docs

} // namespace utest

USERVER_NAMESPACE_END
Loading