Skip to content

Commit

Permalink
stat_sinks: add OpenTelemetry stats sink (envoyproxy#26620)
Browse files Browse the repository at this point in the history
Signed-off-by: ohadvano <[email protected]>
  • Loading branch information
ohadvano authored Apr 25, 2023
1 parent e0269d2 commit a6d46b6
Show file tree
Hide file tree
Showing 27 changed files with 1,336 additions and 2 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ extensions/filters/common/original_src @snowp @klarose
/*/extensions/stat_sinks/graphite_statsd @vaccarium @mattklein123
/*/extensions/stat_sinks/hystrix @trabetti @jmarantz
/*/extensions/stat_sinks/metrics_service @ramaraochavali @jmarantz
/*/extensions/stat_sinks/open_telemetry @ohadvano @mattklein123
# webassembly stat-sink extensions
/*/extensions/stat_sinks/wasm @mpwarres @mathetake @lizan
/*/extensions/resource_monitors/injected_resource @eziskind @htuch
Expand Down
1 change: 1 addition & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ proto_library(
"//envoy/extensions/retry/host/previous_hosts/v3:pkg",
"//envoy/extensions/retry/priority/previous_priorities/v3:pkg",
"//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg",
"//envoy/extensions/stat_sinks/open_telemetry/v3:pkg",
"//envoy/extensions/stat_sinks/wasm/v3:pkg",
"//envoy/extensions/transport_sockets/alts/v3:pkg",
"//envoy/extensions/transport_sockets/http_11_proxy/v3:pkg",
Expand Down
3 changes: 3 additions & 0 deletions api/bazel/external_proto_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ EXTERNAL_PROTO_GO_BAZEL_DEP_MAP = {
"@opencensus_proto//opencensus/proto/trace/v1:trace_config_proto": "@opencensus_proto//opencensus/proto/trace/v1:trace_and_config_proto_go",
"@opentelemetry_proto//:trace": "@opentelemetry_proto//:trace_go_proto",
"@opentelemetry_proto//:logs": "@opentelemetry_proto//:logs_go_proto",
"@opentelemetry_proto//:metrics": "@opentelemetry_proto//:metrics_go_proto",
"@opentelemetry_proto//:common": "@opentelemetry_proto//:common_go_proto",
}

Expand All @@ -45,6 +46,7 @@ EXTERNAL_PROTO_CC_BAZEL_DEP_MAP = {
"@opencensus_proto//opencensus/proto/trace/v1:trace_config_proto": "@opencensus_proto//opencensus/proto/trace/v1:trace_config_proto_cc",
"@opentelemetry_proto//:trace": "@opentelemetry_proto//:trace_cc_proto",
"@opentelemetry_proto//:logs": "@opentelemetry_proto//:logs_cc_proto",
"@opentelemetry_proto//:metrics": "@opentelemetry_proto//:metrics_cc_proto",
"@opentelemetry_proto//:common": "@opentelemetry_proto//:common_cc_proto",
}

Expand All @@ -56,5 +58,6 @@ EXTERNAL_PROTO_PY_BAZEL_DEP_MAP = {
"@opencensus_proto//opencensus/proto/trace/v1:trace_config_proto": "@opencensus_proto//opencensus/proto/trace/v1:trace_config_proto_py",
"@opentelemetry_proto//:trace": "@opentelemetry_proto//:trace_py_proto",
"@opentelemetry_proto//:logs": "@opentelemetry_proto//:logs_py_proto",
"@opentelemetry_proto//:metrics": "@opentelemetry_proto//:metrics_py_proto",
"@opentelemetry_proto//:common": "@opentelemetry_proto//:common_py_proto",
}
20 changes: 20 additions & 0 deletions api/bazel/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,26 @@ go_proto_library(
visibility = ["//visibility:public"],
)
api_cc_py_proto_library(
name = "metrics",
srcs = [
"opentelemetry/proto/collector/metrics/v1/metrics_service.proto",
"opentelemetry/proto/metrics/v1/metrics.proto",
],
deps = [
"//:common",
"//:resource",
],
visibility = ["//visibility:public"],
)
go_proto_library(
name = "metrics_go_proto",
importpath = "go.opentelemetry.io/proto/otlp/metrics/v1",
proto = ":metrics",
visibility = ["//visibility:public"],
)
api_cc_py_proto_library(
name = "trace",
srcs = [
Expand Down
12 changes: 12 additions & 0 deletions api/envoy/extensions/stat_sinks/open_telemetry/v3/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = [
"//envoy/config/core/v3:pkg",
"@com_github_cncf_udpa//udpa/annotations:pkg",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
syntax = "proto3";

package envoy.extensions.stat_sinks.open_telemetry.v3;

import "envoy/config/core/v3/grpc_service.proto";

import "google/protobuf/wrappers.proto";

import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.stat_sinks.open_telemetry.v3";
option java_outer_classname = "OpenTelemetryProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/stat_sinks/open_telemetry/v3;open_telemetryv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Open Telemetry Stats Sink]
// Stats configuration proto schema for ``envoy.stat_sinks.open_telemetry`` sink.
// [#extension: envoy.stat_sinks.open_telemetry]

// [#next-free-field: 6]
message SinkConfig {
oneof protocol_specifier {
option (validate.required) = true;

// The upstream gRPC cluster that implements the OTLP/gRPC collector.
config.core.v3.GrpcService grpc_service = 1 [(validate.rules).message = {required: true}];
}

// If set to true, counters will be emitted as deltas, and the OTLP message will have
// ``AGGREGATION_TEMPORALITY_DELTA`` set as AggregationTemporality.
bool report_counters_as_deltas = 2;

// If set to true, histograms will be emitted as deltas, and the OTLP message will have
// ``AGGREGATION_TEMPORALITY_DELTA`` set as AggregationTemporality.
bool report_histograms_as_deltas = 3;

// If set to true, metrics will have their tags emitted as OTLP attributes, which may
// contain values used by the tag extractor or additional tags added during stats creation.
// Otherwise, no attributes will be associated with the export message. Default value is true.
google.protobuf.BoolValue emit_tags_as_attributes = 4;

// If set to true, metric names will be represented as the tag extracted name instead
// of the full metric name. Default value is true.
google.protobuf.BoolValue use_tag_extracted_name = 5;
}
1 change: 1 addition & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ proto_library(
"//envoy/extensions/retry/host/previous_hosts/v3:pkg",
"//envoy/extensions/retry/priority/previous_priorities/v3:pkg",
"//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg",
"//envoy/extensions/stat_sinks/open_telemetry/v3:pkg",
"//envoy/extensions/stat_sinks/wasm/v3:pkg",
"//envoy/extensions/transport_sockets/alts/v3:pkg",
"//envoy/extensions/transport_sockets/http_11_proxy/v3:pkg",
Expand Down
5 changes: 5 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,14 @@ new_features:
added Runtime feature ``envoy.reloadable_features.max_request_headers_size_kb`` to override the default value of
:ref:`max request headers size
<envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.max_request_headers_kb>`.
- area: stat_sinks
change: |
Added ``envoy.stat_sinks.open_telemetry`` stats_sink, that supports flushing metrics by the OTLP protocol,
for supported Open Telemetry collectors.
- area: redis_proxy
change: |
added new configuration field :ref:`key_formatter
<envoy_v3_api_field_extensions.filters.network.redis_proxy.v3.RedisProxy.PrefixRoutes.Route.key_formatter>` to format redis key.
The field supports using %KEY% as a formatter command for substituting the redis key as part of the substitution formatter expression.
deprecated:
1 change: 1 addition & 0 deletions docs/root/api-v3/config/stat_sinks/stat_sinks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ Stat sinks
:maxdepth: 2

../../extensions/stat_sinks/graphite_statsd/v3/*
../../extensions/stat_sinks/open_telemetry/v3/*
../../extensions/stat_sinks/wasm/v3/*
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.. _config_stat_sinks_open_telemetry:

OpenTelemetry Stat Sink
=========================

The :ref:`OpenTelemetryStatsSink <envoy_v3_api_msg_extensions.stat_sinks.open_telemetry.v3.SinkConfig>` configuration specifies a
stat sink that emits stats according to `OpenTelemetry Protocol Specification <https://opentelemetry.io/docs/reference/specification/protocol/otlp/>`_.
The export requests of this sink are sent to the collector service according to the Protobuf defined in
`MetricService/Export <https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/collector/metrics/v1/metrics_service.proto>`_.
The metric resources exported are defined in `metrics.proto <https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/metrics/v1/metrics.proto>`_.
Any export request that this sink sends, will contain a single ``ResourceMetrics`` message, a single ``ScopeMetrics`` and repeated ``MetricRecord``,
according to the number of metrics collected during the proccess run.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ Stat sinks
:maxdepth: 2

graphite_statsd_stat_sink
open_telemetry_stat_sink
wasm_stat_sink
1 change: 1 addition & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ EXTENSIONS = {
"envoy.stat_sinks.graphite_statsd": "//source/extensions/stat_sinks/graphite_statsd:config",
"envoy.stat_sinks.hystrix": "//source/extensions/stat_sinks/hystrix:config",
"envoy.stat_sinks.metrics_service": "//source/extensions/stat_sinks/metrics_service:config",
"envoy.stat_sinks.open_telemetry": "//source/extensions/stat_sinks/open_telemetry:config",
"envoy.stat_sinks.statsd": "//source/extensions/stat_sinks/statsd:config",
"envoy.stat_sinks.wasm": "//source/extensions/stat_sinks/wasm:config",

Expand Down
7 changes: 7 additions & 0 deletions source/extensions/extensions_metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,13 @@ envoy.stat_sinks.metrics_service:
status: stable
type_urls:
- envoy.config.metrics.v3.MetricsServiceConfig
envoy.stat_sinks.open_telemetry:
categories:
- envoy.stats_sinks
security_posture: data_plane_agnostic
status: alpha
type_urls:
- envoy.extensions.stat_sinks.open_telemetry.v3.SinkConfig
envoy.stat_sinks.statsd:
categories:
- envoy.stats_sinks
Expand Down
45 changes: 45 additions & 0 deletions source/extensions/stat_sinks/open_telemetry/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_extension",
"envoy_cc_library",
"envoy_extension_package",
)

licenses(["notice"]) # Apache 2

envoy_extension_package()

envoy_cc_library(
name = "open_telemetry_lib",
srcs = ["open_telemetry_impl.cc"],
hdrs = ["open_telemetry_impl.h"],
deps = [
"//envoy/grpc:async_client_interface",
"//envoy/singleton:instance_interface",
"//source/common/grpc:async_client_lib",
"@envoy_api//envoy/extensions/stat_sinks/open_telemetry/v3:pkg_cc_proto",
"@opentelemetry_proto//:metrics_cc_proto",
],
)

envoy_cc_library(
name = "open_telemetry_proto_descriptors_lib",
srcs = ["open_telemetry_proto_descriptors.cc"],
hdrs = ["open_telemetry_proto_descriptors.h"],
deps = [
"//source/common/common:assert_lib",
"//source/common/protobuf",
],
)

envoy_cc_extension(
name = "config",
srcs = ["config.cc"],
hdrs = ["config.h"],
deps = [
":open_telemetry_lib",
":open_telemetry_proto_descriptors_lib",
"//envoy/registry",
"//source/server:configuration_lib",
],
)
60 changes: 60 additions & 0 deletions source/extensions/stat_sinks/open_telemetry/config.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "source/extensions/stat_sinks/open_telemetry/config.h"

#include "envoy/registry/registry.h"

#include "source/extensions/stat_sinks/open_telemetry/open_telemetry_impl.h"
#include "source/extensions/stat_sinks/open_telemetry/open_telemetry_proto_descriptors.h"

namespace Envoy {
namespace Extensions {
namespace StatSinks {
namespace OpenTelemetry {

Stats::SinkPtr
OpenTelemetrySinkFactory::createStatsSink(const Protobuf::Message& config,
Server::Configuration::ServerFactoryContext& server) {
validateProtoDescriptors();

const auto& sink_config = MessageUtil::downcastAndValidate<const SinkConfig&>(
config, server.messageValidationContext().staticValidationVisitor());

auto otlp_options = std::make_shared<OtlpOptions>(sink_config);
std::shared_ptr<OtlpMetricsFlusher> otlp_metrics_flusher =
std::make_shared<OtlpMetricsFlusherImpl>(otlp_options);

switch (sink_config.protocol_specifier_case()) {
case SinkConfig::ProtocolSpecifierCase::kGrpcService: {
const auto& grpc_service = sink_config.grpc_service();

std::shared_ptr<OpenTelemetryGrpcMetricsExporter> grpc_metrics_exporter =
std::make_shared<OpenTelemetryGrpcMetricsExporterImpl>(
otlp_options,
server.clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient(
grpc_service, server.scope(), false));

return std::make_unique<OpenTelemetryGrpcSink>(otlp_metrics_flusher, grpc_metrics_exporter);
}

default:
break;
}

throw EnvoyException("unexpected Open Telemetry protocol case num");
}

ProtobufTypes::MessagePtr OpenTelemetrySinkFactory::createEmptyConfigProto() {
return std::make_unique<SinkConfig>();
}

std::string OpenTelemetrySinkFactory::name() const { return OpenTelemetryName; }

/**
* Static registration for the this sink factory. @see RegisterFactory.
*/
LEGACY_REGISTER_FACTORY(OpenTelemetrySinkFactory, Server::Configuration::StatsSinkFactory,
"envoy.open_telemetry_stat_sink");

} // namespace OpenTelemetry
} // namespace StatSinks
} // namespace Extensions
} // namespace Envoy
34 changes: 34 additions & 0 deletions source/extensions/stat_sinks/open_telemetry/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include "envoy/registry/registry.h"
#include "envoy/server/instance.h"

#include "source/server/configuration_impl.h"

namespace Envoy {
namespace Extensions {
namespace StatSinks {
namespace OpenTelemetry {

constexpr char OpenTelemetryName[] = "envoy.stat_sinks.open_telemetry";

/**
* Config registration for the OpenTelemetry stats sink. @see StatsSinkFactory.
*/
class OpenTelemetrySinkFactory : Logger::Loggable<Logger::Id::config>,
public Server::Configuration::StatsSinkFactory {
public:
Stats::SinkPtr createStatsSink(const Protobuf::Message& config,
Server::Configuration::ServerFactoryContext& server) override;

ProtobufTypes::MessagePtr createEmptyConfigProto() override;

std::string name() const override;
};

DECLARE_FACTORY(OpenTelemetrySinkFactory);

} // namespace OpenTelemetry
} // namespace StatSinks
} // namespace Extensions
} // namespace Envoy
Loading

0 comments on commit a6d46b6

Please sign in to comment.