Skip to content

Commit

Permalink
access_logs: extract commands parsing to a separate method (envoyprox…
Browse files Browse the repository at this point in the history
…y#32944)

* extract commands parsing to a separate method

Signed-off-by: ohadvano <[email protected]>

* fix format

Signed-off-by: ohadvano <[email protected]>

---------

Signed-off-by: ohadvano <[email protected]>
  • Loading branch information
ohadvano authored Mar 19, 2024
1 parent d3c90ed commit 1b768b4
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 8 deletions.
31 changes: 23 additions & 8 deletions source/common/formatter/substitution_format_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,18 @@ namespace Formatter {
*/
class SubstitutionFormatStringUtils {
public:
using FormattersConfig =
ProtobufWkt::RepeatedPtrField<envoy::config::core::v3::TypedExtensionConfig>;

/**
* Generate a formatter object from config SubstitutionFormatString.
* Parse list of formatter configurations to commands.
*/
template <class FormatterContext = HttpFormatterContext>
static FormatterBasePtr<FormatterContext>
fromProtoConfig(const envoy::config::core::v3::SubstitutionFormatString& config,
static std::vector<CommandParserBasePtr<FormatterContext>>
parseFormatters(const FormattersConfig& formatters,
Server::Configuration::GenericFactoryContext& context) {
// Instantiate formatter extensions.
std::vector<CommandParserBasePtr<FormatterContext>> commands;
for (const auto& formatter : config.formatters()) {
for (const auto& formatter : formatters) {
auto* factory =
Envoy::Config::Utility::getFactory<CommandParserFactoryBase<FormatterContext>>(formatter);
if (!factory) {
Expand All @@ -47,12 +49,24 @@ class SubstitutionFormatStringUtils {
commands.push_back(std::move(parser));
}

return commands;
}

/**
* Generate a formatter object from config SubstitutionFormatString.
*/
template <class FormatterContext = HttpFormatterContext>
static FormatterBasePtr<FormatterContext>
fromProtoConfig(const envoy::config::core::v3::SubstitutionFormatString& config,
Server::Configuration::GenericFactoryContext& context) {
// Instantiate formatter extensions.
auto commands = parseFormatters<FormatterContext>(config.formatters(), context);
switch (config.format_case()) {
case envoy::config::core::v3::SubstitutionFormatString::FormatCase::kTextFormat:
return std::make_unique<FormatterBaseImpl<FormatterContext>>(
config.text_format(), config.omit_empty_values(), commands);
case envoy::config::core::v3::SubstitutionFormatString::FormatCase::kJsonFormat:
return std::make_unique<JsonFormatterBaseImpl<FormatterContext>>(
return createJsonFormatter<FormatterContext>(
config.json_format(), true, config.omit_empty_values(),
config.has_json_format_options() ? config.json_format_options().sort_properties() : false,
commands);
Expand All @@ -75,9 +89,10 @@ class SubstitutionFormatStringUtils {
template <class FormatterContext = HttpFormatterContext>
static FormatterBasePtr<FormatterContext>
createJsonFormatter(const ProtobufWkt::Struct& struct_format, bool preserve_types,
bool omit_empty_values, bool sort_properties) {
bool omit_empty_values, bool sort_properties,
const std::vector<CommandParserBasePtr<FormatterContext>>& commands = {}) {
return std::make_unique<JsonFormatterBaseImpl<FormatterContext>>(
struct_format, preserve_types, omit_empty_values, sort_properties);
struct_format, preserve_types, omit_empty_values, sort_properties, commands);
}
};

Expand Down
106 changes: 106 additions & 0 deletions test/common/formatter/substitution_format_string_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -212,5 +212,111 @@ TEST_F(SubstitutionFormatStringUtilsTest, TestFromProtoConfigJsonWithMultipleExt
EXPECT_TRUE(TestUtility::jsonStringEqual(out_json, expected));
}

TEST_F(SubstitutionFormatStringUtilsTest, TestParseFormattersWithUnknownExtension) {
const std::string yaml = R"EOF(
name: envoy.formatter.TestFormatterUnknown
typed_config:
"@type": type.googleapis.com/google.protobuf.Any
)EOF";

SubstitutionFormatStringUtils::FormattersConfig config;
auto* entry1 = config.Add();
envoy::config::core::v3::TypedExtensionConfig proto;
TestUtility::loadFromYaml(yaml, proto);
*entry1 = proto;

EXPECT_THROW_WITH_MESSAGE(SubstitutionFormatStringUtils::parseFormatters(config, context_),
EnvoyException,
"Formatter not found: envoy.formatter.TestFormatterUnknown");
}

TEST_F(SubstitutionFormatStringUtilsTest, TestParseFormattersWithInvalidFormatter) {
FailCommandFactory fail_factory;
Registry::InjectFactory<CommandParserFactory> command_register(fail_factory);

const std::string yaml = R"EOF(
name: envoy.formatter.FailFormatter
typed_config:
"@type": type.googleapis.com/google.protobuf.UInt64Value
)EOF";

SubstitutionFormatStringUtils::FormattersConfig config;
auto* entry1 = config.Add();
envoy::config::core::v3::TypedExtensionConfig proto;
TestUtility::loadFromYaml(yaml, proto);
*entry1 = proto;

EXPECT_THROW_WITH_MESSAGE(SubstitutionFormatStringUtils::parseFormatters(config, context_),
EnvoyException,
"Failed to create command parser: envoy.formatter.FailFormatter");
}

TEST_F(SubstitutionFormatStringUtilsTest, TestParseFormattersWithSingleExtension) {
TestCommandFactory factory;
Registry::InjectFactory<CommandParserFactory> command_register(factory);

const std::string yaml = R"EOF(
name: envoy.formatter.TestFormatter
typed_config:
"@type": type.googleapis.com/google.protobuf.StringValue
)EOF";

SubstitutionFormatStringUtils::FormattersConfig config;
auto* entry1 = config.Add();
envoy::config::core::v3::TypedExtensionConfig proto;
TestUtility::loadFromYaml(yaml, proto);
*entry1 = proto;

auto commands = SubstitutionFormatStringUtils::parseFormatters(config, context_);
ASSERT_EQ(1, commands.size());

absl::optional<size_t> max_length = {};
ASSERT_TRUE(commands[0] != nullptr);
auto provider = commands[0]->parse("COMMAND_EXTENSION", "", max_length);
ASSERT_TRUE(provider != nullptr);
}

TEST_F(SubstitutionFormatStringUtilsTest, TestParseFormattersWithMultipleExtensions) {
TestCommandFactory factory;
Registry::InjectFactory<CommandParserFactory> command_register(factory);
AdditionalCommandFactory additional_factory;
Registry::InjectFactory<CommandParserFactory> additional_command_register(additional_factory);

const std::string test_command_yaml = R"EOF(
name: envoy.formatter.TestFormatter
typed_config:
"@type": type.googleapis.com/google.protobuf.StringValue
)EOF";

const std::string additional_command_yaml = R"EOF(
name: envoy.formatter.AdditionalFormatter
typed_config:
"@type": type.googleapis.com/google.protobuf.UInt32Value
)EOF";

SubstitutionFormatStringUtils::FormattersConfig config;

auto* entry1 = config.Add();
envoy::config::core::v3::TypedExtensionConfig test_command_proto;
TestUtility::loadFromYaml(test_command_yaml, test_command_proto);
*entry1 = test_command_proto;

auto* entry2 = config.Add();
envoy::config::core::v3::TypedExtensionConfig additional_command_proto;
TestUtility::loadFromYaml(additional_command_yaml, additional_command_proto);
*entry2 = additional_command_proto;

auto commands = SubstitutionFormatStringUtils::parseFormatters(config, context_);
ASSERT_EQ(2, commands.size());

absl::optional<size_t> max_length = {};
ASSERT_TRUE(commands[0] != nullptr);
auto test_command_provider = commands[0]->parse("COMMAND_EXTENSION", "", max_length);
ASSERT_TRUE(test_command_provider != nullptr);
ASSERT_TRUE(commands[1] != nullptr);
auto additional_command_provider = commands[1]->parse("ADDITIONAL_EXTENSION", "", max_length);
ASSERT_TRUE(additional_command_provider != nullptr);
}

} // namespace Formatter
} // namespace Envoy

0 comments on commit 1b768b4

Please sign in to comment.