Made stats sinks a statically registered component#1506
Made stats sinks a statically registered component#1506htuch merged 7 commits intoenvoyproxy:masterfrom
Conversation
htuch
left a comment
There was a problem hiding this comment.
Thanks for adding this. I'm wondering if we want to go straight to v2 though, we're basically ready to do this now by adding these fields into the bootstrap proto.
| "statsd_udp_ip_address" : {"type" : "string"}, | ||
| "statsd_tcp_cluster_name" : {"type" : "string"}, | ||
| "stats_flush_interval_ms" : {"type" : "integer"}, | ||
| "stats_sinks" : { |
There was a problem hiding this comment.
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?
| 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.
Would prefer we go proto-only on this new feature, see what is being done in https://github.com/lyft/envoy/pull/1495/files.
|
|
||
| // 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.
See the translate*() conversion functions in source/common/config/*_json.cc for the stylized way we are mapping from v1 JSON to v2 proto.
| 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.
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 envoy.statsd_tcp, since I've been using the envoy. prefix other places in v2 for builtins.
|
That makes sense. Let's go straight to v2 with this. |
|
It was intended to be a 1.5.0 deprecation, and there's no rush on getting it merged, so we can definitely wait til next week to keep it from complicating the 1.4.0 release. |
|
OK perfect thank you. |
|
@mrice32 can you merge master, then we can get this in. |
|
I think we should wait on #1521 to get merged. Otherwise, we'll have to reimplement the stats portion of the json -> proto conversion from that PR in this one. If you'd like we can close this for now and reopen once that gets merged. |
|
OK sounds good. I will review #1521. |
|
Merged and should be ready for review. |
|
|
||
| #include <string> | ||
|
|
||
| #include "envoy/registry/registry.h" |
There was a problem hiding this comment.
Nit: Any header that is depended upon in .{cc,h} should be directly reflected in the deps in the BUILD 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 then BUILD dep pointing at libs providing the headers.
|
|
||
| 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.
I think an empty default config is legit, we could have some filters that don't require config.
|
|
||
| /** | ||
| * 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 |
There was a problem hiding this comment.
Why Json::Exception? This is a pure v2 feature, we shouldn't have RapidJSON involved as we're working in proto land here. The only JSON conversion is performed by the protobuf library that won't create these types of exceptions.
There was a problem hiding this comment.
Oh, I see, this is copy+paste from https://github.com/lyft/envoy/blob/master/include/envoy/server/filter_config.h. In filter_config.h, the JSON stuff doesn't apply to the ...FromProto() variants.
There was a problem hiding this comment.
Right, sorry, that was just a typo. Thought I removed it.
| * @param server supplies the server instance | ||
| * @param cluster_manager supplies the cluster_manager instance | ||
| */ | ||
| virtual Stats::SinkPtr createStatsSink(const Protobuf::Message& config, Instance& server, |
There was a problem hiding this comment.
Why is ClusterManager a distinct parameter here? I think it can be inferred from the Server::Instance parameter?
| using testing::NiceMock; | ||
| using testing::Return; | ||
| using testing::ReturnRef; | ||
| using testing::_; |
There was a problem hiding this comment.
Nit: place outside the namespace block as per Envoy convention.
There was a problem hiding this comment.
There are a few other tests (including the one I modeled after) that put it inside the Envoy namespace block. Should I go ahead and update those as well?
| TEST(StatsConfigTest, ValidTcpStatsd) { | ||
| const std::string name = "envoy.statsd"; | ||
| Protobuf::Struct config; | ||
| ProtobufWkt::Map<ProtobufTypes::String, ProtobufWkt::Value>& field_map = *config.mutable_fields(); |
There was a problem hiding this comment.
Prefer using auto here and elsewhere for proto handlers, the extra noise of the complex types doesn't help readability.
| EXPECT_THROW(factory->createStatsSink(*message, server, server.clusterManager()), EnvoyException); | ||
| } | ||
|
|
||
| } // namespace Configuration |
There was a problem hiding this comment.
There's probably a few of the throw EnvoyException cases that don't have coverage in this file. Can you add?
|
Responded to comments. Added tests for other throw cases in the tests for |
| *address_field_map["socket_address"].mutable_struct_value()->mutable_fields(); | ||
| socket_address_field_map["protocol"].set_string_value("UDP"); | ||
| socket_address_field_map["address"].set_string_value("127.0.0.1"); | ||
| socket_address_field_map["port_value"].set_number_value(8125); |
There was a problem hiding this comment.
Why not build a typed envoy::api::v2::Address and the JsonConvert() it to the Struct? Seems a bit more robust.
There was a problem hiding this comment.
Yeah, I had an internal debate about which one was a better way to go about testing it. In hindsight, since we're moving to a protobuf specified bootstrap config, I think your suggestion makes sense. I'll update.
| EXPECT_NE(dynamic_cast<Stats::Statsd::UdpStatsdSink*>(sink.get()), nullptr); | ||
| } | ||
|
|
||
| TEST(StatsConfigTest, EmptyConfig) { |
There was a problem hiding this comment.
I thought you removed the empty config exception above, how come this still throws?
There was a problem hiding this comment.
Because an empty config is invalid for that particular sink (statsd). I can add an expected throw message to clarify.
There was a problem hiding this comment.
These tests are not calling into the ConfigurationImpl object. They are meant to test the configuration of specific instances of stats sinks rather than the general configuration mechanism in ConfigurationImpl.
|
Hmmm, |
|
@mrice32 that's a known flake/failure. |
mattklein123
left a comment
There was a problem hiding this comment.
Nice. Thanks for fixing all the namespace stuff!
Description: This PR modifies the build recipe for `envoy_engine.so` to hide all symbols except for `_PyInit_envoy_engine` by default on maOS, so that envoy_engine can be loaded alongside a [protobuf](http://pypi.org/project/protobuf) wheel without breaking. Loading in protobuf alongside `envoy_engine.so` would register two sets of the same symbols and, on macOS, the runtime linker chooses the first symbol it finds causing problems. See the [similar protobuf change](protocolbuffers/protobuf#8346) and its [sister change in grpc](grpc/grpc#24992) for more information on what's going on. Risk Level: Low Testing: See the now-closed #1504 for how I've been testing this. Docs Changes: N/A Release Notes: N/A Signed-off-by: Cerek Hillen <chillen@lyft.com> Signed-off-by: JP Simard <jp@jpsim.com>
Description: This PR modifies the build recipe for `envoy_engine.so` to hide all symbols except for `_PyInit_envoy_engine` by default on maOS, so that envoy_engine can be loaded alongside a [protobuf](http://pypi.org/project/protobuf) wheel without breaking. Loading in protobuf alongside `envoy_engine.so` would register two sets of the same symbols and, on macOS, the runtime linker chooses the first symbol it finds causing problems. See the [similar protobuf change](protocolbuffers/protobuf#8346) and its [sister change in grpc](grpc/grpc#24992) for more information on what's going on. Risk Level: Low Testing: See the now-closed #1504 for how I've been testing this. Docs Changes: N/A Release Notes: N/A Signed-off-by: Cerek Hillen <chillen@lyft.com> Signed-off-by: JP Simard <jp@jpsim.com>
This is part of a larger effort to make various implementations more flexible by allowing proprietary components to be statically registered with Envoy needing only to be linked to the binary at build time and configured at runtime #967 .
The user-visible configuration changes do involve a few deprecations:
statsd_udp_ip_addressandstatsd_tcp_cluster_namewill be deprecated, and their equivalents will be moved to a newstats_sinksarray where the configurations for any statically registered sink will exist. As a part of this change, all integration tests were moved to the new configuration format, but a new configuration test was added to ensure that the deprecated format continues to work until it is removed in 1.5.0.