-
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
Made stats sinks a statically registered component #1506
Changes from 5 commits
6c427c6
42ea55a
cf5fac0
f99b5a5
441b3a7
d78014d
9dcc3a5
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,23 @@ | ||
licenses(["notice"]) # Apache 2 | ||
|
||
load( | ||
"//bazel:envoy_build_system.bzl", | ||
"envoy_cc_library", | ||
"envoy_package", | ||
) | ||
|
||
envoy_package() | ||
|
||
envoy_cc_library( | ||
name = "statsd_lib", | ||
srcs = ["statsd.cc"], | ||
hdrs = ["statsd.h"], | ||
external_deps = [ | ||
"envoy_bootstrap", | ||
], | ||
deps = [ | ||
"//source/common/network:address_lib", | ||
"//source/common/stats:statsd_lib", | ||
"//source/server:configuration_lib", | ||
], | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#include "server/config/stats/statsd.h" | ||
|
||
#include <string> | ||
|
||
#include "envoy/registry/registry.h" | ||
|
||
#include "common/stats/statsd.h" | ||
|
||
#include "api/bootstrap.pb.h" | ||
|
||
namespace Envoy { | ||
namespace Server { | ||
namespace Configuration { | ||
|
||
Stats::SinkPtr StatsdSinkFactory::createStatsSink(const Protobuf::Message& config, | ||
Server::Instance& server, | ||
Upstream::ClusterManager& cluster_manager) { | ||
|
||
const auto& statsd_sink = dynamic_cast<const envoy::api::v2::StatsdSink&>(config); | ||
switch (statsd_sink.statsd_specifier_case()) { | ||
case envoy::api::v2::StatsdSink::kAddress: { | ||
Network::Address::InstanceConstSharedPtr address = | ||
Network::Utility::fromProtoAddress(statsd_sink.address()); | ||
ENVOY_LOG(info, "statsd UDP ip address: {}", address->asString()); | ||
return Stats::SinkPtr( | ||
new Stats::Statsd::UdpStatsdSink(server.threadLocal(), std::move(address))); | ||
break; | ||
} | ||
case envoy::api::v2::StatsdSink::kTcpClusterName: | ||
ENVOY_LOG(info, "statsd TCP cluster: {}", statsd_sink.tcp_cluster_name()); | ||
return Stats::SinkPtr( | ||
new Stats::Statsd::TcpStatsdSink(server.localInfo(), statsd_sink.tcp_cluster_name(), | ||
server.threadLocal(), cluster_manager, server.stats())); | ||
break; | ||
default: | ||
throw EnvoyException( | ||
fmt::format("No tcp_cluster_name or address provided for {} Stats::Sink config", name())); | ||
} | ||
} | ||
|
||
ProtobufTypes::MessagePtr StatsdSinkFactory::createEmptyConfigProto() { | ||
return std::unique_ptr<envoy::api::v2::StatsdSink>(new envoy::api::v2::StatsdSink()); | ||
} | ||
|
||
std::string StatsdSinkFactory::name() { return "envoy.statsd"; } | ||
|
||
/** | ||
* Static registration for the statsd sink factory. @see RegisterFactory. | ||
*/ | ||
static Registry::RegisterFactory<StatsdSinkFactory, StatsSinkFactory> register_; | ||
|
||
} // namespace Configuration | ||
} // namespace Server | ||
} // namespace Envoy |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
|
||
#include "envoy/server/instance.h" | ||
|
||
#include "server/configuration_impl.h" | ||
|
||
namespace Envoy { | ||
namespace Server { | ||
namespace Configuration { | ||
|
||
/** | ||
* Config registration for the tcp statsd sink. @see StatsSinkFactory. | ||
*/ | ||
class StatsdSinkFactory : Logger::Loggable<Logger::Id::config>, public StatsSinkFactory { | ||
public: | ||
// StatsSinkFactory | ||
Stats::SinkPtr createStatsSink(const Protobuf::Message& config, Instance& server, | ||
Upstream::ClusterManager& cluster_manager) override; | ||
|
||
ProtobufTypes::MessagePtr createEmptyConfigProto() override; | ||
|
||
std::string name() override; | ||
}; | ||
|
||
} // namespace Configuration | ||
} // namespace Server | ||
} // namespace Envoy |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,25 +55,6 @@ void MainImpl::initialize(const envoy::api::v2::Bootstrap& bootstrap, Instance& | |
server.localInfo(), server.stats(), server.listenerManager())); | ||
} | ||
|
||
for (const auto& stats_sink : bootstrap.stats_sinks()) { | ||
// TODO(mrice32): Add support for pluggable stats sinks. | ||
ASSERT(stats_sink.name() == "envoy.statsd"); | ||
envoy::api::v2::StatsdSink statsd_sink; | ||
MessageUtil::jsonConvert(stats_sink.config(), statsd_sink); | ||
|
||
switch (statsd_sink.statsd_specifier_case()) { | ||
case envoy::api::v2::StatsdSink::kAddress: { | ||
statsd_udp_ip_address_ = Network::Utility::fromProtoAddress(statsd_sink.address()); | ||
break; | ||
} | ||
case envoy::api::v2::StatsdSink::kTcpClusterName: | ||
statsd_tcp_cluster_name_.value(statsd_sink.tcp_cluster_name()); | ||
break; | ||
default: | ||
NOT_REACHED; | ||
} | ||
} | ||
|
||
stats_flush_interval_ = | ||
std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(bootstrap, stats_flush_interval, 5000)); | ||
|
||
|
@@ -95,6 +76,8 @@ void MainImpl::initialize(const envoy::api::v2::Bootstrap& bootstrap, Instance& | |
} else { | ||
ratelimit_client_factory_.reset(new RateLimit::NullFactoryImpl()); | ||
} | ||
|
||
initializeStatsSinks(bootstrap, server); | ||
} | ||
|
||
void MainImpl::initializeTracers(const envoy::api::v2::Tracing& configuration, Instance& server) { | ||
|
@@ -127,6 +110,32 @@ void MainImpl::initializeTracers(const envoy::api::v2::Tracing& configuration, I | |
} | ||
} | ||
|
||
void MainImpl::initializeStatsSinks(const envoy::api::v2::Bootstrap& bootstrap, Instance& server) { | ||
ENVOY_LOG(info, "loading stats sink configuration"); | ||
|
||
for (const envoy::api::v2::StatsSink& sink_object : bootstrap.stats_sinks()) { | ||
if (sink_object.name().empty()) { | ||
throw EnvoyException( | ||
"sink object does not have 'name' attribute to look up the implementation"); | ||
} | ||
|
||
if (!sink_object.has_config()) { | ||
throw EnvoyException( | ||
"sink object does not contain the 'config' object to configure the implementation"); | ||
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 an empty default config is legit, we could have some filters that don't require config. |
||
} | ||
|
||
ProtobufTypes::String name = sink_object.name(); | ||
StatsSinkFactory* factory = Registry::FactoryRegistry<StatsSinkFactory>::getFactory(name); | ||
if (factory != nullptr) { | ||
ProtobufTypes::MessagePtr message = factory->createEmptyConfigProto(); | ||
MessageUtil::jsonConvert(sink_object.config(), *message); | ||
stats_sinks_.emplace_back(factory->createStatsSink(*message, server, *cluster_manager_)); | ||
} else { | ||
throw EnvoyException(fmt::format("No Stats::Sink found for name: {}", name)); | ||
} | ||
} | ||
} | ||
|
||
InitialImpl::InitialImpl(const envoy::api::v2::Bootstrap& bootstrap) { | ||
const auto& admin = bootstrap.admin(); | ||
admin_.access_log_path_ = admin.access_log_path(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,6 +55,40 @@ class HttpTracerFactory { | |
virtual std::string name() PURE; | ||
}; | ||
|
||
/** | ||
* Implemented for each Stats::Sink and registered via Registry::registerFactory() or | ||
* the convenience class RegisterFactory. | ||
*/ | ||
class StatsSinkFactory { | ||
public: | ||
virtual ~StatsSinkFactory() {} | ||
|
||
/** | ||
* Create a particular Stats::Sink implementation. If the implementation is unable to produce a | ||
* Stats::Sink with the provided parameters, it should throw an EnvoyException in the case of | ||
* general error or a Json::Exception if the json configuration is erroneous. The returned | ||
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. Why 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. Oh, I see, this is copy+paste from https://github.com/lyft/envoy/blob/master/include/envoy/server/filter_config.h. In 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. Right, sorry, that was just a typo. Thought I removed it. |
||
* pointer should always be valid. | ||
* @param config supplies the custom proto configuration for the Stats::Sink | ||
* @param server supplies the server instance | ||
* @param cluster_manager supplies the cluster_manager instance | ||
*/ | ||
virtual Stats::SinkPtr createStatsSink(const Protobuf::Message& config, Instance& server, | ||
Upstream::ClusterManager& cluster_manager) PURE; | ||
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. Why is |
||
|
||
/** | ||
* @return ProtobufTypes::MessagePtr create empty config proto message for v2. The filter | ||
* config, which arrives in an opaque google.protobuf.Struct message, will be converted to | ||
* JSON and then parsed into this empty proto. | ||
*/ | ||
virtual ProtobufTypes::MessagePtr createEmptyConfigProto() PURE; | ||
|
||
/** | ||
* Returns the identifying name for a particular implementation of Stats::Sink produced by the | ||
* factory. | ||
*/ | ||
virtual std::string name() PURE; | ||
}; | ||
|
||
/** | ||
* Utilities for creating a filter chain for a network connection. | ||
*/ | ||
|
@@ -88,10 +122,7 @@ class MainImpl : Logger::Loggable<Logger::Id::config>, public Main { | |
Upstream::ClusterManager& clusterManager() override { return *cluster_manager_; } | ||
Tracing::HttpTracer& httpTracer() override { return *http_tracer_; } | ||
RateLimit::ClientFactory& rateLimitClientFactory() override { return *ratelimit_client_factory_; } | ||
Optional<std::string> statsdTcpClusterName() override { return statsd_tcp_cluster_name_; } | ||
Network::Address::InstanceConstSharedPtr statsdUdpIpAddress() override { | ||
return statsd_udp_ip_address_; | ||
} | ||
std::list<Stats::SinkPtr>& statsSinks() override { return stats_sinks_; } | ||
std::chrono::milliseconds statsFlushInterval() override { return stats_flush_interval_; } | ||
std::chrono::milliseconds wdMissTimeout() const override { return watchdog_miss_timeout_; } | ||
std::chrono::milliseconds wdMegaMissTimeout() const override { | ||
|
@@ -108,11 +139,12 @@ class MainImpl : Logger::Loggable<Logger::Id::config>, public Main { | |
*/ | ||
void initializeTracers(const envoy::api::v2::Tracing& configuration, Instance& server); | ||
|
||
void initializeStatsSinks(const envoy::api::v2::Bootstrap& bootstrap, Instance& server); | ||
|
||
std::unique_ptr<Upstream::ClusterManager> cluster_manager_; | ||
std::unique_ptr<LdsApi> lds_api_; | ||
Tracing::HttpTracerPtr http_tracer_; | ||
Optional<std::string> statsd_tcp_cluster_name_; | ||
Network::Address::InstanceConstSharedPtr statsd_udp_ip_address_; | ||
std::list<Stats::SinkPtr> stats_sinks_; | ||
RateLimit::ClientFactoryPtr ratelimit_client_factory_; | ||
std::chrono::milliseconds stats_flush_interval_; | ||
std::chrono::milliseconds watchdog_miss_timeout_; | ||
|
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.
Nit: Any header that is depended upon in
.{cc,h}
should be directly reflected in thedeps
in theBUILD
file. This avoids surprises when A depends on B providing C, but later on, B no longer depends on C. Since we lack tool automation for this in OSS, we don't really enforce it (I'm sure I'm guilty of many breaches of this), but best to try and shoot for it. Basically, you want IWYU (include what you use, i.e. have all include headers in a file directly for symbols that appear in the file) and thenBUILD
dep
pointing at libs providing the headers.