-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
quic: add QUIC downstream connection close error stats. #16584
Changes from 1 commit
b7b52e1
a704f7d
e77ca28
1b9275b
a47dc19
c4394c5
71f28c3
a71c23c
79e200b
8957117
5c83f5f
6cd0d83
4fe3fc5
ac867ce
d009105
832b098
8b7047a
0cc03f4
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 |
---|---|---|
|
@@ -17,13 +17,13 @@ EnvoyQuicDispatcher::EnvoyQuicDispatcher( | |
uint8_t expected_server_connection_id_length, Network::ConnectionHandler& connection_handler, | ||
Network::ListenerConfig& listener_config, Server::ListenerStats& listener_stats, | ||
Server::PerHandlerListenerStats& per_worker_stats, Event::Dispatcher& dispatcher, | ||
Network::Socket& listen_socket) | ||
Network::Socket& listen_socket, QuicStats* quic_stats) | ||
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. per above, pass through QuicContext rather than QuicStats and QuicConfig separately. |
||
: quic::QuicDispatcher(&quic_config, crypto_config, version_manager, std::move(helper), | ||
std::make_unique<EnvoyQuicCryptoServerStreamHelper>(), | ||
std::move(alarm_factory), expected_server_connection_id_length), | ||
connection_handler_(connection_handler), listener_config_(listener_config), | ||
listener_stats_(listener_stats), per_worker_stats_(per_worker_stats), dispatcher_(dispatcher), | ||
listen_socket_(listen_socket) { | ||
listen_socket_(listen_socket), quic_stats_(quic_stats) { | ||
// Set send buffer twice of max flow control window to ensure that stream send | ||
// buffer always takes all the data. | ||
// The max amount of data buffered is the per-stream high watermark + the max | ||
|
@@ -46,6 +46,10 @@ void EnvoyQuicDispatcher::OnConnectionClosed(quic::QuicConnectionId connection_i | |
listener_stats_.downstream_cx_active_.dec(); | ||
per_worker_stats_.downstream_cx_active_.dec(); | ||
connection_handler_.decNumConnections(); | ||
if (quic_stats_) { | ||
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 you should just make QuicStats unconditional at this level. I don't see the problem with instantiating QuicStats in the places below where you are currently passing nullptr. |
||
quic_stats_->chargeQuicConnectionCloseStats(listener_config_.listenerScope(), error, source, | ||
/*is_upstream*/ false); | ||
} | ||
} | ||
|
||
std::unique_ptr<quic::QuicSession> EnvoyQuicDispatcher::CreateQuicSession( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#include "common/quic/quic_stats.h" | ||
|
||
namespace Envoy { | ||
namespace Quic { | ||
|
||
QuicStats::QuicStats(Stats::SymbolTable& symbol_table) | ||
: stat_name_pool_(symbol_table), symbol_table_(symbol_table), | ||
downstream_(stat_name_pool_.add("downstream")), upstream_(stat_name_pool_.add("upstream")), | ||
from_self_(stat_name_pool_.add("self")), from_peer_(stat_name_pool_.add("peer")) { | ||
// Preallocate most used counters | ||
ConnectionCloseStatName(quic::QUIC_NETWORK_IDLE_TIMEOUT); | ||
} | ||
|
||
void QuicStats::incCounter(Stats::Scope& scope, const Stats::StatNameVec& names) { | ||
Stats::SymbolTable::StoragePtr stat_name_storage = symbol_table_.join(names); | ||
scope.counterFromStatName(Stats::StatName(stat_name_storage.get())).inc(); | ||
} | ||
|
||
void QuicStats::chargeQuicConnectionCloseStats(Stats::Scope& scope, quic::QuicErrorCode error_code, | ||
quic::ConnectionCloseSource source, | ||
bool is_upstream) { | ||
ASSERT(&symbol_table_ == &scope.symbolTable()); | ||
|
||
const Stats::StatName connection_close = ConnectionCloseStatName(error_code); | ||
incCounter(scope, {is_upstream ? upstream_ : downstream_, | ||
source == quic::ConnectionCloseSource::FROM_SELF ? from_self_ : from_peer_, | ||
connection_close}); | ||
} | ||
|
||
Stats::StatName QuicStats::ConnectionCloseStatName(quic::QuicErrorCode error_code) { | ||
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. connectionCloseStatName per Envoy style guide |
||
ASSERT(error_code < quic::QUIC_LAST_ERROR); | ||
|
||
return Stats::StatName( | ||
connection_error_stat_names_.get(error_code, [this, error_code]() -> const uint8_t* { | ||
return stat_name_pool_.addReturningStorage( | ||
absl::StrCat("quic_connection_close_error_code_", QuicErrorCodeToString(error_code))); | ||
})); | ||
} | ||
|
||
} // namespace Quic | ||
} // namespace Envoy |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#pragma once | ||
|
||
#include "envoy/stats/scope.h" | ||
|
||
#include "common/common/thread.h" | ||
#include "common/stats/symbol_table_impl.h" | ||
|
||
#include "quiche/quic/core/quic_error_codes.h" | ||
#include "quiche/quic/core/quic_types.h" | ||
|
||
namespace Envoy { | ||
namespace Quic { | ||
|
||
class QuicStats { | ||
public: | ||
explicit QuicStats(Stats::SymbolTable& symbol_table); | ||
|
||
void chargeQuicConnectionCloseStats(Stats::Scope& scope, quic::QuicErrorCode error_code, | ||
quic::ConnectionCloseSource source, bool is_upstream); | ||
|
||
private: | ||
void incCounter(Stats::Scope& scope, const Stats::StatNameVec& names); | ||
|
||
Stats::StatName ConnectionCloseStatName(quic::QuicErrorCode error_code); | ||
|
||
Stats::StatNamePool stat_name_pool_; | ||
Stats::SymbolTable& symbol_table_; | ||
const Stats::StatName downstream_; | ||
const Stats::StatName upstream_; | ||
const Stats::StatName from_self_; | ||
const Stats::StatName from_peer_; | ||
Thread::AtomicPtrArray<const uint8_t, quic::QUIC_LAST_ERROR, | ||
Thread::AtomicPtrAllocMode::DoNotDelete> | ||
connection_error_stat_names_; | ||
}; | ||
|
||
} // namespace Quic | ||
} // namespace Envoy |
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.
I'd suggest bundling QuicStats and quic::QuicConfig into a class Quic::Context, which can parallel Http::Context in most ways.
That will cut down by one on the arg-count in a few interfaces in this PR, and give you other good places to put stuff that may need to be shared across workers.
Moreover,
Quic::Context
(or maybeOptRef<Quic::Context>
) could then be returned fromServer::FactoryContext
, also parallel to Http::Context and Grpc::Context, cutting down on how much plumbing through needs to happen for those individually.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.
I originally tried to make QuicStats behave similarly to Http::Context but found it to be quite complicated.
To have the server return QuicStats, we need a pure interface class so that Server::Instance can have a getter interface Quic::QuicStats quicStats().
However, the only public method in QuicStats, chargeQuicConnectionCloseStats(), is dependent on QuicErrorCode, which is defined in third_party library Quiche.
In my understanding, Envoy must to be able to build without quiche. And we probably shouldn't introduce external dependency in the include/ directory either.
Having this dependency makes it hard to follow existing pattern when implementing Quic stats.
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.
On this point, to match the pattern in the other Contexts is to forward-declare QuicStats without defining an interface for it.
So you'd have
So you don't need to expose the error-code type or other types at the interface.