Line data Source code
1 : #include "source/extensions/access_loggers/open_telemetry/access_log_impl.h" 2 : 3 : #include <chrono> 4 : 5 : #include "envoy/config/core/v3/base.pb.h" 6 : #include "envoy/data/accesslog/v3/accesslog.pb.h" 7 : #include "envoy/extensions/access_loggers/grpc/v3/als.pb.h" 8 : #include "envoy/extensions/access_loggers/open_telemetry/v3/logs_service.pb.h" 9 : 10 : #include "source/common/common/assert.h" 11 : #include "source/common/config/utility.h" 12 : #include "source/common/http/headers.h" 13 : #include "source/common/network/utility.h" 14 : #include "source/common/protobuf/message_validator_impl.h" 15 : #include "source/common/protobuf/utility.h" 16 : #include "source/common/stream_info/utility.h" 17 : #include "source/extensions/access_loggers/open_telemetry/substitution_formatter.h" 18 : 19 : #include "opentelemetry/proto/collector/logs/v1/logs_service.pb.h" 20 : #include "opentelemetry/proto/common/v1/common.pb.h" 21 : #include "opentelemetry/proto/logs/v1/logs.pb.h" 22 : #include "opentelemetry/proto/resource/v1/resource.pb.h" 23 : 24 : // Used to pack/unpack the body AnyValue to a KeyValueList. 25 : const char BODY_KEY[] = "body"; 26 : 27 : namespace Envoy { 28 : namespace Extensions { 29 : namespace AccessLoggers { 30 : namespace OpenTelemetry { 31 : 32 : namespace { 33 : 34 : // Packing the body "AnyValue" to a "KeyValueList" with a single key and the body as value. 35 : ::opentelemetry::proto::common::v1::KeyValueList 36 0 : packBody(const ::opentelemetry::proto::common::v1::AnyValue& body) { 37 0 : ::opentelemetry::proto::common::v1::KeyValueList output; 38 0 : auto* kv = output.add_values(); 39 0 : kv->set_key(BODY_KEY); 40 0 : *kv->mutable_value() = body; 41 0 : return output; 42 0 : } 43 : 44 : ::opentelemetry::proto::common::v1::AnyValue 45 0 : unpackBody(const ::opentelemetry::proto::common::v1::KeyValueList& value) { 46 0 : ASSERT(value.values().size() == 1 && value.values(0).key() == BODY_KEY); 47 0 : return value.values(0).value(); 48 0 : } 49 : 50 : } // namespace 51 : 52 : Http::RegisterCustomInlineHeader<Http::CustomInlineHeaderRegistry::Type::RequestHeaders> 53 : referer_handle(Http::CustomHeaders::get().Referer); 54 : 55 : AccessLog::ThreadLocalLogger::ThreadLocalLogger(GrpcAccessLoggerSharedPtr logger) 56 0 : : logger_(std::move(logger)) {} 57 : 58 : AccessLog::AccessLog( 59 : ::Envoy::AccessLog::FilterPtr&& filter, 60 : envoy::extensions::access_loggers::open_telemetry::v3::OpenTelemetryAccessLogConfig config, 61 : ThreadLocal::SlotAllocator& tls, GrpcAccessLoggerCacheSharedPtr access_logger_cache) 62 : : Common::ImplBase(std::move(filter)), tls_slot_(tls.allocateSlot()), 63 0 : access_logger_cache_(std::move(access_logger_cache)) { 64 : 65 0 : THROW_IF_NOT_OK(Envoy::Config::Utility::checkTransportVersion(config.common_config())); 66 0 : tls_slot_->set([this, config](Event::Dispatcher&) { 67 0 : return std::make_shared<ThreadLocalLogger>( 68 0 : access_logger_cache_->getOrCreateLogger(config, Common::GrpcAccessLoggerType::HTTP)); 69 0 : }); 70 : 71 : // Packing the body "AnyValue" to a "KeyValueList" only if it's not empty, otherwise the 72 : // formatter would fail to parse it. 73 0 : if (config.body().value_case() != ::opentelemetry::proto::common::v1::AnyValue::VALUE_NOT_SET) { 74 0 : body_formatter_ = std::make_unique<OpenTelemetryFormatter>(packBody(config.body())); 75 0 : } 76 0 : attributes_formatter_ = std::make_unique<OpenTelemetryFormatter>(config.attributes()); 77 0 : } 78 : 79 : void AccessLog::emitLog(const Formatter::HttpFormatterContext& log_context, 80 0 : const StreamInfo::StreamInfo& stream_info) { 81 0 : opentelemetry::proto::logs::v1::LogRecord log_entry; 82 0 : log_entry.set_time_unix_nano(std::chrono::duration_cast<std::chrono::nanoseconds>( 83 0 : stream_info.startTime().time_since_epoch()) 84 0 : .count()); 85 : 86 : // Unpacking the body "KeyValueList" to "AnyValue". 87 0 : if (body_formatter_) { 88 0 : const auto formatted_body = unpackBody(body_formatter_->format(log_context, stream_info)); 89 0 : *log_entry.mutable_body() = formatted_body; 90 0 : } 91 0 : const auto formatted_attributes = attributes_formatter_->format(log_context, stream_info); 92 0 : *log_entry.mutable_attributes() = formatted_attributes.values(); 93 : 94 0 : tls_slot_->getTyped<ThreadLocalLogger>().logger_->log(std::move(log_entry)); 95 0 : } 96 : 97 : } // namespace OpenTelemetry 98 : } // namespace AccessLoggers 99 : } // namespace Extensions 100 : } // namespace Envoy