-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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 2 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,30 @@ | ||
licenses(["notice"]) # Apache 2 | ||
|
||
load( | ||
"//bazel:envoy_build_system.bzl", | ||
"envoy_cc_library", | ||
"envoy_package", | ||
) | ||
|
||
envoy_package() | ||
|
||
envoy_cc_library( | ||
name = "tcp_statsd_lib", | ||
srcs = ["tcp_statsd.cc"], | ||
hdrs = ["tcp_statsd.h"], | ||
deps = [ | ||
"//source/common/stats:statsd_lib", | ||
"//source/server:configuration_lib", | ||
], | ||
) | ||
|
||
envoy_cc_library( | ||
name = "udp_statsd_lib", | ||
srcs = ["udp_statsd.cc"], | ||
hdrs = ["udp_statsd.h"], | ||
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,36 @@ | ||
#include "server/config/stats/tcp_statsd.h" | ||
|
||
#include <string> | ||
|
||
#include "envoy/registry/registry.h" | ||
|
||
#include "common/stats/statsd.h" | ||
|
||
namespace Envoy { | ||
namespace Server { | ||
namespace Configuration { | ||
|
||
Stats::SinkPtr TcpStatsdSinkFactory::createStatsSink(const Json::Object& json_config, | ||
Server::Instance& server, | ||
Upstream::ClusterManager& cluster_manager) { | ||
if (json_config.hasObject("cluster_name")) { | ||
const std::string cluster_name = json_config.getString("cluster_name"); | ||
ENVOY_LOG(info, "statsd TCP cluster: {}", cluster_name); | ||
return Stats::SinkPtr(new Stats::Statsd::TcpStatsdSink( | ||
server.localInfo(), cluster_name, server.threadLocal(), cluster_manager, server.stats())); | ||
} | ||
|
||
throw EnvoyException( | ||
fmt::format("Didn't find cluster_name in the {} Stats::Sink config", name())); | ||
} | ||
|
||
std::string TcpStatsdSinkFactory::name() { return "statsd_tcp"; } | ||
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. Suggest using the reverse DNS scheme described in https://github.com/lyft/envoy-api/blob/master/README.md#principles for custom components. I think for builtins, we would use |
||
|
||
/** | ||
* Static registration for the tcp statsd sink. @see RegisterFactory. | ||
*/ | ||
static Registry::RegisterFactory<TcpStatsdSinkFactory, StatsSinkFactory> register_; | ||
|
||
} // namespace Configuration | ||
} // namespace Server | ||
} // namespace Envoy |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#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 TcpStatsdSinkFactory : Logger::Loggable<Logger::Id::config>, public StatsSinkFactory { | ||
public: | ||
// StatsSinkFactory | ||
Stats::SinkPtr createStatsSink(const Json::Object& json_config, Instance& server, | ||
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. Would prefer we go proto-only on this new feature, see what is being done in https://github.com/lyft/envoy/pull/1495/files. |
||
Upstream::ClusterManager& cluster_manager) override; | ||
|
||
std::string name() override; | ||
}; | ||
|
||
} // namespace Configuration | ||
} // namespace Server | ||
} // namespace Envoy |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#include "server/config/stats/udp_statsd.h" | ||
|
||
#include <string> | ||
|
||
#include "envoy/registry/registry.h" | ||
|
||
#include "common/network/address_impl.h" | ||
#include "common/stats/statsd.h" | ||
|
||
namespace Envoy { | ||
namespace Server { | ||
namespace Configuration { | ||
|
||
Stats::SinkPtr UdpStatsdSinkFactory::createStatsSink(const Json::Object& json_config, | ||
Server::Instance& server, | ||
Upstream::ClusterManager& cluster_manager) { | ||
UNREFERENCED_PARAMETER(cluster_manager); | ||
if (json_config.hasObject("local_port") && json_config.hasObject("ip_address")) { | ||
throw EnvoyException(fmt::format( | ||
"local_port and ip_address are mutually exclusive in the {} Stats::Sink config", name())); | ||
} | ||
|
||
if (json_config.hasObject("ip_address")) { | ||
const std::string udp_ip_address = json_config.getString("ip_address"); | ||
ENVOY_LOG(info, "statsd UDP ip address: {}", udp_ip_address); | ||
return Stats::SinkPtr(new Stats::Statsd::UdpStatsdSink( | ||
server.threadLocal(), Network::Utility::parseInternetAddressAndPort(udp_ip_address))); | ||
} else if (json_config.hasObject("local_port")) { | ||
const int64_t local_upd_port = json_config.getInteger("local_port"); | ||
// TODO(hennna): DEPRECATED - statsdUdpPort will be removed in 1.4.0. | ||
ENVOY_LOG(warn, "local_port has been DEPRECATED and will be removed in 1.4.0. " | ||
"Consider setting ip_address instead."); | ||
ENVOY_LOG(info, "statsd UDP port: {}", local_upd_port); | ||
Network::Address::InstanceConstSharedPtr address( | ||
new Network::Address::Ipv4Instance(local_upd_port)); | ||
return Stats::SinkPtr( | ||
new Stats::Statsd::UdpStatsdSink(server.threadLocal(), std::move(address))); | ||
} | ||
|
||
throw EnvoyException( | ||
fmt::format("Didn't find local_port or ip_address in the {} Stats::Sink config", name())); | ||
} | ||
|
||
std::string UdpStatsdSinkFactory::name() { return "statsd_udp"; } | ||
|
||
/** | ||
* Static registration for the udp statsd sink. @see RegisterFactory. | ||
*/ | ||
static Registry::RegisterFactory<UdpStatsdSinkFactory, StatsSinkFactory> register_; | ||
|
||
} // namespace Configuration | ||
} // namespace Server | ||
} // namespace Envoy |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
|
||
#include "envoy/server/instance.h" | ||
|
||
#include "server/configuration_impl.h" | ||
|
||
namespace Envoy { | ||
namespace Server { | ||
namespace Configuration { | ||
|
||
/** | ||
* Config registration for the udp statsd sink. @see StatsSinkFactory. | ||
*/ | ||
class UdpStatsdSinkFactory : Logger::Loggable<Logger::Id::config>, public StatsSinkFactory { | ||
public: | ||
// StatsSinkFactory | ||
Stats::SinkPtr createStatsSink(const Json::Object& json_config, Instance& server, | ||
Upstream::ClusterManager& cluster_manager) override; | ||
|
||
std::string name() override; | ||
}; | ||
|
||
} // namespace Configuration | ||
} // namespace Server | ||
} // namespace Envoy |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,24 +60,6 @@ void MainImpl::initialize(const Json::Object& json, const envoy::api::v2::Bootst | |
server.listenerManager())); | ||
} | ||
|
||
if (json.hasObject("statsd_local_udp_port") && json.hasObject("statsd_udp_ip_address")) { | ||
throw EnvoyException("statsd_local_udp_port and statsd_udp_ip_address " | ||
"are mutually exclusive."); | ||
} | ||
|
||
// TODO(hennna): DEPRECATED - statsd_local_udp_port will be removed in 1.4.0. | ||
if (json.hasObject("statsd_local_udp_port")) { | ||
statsd_udp_port_.value(json.getInteger("statsd_local_udp_port")); | ||
} | ||
|
||
if (json.hasObject("statsd_udp_ip_address")) { | ||
statsd_udp_ip_address_.value(json.getString("statsd_udp_ip_address")); | ||
} | ||
|
||
if (json.hasObject("statsd_tcp_cluster_name")) { | ||
statsd_tcp_cluster_name_.value(json.getString("statsd_tcp_cluster_name")); | ||
} | ||
|
||
stats_flush_interval_ = | ||
std::chrono::milliseconds(json.getInteger("stats_flush_interval_ms", 5000)); | ||
|
||
|
@@ -102,6 +84,8 @@ void MainImpl::initialize(const Json::Object& json, const envoy::api::v2::Bootst | |
} else { | ||
ratelimit_client_factory_.reset(new RateLimit::NullFactoryImpl()); | ||
} | ||
|
||
initializeStatsSinks(json, server); | ||
} | ||
|
||
void MainImpl::initializeTracers(const Json::Object& configuration, Instance& server) { | ||
|
@@ -141,6 +125,76 @@ void MainImpl::initializeTracers(const Json::Object& configuration, Instance& se | |
} | ||
} | ||
|
||
void MainImpl::initializeStatsSinks(const Json::Object& configuration, Instance& server) { | ||
ENVOY_LOG(info, "loading stats sink configuration"); | ||
|
||
// TODO(mrice32): DEPRECATED - statsd_local_udp_port, statsd_udp_ip_address, | ||
// statsd_tcp_cluster_name fields in the base json configuration will be moved to subobjects | ||
// inside the stats_sinks array for 1.5.0. | ||
if (configuration.hasObject("statsd_local_udp_port") && | ||
configuration.hasObject("statsd_udp_ip_address")) { | ||
throw EnvoyException("statsd_local_udp_port and statsd_udp_ip_address " | ||
"are mutually exclusive."); | ||
} | ||
|
||
std::vector<Json::ObjectSharedPtr> sinks = configuration.getObjectArray("stats_sinks", true); | ||
|
||
// Used to convert the deprecated statsd configuration into a json snippet for consumption by the | ||
// new sink config parsing logic. | ||
const std::string statsd_json = R"EOF( | ||
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. See the |
||
{{ | ||
"name": "{}", | ||
"config": {{ | ||
"{}": {} | ||
}} | ||
}} | ||
)EOF"; | ||
|
||
// TODO(hennna): DEPRECATED - statsd_local_udp_port will be removed in 1.4.0. | ||
if (configuration.hasObject("statsd_local_udp_port")) { | ||
Json::ObjectSharedPtr json_obj = Json::Factory::loadFromString( | ||
fmt::format(statsd_json, "statsd_udp", "local_port", | ||
configuration.getInteger("statsd_local_udp_port"))); | ||
sinks.emplace_back(std::move(json_obj)); | ||
} | ||
|
||
if (configuration.hasObject("statsd_udp_ip_address")) { | ||
Json::ObjectSharedPtr json_obj = Json::Factory::loadFromString( | ||
fmt::format(statsd_json, "statsd_udp", "ip_address", | ||
"\"" + configuration.getString("statsd_udp_ip_address") + "\"")); | ||
sinks.emplace_back(std::move(json_obj)); | ||
} | ||
|
||
if (configuration.hasObject("statsd_tcp_cluster_name")) { | ||
Json::ObjectSharedPtr json_obj = Json::Factory::loadFromString( | ||
fmt::format(statsd_json, "statsd_tcp", "cluster_name", | ||
"\"" + configuration.getString("statsd_tcp_cluster_name") + "\"")); | ||
sinks.emplace_back(std::move(json_obj)); | ||
} | ||
|
||
for (const auto& sink_object : sinks) { | ||
if (!sink_object->hasObject("name")) { | ||
throw EnvoyException( | ||
"sink object does not have 'name' attribute to look up the implementation"); | ||
} | ||
|
||
if (!sink_object->hasObject("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. |
||
} | ||
|
||
std::string name = sink_object->getString("name"); | ||
Json::ObjectSharedPtr sink_config = sink_object->getObject("config"); | ||
|
||
StatsSinkFactory* factory = Registry::FactoryRegistry<StatsSinkFactory>::getFactory(name); | ||
if (factory != nullptr) { | ||
stats_sinks_.emplace_back(factory->createStatsSink(*sink_config, server, *cluster_manager_)); | ||
} else { | ||
throw EnvoyException(fmt::format("No Stats::Sink found for name: {}", name)); | ||
} | ||
} | ||
} | ||
|
||
InitialImpl::InitialImpl(const Json::Object& json) { | ||
json.validateSchema(Json::Schema::TOP_LEVEL_CONFIG_SCHEMA); | ||
Json::ObjectSharedPtr admin = json.getObject("admin"); | ||
|
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 will be added support to the v2 bootstrap proto (https://github.com/lyft/envoy-api/blob/master/api/bootstrap.proto) to cover this functionality (as well as a bunch of stuff at the top-level) tomorrow. Do you think you want this feature in v1, or maybe it would make sense to make it v2 only?