Skip to content

Commit

Permalink
accesslog: add %TRACE_ID% formatter (#34198)
Browse files Browse the repository at this point in the history
Risk Level: low
Testing: unit test
Docs Changes: formatter documented
Release Notes: add
Fixes #34102
Signed-off-by: zirain <zirain2009@gmail.com>
  • Loading branch information
zirain committed May 23, 2024
1 parent e383e8e commit c28f01c
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 0 deletions.
3 changes: 3 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ new_features:
change: |
added support for :ref:`%UPSTREAM_HOST_NAME% <config_access_log_format_upstream_host_name>` for the upstream host
identifier.
- area: access_loggers
change: |
Added ``TRACE_ID`` :ref:`access log formatter <config_access_log_format>`.
- area: healthcheck
change: |
Added support to healthcheck with ProxyProtocol in TCP Healthcheck by setting
Expand Down
6 changes: 6 additions & 0 deletions docs/root/configuration/observability/access_log/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1216,3 +1216,9 @@ UDP
%ENVIRONMENT(X):Z%
Environment value of environment variable X. If no valid environment variable X, '-' symbol will be used.
Z is an optional parameter denoting string truncation up to Z characters long.

%TRACE_ID%
HTTP
The trace ID of the request. If the request does not have a trace ID, this will be an empty string.
TCP/UDP
Not implemented ("-").
23 changes: 23 additions & 0 deletions source/common/formatter/http_specific_formatter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,25 @@ HeadersByteSizeFormatter::formatValueWithContext(const HttpFormatterContext& con
context.requestHeaders(), context.responseHeaders(), context.responseTrailers()));
}

ProtobufWkt::Value TraceIDFormatter::formatValueWithContext(const HttpFormatterContext& context,
const StreamInfo::StreamInfo&) const {
auto trace_id = context.activeSpan().getTraceIdAsHex();
if (trace_id.empty()) {
return SubstitutionFormatUtils::unspecifiedValue();
}
return ValueUtil::stringValue(trace_id);
}

absl::optional<std::string>
TraceIDFormatter::formatWithContext(const HttpFormatterContext& context,
const StreamInfo::StreamInfo&) const {
auto trace_id = context.activeSpan().getTraceIdAsHex();
if (trace_id.empty()) {
return absl::nullopt;
}
return trace_id;
}

GrpcStatusFormatter::Format GrpcStatusFormatter::parseFormat(absl::string_view format) {
if (format.empty() || format == "CAMEL_STRING") {
return GrpcStatusFormatter::CamelString;
Expand Down Expand Up @@ -390,6 +409,10 @@ HttpBuiltInCommandParser::getKnownFormatters() {

return std::make_unique<RequestHeaderFormatter>(main_header, alternative_header,
max_length);
}}},
{"TRACE_ID",
{CommandSyntaxChecker::COMMAND_ONLY, [](const std::string&, absl::optional<size_t>&) {
return std::make_unique<TraceIDFormatter>();
}}}});
}

Expand Down
13 changes: 13 additions & 0 deletions source/common/formatter/http_specific_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,19 @@ class ResponseTrailerFormatter : public FormatterProvider, HeaderFormatter {
const StreamInfo::StreamInfo& stream_info) const override;
};

/**
* FormatterProvider for trace ID.
*/
class TraceIDFormatter : public FormatterProvider {
public:
absl::optional<std::string>
formatWithContext(const HttpFormatterContext& context,
const StreamInfo::StreamInfo& stream_info) const override;
ProtobufWkt::Value
formatValueWithContext(const HttpFormatterContext& context,
const StreamInfo::StreamInfo& stream_info) const override;
};

class GrpcStatusFormatter : public FormatterProvider, HeaderFormatter {
public:
enum Format {
Expand Down
32 changes: 32 additions & 0 deletions test/common/formatter/substitution_formatter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "test/mocks/network/mocks.h"
#include "test/mocks/ssl/mocks.h"
#include "test/mocks/stream_info/mocks.h"
#include "test/mocks/tracing/mocks.h"
#include "test/mocks/upstream/cluster_info.h"
#include "test/test_common/environment.h"
#include "test/test_common/printers.h"
Expand Down Expand Up @@ -2144,6 +2145,37 @@ TEST(SubstitutionFormatterTest, responseTrailerFormatter) {
}
}

TEST(SubstitutionFormatterTest, TraceIDFormatter) {
StreamInfo::MockStreamInfo stream_info;
Http::TestRequestHeaderMapImpl request_header{};
Http::TestResponseHeaderMapImpl response_header{};
Http::TestResponseTrailerMapImpl response_trailer{};
std::string body;

Tracing::MockSpan active_span;
EXPECT_CALL(active_span, getTraceIdAsHex())
.WillRepeatedly(Return("ae0046f9075194306d7de2931bd38ce3"));

{
HttpFormatterContext formatter_context(&request_header, &response_header, &response_trailer,
body, AccessLogType::NotSet, &active_span);
TraceIDFormatter formatter{};
EXPECT_EQ("ae0046f9075194306d7de2931bd38ce3",
formatter.formatWithContext(formatter_context, stream_info));
EXPECT_THAT(formatter.formatValueWithContext(formatter_context, stream_info),
ProtoEq(ValueUtil::stringValue("ae0046f9075194306d7de2931bd38ce3")));
}

{
HttpFormatterContext formatter_context(&request_header, &response_header, &response_trailer,
body);
TraceIDFormatter formatter{};
EXPECT_EQ(absl::nullopt, formatter.formatWithContext(formatter_context, stream_info));
EXPECT_THAT(formatter.formatValueWithContext(formatter_context, stream_info),
ProtoEq(ValueUtil::nullValue()));
}
}

/**
* Populate a metadata object with the following test data:
* "com.test": {"test_key":"test_value","test_obj":{"inner_key":"inner_value"}}
Expand Down

0 comments on commit c28f01c

Please sign in to comment.