userver: userver/utest/log_capture_fixture.hpp Source File
Loading...
Searching...
No Matches
log_capture_fixture.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utest/log_capture_fixture.hpp
4/// @brief @copybrief utest::LogCaptureFixture
5/// @ingroup userver_universal
6
7#include <iosfwd>
8#include <optional>
9#include <string>
10#include <string_view>
11#include <utility>
12#include <vector>
13
14#include <gtest/gtest.h>
15
16#include <userver/logging/impl/logger_base.hpp>
17#include <userver/logging/level.hpp>
18#include <userver/logging/log.hpp>
19#include <userver/utest/default_logger_fixture.hpp>
20#include <userver/utils/function_ref.hpp>
21#include <userver/utils/impl/internal_tag.hpp>
22#include <userver/utils/impl/source_location.hpp>
23#include <userver/utils/not_null.hpp>
24#include <userver/utils/span.hpp>
25
26USERVER_NAMESPACE_BEGIN
27
28namespace utest {
29
30namespace impl {
31class ToStringLogger;
32} // namespace impl
33
34/// @ingroup userver_utest
35///
36/// @brief Represents single log record, typically written via `LOG_*` macros.
37///
38/// @see @ref utest::LogCaptureLogger
39/// @see @ref utest::LogCaptureFixture
40class LogRecord final {
41public:
42 /// @returns decoded text of the log record
43 /// @throws if no 'text' tag in the log
44 const std::string& GetText() const;
45
46 /// @returns decoded value of the tag in the log record
47 /// @throws if no such tag in the log
48 const std::string& GetTag(std::string_view key) const;
49
50 /// @returns decoded value of the tag in the log record, or `std::nullopt`
51 std::optional<std::string> GetTagOptional(std::string_view key) const;
52
53 /// @returns decoded value of the tag in the log record, or `nullptr`
54 const std::string* GetTagOrNullptr(std::string_view key) const;
55
56 /// @returns serialized log record
57 const std::string& GetLogRaw() const;
58
59 /// @returns the log level of the record
60 logging::Level GetLevel() const;
61
62 /// @cond
63 // For internal use only.
64 LogRecord(utils::impl::InternalTag, logging::Level level, std::string&& log_raw);
65 /// @endcond
66
67private:
68 logging::Level level_;
69 std::string log_raw_;
70 std::vector<std::pair<std::string, std::string>> tags_;
71};
72
73std::ostream& operator<<(std::ostream&, const LogRecord& data);
74
75std::ostream& operator<<(std::ostream&, const std::vector<LogRecord>& data);
76
77/// Thrown by @ref GetSingleLog.
78class NotSingleLogError final : public std::runtime_error {
79public:
80 using std::runtime_error::runtime_error;
81};
82
83/// @returns the only log record from `log`.
84/// @throws NotSingleLogError if there are zero or multiple log records.
85LogRecord GetSingleLog(
86 utils::span<const LogRecord> log,
87 const utils::impl::SourceLocation& source_location = utils::impl::SourceLocation::Current()
88);
89
90/// @ingroup userver_utest
91///
92/// @brief A mocked logger that stores the log records in memory.
93///
94/// @snippet grpc/tests/cancel_test.cpp Sample of LogCaptureFixture
95///
96/// @see @ref utest::LogCaptureFixture
97class LogCaptureLogger final {
98public:
99 explicit LogCaptureLogger(logging::Format format = logging::Format::kRaw);
100
101 /// @returns the mocked logger.
102 logging::TextLoggerPtr GetLogger() const;
103
104 /// @returns all collected logs.
105 /// @see @ref GetSingleLog
106 std::vector<LogRecord> GetAll() const;
107
108 /// @returns logs filtered by (optional) text substring and (optional) tags substrings.
109 /// @see @ref GetSingleLog
110 std::vector<LogRecord> Filter(
111 std::string_view text_substring,
112 utils::span<const std::pair<std::string_view, std::string_view>> tag_substrings = {}
113 ) const;
114
115 /// @returns logs filtered by an arbitrary predicate.
116 /// @see @ref GetSingleLog
117 std::vector<LogRecord> Filter(utils::function_ref<bool(const LogRecord&)> predicate) const;
118
119 /// @brief Discards the collected logs.
120 void Clear() noexcept;
121
122 /// @brief Logs @a value as-if using `LOG_*`, then extracts the log text.
123 template <typename T>
124 std::string ToStringViaLogging(const T& value) {
125 Clear();
126 LOG_CRITICAL() << value;
128 Clear();
129 return text;
130 }
131
132private:
133 utils::SharedRef<impl::ToStringLogger> logger_;
134};
135
136/// @ingroup userver_utest
137///
138/// @brief Fixture that allows to capture and extract log written into the default logger.
139///
140/// @snippet grpc/tests/cancel_test.cpp Sample of LogCaptureFixture
141///
142/// @see @ref utest::LogCaptureLogger
143template <typename Base = ::testing::Test>
145protected:
146 LogCaptureFixture() { DefaultLoggerFixture<Base>::SetDefaultLogger(logger_.GetLogger()); }
147
148 /// @returns logger that holds the log records of the unit test
149 LogCaptureLogger& GetLogCapture() { return logger_; }
150
151private:
152 LogCaptureLogger logger_;
153};
154
155} // namespace utest
156
157USERVER_NAMESPACE_END