@@ -127,258 +127,5 @@ class JsonFormatterImpl : public Formatter {
127127 std::vector<ParsedFormatElement> parsed_elements_;
128128};
129129
130- // Helper classes for StructFormatter::StructFormatMapVisitor.
131- template <class ... Ts> struct StructFormatMapVisitorHelper : Ts... {
132- using Ts::operator ()...;
133- };
134- template <class ... Ts> StructFormatMapVisitorHelper (Ts...) -> StructFormatMapVisitorHelper<Ts...>;
135-
136- #ifndef ENVOY_DISABLE_EXCEPTIONS
137- /* *
138- * An formatter for structured log formats, which returns a Struct proto that
139- * can be converted easily into multiple formats.
140- */
141- class StructFormatter {
142- public:
143- using CommandParsers = std::vector<CommandParserPtr>;
144- using PlainNumber = PlainNumberFormatter;
145- using PlainString = PlainStringFormatter;
146-
147- StructFormatter (const ProtobufWkt::Struct& format_mapping, bool preserve_types,
148- bool omit_empty_values, const CommandParsers& commands = {})
149- : omit_empty_values_(omit_empty_values), preserve_types_(preserve_types),
150- struct_output_format_ (FormatBuilder(commands).toFormatMapValue(format_mapping)) {}
151-
152- ProtobufWkt::Struct formatWithContext (const Context& context,
153- const StreamInfo::StreamInfo& info) const {
154- StructFormatMapVisitor visitor{
155- [&](const std::vector<FormatterProviderPtr>& providers) {
156- return providersCallback (providers, context, info);
157- },
158- [&, this ](const StructFormatter::StructFormatMapWrapper& format_map) {
159- return structFormatMapCallback (format_map, visitor);
160- },
161- [&, this ](const StructFormatter::StructFormatListWrapper& format_list) {
162- return structFormatListCallback (format_list, visitor);
163- },
164- };
165- return structFormatMapCallback (struct_output_format_, visitor).struct_value ();
166- }
167-
168- private:
169- struct StructFormatMapWrapper ;
170- struct StructFormatListWrapper ;
171- using StructFormatValue =
172- absl::variant<const std::vector<FormatterProviderPtr>, const StructFormatMapWrapper,
173- const StructFormatListWrapper>;
174- // Although not required for Struct/JSON, it is nice to have the order of
175- // properties preserved between the format and the log entry, thus std::map.
176- using StructFormatMap = std::map<std::string, StructFormatValue>;
177- using StructFormatMapPtr = std::unique_ptr<StructFormatMap>;
178- struct StructFormatMapWrapper {
179- StructFormatMapPtr value_;
180- };
181-
182- using StructFormatList = std::list<StructFormatValue>;
183- using StructFormatListPtr = std::unique_ptr<StructFormatList>;
184- struct StructFormatListWrapper {
185- StructFormatListPtr value_;
186- };
187-
188- using StructFormatMapVisitor = StructFormatMapVisitorHelper<
189- const std::function<ProtobufWkt::Value(const std::vector<FormatterProviderPtr>&)>,
190- const std::function<ProtobufWkt::Value(const StructFormatter::StructFormatMapWrapper&)>,
191- const std::function<ProtobufWkt::Value(const StructFormatter::StructFormatListWrapper&)>>;
192-
193- // Methods for building the format map.
194- class FormatBuilder {
195- public:
196- explicit FormatBuilder (const CommandParsers& commands) : commands_(commands) {}
197- absl::StatusOr<std::vector<FormatterProviderPtr>>
198- toFormatStringValue (const std::string& string_format) const {
199- return SubstitutionFormatParser::parse (string_format, commands_);
200- }
201- std::vector<FormatterProviderPtr> toFormatNumberValue (double value) const {
202- std::vector<FormatterProviderPtr> formatters;
203- formatters.emplace_back (FormatterProviderPtr{new PlainNumber (value)});
204- return formatters;
205- }
206- StructFormatMapWrapper toFormatMapValue (const ProtobufWkt::Struct& struct_format) const {
207- auto output = std::make_unique<StructFormatMap>();
208- for (const auto & pair : struct_format.fields ()) {
209- switch (pair.second .kind_case ()) {
210- case ProtobufWkt::Value::kStringValue :
211- output->emplace (pair.first ,
212- THROW_OR_RETURN_VALUE (toFormatStringValue (pair.second .string_value ()),
213- std::vector<FormatterProviderPtr>));
214- break ;
215-
216- case ProtobufWkt::Value::kStructValue :
217- output->emplace (pair.first , toFormatMapValue (pair.second .struct_value ()));
218- break ;
219-
220- case ProtobufWkt::Value::kListValue :
221- output->emplace (pair.first , toFormatListValue (pair.second .list_value ()));
222- break ;
223-
224- case ProtobufWkt::Value::kNumberValue :
225- output->emplace (pair.first , toFormatNumberValue (pair.second .number_value ()));
226- break ;
227- default :
228- throw EnvoyException (
229- " Only string values, nested structs, list values and number values are "
230- " supported in structured access log format." );
231- }
232- }
233- return {std::move (output)};
234- }
235- StructFormatListWrapper
236- toFormatListValue (const ProtobufWkt::ListValue& list_value_format) const {
237- auto output = std::make_unique<StructFormatList>();
238- for (const auto & value : list_value_format.values ()) {
239- switch (value.kind_case ()) {
240- case ProtobufWkt::Value::kStringValue :
241- output->emplace_back (THROW_OR_RETURN_VALUE (toFormatStringValue (value.string_value ()),
242- std::vector<FormatterProviderPtr>));
243- break ;
244-
245- case ProtobufWkt::Value::kStructValue :
246- output->emplace_back (toFormatMapValue (value.struct_value ()));
247- break ;
248-
249- case ProtobufWkt::Value::kListValue :
250- output->emplace_back (toFormatListValue (value.list_value ()));
251- break ;
252-
253- case ProtobufWkt::Value::kNumberValue :
254- output->emplace_back (toFormatNumberValue (value.number_value ()));
255- break ;
256-
257- default :
258- throw EnvoyException (
259- " Only string values, nested structs, list values and number values are "
260- " supported in structured access log format." );
261- }
262- }
263- return {std::move (output)};
264- }
265-
266- private:
267- const CommandParsers& commands_;
268- };
269-
270- // Methods for doing the actual formatting.
271- ProtobufWkt::Value providersCallback (const std::vector<FormatterProviderPtr>& providers,
272- const Context& context,
273- const StreamInfo::StreamInfo& stream_info) const {
274- ASSERT (!providers.empty ());
275- if (providers.size () == 1 ) {
276- const auto & provider = providers.front ();
277- if (preserve_types_) {
278- return provider->formatValueWithContext (context, stream_info);
279- }
280-
281- if (omit_empty_values_) {
282- return ValueUtil::optionalStringValue (provider->formatWithContext (context, stream_info));
283- }
284-
285- const auto str = provider->formatWithContext (context, stream_info);
286- if (str.has_value ()) {
287- return ValueUtil::stringValue (*str);
288- }
289- // Returning an "empty string" (depending on omit_empty_values_) in case
290- // of a formatting error.
291- return ValueUtil::stringValue (omit_empty_values_ ? EMPTY_STRING
292- : DefaultUnspecifiedValueStringView);
293- }
294- // Multiple providers forces string output.
295- std::string str;
296- for (const auto & provider : providers) {
297- const auto bit = provider->formatWithContext (context, stream_info);
298- // Add the formatted value if there is one. Otherwise add a default value
299- // of "-" if omit_empty_values_ is not set.
300- if (bit.has_value ()) {
301- str += bit.value ();
302- } else if (!omit_empty_values_) {
303- str += DefaultUnspecifiedValueStringView;
304- }
305- }
306- return ValueUtil::stringValue (str);
307- }
308- ProtobufWkt::Value
309- structFormatMapCallback (const StructFormatter::StructFormatMapWrapper& format_map,
310- const StructFormatMapVisitor& visitor) const {
311- ProtobufWkt::Struct output;
312- auto * fields = output.mutable_fields ();
313- for (const auto & pair : *format_map.value_ ) {
314- ProtobufWkt::Value value = absl::visit (visitor, pair.second );
315- if (omit_empty_values_ && value.kind_case () == ProtobufWkt::Value::kNullValue ) {
316- continue ;
317- }
318- (*fields)[pair.first ] = value;
319- }
320- if (omit_empty_values_ && output.fields ().empty ()) {
321- return ValueUtil::nullValue ();
322- }
323- return ValueUtil::structValue (output);
324- }
325- ProtobufWkt::Value
326- structFormatListCallback (const StructFormatter::StructFormatListWrapper& format_list,
327- const StructFormatMapVisitor& visitor) const {
328- std::vector<ProtobufWkt::Value> output;
329- for (const auto & val : *format_list.value_ ) {
330- ProtobufWkt::Value value = absl::visit (visitor, val);
331- if (omit_empty_values_ && value.kind_case () == ProtobufWkt::Value::kNullValue ) {
332- continue ;
333- }
334- output.push_back (value);
335- }
336- return ValueUtil::listValue (output);
337- }
338-
339- const bool omit_empty_values_;
340- const bool preserve_types_;
341-
342- const StructFormatMapWrapper struct_output_format_;
343- };
344-
345- using StructFormatterPtr = std::unique_ptr<StructFormatter>;
346-
347- class LegacyJsonFormatterImpl : public Formatter {
348- public:
349- using CommandParsers = std::vector<CommandParserPtr>;
350-
351- LegacyJsonFormatterImpl (const ProtobufWkt::Struct& format_mapping, bool preserve_types,
352- bool omit_empty_values, bool sort_properties,
353- const CommandParsers& commands = {})
354- : struct_formatter_(format_mapping, preserve_types, omit_empty_values, commands),
355- sort_properties_ (sort_properties) {}
356-
357- // Formatter
358- std::string formatWithContext (const Context& context,
359- const StreamInfo::StreamInfo& info) const override {
360- const ProtobufWkt::Struct output_struct = struct_formatter_.formatWithContext (context, info);
361-
362- std::string log_line = " " ;
363- #ifdef ENVOY_ENABLE_YAML
364- if (sort_properties_) {
365- log_line = Json::Factory::loadFromProtobufStruct (output_struct)->asJsonString ();
366- } else {
367- log_line = MessageUtil::getJsonStringFromMessageOrError (output_struct, false , true );
368- }
369- #else
370- UNREFERENCED_PARAMETER (sort_properties_);
371- IS_ENVOY_BUG (" Json support compiled out" );
372- #endif
373- return absl::StrCat (log_line, " \n " );
374- }
375-
376- private:
377- const StructFormatter struct_formatter_;
378- const bool sort_properties_;
379- };
380-
381- #endif // ENVOY_DISABLE_EXCEPTIONS
382-
383130} // namespace Formatter
384131} // namespace Envoy
0 commit comments