Line data Source code
1 : #include "source/extensions/access_loggers/open_telemetry/substitution_formatter.h" 2 : 3 : #include <algorithm> 4 : #include <list> 5 : #include <string> 6 : #include <vector> 7 : 8 : #include "envoy/stream_info/stream_info.h" 9 : 10 : #include "source/common/common/assert.h" 11 : #include "source/common/formatter/substitution_formatter.h" 12 : 13 : #include "absl/strings/str_join.h" 14 : #include "opentelemetry/proto/common/v1/common.pb.h" 15 : 16 : static const std::string DefaultUnspecifiedValueString = "-"; 17 : 18 : namespace Envoy { 19 : namespace Extensions { 20 : namespace AccessLoggers { 21 : namespace OpenTelemetry { 22 : 23 : OpenTelemetryFormatter::OpenTelemetryFormatter( 24 : const ::opentelemetry::proto::common::v1::KeyValueList& format_mapping) 25 0 : : kv_list_output_format_(FormatBuilder().toFormatMapValue(format_mapping)) {} 26 : 27 : OpenTelemetryFormatter::OpenTelemetryFormatMapWrapper 28 : OpenTelemetryFormatter::FormatBuilder::toFormatMapValue( 29 0 : const ::opentelemetry::proto::common::v1::KeyValueList& kv_list_format) const { 30 0 : auto output = std::make_unique<OpenTelemetryFormatMap>(); 31 0 : for (const auto& pair : kv_list_format.values()) { 32 0 : switch (pair.value().value_case()) { 33 0 : case ::opentelemetry::proto::common::v1::AnyValue::kStringValue: 34 0 : output->emplace_back(pair.key(), toFormatStringValue(pair.value().string_value())); 35 0 : break; 36 : 37 0 : case ::opentelemetry::proto::common::v1::AnyValue::kKvlistValue: 38 0 : output->emplace_back(pair.key(), toFormatMapValue(pair.value().kvlist_value())); 39 0 : break; 40 : 41 0 : case ::opentelemetry::proto::common::v1::AnyValue::kArrayValue: 42 0 : output->emplace_back(pair.key(), toFormatListValue(pair.value().array_value())); 43 0 : break; 44 : 45 0 : default: 46 0 : throw EnvoyException("Only string values, nested key value lists and array values are " 47 0 : "supported in OpenTelemetry access log format."); 48 0 : } 49 0 : } 50 0 : return {std::move(output)}; 51 0 : } 52 : 53 : OpenTelemetryFormatter::OpenTelemetryFormatListWrapper 54 : OpenTelemetryFormatter::FormatBuilder::toFormatListValue( 55 0 : const ::opentelemetry::proto::common::v1::ArrayValue& list_value_format) const { 56 0 : auto output = std::make_unique<OpenTelemetryFormatList>(); 57 0 : for (const auto& value : list_value_format.values()) { 58 0 : switch (value.value_case()) { 59 0 : case ::opentelemetry::proto::common::v1::AnyValue::kStringValue: 60 0 : output->emplace_back(toFormatStringValue(value.string_value())); 61 0 : break; 62 : 63 0 : case ::opentelemetry::proto::common::v1::AnyValue::kKvlistValue: 64 0 : output->emplace_back(toFormatMapValue(value.kvlist_value())); 65 0 : break; 66 : 67 0 : case ::opentelemetry::proto::common::v1::AnyValue::kArrayValue: 68 0 : output->emplace_back(toFormatListValue(value.array_value())); 69 0 : break; 70 0 : default: 71 0 : throw EnvoyException("Only string values, nested key value lists and array values are " 72 0 : "supported in OpenTelemetry access log format."); 73 0 : } 74 0 : } 75 0 : return {std::move(output)}; 76 0 : } 77 : 78 : std::vector<Formatter::FormatterProviderPtr> 79 0 : OpenTelemetryFormatter::FormatBuilder::toFormatStringValue(const std::string& string_format) const { 80 0 : return Formatter::SubstitutionFormatParser::parse(string_format, {}); 81 0 : } 82 : 83 : ::opentelemetry::proto::common::v1::AnyValue OpenTelemetryFormatter::providersCallback( 84 : const std::vector<Formatter::FormatterProviderPtr>& providers, 85 0 : const Formatter::HttpFormatterContext& context, const StreamInfo::StreamInfo& info) const { 86 0 : ASSERT(!providers.empty()); 87 0 : ::opentelemetry::proto::common::v1::AnyValue output; 88 0 : std::vector<std::string> bits(providers.size()); 89 : 90 0 : std::transform( 91 0 : providers.begin(), providers.end(), bits.begin(), 92 0 : [&](const Formatter::FormatterProviderPtr& provider) { 93 0 : return provider->formatWithContext(context, info).value_or(DefaultUnspecifiedValueString); 94 0 : }); 95 : 96 0 : output.set_string_value(absl::StrJoin(bits, "")); 97 0 : return output; 98 0 : } 99 : 100 : ::opentelemetry::proto::common::v1::AnyValue OpenTelemetryFormatter::openTelemetryFormatMapCallback( 101 : const OpenTelemetryFormatter::OpenTelemetryFormatMapWrapper& format_map, 102 0 : const OpenTelemetryFormatter::OpenTelemetryFormatMapVisitor& visitor) const { 103 0 : ::opentelemetry::proto::common::v1::AnyValue output; 104 0 : auto* kv_list = output.mutable_kvlist_value(); 105 0 : for (const auto& pair : *format_map.value_) { 106 0 : ::opentelemetry::proto::common::v1::AnyValue value = absl::visit(visitor, pair.second); 107 0 : auto* kv = kv_list->add_values(); 108 0 : kv->set_key(pair.first); 109 0 : *kv->mutable_value() = value; 110 0 : } 111 0 : return output; 112 0 : } 113 : 114 : ::opentelemetry::proto::common::v1::AnyValue 115 : OpenTelemetryFormatter::openTelemetryFormatListCallback( 116 : const OpenTelemetryFormatter::OpenTelemetryFormatListWrapper& format_list, 117 0 : const OpenTelemetryFormatter::OpenTelemetryFormatMapVisitor& visitor) const { 118 0 : ::opentelemetry::proto::common::v1::AnyValue output; 119 0 : auto* array_value = output.mutable_array_value(); 120 0 : for (const auto& val : *format_list.value_) { 121 0 : ::opentelemetry::proto::common::v1::AnyValue value = absl::visit(visitor, val); 122 0 : *array_value->add_values() = value; 123 0 : } 124 0 : return output; 125 0 : } 126 : 127 : ::opentelemetry::proto::common::v1::KeyValueList 128 : OpenTelemetryFormatter::format(const Formatter::HttpFormatterContext& context, 129 0 : const StreamInfo::StreamInfo& info) const { 130 0 : OpenTelemetryFormatMapVisitor visitor{ 131 0 : [&](const std::vector<Formatter::FormatterProviderPtr>& providers) { 132 0 : return providersCallback(providers, context, info); 133 0 : }, 134 0 : [&, this](const OpenTelemetryFormatter::OpenTelemetryFormatMapWrapper& format_map) { 135 0 : return openTelemetryFormatMapCallback(format_map, visitor); 136 0 : }, 137 0 : [&, this](const OpenTelemetryFormatter::OpenTelemetryFormatListWrapper& format_list) { 138 0 : return openTelemetryFormatListCallback(format_list, visitor); 139 0 : }, 140 0 : }; 141 0 : return openTelemetryFormatMapCallback(kv_list_output_format_, visitor).kvlist_value(); 142 0 : } 143 : 144 : } // namespace OpenTelemetry 145 : } // namespace AccessLoggers 146 : } // namespace Extensions 147 : } // namespace Envoy