diff --git a/include/istio/control/http/report_data.h b/include/istio/control/http/report_data.h index 11b1e7e9f59..7b4968200da 100644 --- a/include/istio/control/http/report_data.h +++ b/include/istio/control/http/report_data.h @@ -63,6 +63,10 @@ class ReportData { std::string message; }; virtual bool GetGrpcStatus(GrpcStatus* status) const = 0; + + // Get dynamic metadata generated by Envoy filters. + // Useful for logging info generated by custom codecs. + virtual bool GetDynamicFilterState(std::string* filter_state) const = 0; }; } // namespace http diff --git a/include/istio/control/tcp/report_data.h b/include/istio/control/tcp/report_data.h index 7535b5904ba..b8d2bc02e31 100644 --- a/include/istio/control/tcp/report_data.h +++ b/include/istio/control/tcp/report_data.h @@ -50,6 +50,10 @@ class ReportData { CLOSE, CONTINUE, }; + + // Get dynamic metadata generated by Envoy filters. + // Useful for logging info generated by custom codecs. + virtual bool GetDynamicFilterState(std::string* filter_state) const = 0; }; } // namespace tcp diff --git a/include/istio/utils/attribute_names.h b/include/istio/utils/attribute_names.h index c355e8d843e..4cc8b8cc336 100644 --- a/include/istio/utils/attribute_names.h +++ b/include/istio/utils/attribute_names.h @@ -47,6 +47,9 @@ struct AttributeName { static const char kRequestUserAgent[]; static const char kRequestApiKey[]; + // Dynamic state generated by various envoy http filters + static const char kRequestDynamicState[]; + static const char kResponseCode[]; static const char kResponseDuration[]; static const char kResponseHeaders[]; @@ -77,6 +80,9 @@ struct AttributeName { // Record TCP connection status: open, continue, close static const char kConnectionEvent[]; + // Dynamic state generated by various envoy network filters + static const char kConnectionDynamicState[]; + // Context attributes static const char kContextProtocol[]; static const char kContextReporterKind[]; diff --git a/src/envoy/http/mixer/report_data.h b/src/envoy/http/mixer/report_data.h index 161316a4e02..338e188fbfb 100644 --- a/src/envoy/http/mixer/report_data.h +++ b/src/envoy/http/mixer/report_data.h @@ -156,6 +156,15 @@ class ReportData : public ::istio::control::http::ReportData, return !report_info->permissive_resp_code.empty() || !report_info->permissive_policy_id.empty(); } + + // Get attributes generated by http filters + bool GetDynamicFilterState(std::string *filter_state) const override { + if (info_.dynamicMetadata().filter_metadata_size() > 0) { + info_.dynamicMetadata().SerializeToString(filter_state); + return true; + } + return false; + } }; } // namespace Mixer diff --git a/src/envoy/tcp/mixer/filter.cc b/src/envoy/tcp/mixer/filter.cc index 105db9d19b6..dee47a00982 100644 --- a/src/envoy/tcp/mixer/filter.cc +++ b/src/envoy/tcp/mixer/filter.cc @@ -24,7 +24,7 @@ namespace Envoy { namespace Tcp { namespace Mixer { -Filter::Filter(Control& control) : control_(control) { +Filter::Filter(Control &control) : control_(control) { ENVOY_LOG(debug, "Called tcp filter: {}", __func__); } @@ -34,7 +34,7 @@ Filter::~Filter() { } void Filter::initializeReadFilterCallbacks( - Network::ReadFilterCallbacks& callbacks) { + Network::ReadFilterCallbacks &callbacks) { ENVOY_LOG(debug, "Called tcp filter: {}", __func__); filter_callbacks_ = &callbacks; filter_callbacks_->connection().addConnectionCallbacks(*this); @@ -60,14 +60,14 @@ void Filter::callCheck() { state_ = State::Calling; filter_callbacks_->connection().readDisable(true); calling_check_ = true; - cancel_check_ = handler_->Check(this, [this](const CheckResponseInfo& info) { + cancel_check_ = handler_->Check(this, [this](const CheckResponseInfo &info) { completeCheck(info.response_status); }); calling_check_ = false; } // Network::ReadFilter -Network::FilterStatus Filter::onData(Buffer::Instance& data, bool) { +Network::FilterStatus Filter::onData(Buffer::Instance &data, bool) { if (state_ == State::NotStarted) { // By waiting to invoke the callCheck() at onData(), the call to Mixer // will have sufficient SSL information to fill the check Request. @@ -83,7 +83,7 @@ Network::FilterStatus Filter::onData(Buffer::Instance& data, bool) { } // Network::WriteFilter -Network::FilterStatus Filter::onWrite(Buffer::Instance& data, bool) { +Network::FilterStatus Filter::onWrite(Buffer::Instance &data, bool) { ENVOY_CONN_LOG(debug, "Called tcp filter onWrite bytes: {}", filter_callbacks_->connection(), data.length()); send_bytes_ += data.length(); @@ -101,7 +101,7 @@ Network::FilterStatus Filter::onNewConnection() { return Network::FilterStatus::Continue; } -void Filter::completeCheck(const Status& status) { +void Filter::completeCheck(const Status &status) { ENVOY_LOG(debug, "Called tcp filter completeCheck: {}", status.ToString()); cancel_check_ = nullptr; if (state_ == State::Closed) { @@ -146,11 +146,11 @@ void Filter::onEvent(Network::ConnectionEvent event) { } } -bool Filter::GetSourceIpPort(std::string* str_ip, int* port) const { +bool Filter::GetSourceIpPort(std::string *str_ip, int *port) const { return Utils::GetIpPort(filter_callbacks_->connection().remoteAddress()->ip(), str_ip, port); } -bool Filter::GetPrincipal(bool peer, std::string* user) const { +bool Filter::GetPrincipal(bool peer, std::string *user) const { return Utils::GetPrincipal(&filter_callbacks_->connection(), peer, user); } @@ -158,11 +158,11 @@ bool Filter::IsMutualTLS() const { return Utils::IsMutualTLS(&filter_callbacks_->connection()); } -bool Filter::GetRequestedServerName(std::string* name) const { +bool Filter::GetRequestedServerName(std::string *name) const { return Utils::GetRequestedServerName(&filter_callbacks_->connection(), name); } -bool Filter::GetDestinationIpPort(std::string* str_ip, int* port) const { +bool Filter::GetDestinationIpPort(std::string *str_ip, int *port) const { if (filter_callbacks_->upstreamHost() && filter_callbacks_->upstreamHost()->address()) { return Utils::GetIpPort(filter_callbacks_->upstreamHost()->address()->ip(), @@ -170,15 +170,29 @@ bool Filter::GetDestinationIpPort(std::string* str_ip, int* port) const { } return false; } -bool Filter::GetDestinationUID(std::string* uid) const { +bool Filter::GetDestinationUID(std::string *uid) const { if (filter_callbacks_->upstreamHost()) { return Utils::GetDestinationUID( *filter_callbacks_->upstreamHost()->metadata(), uid); } return false; } +bool Filter::GetDynamicFilterState(std::string *filter_state) const { + if (filter_callbacks_->connection() + .streamInfo() + .dynamicMetadata() + .filter_metadata_size() > 0) { + filter_callbacks_->connection() + .streamInfo() + .dynamicMetadata() + .SerializeToString(filter_state); + return true; + } + + return false; +} void Filter::GetReportInfo( - ::istio::control::tcp::ReportData::ReportInfo* data) const { + ::istio::control::tcp::ReportData::ReportInfo *data) const { data->received_bytes = received_bytes_; data->send_bytes = send_bytes_; data->duration = std::chrono::duration_cast( diff --git a/src/envoy/tcp/mixer/filter.h b/src/envoy/tcp/mixer/filter.h index a06daa9f852..c897e038d49 100644 --- a/src/envoy/tcp/mixer/filter.h +++ b/src/envoy/tcp/mixer/filter.h @@ -58,6 +58,7 @@ class Filter : public Network::Filter, // ReportData virtual functions. bool GetDestinationIpPort(std::string* str_ip, int* port) const override; bool GetDestinationUID(std::string* uid) const override; + bool GetDynamicFilterState(std::string* filter_state) const override; void GetReportInfo( ::istio::control::tcp::ReportData::ReportInfo* data) const override; std::string GetConnectionId() const override; diff --git a/src/istio/control/http/attributes_builder.cc b/src/istio/control/http/attributes_builder.cc index 2c0babcbabf..fce41d3a480 100644 --- a/src/istio/control/http/attributes_builder.cc +++ b/src/istio/control/http/attributes_builder.cc @@ -252,6 +252,11 @@ void AttributesBuilder::ExtractReportAttributes(ReportData *report_data) { rbac_info.permissive_policy_id); } } + + std::string filter_state; + if (report_data->GetDynamicFilterState(&filter_state)) { + builder.AddBytes(utils::AttributeName::kRequestDynamicState, filter_state); + } } } // namespace http diff --git a/src/istio/control/http/attributes_builder_test.cc b/src/istio/control/http/attributes_builder_test.cc index f14c32cb98d..a0ceaa58f5b 100644 --- a/src/istio/control/http/attributes_builder_test.cc +++ b/src/istio/control/http/attributes_builder_test.cc @@ -406,6 +406,12 @@ attributes { string_value: "policy-foo" } } +attributes { + key: "request.dynamic_state" + value { + bytes_value: "aeiou" + } +} )"; constexpr char kAuthenticationResultStruct[] = R"( @@ -750,6 +756,11 @@ TEST(AttributesBuilderTest, TestReportAttributes) { report_info->permissive_policy_id = "policy-foo"; return true; })); + EXPECT_CALL(mock_data, GetDynamicFilterState(_)) + .WillOnce(Invoke([](std::string *dynamic_state) -> bool { + *dynamic_state = "aeiou"; + return true; + })); RequestContext request; AttributesBuilder builder(&request); @@ -805,6 +816,11 @@ TEST(AttributesBuilderTest, TestReportAttributesWithDestIP) { report_info->permissive_policy_id = "policy-foo"; return true; })); + EXPECT_CALL(mock_data, GetDynamicFilterState(_)) + .WillOnce(Invoke([](std::string *dynamic_state) -> bool { + *dynamic_state = "aeiou"; + return true; + })); RequestContext request; SetDestinationIp(&request, "1.2.3.4"); diff --git a/src/istio/control/http/mock_report_data.h b/src/istio/control/http/mock_report_data.h index 423a1b6ef4f..580a1c4d074 100644 --- a/src/istio/control/http/mock_report_data.h +++ b/src/istio/control/http/mock_report_data.h @@ -32,6 +32,7 @@ class MockReportData : public ReportData { MOCK_CONST_METHOD1(GetDestinationUID, bool(std::string* ip)); MOCK_CONST_METHOD1(GetGrpcStatus, bool(GrpcStatus* status)); MOCK_CONST_METHOD1(GetRbacReportInfo, bool(RbacReportInfo* info)); + MOCK_CONST_METHOD1(GetDynamicFilterState, bool(std::string* filter_state)); }; } // namespace http diff --git a/src/istio/control/tcp/attributes_builder.cc b/src/istio/control/tcp/attributes_builder.cc index 47e2dfa2c9c..d523e605f0c 100644 --- a/src/istio/control/tcp/attributes_builder.cc +++ b/src/istio/control/tcp/attributes_builder.cc @@ -29,7 +29,7 @@ const std::string kConnectionContinue("continue"); const std::string kConnectionClose("close"); } // namespace -void AttributesBuilder::ExtractCheckAttributes(CheckData* check_data) { +void AttributesBuilder::ExtractCheckAttributes(CheckData *check_data) { utils::AttributesBuilder builder(request_->attributes); std::string source_ip; @@ -81,8 +81,8 @@ void AttributesBuilder::ExtractCheckAttributes(CheckData* check_data) { } void AttributesBuilder::ExtractReportAttributes( - ReportData* report_data, ReportData::ConnectionEvent event, - ReportData::ReportInfo* last_report_info) { + ReportData *report_data, ReportData::ConnectionEvent event, + ReportData::ReportInfo *last_report_info) { utils::AttributesBuilder builder(request_->attributes); ReportData::ReportInfo info; @@ -132,6 +132,12 @@ void AttributesBuilder::ExtractReportAttributes( builder.AddString(utils::AttributeName::kDestinationUID, uid); } + std::string filter_state; + if (report_data->GetDynamicFilterState(&filter_state)) { + builder.AddBytes(utils::AttributeName::kConnectionDynamicState, + filter_state); + } + builder.AddTimestamp(utils::AttributeName::kContextTime, std::chrono::system_clock::now()); } diff --git a/src/istio/control/tcp/attributes_builder_test.cc b/src/istio/control/tcp/attributes_builder_test.cc index 1ce0afe0aa5..02c96306fb4 100644 --- a/src/istio/control/tcp/attributes_builder_test.cc +++ b/src/istio/control/tcp/attributes_builder_test.cc @@ -162,6 +162,12 @@ attributes { string_value: "pod1.ns2" } } +attributes { + key: "connection.dynamic_state" + value { + bytes_value: "aeiou" + } +} )"; const char kReportAttributes[] = R"( @@ -240,6 +246,12 @@ attributes { string_value: "pod1.ns2" } } +attributes { + key: "connection.dynamic_state" + value { + bytes_value: "aeiou" + } +} )"; const char kDeltaOneReportAttributes[] = R"( @@ -298,6 +310,12 @@ attributes { string_value: "pod1.ns2" } } +attributes { + key: "connection.dynamic_state" + value { + bytes_value: "aeiou" + } +} )"; const char kDeltaTwoReportAttributes[] = R"( @@ -356,6 +374,12 @@ attributes { string_value: "pod1.ns2" } } +attributes { + key: "connection.dynamic_state" + value { + bytes_value: "aeiou" + } +} )"; void ClearContextTime(RequestContext* request) { @@ -423,6 +447,12 @@ TEST(AttributesBuilderTest, TestReportAttributes) { *uid = "pod1.ns2"; return true; })); + EXPECT_CALL(mock_data, GetDynamicFilterState(_)) + .Times(4) + .WillRepeatedly(Invoke([](std::string* dynamic_state) -> bool { + *dynamic_state = "aeiou"; + return true; + })); EXPECT_CALL(mock_data, GetReportInfo(_)) .Times(4) .WillOnce(Invoke([](ReportData::ReportInfo* info) { diff --git a/src/istio/control/tcp/mock_report_data.h b/src/istio/control/tcp/mock_report_data.h index 65c18492c82..1631cebfae6 100644 --- a/src/istio/control/tcp/mock_report_data.h +++ b/src/istio/control/tcp/mock_report_data.h @@ -28,6 +28,7 @@ class MockReportData : public ReportData { public: MOCK_CONST_METHOD2(GetDestinationIpPort, bool(std::string* ip, int* port)); MOCK_CONST_METHOD1(GetDestinationUID, bool(std::string*)); + MOCK_CONST_METHOD1(GetDynamicFilterState, bool(std::string*)); MOCK_CONST_METHOD1(GetReportInfo, void(ReportInfo* info)); }; diff --git a/src/istio/utils/attribute_names.cc b/src/istio/utils/attribute_names.cc index 392bc1c45ef..86c04960814 100644 --- a/src/istio/utils/attribute_names.cc +++ b/src/istio/utils/attribute_names.cc @@ -39,6 +39,9 @@ const char AttributeName::kRequestTime[] = "request.time"; const char AttributeName::kRequestUserAgent[] = "request.useragent"; const char AttributeName::kRequestApiKey[] = "request.api_key"; +// Dynamic state generated by various envoy http filters +const char AttributeName::kRequestDynamicState[] = "request.dynamic_state"; + const char AttributeName::kResponseCode[] = "response.code"; const char AttributeName::kResponseDuration[] = "response.duration"; const char AttributeName::kResponseHeaders[] = "response.headers"; @@ -72,6 +75,10 @@ const char AttributeName::kConnectionRequestedServerName[] = const char AttributeName::kConnectionId[] = "connection.id"; const char AttributeName::kConnectionEvent[] = "connection.event"; +// Dynamic state generated by various envoy network filters +const char AttributeName::kConnectionDynamicState[] = + "connection.dynamic_state"; + // Context attributes const char AttributeName::kContextProtocol[] = "context.protocol"; const char AttributeName::kContextReporterKind[] = "context.reporter.kind";