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
    const std::vector<Formatter::CommandParserPtr>& commands)
26
57
    : kv_list_output_format_(FormatBuilder(commands).toFormatMapValue(format_mapping)) {}
27

            
28
OpenTelemetryFormatter::OpenTelemetryFormatMapWrapper
29
OpenTelemetryFormatter::FormatBuilder::toFormatMapValue(
30
64
    const ::opentelemetry::proto::common::v1::KeyValueList& kv_list_format) const {
31
64
  auto output = std::make_unique<OpenTelemetryFormatMap>();
32
109
  for (const auto& pair : kv_list_format.values()) {
33
105
    switch (pair.value().value_case()) {
34
93
    case ::opentelemetry::proto::common::v1::AnyValue::kStringValue:
35
93
      output->emplace_back(pair.key(), toFormatStringValue(pair.value().string_value()));
36
93
      break;
37

            
38
5
    case ::opentelemetry::proto::common::v1::AnyValue::kKvlistValue:
39
5
      output->emplace_back(pair.key(), toFormatMapValue(pair.value().kvlist_value()));
40
5
      break;
41

            
42
6
    case ::opentelemetry::proto::common::v1::AnyValue::kArrayValue:
43
6
      output->emplace_back(pair.key(), toFormatListValue(pair.value().array_value()));
44
6
      break;
45

            
46
1
    default:
47
1
      throw EnvoyException("Only string values, nested key value lists and array values are "
48
1
                           "supported in OpenTelemetry access log format.");
49
105
    }
50
105
  }
51
60
  return {std::move(output)};
52
64
}
53

            
54
OpenTelemetryFormatter::OpenTelemetryFormatListWrapper
55
OpenTelemetryFormatter::FormatBuilder::toFormatListValue(
56
9
    const ::opentelemetry::proto::common::v1::ArrayValue& list_value_format) const {
57
9
  auto output = std::make_unique<OpenTelemetryFormatList>();
58
22
  for (const auto& value : list_value_format.values()) {
59
22
    switch (value.value_case()) {
60
16
    case ::opentelemetry::proto::common::v1::AnyValue::kStringValue:
61
16
      output->emplace_back(toFormatStringValue(value.string_value()));
62
16
      break;
63

            
64
2
    case ::opentelemetry::proto::common::v1::AnyValue::kKvlistValue:
65
2
      output->emplace_back(toFormatMapValue(value.kvlist_value()));
66
2
      break;
67

            
68
3
    case ::opentelemetry::proto::common::v1::AnyValue::kArrayValue:
69
3
      output->emplace_back(toFormatListValue(value.array_value()));
70
3
      break;
71
1
    default:
72
1
      throw EnvoyException("Only string values, nested key value lists and array values are "
73
1
                           "supported in OpenTelemetry access log format.");
74
22
    }
75
22
  }
76
8
  return {std::move(output)};
77
9
}
78

            
79
std::vector<Formatter::FormatterProviderPtr>
80
109
OpenTelemetryFormatter::FormatBuilder::toFormatStringValue(const std::string& string_format) const {
81
109
  return THROW_OR_RETURN_VALUE(Formatter::SubstitutionFormatParser::parse(string_format, commands_),
82
109
                               std::vector<Formatter::FormatterProviderPtr>);
83
109
}
84

            
85
::opentelemetry::proto::common::v1::AnyValue OpenTelemetryFormatter::providersCallback(
86
    const std::vector<Formatter::FormatterProviderPtr>& providers,
87
102
    const Formatter::Context& context, const StreamInfo::StreamInfo& info) const {
88
102
  ASSERT(!providers.empty());
89
102
  ::opentelemetry::proto::common::v1::AnyValue output;
90
102
  std::vector<std::string> bits(providers.size());
91

            
92
102
  std::transform(providers.begin(), providers.end(), bits.begin(),
93
175
                 [&](const Formatter::FormatterProviderPtr& provider) {
94
175
                   return provider->format(context, info).value_or(DefaultUnspecifiedValueString);
95
175
                 });
96

            
97
102
  output.set_string_value(absl::StrJoin(bits, ""));
98
102
  return output;
99
102
}
100

            
101
::opentelemetry::proto::common::v1::AnyValue OpenTelemetryFormatter::openTelemetryFormatMapCallback(
102
    const OpenTelemetryFormatter::OpenTelemetryFormatMapWrapper& format_map,
103
62
    const OpenTelemetryFormatter::OpenTelemetryFormatMapVisitor& visitor) const {
104
62
  ::opentelemetry::proto::common::v1::AnyValue output;
105
62
  auto* kv_list = output.mutable_kvlist_value();
106
97
  for (const auto& pair : *format_map.value_) {
107
96
    ::opentelemetry::proto::common::v1::AnyValue value = absl::visit(visitor, pair.second);
108
96
    auto* kv = kv_list->add_values();
109
96
    kv->set_key(pair.first);
110
96
    *kv->mutable_value() = value;
111
96
  }
112
62
  return output;
113
62
}
114

            
115
::opentelemetry::proto::common::v1::AnyValue
116
OpenTelemetryFormatter::openTelemetryFormatListCallback(
117
    const OpenTelemetryFormatter::OpenTelemetryFormatListWrapper& format_list,
118
8
    const OpenTelemetryFormatter::OpenTelemetryFormatMapVisitor& visitor) const {
119
8
  ::opentelemetry::proto::common::v1::AnyValue output;
120
8
  auto* array_value = output.mutable_array_value();
121
21
  for (const auto& val : *format_list.value_) {
122
21
    ::opentelemetry::proto::common::v1::AnyValue value = absl::visit(visitor, val);
123
21
    *array_value->add_values() = value;
124
21
  }
125
8
  return output;
126
8
}
127

            
128
::opentelemetry::proto::common::v1::KeyValueList
129
OpenTelemetryFormatter::format(const Formatter::Context& context,
130
55
                               const StreamInfo::StreamInfo& info) const {
131
55
  OpenTelemetryFormatMapVisitor visitor{
132
103
      [&](const std::vector<Formatter::FormatterProviderPtr>& providers) {
133
102
        return providersCallback(providers, context, info);
134
102
      },
135
55
      [&, this](const OpenTelemetryFormatter::OpenTelemetryFormatMapWrapper& format_map) {
136
7
        return openTelemetryFormatMapCallback(format_map, visitor);
137
7
      },
138
55
      [&, this](const OpenTelemetryFormatter::OpenTelemetryFormatListWrapper& format_list) {
139
8
        return openTelemetryFormatListCallback(format_list, visitor);
140
8
      },
141
55
  };
142
55
  return openTelemetryFormatMapCallback(kv_list_output_format_, visitor).kvlist_value();
143
55
}
144

            
145
} // namespace OpenTelemetry
146
} // namespace AccessLoggers
147
} // namespace Extensions
148
} // namespace Envoy