Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/envoy/data/accesslog/v3/accesslog.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ enum AccessLogType {
NotSet = 0;
TcpUpstreamConnected = 1;
TcpPeriodic = 2;
TcpConnectionStart = 14;
TcpConnectionEnd = 3;
DownstreamStart = 4;
DownstreamPeriodic = 5;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ message TcpProxy {

// The path used with the POST method. The default path is ``/``. If this field is specified and
// :ref:`use_post field <envoy_v3_api_field_extensions.filters.network.tcp_proxy.v3.TcpProxy.TunnelingConfig.use_post>`
// is not set to true, the configuration will be rejected.
// is not set to ``true``, the configuration will be rejected.
string post_path = 5;

// Save response trailers to the downstream connection's filter state for consumption
Expand Down Expand Up @@ -206,9 +206,12 @@ message TcpProxy {
google.protobuf.Duration access_log_flush_interval = 1
[(validate.rules).duration = {gte {nanos: 1000000}}];

// If set to true, the access log is flushed when the TCP proxy successfully establishes a
// If set to ``true``, the access log is flushed when the TCP proxy successfully establishes a
// connection with the upstream. If the connection fails, the access log is not flushed.
bool flush_access_log_on_connected = 2;

// If set to ``true``, the access log is flushed when the TCP proxy accepts a connection.
bool flush_access_log_on_start = 3;
}

reserved 6;
Expand Down
3 changes: 3 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,8 @@ new_features:
change: |
Added ``%UPSTREAM_DETECTED_CLOSE_TYPE%`` and ``%DOWNSTREAM_DETECTED_CLOSE_TYPE%`` to expose the detected close type
of downstream and connections. The possible values are ``Normal``, ``LocalReset``, and ``RemoteReset``.
- area: tcp_proxy
change: |
Added an option to emit a log entry when the connection is accepted.

deprecated:
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,7 @@ Current supported substitution commands include:
* ``TcpUpstreamConnected`` - When TCP Proxy filter has successfully established an upstream connection.
* ``TcpPeriodic`` - On any TCP Proxy filter periodic log record.
* ``TcpConnectionEnd`` - When a TCP connection is ended on TCP Proxy filter.
* ``TcpConnectionStart`` - When a TCP connection is accepted by the TCP Proxy filter.
* ``DownstreamStart`` - When HTTP Connection Manager filter receives a new HTTP request.
* ``DownstreamTunnelSuccessfullyEstablished`` - When the HTTP Connection Manager sends response headers indicating a successful HTTP tunnel.
* ``DownstreamPeriodic`` - On any HTTP Connection Manager periodic log record.
Expand Down
6 changes: 5 additions & 1 deletion source/common/tcp_proxy/tcp_proxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ Config::SharedConfig::SharedConfig(
const envoy::extensions::filters::network::tcp_proxy::v3::TcpProxy& config,
Server::Configuration::FactoryContext& context)
: stats_scope_(context.scope().createScope(fmt::format("tcp.{}", config.stat_prefix()))),
stats_(generateStats(*stats_scope_)) {
stats_(generateStats(*stats_scope_)),
flush_access_log_on_start_(config.access_log_options().flush_access_log_on_start()) {
if (config.has_idle_timeout()) {
const uint64_t timeout = DurationUtil::durationToMilliseconds(config.idle_timeout());
if (timeout > 0) {
Expand Down Expand Up @@ -1071,6 +1072,9 @@ Network::FilterStatus Filter::onNewConnection() {
// Set UUID for the connection. This is used for logging and tracing.
getStreamInfo().setStreamIdProvider(
std::make_shared<StreamInfo::StreamIdProviderImpl>(config_->randomGenerator().uuid()));
if (config_->flushAccessLogOnStart()) {
flushAccessLog(AccessLog::AccessLogType::TcpConnectionStart);
}

ASSERT(upstream_ == nullptr);

Expand Down
5 changes: 4 additions & 1 deletion source/common/tcp_proxy/tcp_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ class Config {
const TcpProxyStats& stats() { return stats_; }
const absl::optional<std::chrono::milliseconds>& idleTimeout() { return idle_timeout_; }
bool flushAccessLogOnConnected() const { return flush_access_log_on_connected_; }
bool flushAccessLogOnStart() const { return flush_access_log_on_start_; }
const absl::optional<std::chrono::milliseconds>& maxDownstreamConnectionDuration() const {
return max_downstream_connection_duration_;
}
Expand Down Expand Up @@ -287,7 +288,8 @@ class Config {
const Stats::ScopeSharedPtr stats_scope_;

const TcpProxyStats stats_;
bool flush_access_log_on_connected_;
bool flush_access_log_on_connected_ : 1;
const bool flush_access_log_on_start_ : 1;
absl::optional<std::chrono::milliseconds> idle_timeout_;
absl::optional<std::chrono::milliseconds> max_downstream_connection_duration_;
absl::optional<double> max_downstream_connection_duration_jitter_percentage_;
Expand Down Expand Up @@ -355,6 +357,7 @@ class Config {
const OnDemandStats& onDemandStats() const { return shared_config_->onDemandConfig()->stats(); }
Random::RandomGenerator& randomGenerator() { return random_generator_; }
bool flushAccessLogOnConnected() const { return shared_config_->flushAccessLogOnConnected(); }
bool flushAccessLogOnStart() const { return shared_config_->flushAccessLogOnStart(); }
Regex::Engine& regexEngine() const { return regex_engine_; }
const BackOffStrategyPtr& backoffStrategy() const { return shared_config_->backoffStrategy(); };
const Network::ProxyProtocolTLVVector& proxyProtocolTLVs() const {
Expand Down
26 changes: 26 additions & 0 deletions test/common/tcp_proxy/config_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,32 @@ TEST(ConfigTest, FlushAccessLogOnConnected) {
}
}

TEST(ConfigTest, FlushAccessLogOnStart) {
NiceMock<Server::Configuration::MockFactoryContext> factory_context;

{
const std::string yaml = R"EOF(
stat_prefix: name
cluster: foo
)EOF";

Config config_obj(constructConfigFromYaml(yaml, factory_context));
EXPECT_FALSE(config_obj.sharedConfig()->flushAccessLogOnStart());
}

{
const std::string yaml = R"EOF(
stat_prefix: name
cluster: foo
access_log_options:
flush_access_log_on_start: true
)EOF";

Config config_obj(constructConfigFromYaml(yaml, factory_context));
EXPECT_TRUE(config_obj.sharedConfig()->flushAccessLogOnStart());
}
}

TEST(ConfigTest, DEPRECATED_FEATURE_TEST(DeprecatedFlushAccessLogOnConnected)) {
NiceMock<Server::Configuration::MockFactoryContext> factory_context;

Expand Down
37 changes: 37 additions & 0 deletions test/integration/tcp_proxy_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,43 @@ TEST_P(TcpProxyIntegrationTest, AccessLogOnUpstreamConnect) {
EXPECT_GT(upstream_connection_id, 0);
}

TEST_P(TcpProxyIntegrationTest, AccessLogOnStart) {
std::string access_log_path = TestEnvironment::temporaryPath(
fmt::format("access_log{}{}.txt", version_ == Network::Address::IpVersion::v4 ? "v4" : "v6",
TestUtility::uniqueFilename()));

setupByteMeterAccessLog();
config_helper_.addConfigModifier([&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void {
auto* listener = bootstrap.mutable_static_resources()->mutable_listeners(0);
auto* filter_chain = listener->mutable_filter_chains(0);
auto* config_blob = filter_chain->mutable_filters(0)->mutable_typed_config();

ASSERT_TRUE(config_blob->Is<envoy::extensions::filters::network::tcp_proxy::v3::TcpProxy>());
auto tcp_proxy_config =
MessageUtil::anyConvert<envoy::extensions::filters::network::tcp_proxy::v3::TcpProxy>(
*config_blob);

tcp_proxy_config.mutable_access_log_options()->set_flush_access_log_on_start(true);
auto* access_log = tcp_proxy_config.add_access_log();
access_log->set_name("accesslog");
envoy::extensions::access_loggers::file::v3::FileAccessLog access_log_config;
access_log_config.set_path(access_log_path);
access_log_config.mutable_log_format()->mutable_text_format_source()->set_inline_string(
"%ACCESS_LOG_TYPE%\n");
access_log->mutable_typed_config()->PackFrom(access_log_config);
config_blob->PackFrom(tcp_proxy_config);
});

initialize();
auto tcp_client = makeTcpConnection(lookupPort("tcp_proxy"));
auto log_result = waitForAccessLog(access_log_path);
EXPECT_EQ(AccessLogType_Name(AccessLog::AccessLogType::TcpConnectionStart), log_result);
FakeRawConnectionPtr fake_upstream_connection;
ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection));
tcp_client->close();
ASSERT_TRUE(fake_upstream_connection->close());
}

TEST_P(TcpProxyIntegrationTest, PeriodicAccessLog) {
std::string access_log_path = TestEnvironment::temporaryPath(
fmt::format("access_log{}{}.txt", version_ == Network::Address::IpVersion::v4 ? "v4" : "v6",
Expand Down
Loading