Add quic_logging_impl.(h|cc) to QUICHE platform implementation.#5758
Add quic_logging_impl.(h|cc) to QUICHE platform implementation.#5758htuch merged 8 commits intoenvoyproxy:masterfrom
Conversation
Signed-off-by: Bin Wu <wub@google.com>
|
Tagging issue #2557 |
|
Looks like you want to check CI on this one. FWIW you can also set up circle ci to email you on build failures - I don't think it does by default but it's super useful to get the reports |
|
/wait |
|
@alyssawilk : This PR needs to wait for the resolution of #5767 |
|
Totally fine - this just flags it on github dashboards as something I don't need to look at :-) |
mpwarres
left a comment
There was a problem hiding this comment.
Looks awesome! I know this is blocked behind other things, but figured I'd give some comments in the meantime.
| case 1: \ | ||
| logstream | ||
|
|
||
| #define QUIC_LOGGER() Envoy::Logger::Registry::getLog(Envoy::Logger::Id::misc) |
There was a problem hiding this comment.
nit: does QUIC_LOGGER have to be a macro? Wondering if you could instead just define a GetQuicLogger() function.
There was a problem hiding this comment.
Replaced QUIC_LOGGER() by quic::GetLogger() function.
|
|
||
| #include "absl/base/optimization.h" | ||
|
|
||
| #define QUIC_LOG_IMPL_INTERNAL(condition, logstream) \ |
There was a problem hiding this comment.
A brief comment explaining roughly how this works, and that it is done in order to instantiate logstream only if condition is true, would be nice.
Side question: I was noticing that base/logging.h does this slightly differently, placing the log stream expression in the default case of a switch(0), do you have any idea why that is? I agree your formulation seems simpler, just wondering if there's some reason behind the base/logging.h form.
There was a problem hiding this comment.
Comment added.
I was following the style in go/onelog, not base/logging.h. But the style in go/onelog no longer compiles after I updated my clang to 7.0, so I've switched to the base/logging.h style.
About the switch(0):
If a macro is implemented in the form of "if (x) {} else {}", the switch(0) can be used to suppress a warning about ambiguous else blocks. Suppose there is
#define MACRO() if (x) {} else {}
And a call site:
if (y) MACRO();
Which expands to:
if (y) if (x) {} else {};
The "else" is bind to the second "if", but some compiler worries that the intent is to bind to the first "if", so they give warnings. The switch(0) trick eliminates this warning.
| QUIC_LOG_IMPL_INTERNAL((condition) && quic::IsLogLevelEnabled(quic::severity), \ | ||
| quic::QuicLogEmitter(quic::severity).stream()) | ||
|
|
||
| #define QUIC_LOG_IMPL(severity) QUIC_LOG_IF_IMPL(severity, true) |
There was a problem hiding this comment.
(optional) slight preference for defining this directly in terms of QUIC_LOG_IMPL_INTERNAL, even though it's longer textually.
There was a problem hiding this comment.
QUIC_LOG_IF_IMPL is easier to read and I think it compiles to the same code.
| static const QuicLogLevel WARNING = spdlog::level::warn; | ||
| static const QuicLogLevel ERROR = spdlog::level::err; | ||
| static const QuicLogLevel FATAL = spdlog::level::critical; | ||
|
|
There was a problem hiding this comment.
should there be a TODO for DFATAL here?
There was a problem hiding this comment.
Sorry, I forgot that, added to this PR, please take a look.
| static const QuicLogLevel INFO = spdlog::level::info; | ||
| static const QuicLogLevel WARNING = spdlog::level::warn; | ||
| static const QuicLogLevel ERROR = spdlog::level::err; | ||
| static const QuicLogLevel FATAL = spdlog::level::critical; |
There was a problem hiding this comment.
does logging spdylog::level::critical kill the process? I couldn't find indication of that in spdlog documentation. If it does, perhaps this could be verified with a death test.
There was a problem hiding this comment.
It doesn't, but I've updated this PR to kill the process when QUIC_LOG(FATAL) is hit.
| QUIC_LOG_IF(ERROR, false) << i++; | ||
| EXPECT_EQ(11, i); | ||
|
|
||
| QUIC_LOG_IF(ERROR, true) << i++; |
There was a problem hiding this comment.
would it be possible to have the test verify, for at least one of the log statements that actually executes, that the expected message actually makes it to spdlog? Might not be too bad if you mock spdlog::sinks::sink or base_sink.
If this ends up being more complicated, then maybe not worth the effort.
There was a problem hiding this comment.
I plan to work on it in a follow up PR, in the context of quic_mock_log_impl.h.
There was a problem hiding this comment.
SG. Could you add a TODO comment for that?
| #define QUIC_LOG_INFO_IS_ON_IMPL quic::IsLogLevelEnabled(quic::INFO) | ||
| #define QUIC_LOG_WARNING_IS_ON_IMPL quic::IsLogLevelEnabled(quic::WARNING) | ||
| #define QUIC_LOG_ERROR_IS_ON_IMPL quic::IsLogLevelEnabled(quic::ERROR) | ||
|
|
There was a problem hiding this comment.
I think we may need TODOs for CHECK and DCHECK macros (including the various (D)CHECK_ variants), since google3 quic_logging_impl.h implicitly provides those as well (by directly #including base/logging.h), and QUICHE code definitely uses them.
…ging Update the QUIC_LOG_IMPL_INTERNAL macro. Signed-off-by: Bin Wu <wub@google.com>
Signed-off-by: Bin Wu <wub@google.com>
mpwarres
left a comment
There was a problem hiding this comment.
LGTM, thanks for implementing this!
| QUIC_LOG_IMPL_INTERNAL((condition) && quic::IsLogLevelEnabled(quic::severity), \ | ||
| quic::QuicLogEmitter(quic::severity).stream()) | ||
|
|
||
| #define QUIC_LOG_IMPL(severity) QUIC_LOG_IF_IMPL(severity, true) |
| #define QUIC_LOG_INFO_IS_ON_IMPL quic::IsLogLevelEnabled(quic::INFO) | ||
| #define QUIC_LOG_WARNING_IS_ON_IMPL quic::IsLogLevelEnabled(quic::WARNING) | ||
| #define QUIC_LOG_ERROR_IS_ON_IMPL quic::IsLogLevelEnabled(quic::ERROR) | ||
|
|
| static const QuicLogLevel INFO = spdlog::level::info; | ||
| static const QuicLogLevel WARNING = spdlog::level::warn; | ||
| static const QuicLogLevel ERROR = spdlog::level::err; | ||
| static const QuicLogLevel FATAL = spdlog::level::critical; |
| static const QuicLogLevel WARNING = spdlog::level::warn; | ||
| static const QuicLogLevel ERROR = spdlog::level::err; | ||
| static const QuicLogLevel FATAL = spdlog::level::critical; | ||
|
|
| QUIC_LOG_IF(ERROR, false) << i++; | ||
| EXPECT_EQ(11, i); | ||
|
|
||
| QUIC_LOG_IF(ERROR, true) << i++; |
There was a problem hiding this comment.
SG. Could you add a TODO comment for that?
| // Test the behaviors of the cross products of | ||
| // | ||
| // {QUIC_LOG, QUIC_DLOG} x {FATAL, DFATAL} x {debug, release} | ||
| TEST(QuicPlatformTest, QuicFatalLog) { |
There was a problem hiding this comment.
Cool, nice to have a test for this
| quic::GetLogger().set_level(quic::INFO); | ||
|
|
||
| if (QUIC_PREDICT_FALSE(rand() % RAND_MAX == 123456789)) { | ||
| QUIC_LOG(INFO) << "Go buy some lottery tickets."; |
Signed-off-by: Bin Wu <wub@google.com>
building it unless "--define quiche=enabled" is used. Signed-off-by: Bin Wu <wub@google.com>
Signed-off-by: Bin Wu <wub@google.com>
Signed-off-by: Bin Wu <wub@google.com>
|
/retest |
|
🔨 rebuilding |
|
@alyssawilk : Can you take a look at this and (if no problem) merge it? Thanks! |
| QuicLogEmitter::~QuicLogEmitter() { | ||
| if (is_perror_) { | ||
| // TODO(wub): Change to a thread-safe version of strerror. | ||
| stream_ << ": " << strerror(saved_errno_) << " [" << saved_errno_ << "]"; |
There was a problem hiding this comment.
If this is as simple as switching to strerror_r might as well do it here
There was a problem hiding this comment.
strerror is prevalent in Envoy code, I'd prefer to stick to it in this PR.
In the future, I can add a thread safe version of strerror to some Envoy utility class, and use that everywhere, but it will be in low priority.
| template <typename T> inline NullLogStream& operator<<(NullLogStream& s, const T&) { return s; } | ||
|
|
||
| inline spdlog::logger& GetLogger() { | ||
| return Envoy::Logger::Registry::getLog(Envoy::Logger::Id::misc); |
There was a problem hiding this comment.
I think we should probably declare a quic-specific logger in
source/common/common/logger.h
If it ends up being complicated a TODO is fine.
There was a problem hiding this comment.
Done. (seems easier than I thought, hopefully ci won't complain:)
| static const QuicLogLevel INFO = spdlog::level::info; | ||
| static const QuicLogLevel WARNING = spdlog::level::warn; | ||
| static const QuicLogLevel ERROR = spdlog::level::err; | ||
| static const QuicLogLevel FATAL = spdlog::level::critical; |
There was a problem hiding this comment.
Just something to keep in mid as we code, in Envoy only critical logs flush immediately.
It won't cause problems and I think while we could set Enovy QUIC logs to flush at error it makes more sense to stick with the defaults, but worth being aware when we debug.
|
|
||
| int i = 0; | ||
|
|
||
| QUIC_LOG(INFO) << (i = 10); |
There was a problem hiding this comment.
Mind using EXPECT_LOG_[NOT_]ONTAINS macros instead of or in additon to the math checks?
It'll also verify we did the log mapping correctly.
There was a problem hiding this comment.
I added some EXPECT_LOG_CONTAINS.
These macros forcefully set the log level to trace(example), so things like EXPECT_NO_LOGS do not work for the test where log is not emitted due to log level.
After this PR, I'll work on quic_mock_log_impl.h and add tests for the "no log expected" case.
Signed-off-by: Bin Wu <wub@google.com>
wu-bin
left a comment
There was a problem hiding this comment.
@alyssawilk Thanks for the review! PTAL.
| QuicLogEmitter::~QuicLogEmitter() { | ||
| if (is_perror_) { | ||
| // TODO(wub): Change to a thread-safe version of strerror. | ||
| stream_ << ": " << strerror(saved_errno_) << " [" << saved_errno_ << "]"; |
There was a problem hiding this comment.
strerror is prevalent in Envoy code, I'd prefer to stick to it in this PR.
In the future, I can add a thread safe version of strerror to some Envoy utility class, and use that everywhere, but it will be in low priority.
| static const QuicLogLevel INFO = spdlog::level::info; | ||
| static const QuicLogLevel WARNING = spdlog::level::warn; | ||
| static const QuicLogLevel ERROR = spdlog::level::err; | ||
| static const QuicLogLevel FATAL = spdlog::level::critical; |
| template <typename T> inline NullLogStream& operator<<(NullLogStream& s, const T&) { return s; } | ||
|
|
||
| inline spdlog::logger& GetLogger() { | ||
| return Envoy::Logger::Registry::getLog(Envoy::Logger::Id::misc); |
There was a problem hiding this comment.
Done. (seems easier than I thought, hopefully ci won't complain:)
|
|
||
| int i = 0; | ||
|
|
||
| QUIC_LOG(INFO) << (i = 10); |
There was a problem hiding this comment.
I added some EXPECT_LOG_CONTAINS.
These macros forcefully set the log level to trace(example), so things like EXPECT_NO_LOGS do not work for the test where log is not emitted due to log level.
After this PR, I'll work on quic_mock_log_impl.h and add tests for the "no log expected" case.
…yproxy#5758) Add quic_logging_impl.(h|cc) and unit tests to QUICHE platform implementation. QUICHE code uses stream-style logging macros to do logging, e.g.: QUIC_LOG(INFO) << "x = " << x; The implementation in this PR uses a temporary std::ostringstream (one per macro invocation) to convert the stream into a std::string, then send the string to spdlog. Risk Level: minimal: code not used yet Testing: [Unit test in release mode] bazel test --experimental_remap_main_repo -c opt test/extensions/quic_listeners/quiche/platform:quic_platform_test [Unit test in debug mode] bazel test --experimental_remap_main_repo test/extensions/quic_listeners/quiche/platform:quic_platform_test Signed-off-by: Bin Wu <wub@google.com> Signed-off-by: Fred Douglas <fredlas@google.com>
Description:
Add quic_logging_impl.(h|cc) and unit tests to QUICHE platform implementation.
QUICHE code uses stream-style logging macros to do logging, e.g.:
QUIC_LOG(INFO) << "x = " << x;
The implementation in this PR uses a temporary std::ostringstream (one per macro invocation) to convert the stream into a std::string, then send the string to spdlog.
Risk Level: minimal: code not used yet
Testing:
[Unit test in release mode] bazel test --experimental_remap_main_repo -c opt test/extensions/quic_listeners/quiche/platform:quic_platform_test
[Unit test in debug mode] bazel test --experimental_remap_main_repo test/extensions/quic_listeners/quiche/platform:quic_platform_test
Docs Changes: none
Release Notes: none
[Optional Fixes #Issue]
[Optional Deprecated:]