-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an OpenTelemetry gRPC access logger (just gRPC handling) (#14818)
Signed-off-by: Itamar Kaminski <[email protected]>
- Loading branch information
Showing
12 changed files
with
545 additions
and
1 deletion.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
load( | ||
"//bazel:envoy_build_system.bzl", | ||
"envoy_cc_library", | ||
"envoy_extension_package", | ||
) | ||
|
||
licenses(["notice"]) # Apache 2 | ||
|
||
envoy_extension_package() | ||
|
||
envoy_cc_library( | ||
name = "grpc_access_log_lib", | ||
srcs = ["grpc_access_log_impl.cc"], | ||
hdrs = ["grpc_access_log_impl.h"], | ||
deps = [ | ||
"//include/envoy/event:dispatcher_interface", | ||
"//include/envoy/grpc:async_client_manager_interface", | ||
"//include/envoy/local_info:local_info_interface", | ||
"//include/envoy/thread_local:thread_local_interface", | ||
"//source/common/config:utility_lib", | ||
"//source/common/grpc:typed_async_client_lib", | ||
"//source/common/protobuf", | ||
"//source/extensions/access_loggers/common:grpc_access_logger", | ||
"@envoy_api//envoy/extensions/access_loggers/grpc/v3:pkg_cc_proto", | ||
"@opentelemetry_proto//:logs_cc_proto", | ||
], | ||
) |
91 changes: 91 additions & 0 deletions
91
source/extensions/access_loggers/open_telemetry/grpc_access_log_impl.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
#include "extensions/access_loggers/open_telemetry/grpc_access_log_impl.h" | ||
|
||
#include "envoy/extensions/access_loggers/grpc/v3/als.pb.h" | ||
#include "envoy/grpc/async_client_manager.h" | ||
#include "envoy/local_info/local_info.h" | ||
|
||
#include "common/config/utility.h" | ||
#include "common/grpc/typed_async_client.h" | ||
|
||
#include "opentelemetry/proto/collector/logs/v1/logs_service.pb.h" | ||
#include "opentelemetry/proto/common/v1/common.pb.h" | ||
#include "opentelemetry/proto/logs/v1/logs.pb.h" | ||
#include "opentelemetry/proto/resource/v1/resource.pb.h" | ||
|
||
const char GRPC_LOG_STATS_PREFIX[] = "access_logs.open_telemetry_access_log."; | ||
|
||
namespace Envoy { | ||
namespace Extensions { | ||
namespace AccessLoggers { | ||
namespace OpenTelemetry { | ||
|
||
GrpcAccessLoggerImpl::GrpcAccessLoggerImpl( | ||
Grpc::RawAsyncClientPtr&& client, std::string log_name, | ||
std::chrono::milliseconds buffer_flush_interval_msec, uint64_t max_buffer_size_bytes, | ||
Event::Dispatcher& dispatcher, const LocalInfo::LocalInfo& local_info, Stats::Scope& scope, | ||
envoy::config::core::v3::ApiVersion transport_api_version) | ||
: GrpcAccessLogger( | ||
std::move(client), buffer_flush_interval_msec, max_buffer_size_bytes, dispatcher, scope, | ||
GRPC_LOG_STATS_PREFIX, | ||
Grpc::VersionedMethods("opentelemetry.proto.collector.logs.v1.LogsService.Export", | ||
"opentelemetry.proto.collector.logs.v1.LogsService.Export") | ||
.getMethodDescriptorForVersion(transport_api_version), | ||
transport_api_version) { | ||
initMessageRoot(log_name, local_info); | ||
} | ||
|
||
namespace { | ||
|
||
opentelemetry::proto::common::v1::KeyValue getStringKeyValue(const std::string& key, | ||
const std::string& value) { | ||
opentelemetry::proto::common::v1::KeyValue keyValue; | ||
keyValue.set_key(key); | ||
keyValue.mutable_value()->set_string_value(value); | ||
return keyValue; | ||
} | ||
|
||
} // namespace | ||
|
||
// See comment about the structure of repeated fields in the header file. | ||
// TODO(itamarkam): allow user configurable attributes. | ||
void GrpcAccessLoggerImpl::initMessageRoot(const std::string& log_name, | ||
const LocalInfo::LocalInfo& local_info) { | ||
auto* resource_logs = message_.add_resource_logs(); | ||
root_ = resource_logs->add_instrumentation_library_logs(); | ||
auto* resource = resource_logs->mutable_resource(); | ||
*resource->add_attributes() = getStringKeyValue("log_name", log_name); | ||
*resource->add_attributes() = getStringKeyValue("zone_name", local_info.zoneName()); | ||
*resource->add_attributes() = getStringKeyValue("cluster_name", local_info.clusterName()); | ||
*resource->add_attributes() = getStringKeyValue("node_name", local_info.nodeName()); | ||
} | ||
|
||
void GrpcAccessLoggerImpl::addEntry(opentelemetry::proto::logs::v1::LogRecord&& entry) { | ||
root_->mutable_logs()->Add(std::move(entry)); | ||
} | ||
|
||
bool GrpcAccessLoggerImpl::isEmpty() { return root_->logs().empty(); } | ||
|
||
// The message is already initialized in the c'tor, and only the logs are cleared. | ||
void GrpcAccessLoggerImpl::initMessage() {} | ||
|
||
void GrpcAccessLoggerImpl::clearMessage() { root_->clear_logs(); } | ||
|
||
GrpcAccessLoggerCacheImpl::GrpcAccessLoggerCacheImpl(Grpc::AsyncClientManager& async_client_manager, | ||
Stats::Scope& scope, | ||
ThreadLocal::SlotAllocator& tls, | ||
const LocalInfo::LocalInfo& local_info) | ||
: GrpcAccessLoggerCache(async_client_manager, scope, tls), local_info_(local_info) {} | ||
|
||
GrpcAccessLoggerImpl::SharedPtr GrpcAccessLoggerCacheImpl::createLogger( | ||
const envoy::extensions::access_loggers::grpc::v3::CommonGrpcAccessLogConfig& config, | ||
Grpc::RawAsyncClientPtr&& client, std::chrono::milliseconds buffer_flush_interval_msec, | ||
uint64_t max_buffer_size_bytes, Event::Dispatcher& dispatcher, Stats::Scope& scope) { | ||
return std::make_shared<GrpcAccessLoggerImpl>( | ||
std::move(client), config.log_name(), buffer_flush_interval_msec, max_buffer_size_bytes, | ||
dispatcher, local_info_, scope, Config::Utility::getAndCheckTransportVersion(config)); | ||
} | ||
|
||
} // namespace OpenTelemetry | ||
} // namespace AccessLoggers | ||
} // namespace Extensions | ||
} // namespace Envoy |
90 changes: 90 additions & 0 deletions
90
source/extensions/access_loggers/open_telemetry/grpc_access_log_impl.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
#pragma once | ||
|
||
#include <memory> | ||
|
||
#include "envoy/event/dispatcher.h" | ||
#include "envoy/extensions/access_loggers/grpc/v3/als.pb.h" | ||
#include "envoy/grpc/async_client_manager.h" | ||
#include "envoy/local_info/local_info.h" | ||
#include "envoy/thread_local/thread_local.h" | ||
|
||
#include "common/protobuf/protobuf.h" | ||
|
||
#include "extensions/access_loggers/common/grpc_access_logger.h" | ||
|
||
#include "opentelemetry/proto/collector/logs/v1/logs_service.pb.h" | ||
#include "opentelemetry/proto/common/v1/common.pb.h" | ||
#include "opentelemetry/proto/logs/v1/logs.pb.h" | ||
#include "opentelemetry/proto/resource/v1/resource.pb.h" | ||
|
||
namespace Envoy { | ||
namespace Extensions { | ||
namespace AccessLoggers { | ||
namespace OpenTelemetry { | ||
|
||
// Note: OpenTelemetry protos are extra flexible and used also in the OT collector for batching and | ||
// so forth. As a result, some fields are repeated, but for our use case we assume the following | ||
// structure: | ||
// ExportLogsServiceRequest -> (single) ResourceLogs -> (single) InstrumentationLibraryLogs -> | ||
// (repeated) LogRecord. | ||
class GrpcAccessLoggerImpl | ||
: public Common::GrpcAccessLogger< | ||
opentelemetry::proto::logs::v1::LogRecord, | ||
// OpenTelemetry logging uses LogRecord for both HTTP and TCP, so protobuf::Empty is used | ||
// as an empty placeholder for the non-used addEntry method. | ||
// TODO(itamarkam): Don't cache OpenTelemetry loggers by type (HTTP/TCP). | ||
ProtobufWkt::Empty, opentelemetry::proto::collector::logs::v1::ExportLogsServiceRequest, | ||
opentelemetry::proto::collector::logs::v1::ExportLogsServiceResponse> { | ||
public: | ||
GrpcAccessLoggerImpl(Grpc::RawAsyncClientPtr&& client, std::string log_name, | ||
std::chrono::milliseconds buffer_flush_interval_msec, | ||
uint64_t max_buffer_size_bytes, Event::Dispatcher& dispatcher, | ||
const LocalInfo::LocalInfo& local_info, Stats::Scope& scope, | ||
envoy::config::core::v3::ApiVersion transport_api_version); | ||
|
||
private: | ||
void initMessageRoot(const std::string& log_name, const LocalInfo::LocalInfo& local_info); | ||
// Extensions::AccessLoggers::GrpcCommon::GrpcAccessLogger | ||
void addEntry(opentelemetry::proto::logs::v1::LogRecord&& entry) override; | ||
// Non used addEntry method (the above is used for both TCP and HTTP). | ||
void addEntry(ProtobufWkt::Empty&& entry) override { (void)entry; }; | ||
bool isEmpty() override; | ||
void initMessage() override; | ||
void clearMessage() override; | ||
|
||
opentelemetry::proto::logs::v1::InstrumentationLibraryLogs* root_; | ||
}; | ||
|
||
class GrpcAccessLoggerCacheImpl | ||
: public Common::GrpcAccessLoggerCache< | ||
GrpcAccessLoggerImpl, | ||
envoy::extensions::access_loggers::grpc::v3::CommonGrpcAccessLogConfig> { | ||
public: | ||
GrpcAccessLoggerCacheImpl(Grpc::AsyncClientManager& async_client_manager, Stats::Scope& scope, | ||
ThreadLocal::SlotAllocator& tls, | ||
const LocalInfo::LocalInfo& local_info); | ||
|
||
private: | ||
// Common::GrpcAccessLoggerCache | ||
GrpcAccessLoggerImpl::SharedPtr | ||
createLogger(const envoy::extensions::access_loggers::grpc::v3::CommonGrpcAccessLogConfig& config, | ||
Grpc::RawAsyncClientPtr&& client, | ||
std::chrono::milliseconds buffer_flush_interval_msec, uint64_t max_buffer_size_bytes, | ||
Event::Dispatcher& dispatcher, Stats::Scope& scope) override; | ||
|
||
const LocalInfo::LocalInfo& local_info_; | ||
}; | ||
|
||
/** | ||
* Aliases for class interfaces for mock definitions. | ||
*/ | ||
using GrpcAccessLogger = GrpcAccessLoggerImpl::Interface; | ||
using GrpcAccessLoggerSharedPtr = GrpcAccessLogger::SharedPtr; | ||
|
||
using GrpcAccessLoggerCache = GrpcAccessLoggerCacheImpl::Interface; | ||
using GrpcAccessLoggerCacheSharedPtr = GrpcAccessLoggerCache::SharedPtr; | ||
|
||
} // namespace OpenTelemetry | ||
} // namespace AccessLoggers | ||
} // namespace Extensions | ||
} // namespace Envoy |
Oops, something went wrong.