-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Add quic_logging_impl.(h|cc) to QUICHE platform implementation. #5758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e04c28c
75e7024
0ae37c0
a2956eb
eefc0ac
a470825
b9ed2f6
d67cf0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // NOLINT(namespace-envoy) | ||
|
|
||
| // This file is part of the QUICHE platform implementation, and is not to be | ||
| // consumed or referenced directly by other Envoy code. It serves purely as a | ||
| // porting layer for QUICHE. | ||
|
|
||
| #include "extensions/quic_listeners/quiche/platform/quic_logging_impl.h" | ||
|
|
||
| #include <atomic> | ||
|
|
||
| namespace quic { | ||
|
|
||
| namespace { | ||
| std::atomic<int>& VerbosityLogThreshold() { | ||
| static std::atomic<int> threshold(0); | ||
| return threshold; | ||
| } | ||
| } // namespace | ||
|
|
||
| QuicLogEmitter::QuicLogEmitter(QuicLogLevel level) : level_(level), saved_errno_(errno) {} | ||
|
|
||
| QuicLogEmitter::~QuicLogEmitter() { | ||
| if (is_perror_) { | ||
| // TODO(wub): Change to a thread-safe version of strerror. | ||
| stream_ << ": " << strerror(saved_errno_) << " [" << saved_errno_ << "]"; | ||
| } | ||
| GetLogger().log(level_, "quic: {}", stream_.str().c_str()); | ||
| if (level_ == FATAL) { | ||
| abort(); | ||
| } | ||
| } | ||
|
|
||
| int GetVerbosityLogThreshold() { return VerbosityLogThreshold().load(std::memory_order_relaxed); } | ||
|
|
||
| void SetVerbosityLogThreshold(int new_verbosity) { | ||
| VerbosityLogThreshold().store(new_verbosity, std::memory_order_relaxed); | ||
| } | ||
|
|
||
| } // namespace quic | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| #pragma once | ||
|
|
||
| // NOLINT(namespace-envoy) | ||
|
|
||
| // This file is part of the QUICHE platform implementation, and is not to be | ||
| // consumed or referenced directly by other Envoy code. It serves purely as a | ||
| // porting layer for QUICHE. | ||
|
|
||
| #include <cerrno> | ||
| #include <cstring> | ||
| #include <iostream> | ||
| #include <sstream> | ||
|
|
||
| #include "common/common/assert.h" | ||
| #include "common/common/logger.h" | ||
|
|
||
| #include "absl/base/optimization.h" | ||
|
|
||
| // TODO(wub): Add CHECK/DCHECK and variants, which are not explicitly exposed by quic_logging.h. | ||
| // TODO(wub): Implement quic_mock_log_impl.h for testing. | ||
|
|
||
| // If |condition| is true, use |logstream| to stream the log message and send it to spdlog. | ||
| // If |condition| is false, |logstream| will not be instantiated. | ||
| // The switch(0) is used to suppress a compiler warning on ambiguous "else". | ||
| #define QUIC_LOG_IMPL_INTERNAL(condition, logstream) \ | ||
| switch (0) \ | ||
| default: \ | ||
| if (!(condition)) { \ | ||
| } else \ | ||
| logstream | ||
|
|
||
| #define QUIC_LOG_IF_IMPL(severity, condition) \ | ||
| 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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (optional) slight preference for defining this directly in terms of QUIC_LOG_IMPL_INTERNAL, even though it's longer textually.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. QUIC_LOG_IF_IMPL is easier to read and I think it compiles to the same code.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough, SG |
||
|
|
||
| #define QUIC_VLOG_IF_IMPL(verbosity, condition) \ | ||
| QUIC_LOG_IMPL_INTERNAL((condition) && quic::IsVerboseLogEnabled(verbosity), \ | ||
| quic::QuicLogEmitter(quic::INFO).stream()) | ||
|
|
||
| #define QUIC_VLOG_IMPL(verbosity) QUIC_VLOG_IF_IMPL(verbosity, true) | ||
|
|
||
| // TODO(wub): Implement QUIC_LOG_FIRST_N_IMPL. | ||
| #define QUIC_LOG_FIRST_N_IMPL(severity, n) QUIC_LOG_IMPL(severity) | ||
|
|
||
| // TODO(wub): Implement QUIC_LOG_EVERY_N_SEC_IMPL. | ||
| #define QUIC_LOG_EVERY_N_SEC_IMPL(severity, seconds) QUIC_LOG_IMPL(severity) | ||
|
|
||
| #define QUIC_PLOG_IMPL(severity) \ | ||
| QUIC_LOG_IMPL_INTERNAL(quic::IsLogLevelEnabled(quic::severity), \ | ||
| quic::QuicLogEmitter(quic::severity).SetPerror().stream()) | ||
|
|
||
| #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) | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SG, added a TODO.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks |
||
| #ifdef NDEBUG | ||
| // Release build | ||
| #define QUIC_COMPILED_OUT_LOG() QUIC_LOG_IMPL_INTERNAL(false, quic::NullLogStream().stream()) | ||
| #define QUIC_DVLOG_IMPL(verbosity) QUIC_COMPILED_OUT_LOG() | ||
| #define QUIC_DVLOG_IF_IMPL(verbosity, condition) QUIC_COMPILED_OUT_LOG() | ||
| #define QUIC_DLOG_IMPL(severity) QUIC_COMPILED_OUT_LOG() | ||
| #define QUIC_DLOG_IF_IMPL(severity, condition) QUIC_COMPILED_OUT_LOG() | ||
| #define QUIC_DLOG_INFO_IS_ON_IMPL 0 | ||
| #define QUIC_NOTREACHED_IMPL() | ||
| #else | ||
| // Debug build | ||
| #define QUIC_DVLOG_IMPL(verbosity) QUIC_VLOG_IMPL(verbosity) | ||
| #define QUIC_DVLOG_IF_IMPL(verbosity, condition) QUIC_VLOG_IF_IMPL(verbosity, condition) | ||
| #define QUIC_DLOG_IMPL(severity) QUIC_LOG_IMPL(severity) | ||
| #define QUIC_DLOG_IF_IMPL(severity, condition) QUIC_LOG_IF_IMPL(severity, condition) | ||
| #define QUIC_DLOG_INFO_IS_ON_IMPL QUIC_LOG_INFO_IS_ON_IMPL | ||
| #define QUIC_NOTREACHED_IMPL() NOT_REACHED_GCOVR_EXCL_LINE | ||
| #endif | ||
|
|
||
| #define QUIC_PREDICT_FALSE_IMPL(x) ABSL_PREDICT_FALSE(x) | ||
|
|
||
| namespace quic { | ||
|
|
||
| using QuicLogLevel = spdlog::level::level_enum; | ||
|
|
||
| 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; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't, but I've updated this PR to kill the process when QUIC_LOG(FATAL) is hit.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LG, thanks
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just something to keep in mid as we code, in Envoy only critical logs flush immediately.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it, thanks! |
||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should there be a TODO for DFATAL here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I forgot that, added to this PR, please take a look.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LG |
||
| // DFATAL is FATAL in debug mode, ERROR in release mode. | ||
| #ifdef NDEBUG | ||
| static const QuicLogLevel DFATAL = ERROR; | ||
| #else | ||
| static const QuicLogLevel DFATAL = FATAL; | ||
| #endif | ||
|
|
||
| class QuicLogEmitter { | ||
| public: | ||
| explicit QuicLogEmitter(QuicLogLevel level); | ||
|
|
||
| ~QuicLogEmitter(); | ||
|
|
||
| QuicLogEmitter& SetPerror() { | ||
| is_perror_ = true; | ||
| return *this; | ||
| } | ||
|
|
||
| std::ostringstream& stream() { return stream_; } | ||
|
|
||
| private: | ||
| const QuicLogLevel level_; | ||
| const int saved_errno_; | ||
| bool is_perror_ = false; | ||
| std::ostringstream stream_; | ||
| }; | ||
|
|
||
| class NullLogStream { | ||
| public: | ||
| NullLogStream& stream() { return *this; } | ||
| }; | ||
|
|
||
| template <typename T> inline NullLogStream& operator<<(NullLogStream& s, const T&) { return s; } | ||
|
|
||
| inline spdlog::logger& GetLogger() { | ||
| return Envoy::Logger::Registry::getLog(Envoy::Logger::Id::quic); | ||
| } | ||
|
|
||
| inline bool IsLogLevelEnabled(QuicLogLevel level) { return level >= GetLogger().level(); } | ||
|
|
||
| int GetVerbosityLogThreshold(); | ||
| void SetVerbosityLogThreshold(int new_verbosity); | ||
|
|
||
| inline bool IsVerboseLogEnabled(int verbosity) { | ||
| return IsLogLevelEnabled(INFO) && verbosity <= GetVerbosityLogThreshold(); | ||
| } | ||
|
|
||
| } // namespace quic | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is as simple as switching to strerror_r might as well do it here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.