From 208e6827c6ae474d693e9dfbe5d46af005c115a5 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Tue, 26 Mar 2024 01:33:35 +0100 Subject: [PATCH 01/43] feat: Extend telemetryapi receiver to collect metrics, logs, and more traces --- collector/go.mod | 14 +- collector/go.sum | 28 +- collector/internal/telemetryapi/types.go | 8 + .../receiver/telemetryapireceiver/README.md | 30 +- .../receiver/telemetryapireceiver/config.go | 7 + .../receiver/telemetryapireceiver/factory.go | 63 ++- .../receiver/telemetryapireceiver/go.mod | 22 +- .../receiver/telemetryapireceiver/go.sum | 37 +- .../receiver/telemetryapireceiver/receiver.go | 382 ++++++++++++++---- .../telemetryapireceiver/receiver_test.go | 280 ++++++------- .../telemetryapireceiver/transform.go | 101 +++++ .../receiver/telemetryapireceiver/types.go | 40 ++ 12 files changed, 726 insertions(+), 286 deletions(-) create mode 100644 collector/receiver/telemetryapireceiver/transform.go diff --git a/collector/go.mod b/collector/go.mod index 9eee66b3c6..a1a0efcc1d 100644 --- a/collector/go.mod +++ b/collector/go.mod @@ -61,7 +61,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/gobwas/glob v0.2.3 // indirect @@ -159,7 +159,7 @@ require ( go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.21.1 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/bridge/opencensus v0.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 // indirect @@ -169,14 +169,14 @@ require ( go.opentelemetry.io/otel/exporters/prometheus v0.44.1-0.20231201153405-6027c1ae76f2 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.44.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/otel/sdk v1.21.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/sdk v1.24.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect gonum.org/v1/gonum v0.14.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect diff --git a/collector/go.sum b/collector/go.sum index c3a1d0e03e..20112e9fb0 100644 --- a/collector/go.sum +++ b/collector/go.sum @@ -330,8 +330,8 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= @@ -668,8 +668,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1: go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= go.opentelemetry.io/contrib/zpages v0.46.1 h1:U8Hh84dc+vJTVgRnL+QKWtWD2iqTSKibrQ85EeQqsNg= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/bridge/opencensus v0.44.0 h1:/inELPJztkn6Xx3ap9qw8i8XdeWF0B/OjGHOdRTePZ8= go.opentelemetry.io/otel/bridge/opencensus v0.44.0/go.mod h1:dQTBJVBx1xahrXEFBV1BGPAnGuXC92LCj55fxIrtj7I= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI= @@ -688,14 +688,14 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.44.0 h1:dEZWPjVN22urgY go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.44.0/go.mod h1:sTt30Evb7hJB/gEk27qLb1+l9n4Tb8HvHkR0Wx3S6CU= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYfrPk5SOryw1e9LDDTZCbIPFrho0ec= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= -go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= -go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/sdk/metric v1.24.0 h1:yyMQrPzF+k88/DbH7o4FMAs80puqd+9osbiBrJrz/w8= +go.opentelemetry.io/otel/sdk/metric v1.24.0/go.mod h1:I6Y5FjH6rvEnTTAYQz3Mmv2kl6Ek5IIrmwTLqMrrOE0= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= @@ -830,8 +830,8 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/collector/internal/telemetryapi/types.go b/collector/internal/telemetryapi/types.go index 56ca237e6f..aaf38d00f8 100644 --- a/collector/internal/telemetryapi/types.go +++ b/collector/internal/telemetryapi/types.go @@ -24,6 +24,14 @@ const ( PlatformInitStart EventType = Platform + ".initStart" // PlatformInitRuntimeDone is used when function initialization ended. PlatformInitRuntimeDone EventType = Platform + ".initRuntimeDone" + // PlatformInitReport is used to report on function initialization. + PlatformInitReport EventType = Platform + ".initReport" + // PlatformStart is used when function invocation started. + PlatformStart EventType = Platform + ".start" + // PlatformRuntimeDone is used when function invocation ended. + PlatformRuntimeDone EventType = Platform + ".runtimeDone" + // PlatformReport is used to report on function invocation. + PlatformReport EventType = Platform + ".report" // Function is used to receive log events emitted by the function Function EventType = "function" // Extension is used is to receive log events emitted by the extension diff --git a/collector/receiver/telemetryapireceiver/README.md b/collector/receiver/telemetryapireceiver/README.md index ddb836c0b1..414abda1d8 100644 --- a/collector/receiver/telemetryapireceiver/README.md +++ b/collector/receiver/telemetryapireceiver/README.md @@ -1,25 +1,35 @@ # Telemetry API Receiver -| Status | | -| ------------------------ |-----------------| -| Stability | [in development]| -| Supported pipeline types | traces | -| Distributions | [extension] | +| Status | | +| ------------------------ | ---------------- | +| Stability | [in development] | +| Supported pipeline types | traces, metrics | +| Distributions | [extension] | -This receiver generates telemetry in response to events from the [Telemetry API](https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api.html). It does this by setting up an endpoint and registering itself with the Telemetry API on startup. +This receiver generates telemetry in response to events from the +[Telemetry API](https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api.html). It does this by setting up an +endpoint and registering itself with the Telemetry API on startup. Supported events: -* `platform.initStart` - The receiver uses this event to record the start time of the function initialization period. Once both start and end times are recorded, the receiver generates a span named `platform.initRuntimeDone` to record the event. -* `platform.initRuntimeDone` - The receiver uses this event to record the end time of the function initialization period. Once both start and end times are recorded, the receiver generates a span named `platform.initRuntimeDone` to record the event. +- `platform.initStart` - The receiver uses this event to record the start time of the function initialization period. + Once both start and end times are recorded, the receiver generates a span named `platform.initRuntimeDone` to record + the event. +- `platform.initRuntimeDone` - The receiver uses this event to record the end time of the function initialization + period. Once both start and end times are recorded, the receiver generates a span named `platform.initRuntimeDone` to + record the event. ## Configuration -There are currently no configuration parameters available for this receiver. It can be enabled via the following configuration: +There are currently no configuration parameters available for this receiver. It can be enabled via the following +configuration: ```yaml receivers: - telemetryapi: + telemetryapi: + metrics: + useExponentialHistograms: true + includeBilledDuration: true ``` [in development]: https://github.com/open-telemetry/opentelemetry-collector#development diff --git a/collector/receiver/telemetryapireceiver/config.go b/collector/receiver/telemetryapireceiver/config.go index 86b5250196..0f1ada5c75 100644 --- a/collector/receiver/telemetryapireceiver/config.go +++ b/collector/receiver/telemetryapireceiver/config.go @@ -17,6 +17,13 @@ package telemetryapireceiver // import "github.com/open-telemetry/opentelemetry- // Config defines the configuration for the various elements of the receiver agent. type Config struct { extensionID string + Metrics MetricsConfig `mapstructure:"metrics"` +} + +// MetricsConfig defines configuration for the collection of metrics from the Telemetry API. +type MetricsConfig struct { + UseExponentialHistograms bool `mapstructure:"use_exponential_histograms"` + IncludeBilledDuration bool `mapstructure:"include_billed_duration"` } // Validate validates the configuration by checking for missing or invalid fields diff --git a/collector/receiver/telemetryapireceiver/factory.go b/collector/receiver/telemetryapireceiver/factory.go index 3bb800f164..16267f2528 100644 --- a/collector/receiver/telemetryapireceiver/factory.go +++ b/collector/receiver/telemetryapireceiver/factory.go @@ -17,6 +17,7 @@ package telemetryapireceiver // import "github.com/open-telemetry/opentelemetry- import ( "context" "errors" + "sync" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" @@ -32,6 +33,7 @@ var errConfigNotTelemetryAPI = errors.New("config was not a Telemetry API receiv // NewFactory creates a new receiver factory func NewFactory(extensionID string) receiver.Factory { + cache := &ReceiverCache{} return receiver.NewFactory( typeStr, func() component.Config { @@ -39,14 +41,65 @@ func NewFactory(extensionID string) receiver.Factory { extensionID: extensionID, } }, - receiver.WithTraces(createTracesReceiver, stability)) + receiver.WithTraces(cache.createTracesReceiver, stability), + receiver.WithMetrics(cache.createMetricsReceiver, stability), + ) } -func createTracesReceiver(ctx context.Context, params receiver.CreateSettings, rConf component.Config, next consumer.Traces) (receiver.Traces, error) { +/* ------------------------------------------- CACHE ------------------------------------------- */ + +type ReceiverCache struct { + lock sync.Mutex + receiver *telemetryAPIReceiver +} + +func (c *ReceiverCache) createTracesReceiver( + _ context.Context, + params receiver.CreateSettings, + rConf component.Config, + next consumer.Traces, +) (receiver.Traces, error) { + c.lock.Lock() + defer c.lock.Unlock() + + if c.receiver == nil { + if err := c.setReceiver(params, rConf); err != nil { + return nil, err + } + } + c.receiver.setTracesConsumer(next) + return c.receiver, nil +} + +func (c *ReceiverCache) createMetricsReceiver( + _ context.Context, + params receiver.CreateSettings, + rConf component.Config, + next consumer.Metrics, +) (receiver.Metrics, error) { + c.lock.Lock() + defer c.lock.Unlock() + + if c.receiver == nil { + if err := c.setReceiver(params, rConf); err != nil { + return nil, err + } + } + c.receiver.setMetricsConsumer(next) + return c.receiver, nil +} + +func (c *ReceiverCache) setReceiver( + params receiver.CreateSettings, rConf component.Config, +) error { cfg, ok := rConf.(*Config) if !ok { - return nil, errConfigNotTelemetryAPI + return errConfigNotTelemetryAPI } - - return newTelemetryAPIReceiver(cfg, next, params) + receiver, err := newTelemetryAPIReceiver(cfg, params) + if err != nil { + return err + } + c.receiver = receiver + return nil } diff --git a/collector/receiver/telemetryapireceiver/go.mod b/collector/receiver/telemetryapireceiver/go.mod index 70504157c5..73a6463385 100644 --- a/collector/receiver/telemetryapireceiver/go.mod +++ b/collector/receiver/telemetryapireceiver/go.mod @@ -5,20 +5,25 @@ go 1.20 replace github.com/open-telemetry/opentelemetry-lambda/collector => ../../ require ( - github.com/golang-collections/go-datastructures v0.0.0-20150211160725-59788d5eb259 + github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 github.com/open-telemetry/opentelemetry-lambda/collector v0.91.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 go.opentelemetry.io/collector/component v0.92.0 go.opentelemetry.io/collector/consumer v0.92.0 go.opentelemetry.io/collector/pdata v1.0.1 go.opentelemetry.io/collector/receiver v0.92.0 go.opentelemetry.io/collector/semconv v0.92.0 - go.uber.org/zap v1.26.0 + go.opentelemetry.io/otel/metric v1.24.0 + go.opentelemetry.io/otel/sdk/metric v1.24.0 + go.uber.org/zap v1.27.0 ) require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-collections/go-datastructures v0.0.0-20150211160725-59788d5eb259 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -26,7 +31,6 @@ require ( github.com/knadh/koanf/providers/confmap v0.1.0 // indirect github.com/knadh/koanf/v2 v2.0.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -34,15 +38,15 @@ require ( go.opentelemetry.io/collector/config/configtelemetry v0.92.0 // indirect go.opentelemetry.io/collector/confmap v0.92.0 // indirect go.opentelemetry.io/collector/featuregate v1.0.1 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/sdk v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect google.golang.org/grpc v1.60.1 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/collector/receiver/telemetryapireceiver/go.sum b/collector/receiver/telemetryapireceiver/go.sum index 4bfd206451..9dac2c4688 100644 --- a/collector/receiver/telemetryapireceiver/go.sum +++ b/collector/receiver/telemetryapireceiver/go.sum @@ -2,8 +2,11 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-collections/go-datastructures v0.0.0-20150211160725-59788d5eb259 h1:ZHJ7+IGpuOXtVf6Zk/a3WuHQgkC+vXwaqfUBDFwahtI= @@ -45,8 +48,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/collector v0.92.0 h1:XiC0ptaT1EmOkK2RI0gt3n2tkzLAkNQGf0E7hrGdyeA= @@ -66,17 +69,21 @@ go.opentelemetry.io/collector/receiver v0.92.0 h1:TRz4ufr5bFEszpAWgYVEx/b7VPZzEc go.opentelemetry.io/collector/receiver v0.92.0/go.mod h1:bYAAYbMuUVj3wx7ave2iyyJ+aGUpACliYOQ5xI92I7k= go.opentelemetry.io/collector/semconv v0.92.0 h1:3+OGPPuVu4rtrz8qGbpbiw7eKKULj4iJaSDTV52HM40= go.opentelemetry.io/collector/semconv v0.92.0/go.mod h1:gZ0uzkXsN+J5NpiRcdp9xOhNGQDDui8Y62p15sKrlzo= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/sdk/metric v1.24.0 h1:yyMQrPzF+k88/DbH7o4FMAs80puqd+9osbiBrJrz/w8= +go.opentelemetry.io/otel/sdk/metric v1.24.0/go.mod h1:I6Y5FjH6rvEnTTAYQz3Mmv2kl6Ek5IIrmwTLqMrrOE0= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -94,8 +101,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -114,8 +121,8 @@ google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 4df8b7764d..2507251cb1 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -26,32 +26,173 @@ import ( "os" "time" - "github.com/golang-collections/go-datastructures/queue" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/receiver" - semconv "go.opentelemetry.io/collector/semconv/v1.5.0" + semconv "go.opentelemetry.io/collector/semconv/v1.22.0" + "go.opentelemetry.io/otel/metric" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.uber.org/zap" + "github.com/mitchellh/mapstructure" "github.com/open-telemetry/opentelemetry-lambda/collector/internal/telemetryapi" ) -const defaultListenerPort = "4325" -const initialQueueSize = 5 +const ( + defaultListenerPort = "4325" + instrumentationScope = "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapi" +) + +/* ------------------------------------------ CREATION ----------------------------------------- */ type telemetryAPIReceiver struct { - httpServer *http.Server - logger *zap.Logger - queue *queue.Queue // queue is a synchronous queue and is used to put the received log events to be dispatched later - nextConsumer consumer.Traces - lastPlatformStartTime string - lastPlatformEndTime string - extensionID string - resource pcommon.Resource + // SHARED + httpServer *http.Server + logger *zap.Logger + extensionID string + resource pcommon.Resource + cfg *Config + // TRACES + nextTracesConsumer consumer.Traces + lastPlatformInitStartTime string + lastPlatformInitEndTime string + // METRICS + // NOTE: We're using the OpenTelemetry SDK here as generating 'pmetric' structures entirely + // manually is error-prone and would duplicate plenty of code available in the SDK. + nextMetricsConsumer consumer.Metrics + metricsReader *sdkmetric.ManualReader + metricInitDurations metric.Float64Histogram + metricInvokeDurations metric.Float64Histogram + metricColdstarts metric.Int64Counter + metricBilledDuration metric.Float64Counter + metricSuccesses metric.Int64Counter + metricFailures metric.Int64Counter + metricTimeouts metric.Int64Counter + metricMemoryUsages metric.Int64Histogram } +func newTelemetryAPIReceiver( + cfg *Config, + set receiver.CreateSettings, +) (*telemetryAPIReceiver, error) { + r := pcommon.NewResource() + if val, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_NAME"); ok { + r.Attributes().PutStr(semconv.AttributeServiceName, val) + r.Attributes().PutStr(semconv.AttributeFaaSName, val) + } else { + r.Attributes().PutStr(semconv.AttributeServiceName, "unknown_service") + } + envSources := map[string]string{ + semconv.AttributeFaaSMaxMemory: "AWS_LAMBDA_FUNCTION_MEMORY_SIZE", + semconv.AttributeFaaSVersion: "AWS_LAMBDA_FUNCTION_VERSION", + semconv.AttributeFaaSInstance: "AWS_LAMBDA_LOG_STREAM_NAME", + } + for resourceAttribute, env := range envSources { + if val, ok := os.LookupEnv(env); ok { + r.Attributes().PutStr(resourceAttribute, val) + } + } + + // This telemetry API receiver is very minimal. We're lazily initializing most members as this + // receiver is requested in processing pipelines. + return &telemetryAPIReceiver{ + logger: set.Logger, + extensionID: cfg.extensionID, + resource: r, + cfg: cfg, + }, nil +} + +func (r *telemetryAPIReceiver) setTracesConsumer(next consumer.Traces) { + r.nextTracesConsumer = next +} + +func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { + r.nextMetricsConsumer = next + r.metricsReader = sdkmetric.NewManualReader() + + // Configure histogram aggregation based on configuration + var aggregation sdkmetric.Aggregation + if r.cfg.Metrics.UseExponentialHistograms { + aggregation = sdkmetric.AggregationExplicitBucketHistogram{ + Boundaries: []float64{ + 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10, + }, + } + } else { + aggregation = sdkmetric.AggregationBase2ExponentialHistogram{ + MaxSize: 160, + MaxScale: 20, + } + } + view := sdkmetric.NewView( + sdkmetric.Instrument{Kind: sdkmetric.InstrumentKindHistogram}, + sdkmetric.Stream{Aggregation: aggregation}, + ) + + // Initialize a meter for all metrics + provider := sdkmetric.NewMeterProvider( + sdkmetric.WithReader(r.metricsReader), + sdkmetric.WithView(view), + ) + meter := provider.Meter(instrumentationScope) + + // Build the metrics and propagate the last error + // NOTE: The metrics defined here follow the semantic conventions for FaaS Metrics: + // https://opentelemetry.io/docs/specs/semconv/faas/faas-metrics/ + // The only exception is `faas.billed_duration` which can be enabled via config. + var err error + r.metricInvokeDurations, err = meter.Float64Histogram( + "faas.invoke_duration", + metric.WithDescription("The duration of the function's logic execution."), + metric.WithUnit("s"), + ) + r.metricInitDurations, err = meter.Float64Histogram( + "faas.init_duration", + metric.WithDescription("The duration of the function's initialization."), + metric.WithUnit("s"), + ) + if r.cfg.Metrics.IncludeBilledDuration { + r.metricBilledDuration, err = meter.Float64Counter( + "faas.billed_duration", + metric.WithDescription("The duration for which the function was billed."), + metric.WithUnit("s"), + ) + } + r.metricColdstarts, err = meter.Int64Counter( + "faas.coldstarts", + metric.WithDescription("Number of invocation cold starts."), + metric.WithUnit("s"), + ) + r.metricSuccesses, err = meter.Int64Counter( + "faas.invocations", + metric.WithDescription("Number of successful invocations."), + metric.WithUnit("1"), + ) + r.metricFailures, err = meter.Int64Counter( + "faas.errors", + metric.WithDescription("Number of invocation errors."), + metric.WithUnit("1"), + ) + r.metricTimeouts, err = meter.Int64Counter( + "faas.timeouts", + metric.WithDescription("Number of invocation timeouts."), + metric.WithUnit("1"), + ) + r.metricMemoryUsages, err = meter.Int64Histogram( + "faas.mem_usage", + metric.WithDescription("Max memory usage per invocation."), + metric.WithUnit("By"), + ) + return err +} + +/* ------------------------------------ COMPONENT INTERFACE ------------------------------------ */ + func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) error { address := listenOnAddress() r.logger.Info("Listening for requests", zap.String("address", address)) @@ -66,7 +207,10 @@ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) e telemetryClient := telemetryapi.NewClient(r.logger) _, err := telemetryClient.Subscribe(ctx, r.extensionID, fmt.Sprintf("http://%s/", address)) if err != nil { - r.logger.Info("Listening for requests", zap.String("address", address), zap.String("extensionID", r.extensionID)) + r.logger.Info( + "Listening for requests", + zap.String("address", address), zap.String("extensionID", r.extensionID), + ) return err } return nil @@ -76,27 +220,9 @@ func (r *telemetryAPIReceiver) Shutdown(ctx context.Context) error { return nil } -func newSpanID() pcommon.SpanID { - var rngSeed int64 - _ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) - randSource := rand.New(rand.NewSource(rngSeed)) - sid := pcommon.SpanID{} - _, _ = randSource.Read(sid[:]) - return sid -} - -func newTraceID() pcommon.TraceID { - var rngSeed int64 - _ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) - randSource := rand.New(rand.NewSource(rngSeed)) - tid := pcommon.TraceID{} - _, _ = randSource.Read(tid[:]) - return tid -} +/* --------------------------------------- EVENT HANDLER --------------------------------------- */ // httpHandler handles the requests coming from the Telemetry API. -// Everytime Telemetry API sends events, this function will read them from the response body -// and put into a synchronous queue to be dispatched later. // Logging or printing besides the error cases below is not recommended if you have subscribed to // receive extension logs. Otherwise, logging here will cause Telemetry API to send new logs for // the printed lines which may create an infinite loop. @@ -113,27 +239,66 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ return } + ctx := context.Background() for _, el := range slice { - r.logger.Debug(fmt.Sprintf("Event: %s", el.Type), zap.Any("event", el)) switch el.Type { // Function initialization started. case string(telemetryapi.PlatformInitStart): - r.logger.Info(fmt.Sprintf("Init start: %s", r.lastPlatformStartTime), zap.Any("event", el)) - r.lastPlatformStartTime = el.Time + r.logger.Debug(fmt.Sprintf("Init start: %s", el.Time), zap.Any("event", el)) + r.lastPlatformInitStartTime = el.Time // Function initialization completed. case string(telemetryapi.PlatformInitRuntimeDone): - r.logger.Info(fmt.Sprintf("Init end: %s", r.lastPlatformEndTime), zap.Any("event", el)) - r.lastPlatformEndTime = el.Time - } - // TODO: add support for additional events, see https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api.html - // A report of function initialization. - // case "platform.initReport": + r.logger.Debug(fmt.Sprintf("Init end: %s", el.Time), zap.Any("event", el)) + r.lastPlatformInitEndTime = el.Time + // Concluding report on function initialization. + case string(telemetryapi.PlatformInitReport): + r.logger.Debug(fmt.Sprintf("Init report: %s", el.Time), zap.Any("event", el)) + if r.metricsReader == nil { + continue + } + if record, err := parseRecord[platformInitReportRecord](el, r.logger); err == nil { + r.metricColdstarts.Add(ctx, 1) + r.metricInitDurations.Record(ctx, record.Metrics.DurationMs/1000.0) + } // Function invocation started. - // case "platform.start": - // The runtime finished processing an event with either success or failure. - // case "platform.runtimeDone": - // A report of function invocation. - // case "platform.report": + case string(telemetryapi.PlatformStart): + r.logger.Debug(fmt.Sprintf("Invoke start: %s", el.Time), zap.Any("event", el)) + continue + // Function invocation completed. + case string(telemetryapi.PlatformRuntimeDone): + r.logger.Debug(fmt.Sprintf("Invoke end: %s", el.Time), zap.Any("event", el)) + if r.metricsReader == nil { + continue + } + if record, err := parseRecord[platformRuntimeDoneRecord](el, r.logger); err == nil { + r.metricInvokeDurations.Record(ctx, record.Metrics.DurationMs/1000.0) + switch record.Status { + case statusSuccess: + r.metricSuccesses.Add(ctx, 1) + case statusError, statusFailure: + r.metricFailures.Add(ctx, 1) + case statusTimeout: + r.metricTimeouts.Add(ctx, 1) + } + } + // Concluding report on function invocation (after runtime freeze). + case string(telemetryapi.PlatformReport): + r.logger.Debug(fmt.Sprintf("Invoke report: %s", el.Time), zap.Any("event", el)) + if r.metricsReader == nil { + continue + } + if record, err := parseRecord[platformReport](el, r.logger); err == nil { + if r.metricBilledDuration != nil { // conditionally initialized + r.metricBilledDuration.Add(ctx, record.Metrics.BilledDurationMs/1000.0) + } + r.metricMemoryUsages.Record(ctx, record.Metrics.MaxMemoryUsedMb*1024*1024) + } + // Log record emitted by function. + case string(telemetryapi.Function): + r.logger.Debug(fmt.Sprintf("Log entry: %s", el.Time), zap.Any("event", el)) + continue + } + // TODO: potentially add support for additional events, see https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api.html // Runtime restore started (reserved for future use) // case "platform.restoreStart": // Runtime restore completed (reserved for future use) @@ -145,20 +310,96 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Lambda dropped log entries. // case "platform.logsDropped": } - if len(r.lastPlatformStartTime) > 0 && len(r.lastPlatformEndTime) > 0 { - if td, err := r.createPlatformInitSpan(r.lastPlatformStartTime, r.lastPlatformEndTime); err == nil { - err := r.nextConsumer.ConsumeTraces(context.Background(), td) + r.forwardTraces() + r.forwardMetrics() + slice = nil +} + +func parseRecord[T any](el event, logger *zap.Logger) (T, error) { + var record T + if err := mapstructure.Decode(el.Record, &record); err != nil { + logger.Error( + fmt.Sprintf("Failed to parse %s record", el.Type), + zap.Error(err), zap.Any("event", el), + ) + return record, err + } + return record, nil +} + +/* ----------------------------------------- FORWARDING ---------------------------------------- */ + +func (r *telemetryAPIReceiver) forwardTraces() { + // Create trace for init span + if len(r.lastPlatformInitStartTime) > 0 && len(r.lastPlatformInitEndTime) > 0 { + if td, err := r.createPlatformInitSpan(r.lastPlatformInitStartTime, r.lastPlatformInitEndTime); err == nil { + err := r.nextTracesConsumer.ConsumeTraces(context.Background(), td) if err == nil { - r.lastPlatformEndTime = "" - r.lastPlatformStartTime = "" + r.lastPlatformInitEndTime = "" + r.lastPlatformInitStartTime = "" } else { r.logger.Error("error receiving traces", zap.Error(err)) } } } +} + +func (r *telemetryAPIReceiver) forwardMetrics() { + if r.metricsReader == nil { + // If the metrics reader is not set, no metrics consumer is set, we can stop. + return + } - r.logger.Debug("logEvents received", zap.Int("count", len(slice)), zap.Int64("queue_length", r.queue.Len())) - slice = nil + // Collect metrics from the metrics reader + var resourceMetrics metricdata.ResourceMetrics + if err := r.metricsReader.Collect(context.Background(), &resourceMetrics); err != nil { + r.logger.Error("error collecting metrics", zap.Error(err)) + return + } + + // Initialize internal metrics representation + metricData := pmetric.NewMetrics() + rs := metricData.ResourceMetrics().AppendEmpty() + r.resource.CopyTo(rs.Resource()) + resourceMetricData := metricData.ResourceMetrics().AppendEmpty() + + // Parse metrics from metrics reader into internal representation + for _, scope := range resourceMetrics.ScopeMetrics { + scopeMetrics := resourceMetricData.ScopeMetrics().AppendEmpty() + scopeMetrics.Scope().SetName(scope.Scope.Name) + for _, metric := range scope.Metrics { + innerMetric := scopeMetrics.Metrics().AppendEmpty() + if err := transformMetric(metric, innerMetric); err != nil { + r.logger.Error("error parsing collected metrics", zap.Error(err)) + return + } + } + } + + // Eventually, forward the metrics to the consumer + if err := r.nextMetricsConsumer.ConsumeMetrics(context.Background(), metricData); err != nil { + r.logger.Error("error receiving metrics", zap.Error(err)) + } +} + +/* ------------------------------------------- TRACES ------------------------------------------ */ + +func newSpanID() pcommon.SpanID { + var rngSeed int64 + _ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) + randSource := rand.New(rand.NewSource(rngSeed)) + sid := pcommon.SpanID{} + _, _ = randSource.Read(sid[:]) + return sid +} + +func newTraceID() pcommon.TraceID { + var rngSeed int64 + _ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) + randSource := rand.New(rand.NewSource(rngSeed)) + tid := pcommon.TraceID{} + _, _ = randSource.Read(tid[:]) + return tid } func (r *telemetryAPIReceiver) createPlatformInitSpan(start, end string) (ptrace.Traces, error) { @@ -167,7 +408,7 @@ func (r *telemetryAPIReceiver) createPlatformInitSpan(start, end string) (ptrace r.resource.CopyTo(rs.Resource()) ss := rs.ScopeSpans().AppendEmpty() - ss.Scope().SetName("github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapi") + ss.Scope().SetName(instrumentationScope) span := ss.Spans().AppendEmpty() span.SetTraceID(newTraceID()) span.SetSpanID(newSpanID()) @@ -188,38 +429,7 @@ func (r *telemetryAPIReceiver) createPlatformInitSpan(start, end string) (ptrace return traceData, nil } -func newTelemetryAPIReceiver( - cfg *Config, - next consumer.Traces, - set receiver.CreateSettings, -) (*telemetryAPIReceiver, error) { - envResourceMap := map[string]string{ - "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": semconv.AttributeFaaSMaxMemory, - "AWS_LAMBDA_FUNCTION_VERSION": semconv.AttributeFaaSVersion, - "AWS_REGION": semconv.AttributeFaaSInvokedRegion, - } - r := pcommon.NewResource() - r.Attributes().PutStr(semconv.AttributeFaaSInvokedProvider, semconv.AttributeFaaSInvokedProviderAWS) - if val, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_NAME"); ok { - r.Attributes().PutStr(semconv.AttributeServiceName, val) - r.Attributes().PutStr(semconv.AttributeFaaSName, val) - } else { - r.Attributes().PutStr(semconv.AttributeServiceName, "unknown_service") - } - - for env, resourceAttribute := range envResourceMap { - if val, ok := os.LookupEnv(env); ok { - r.Attributes().PutStr(resourceAttribute, val) - } - } - return &telemetryAPIReceiver{ - logger: set.Logger, - queue: queue.New(initialQueueSize), - nextConsumer: next, - extensionID: cfg.extensionID, - resource: r, - }, nil -} +/* ------------------------------------------- UTILS ------------------------------------------- */ func listenOnAddress() string { envAwsLocal, ok := os.LookupEnv("AWS_SAM_LOCAL") diff --git a/collector/receiver/telemetryapireceiver/receiver_test.go b/collector/receiver/telemetryapireceiver/receiver_test.go index 7f7b46572f..43de6df252 100644 --- a/collector/receiver/telemetryapireceiver/receiver_test.go +++ b/collector/receiver/telemetryapireceiver/receiver_test.go @@ -14,150 +14,150 @@ package telemetryapireceiver // import "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver" -import ( - "context" - "net/http/httptest" - "strings" - "testing" +// import ( +// "context" +// "net/http/httptest" +// "strings" +// "testing" - "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/consumer" - "go.opentelemetry.io/collector/pdata/ptrace" - "go.opentelemetry.io/collector/receiver/receivertest" -) +// "github.com/stretchr/testify/require" +// "go.opentelemetry.io/collector/consumer" +// "go.opentelemetry.io/collector/pdata/ptrace" +// "go.opentelemetry.io/collector/receiver/receivertest" +// ) -func TestListenOnAddress(t *testing.T) { - testCases := []struct { - desc string - testFunc func(*testing.T) - }{ - { - desc: "listen on address without AWS_SAM_LOCAL env variable", - testFunc: func(t *testing.T) { - addr := listenOnAddress() - require.EqualValues(t, "sandbox.localdomain:4325", addr) - }, - }, - { - desc: "listen on address with AWS_SAM_LOCAL env variable", - testFunc: func(t *testing.T) { - t.Setenv("AWS_SAM_LOCAL", "true") - addr := listenOnAddress() - require.EqualValues(t, ":4325", addr) - }, - }, - } - for _, tc := range testCases { - t.Run(tc.desc, tc.testFunc) - } -} +// func TestListenOnAddress(t *testing.T) { +// testCases := []struct { +// desc string +// testFunc func(*testing.T) +// }{ +// { +// desc: "listen on address without AWS_SAM_LOCAL env variable", +// testFunc: func(t *testing.T) { +// addr := listenOnAddress() +// require.EqualValues(t, "sandbox.localdomain:4325", addr) +// }, +// }, +// { +// desc: "listen on address with AWS_SAM_LOCAL env variable", +// testFunc: func(t *testing.T) { +// t.Setenv("AWS_SAM_LOCAL", "true") +// addr := listenOnAddress() +// require.EqualValues(t, ":4325", addr) +// }, +// }, +// } +// for _, tc := range testCases { +// t.Run(tc.desc, tc.testFunc) +// } +// } -type mockConsumer struct { - consumed int -} +// type mockConsumer struct { +// consumed int +// } -func (c *mockConsumer) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { - c.consumed += td.SpanCount() - return nil -} +// func (c *mockConsumer) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { +// c.consumed += td.SpanCount() +// return nil +// } -func (c *mockConsumer) Capabilities() consumer.Capabilities { - return consumer.Capabilities{MutatesData: true} -} +// func (c *mockConsumer) Capabilities() consumer.Capabilities { +// return consumer.Capabilities{MutatesData: true} +// } -func TestHandler(t *testing.T) { - testCases := []struct { - desc string - body string - expectedSpans int - }{ - { - desc: "empty body", - body: `{}`, - }, - { - desc: "invalid json", - body: `invalid json`, - }, - { - desc: "valid event", - body: `[{"time":"", "type":"", "record": {}}]`, - }, - { - desc: "valid event", - body: `[{"time":"", "type":"platform.initStart", "record": {}}]`, - }, - { - desc: "valid start/end events", - body: `[ - {"time":"2006-01-02T15:04:04.000Z", "type":"platform.initStart", "record": {}}, - {"time":"2006-01-02T15:04:05.000Z", "type":"platform.initRuntimeDone", "record": {}} - ]`, - expectedSpans: 1, - }, - } - for _, tc := range testCases { - t.Run(tc.desc, func(t *testing.T) { - consumer := mockConsumer{} - r, err := newTelemetryAPIReceiver( - &Config{}, - &consumer, - receivertest.NewNopCreateSettings(), - ) - require.NoError(t, err) - req := httptest.NewRequest("POST", - "http://localhost:53612/someevent", strings.NewReader(tc.body)) - rec := httptest.NewRecorder() - r.httpHandler(rec, req) - require.Equal(t, tc.expectedSpans, consumer.consumed) - }) - } -} +// func TestHandler(t *testing.T) { +// testCases := []struct { +// desc string +// body string +// expectedSpans int +// }{ +// { +// desc: "empty body", +// body: `{}`, +// }, +// { +// desc: "invalid json", +// body: `invalid json`, +// }, +// { +// desc: "valid event", +// body: `[{"time":"", "type":"", "record": {}}]`, +// }, +// { +// desc: "valid event", +// body: `[{"time":"", "type":"platform.initStart", "record": {}}]`, +// }, +// { +// desc: "valid start/end events", +// body: `[ +// {"time":"2006-01-02T15:04:04.000Z", "type":"platform.initStart", "record": {}}, +// {"time":"2006-01-02T15:04:05.000Z", "type":"platform.initRuntimeDone", "record": {}} +// ]`, +// expectedSpans: 1, +// }, +// } +// for _, tc := range testCases { +// t.Run(tc.desc, func(t *testing.T) { +// consumer := mockConsumer{} +// r, err := newTelemetryAPIReceiver( +// &Config{}, +// &consumer, +// receivertest.NewNopCreateSettings(), +// ) +// require.NoError(t, err) +// req := httptest.NewRequest("POST", +// "http://localhost:53612/someevent", strings.NewReader(tc.body)) +// rec := httptest.NewRecorder() +// r.httpHandler(rec, req) +// require.Equal(t, tc.expectedSpans, consumer.consumed) +// }) +// } +// } -func TestCreatePlatformInitSpan(t *testing.T) { - testCases := []struct { - desc string - start string - end string - expected int - expectError bool - }{ - { - desc: "no start/end times", - expectError: true, - }, - { - desc: "no end time", - start: "2006-01-02T15:04:05.000Z", - expectError: true, - }, - { - desc: "no start times", - end: "2006-01-02T15:04:05.000Z", - expectError: true, - }, - { - desc: "valid times", - start: "2006-01-02T15:04:04.000Z", - end: "2006-01-02T15:04:05.000Z", - expected: 1, - expectError: false, - }, - } - for _, tc := range testCases { - t.Run(tc.desc, func(t *testing.T) { - r, err := newTelemetryAPIReceiver( - &Config{}, - nil, - receivertest.NewNopCreateSettings(), - ) - require.NoError(t, err) - td, err := r.createPlatformInitSpan(tc.start, tc.end) - if tc.expectError { - require.Error(t, err) - } else { - require.Equal(t, tc.expected, td.SpanCount()) - } - }) - } -} +// func TestCreatePlatformInitSpan(t *testing.T) { +// testCases := []struct { +// desc string +// start string +// end string +// expected int +// expectError bool +// }{ +// { +// desc: "no start/end times", +// expectError: true, +// }, +// { +// desc: "no end time", +// start: "2006-01-02T15:04:05.000Z", +// expectError: true, +// }, +// { +// desc: "no start times", +// end: "2006-01-02T15:04:05.000Z", +// expectError: true, +// }, +// { +// desc: "valid times", +// start: "2006-01-02T15:04:04.000Z", +// end: "2006-01-02T15:04:05.000Z", +// expected: 1, +// expectError: false, +// }, +// } +// for _, tc := range testCases { +// t.Run(tc.desc, func(t *testing.T) { +// r, err := newTelemetryAPIReceiver( +// &Config{}, +// nil, +// receivertest.NewNopCreateSettings(), +// ) +// require.NoError(t, err) +// td, err := r.createPlatformInitSpan(tc.start, tc.end) +// if tc.expectError { +// require.Error(t, err) +// } else { +// require.Equal(t, tc.expected, td.SpanCount()) +// } +// }) +// } +// } diff --git a/collector/receiver/telemetryapireceiver/transform.go b/collector/receiver/telemetryapireceiver/transform.go new file mode 100644 index 0000000000..603bc1ff85 --- /dev/null +++ b/collector/receiver/telemetryapireceiver/transform.go @@ -0,0 +1,101 @@ +package telemetryapireceiver + +import ( + "errors" + + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +// NOTE: The transformations in this file are *incomplete* for general use and should, thus, +// not be relied upon in contexts other than this package. + +var errUnsupportedInstrumentType = errors.New("instrument type is currently unsupported") + +func transformMetric(src metricdata.Metrics, dst pmetric.Metric) error { + dst.SetName(src.Name) + dst.SetDescription(src.Description) + dst.SetUnit(src.Unit) + switch data := src.Data.(type) { + case metricdata.ExponentialHistogram[float64]: + instrument := dst.SetEmptyExponentialHistogram() + transformExponentialHistogram(data, instrument) + case metricdata.ExponentialHistogram[int64]: + instrument := dst.SetEmptyExponentialHistogram() + transformExponentialHistogram(data, instrument) + case metricdata.Sum[int64]: + instrument := dst.SetEmptySum() + transformCounterInt(data, instrument) + case metricdata.Sum[float64]: + instrument := dst.SetEmptySum() + transformCounterFloat(data, instrument) + default: + return errUnsupportedInstrumentType + } + return nil +} + +/* ---------------------------------------- INSTRUMENTS ---------------------------------------- */ + +func transformExponentialHistogram[N int64 | float64]( + src metricdata.ExponentialHistogram[N], + dst pmetric.ExponentialHistogram, +) { + dst.SetAggregationTemporality(mapTemporality(src.Temporality)) + for _, datapoint := range src.DataPoints { + dp := dst.DataPoints().AppendEmpty() + dp.SetCount(datapoint.Count) + if v, ok := datapoint.Max.Value(); ok { + dp.SetMax(float64(v)) + } + if v, ok := datapoint.Max.Value(); ok { + dp.SetMin(float64(v)) + } + dp.SetScale(datapoint.Scale) + dp.SetStartTimestamp(pcommon.NewTimestampFromTime(datapoint.StartTime)) + dp.SetSum(float64(datapoint.Sum)) + dp.SetTimestamp(pcommon.NewTimestampFromTime(datapoint.Time)) + dp.SetZeroCount(datapoint.ZeroCount) + dp.SetZeroThreshold(datapoint.ZeroThreshold) + dp.Negative().SetOffset(datapoint.NegativeBucket.Offset) + dp.Negative().BucketCounts().Append(datapoint.NegativeBucket.Counts...) + dp.Positive().SetOffset(datapoint.PositiveBucket.Offset) + dp.Positive().BucketCounts().Append(datapoint.PositiveBucket.Counts...) + } +} + +func transformCounterInt(src metricdata.Sum[int64], dst pmetric.Sum) { + dst.SetAggregationTemporality(mapTemporality(src.Temporality)) + dst.SetIsMonotonic(src.IsMonotonic) + for _, datapoint := range src.DataPoints { + dp := dst.DataPoints().AppendEmpty() + dp.SetIntValue(datapoint.Value) + dp.SetStartTimestamp(pcommon.NewTimestampFromTime(datapoint.StartTime)) + dp.SetTimestamp(pcommon.NewTimestampFromTime(datapoint.Time)) + } +} + +func transformCounterFloat(src metricdata.Sum[float64], dst pmetric.Sum) { + dst.SetAggregationTemporality(mapTemporality(src.Temporality)) + dst.SetIsMonotonic(src.IsMonotonic) + for _, datapoint := range src.DataPoints { + dp := dst.DataPoints().AppendEmpty() + dp.SetDoubleValue(datapoint.Value) + dp.SetStartTimestamp(pcommon.NewTimestampFromTime(datapoint.StartTime)) + dp.SetTimestamp(pcommon.NewTimestampFromTime(datapoint.Time)) + } +} + +/* ------------------------------------------- UTILS ------------------------------------------- */ + +func mapTemporality(t metricdata.Temporality) pmetric.AggregationTemporality { + switch t { + case metricdata.CumulativeTemporality: + return pmetric.AggregationTemporalityCumulative + case metricdata.DeltaTemporality: + return pmetric.AggregationTemporalityDelta + default: + return pmetric.AggregationTemporalityUnspecified + } +} diff --git a/collector/receiver/telemetryapireceiver/types.go b/collector/receiver/telemetryapireceiver/types.go index 40bbc6ff94..54ec212a5b 100644 --- a/collector/receiver/telemetryapireceiver/types.go +++ b/collector/receiver/telemetryapireceiver/types.go @@ -19,3 +19,43 @@ type event struct { Type string `json:"type"` Record map[string]any `json:"record"` } + +// NOTE: Types defined here do not include all attributes sent by the Telemetry API but only those +// relevant to this package. For a full overview, consult the documentation: +// https://docs.aws.amazon.com/lambda/latest/dg/telemetry-schema-reference.html#telemetry-api-events + +type platformInitReportRecord struct { + Metrics struct { + DurationMs float64 `mapstructure:"durationMs"` + } `mapstructure:"metrics"` +} + +type platformStartRecord struct { + RequestID string `mapstructure:"requestId"` +} + +type platformRuntimeDoneRecord struct { + RequestID string `mapstructure:"requestId"` + Status status `mapstructure:"status"` + Metrics *struct { + DurationMs float64 `mapstructure:"durationMs"` + } `mapstructure:"metrics"` +} + +type platformReport struct { + Metrics struct { + BilledDurationMs float64 `mapstructure:"billedDurationMs"` + MaxMemoryUsedMb int64 `mapstructure:"maxMemoryUsedMB"` + } `mapstructure:"metrics"` +} + +/* ----------------------------------------- CONSTANTS ----------------------------------------- */ + +type status string + +const ( + statusSuccess = status("success") + statusFailure = status("failure") + statusError = status("error") + statusTimeout = status("timeout") +) From c5116cd74867f3217c653b8cc8ccac702450dab7 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Tue, 26 Mar 2024 02:33:21 +0100 Subject: [PATCH 02/43] Fix --- collector/receiver/telemetryapireceiver/receiver.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 2507251cb1..e2608fec17 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -118,16 +118,16 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { // Configure histogram aggregation based on configuration var aggregation sdkmetric.Aggregation if r.cfg.Metrics.UseExponentialHistograms { + aggregation = sdkmetric.AggregationBase2ExponentialHistogram{ + MaxSize: 160, + MaxScale: 20, + } + } else { aggregation = sdkmetric.AggregationExplicitBucketHistogram{ Boundaries: []float64{ 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10, }, } - } else { - aggregation = sdkmetric.AggregationBase2ExponentialHistogram{ - MaxSize: 160, - MaxScale: 20, - } } view := sdkmetric.NewView( sdkmetric.Instrument{Kind: sdkmetric.InstrumentKindHistogram}, @@ -166,7 +166,7 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { r.metricColdstarts, err = meter.Int64Counter( "faas.coldstarts", metric.WithDescription("Number of invocation cold starts."), - metric.WithUnit("s"), + metric.WithUnit("1"), ) r.metricSuccesses, err = meter.Int64Counter( "faas.invocations", From 6326239c93849cb2de422488844c30ba5cb07043 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Tue, 26 Mar 2024 02:47:27 +0100 Subject: [PATCH 03/43] Try --- .../receiver/telemetryapireceiver/transform.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/transform.go b/collector/receiver/telemetryapireceiver/transform.go index 603bc1ff85..5883b1bab9 100644 --- a/collector/receiver/telemetryapireceiver/transform.go +++ b/collector/receiver/telemetryapireceiver/transform.go @@ -18,12 +18,12 @@ func transformMetric(src metricdata.Metrics, dst pmetric.Metric) error { dst.SetDescription(src.Description) dst.SetUnit(src.Unit) switch data := src.Data.(type) { - case metricdata.ExponentialHistogram[float64]: - instrument := dst.SetEmptyExponentialHistogram() - transformExponentialHistogram(data, instrument) - case metricdata.ExponentialHistogram[int64]: - instrument := dst.SetEmptyExponentialHistogram() - transformExponentialHistogram(data, instrument) + // case metricdata.ExponentialHistogram[float64]: + // instrument := dst.SetEmptyExponentialHistogram() + // transformExponentialHistogram(data, instrument) + // case metricdata.ExponentialHistogram[int64]: + // instrument := dst.SetEmptyExponentialHistogram() + // transformExponentialHistogram(data, instrument) case metricdata.Sum[int64]: instrument := dst.SetEmptySum() transformCounterInt(data, instrument) @@ -31,7 +31,8 @@ func transformMetric(src metricdata.Metrics, dst pmetric.Metric) error { instrument := dst.SetEmptySum() transformCounterFloat(data, instrument) default: - return errUnsupportedInstrumentType + break + // return errUnsupportedInstrumentType } return nil } From 2606caf426b37139559d28149a61310c190a9c86 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Tue, 26 Mar 2024 21:44:58 +0100 Subject: [PATCH 04/43] No metrics --- .../telemetryapireceiver/transform.go | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/transform.go b/collector/receiver/telemetryapireceiver/transform.go index 5883b1bab9..fd8b7e1e50 100644 --- a/collector/receiver/telemetryapireceiver/transform.go +++ b/collector/receiver/telemetryapireceiver/transform.go @@ -17,23 +17,23 @@ func transformMetric(src metricdata.Metrics, dst pmetric.Metric) error { dst.SetName(src.Name) dst.SetDescription(src.Description) dst.SetUnit(src.Unit) - switch data := src.Data.(type) { + // switch data := src.Data.(type) { // case metricdata.ExponentialHistogram[float64]: // instrument := dst.SetEmptyExponentialHistogram() // transformExponentialHistogram(data, instrument) // case metricdata.ExponentialHistogram[int64]: // instrument := dst.SetEmptyExponentialHistogram() // transformExponentialHistogram(data, instrument) - case metricdata.Sum[int64]: - instrument := dst.SetEmptySum() - transformCounterInt(data, instrument) - case metricdata.Sum[float64]: - instrument := dst.SetEmptySum() - transformCounterFloat(data, instrument) - default: - break - // return errUnsupportedInstrumentType - } + // case metricdata.Sum[int64]: + // instrument := dst.SetEmptySum() + // transformCounterInt(data, instrument) + // case metricdata.Sum[float64]: + // instrument := dst.SetEmptySum() + // transformCounterFloat(data, instrument) + // default: + // break + // return errUnsupportedInstrumentType + // } return nil } From 937fbe520806a7ae2ec080130a76c308c6d9b06c Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Tue, 26 Mar 2024 22:11:54 +0100 Subject: [PATCH 05/43] try --- .../telemetryapireceiver/transform.go | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/transform.go b/collector/receiver/telemetryapireceiver/transform.go index fd8b7e1e50..0c7463458a 100644 --- a/collector/receiver/telemetryapireceiver/transform.go +++ b/collector/receiver/telemetryapireceiver/transform.go @@ -5,6 +5,7 @@ import ( "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" ) @@ -17,23 +18,23 @@ func transformMetric(src metricdata.Metrics, dst pmetric.Metric) error { dst.SetName(src.Name) dst.SetDescription(src.Description) dst.SetUnit(src.Unit) - // switch data := src.Data.(type) { + switch data := src.Data.(type) { // case metricdata.ExponentialHistogram[float64]: // instrument := dst.SetEmptyExponentialHistogram() // transformExponentialHistogram(data, instrument) // case metricdata.ExponentialHistogram[int64]: // instrument := dst.SetEmptyExponentialHistogram() // transformExponentialHistogram(data, instrument) - // case metricdata.Sum[int64]: - // instrument := dst.SetEmptySum() - // transformCounterInt(data, instrument) + case metricdata.Sum[int64]: + instrument := dst.SetEmptySum() + transformCounterInt(data, instrument) // case metricdata.Sum[float64]: // instrument := dst.SetEmptySum() // transformCounterFloat(data, instrument) - // default: - // break - // return errUnsupportedInstrumentType - // } + default: + break + // return errUnsupportedInstrumentType + } return nil } @@ -74,6 +75,7 @@ func transformCounterInt(src metricdata.Sum[int64], dst pmetric.Sum) { dp.SetIntValue(datapoint.Value) dp.SetStartTimestamp(pcommon.NewTimestampFromTime(datapoint.StartTime)) dp.SetTimestamp(pcommon.NewTimestampFromTime(datapoint.Time)) + transformAttributes(datapoint.Attributes, dp.Attributes()) } } @@ -90,6 +92,28 @@ func transformCounterFloat(src metricdata.Sum[float64], dst pmetric.Sum) { /* ------------------------------------------- UTILS ------------------------------------------- */ +func transformAttributes(src attribute.Set, dst pcommon.Map) { + iter := src.Iter() + for _, kv := range iter.ToSlice() { + if !kv.Valid() || !kv.Key.Defined() { + continue + } + key := string(kv.Key) + switch kv.Value.Type() { + case attribute.BOOL: + dst.PutBool(key, kv.Value.AsBool()) + case attribute.FLOAT64: + dst.PutDouble(key, kv.Value.AsFloat64()) + case attribute.INT64: + dst.PutInt(key, kv.Value.AsInt64()) + case attribute.STRING: + dst.PutStr(key, kv.Value.AsString()) + default: + continue + } + } +} + func mapTemporality(t metricdata.Temporality) pmetric.AggregationTemporality { switch t { case metricdata.CumulativeTemporality: From f381938876f7c5ca0d5e53441a9c7126e25a8c67 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Tue, 26 Mar 2024 22:38:41 +0100 Subject: [PATCH 06/43] Debug --- collector/receiver/telemetryapireceiver/receiver.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index e2608fec17..d39547ecbd 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -30,6 +30,7 @@ import ( "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/receiver" semconv "go.opentelemetry.io/collector/semconv/v1.22.0" @@ -376,6 +377,11 @@ func (r *telemetryAPIReceiver) forwardMetrics() { } } + rr := pmetricotlp.NewExportRequestFromMetrics(metricData) + json, err := rr.MarshalJSON() + fmt.Printf("JSON: %s\n", string(json)) + fmt.Printf("Error: %s\n", err) + // Eventually, forward the metrics to the consumer if err := r.nextMetricsConsumer.ConsumeMetrics(context.Background(), metricData); err != nil { r.logger.Error("error receiving metrics", zap.Error(err)) From 5a7184a92f42a10bbfaf4cd7710febbf8ab52ac6 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Tue, 26 Mar 2024 23:06:16 +0100 Subject: [PATCH 07/43] Fix --- collector/receiver/telemetryapireceiver/receiver.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index d39547ecbd..06be97419f 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -360,9 +360,8 @@ func (r *telemetryAPIReceiver) forwardMetrics() { // Initialize internal metrics representation metricData := pmetric.NewMetrics() - rs := metricData.ResourceMetrics().AppendEmpty() - r.resource.CopyTo(rs.Resource()) resourceMetricData := metricData.ResourceMetrics().AppendEmpty() + r.resource.CopyTo(resourceMetricData.Resource()) // Parse metrics from metrics reader into internal representation for _, scope := range resourceMetrics.ScopeMetrics { From 0efab13f7bf56ad64ec140ca10c1222c2ed616a1 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Wed, 27 Mar 2024 01:15:00 +0100 Subject: [PATCH 08/43] try --- .../receiver/telemetryapireceiver/receiver.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 06be97419f..8e1e492e04 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -24,6 +24,7 @@ import ( "math/rand" "net/http" "os" + "strconv" "time" "go.opentelemetry.io/collector/component" @@ -87,14 +88,15 @@ func newTelemetryAPIReceiver( } else { r.Attributes().PutStr(semconv.AttributeServiceName, "unknown_service") } - envSources := map[string]string{ - semconv.AttributeFaaSMaxMemory: "AWS_LAMBDA_FUNCTION_MEMORY_SIZE", - semconv.AttributeFaaSVersion: "AWS_LAMBDA_FUNCTION_VERSION", - semconv.AttributeFaaSInstance: "AWS_LAMBDA_LOG_STREAM_NAME", + if val, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_VERSION"); ok { + r.Attributes().PutStr(semconv.AttributeFaaSVersion, val) } - for resourceAttribute, env := range envSources { - if val, ok := os.LookupEnv(env); ok { - r.Attributes().PutStr(resourceAttribute, val) + if val, ok := os.LookupEnv("AWS_LAMBDA_LOG_STREAM_NAME"); ok { + r.Attributes().PutStr(semconv.AttributeFaaSInstance, val) + } + if val, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE"); ok { + if mb, err := strconv.Atoi(val); err == nil { + r.Attributes().PutInt(semconv.AttributeFaaSMaxMemory, int64(mb)*1024*1024) } } @@ -110,6 +112,7 @@ func newTelemetryAPIReceiver( func (r *telemetryAPIReceiver) setTracesConsumer(next consumer.Traces) { r.nextTracesConsumer = next + r.logger.Info("set traces consumer") } func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { @@ -189,6 +192,7 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { metric.WithDescription("Max memory usage per invocation."), metric.WithUnit("By"), ) + r.logger.Info("set metrics consumer") return err } From d82795706e1fc7eb9ab9bdd25aadf06362ca0899 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Wed, 27 Mar 2024 01:38:22 +0100 Subject: [PATCH 09/43] fix? --- collector/receiver/telemetryapireceiver/receiver.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 8e1e492e04..57661677a3 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -112,7 +112,6 @@ func newTelemetryAPIReceiver( func (r *telemetryAPIReceiver) setTracesConsumer(next consumer.Traces) { r.nextTracesConsumer = next - r.logger.Info("set traces consumer") } func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { @@ -192,7 +191,6 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { metric.WithDescription("Max memory usage per invocation."), metric.WithUnit("By"), ) - r.logger.Info("set metrics consumer") return err } @@ -361,6 +359,10 @@ func (r *telemetryAPIReceiver) forwardMetrics() { r.logger.Error("error collecting metrics", zap.Error(err)) return } + if len(resourceMetrics.ScopeMetrics) == 0 { + // If there are no scope metrics, we do not need to export anything + return + } // Initialize internal metrics representation metricData := pmetric.NewMetrics() From 7e5d76c583731f75b1a9593f18dd6a5104e1f212 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Wed, 27 Mar 2024 01:54:01 +0100 Subject: [PATCH 10/43] Fix --- .../telemetryapireceiver/transform.go | 45 +++++-------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/transform.go b/collector/receiver/telemetryapireceiver/transform.go index 0c7463458a..603bc1ff85 100644 --- a/collector/receiver/telemetryapireceiver/transform.go +++ b/collector/receiver/telemetryapireceiver/transform.go @@ -5,7 +5,6 @@ import ( "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" - "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" ) @@ -19,21 +18,20 @@ func transformMetric(src metricdata.Metrics, dst pmetric.Metric) error { dst.SetDescription(src.Description) dst.SetUnit(src.Unit) switch data := src.Data.(type) { - // case metricdata.ExponentialHistogram[float64]: - // instrument := dst.SetEmptyExponentialHistogram() - // transformExponentialHistogram(data, instrument) - // case metricdata.ExponentialHistogram[int64]: - // instrument := dst.SetEmptyExponentialHistogram() - // transformExponentialHistogram(data, instrument) + case metricdata.ExponentialHistogram[float64]: + instrument := dst.SetEmptyExponentialHistogram() + transformExponentialHistogram(data, instrument) + case metricdata.ExponentialHistogram[int64]: + instrument := dst.SetEmptyExponentialHistogram() + transformExponentialHistogram(data, instrument) case metricdata.Sum[int64]: instrument := dst.SetEmptySum() transformCounterInt(data, instrument) - // case metricdata.Sum[float64]: - // instrument := dst.SetEmptySum() - // transformCounterFloat(data, instrument) + case metricdata.Sum[float64]: + instrument := dst.SetEmptySum() + transformCounterFloat(data, instrument) default: - break - // return errUnsupportedInstrumentType + return errUnsupportedInstrumentType } return nil } @@ -75,7 +73,6 @@ func transformCounterInt(src metricdata.Sum[int64], dst pmetric.Sum) { dp.SetIntValue(datapoint.Value) dp.SetStartTimestamp(pcommon.NewTimestampFromTime(datapoint.StartTime)) dp.SetTimestamp(pcommon.NewTimestampFromTime(datapoint.Time)) - transformAttributes(datapoint.Attributes, dp.Attributes()) } } @@ -92,28 +89,6 @@ func transformCounterFloat(src metricdata.Sum[float64], dst pmetric.Sum) { /* ------------------------------------------- UTILS ------------------------------------------- */ -func transformAttributes(src attribute.Set, dst pcommon.Map) { - iter := src.Iter() - for _, kv := range iter.ToSlice() { - if !kv.Valid() || !kv.Key.Defined() { - continue - } - key := string(kv.Key) - switch kv.Value.Type() { - case attribute.BOOL: - dst.PutBool(key, kv.Value.AsBool()) - case attribute.FLOAT64: - dst.PutDouble(key, kv.Value.AsFloat64()) - case attribute.INT64: - dst.PutInt(key, kv.Value.AsInt64()) - case attribute.STRING: - dst.PutStr(key, kv.Value.AsString()) - default: - continue - } - } -} - func mapTemporality(t metricdata.Temporality) pmetric.AggregationTemporality { switch t { case metricdata.CumulativeTemporality: From 8e504b55bdd421bf9227d5bc7de7cd7502a7a052 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Wed, 27 Mar 2024 19:43:46 +0100 Subject: [PATCH 11/43] Add zeros --- .../receiver/telemetryapireceiver/factory.go | 19 ++++++++++ .../receiver/telemetryapireceiver/receiver.go | 38 ++++++++++++++++--- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/factory.go b/collector/receiver/telemetryapireceiver/factory.go index 16267f2528..47a69c60f0 100644 --- a/collector/receiver/telemetryapireceiver/factory.go +++ b/collector/receiver/telemetryapireceiver/factory.go @@ -43,6 +43,7 @@ func NewFactory(extensionID string) receiver.Factory { }, receiver.WithTraces(cache.createTracesReceiver, stability), receiver.WithMetrics(cache.createMetricsReceiver, stability), + receiver.WithLogs(cache.createLogsReceiver, stability), ) } @@ -89,6 +90,24 @@ func (c *ReceiverCache) createMetricsReceiver( return c.receiver, nil } +func (c *ReceiverCache) createLogsReceiver( + _ context.Context, + params receiver.CreateSettings, + rConf component.Config, + next consumer.Logs, +) (receiver.Logs, error) { + c.lock.Lock() + defer c.lock.Unlock() + + if c.receiver == nil { + if err := c.setReceiver(params, rConf); err != nil { + return nil, err + } + } + c.receiver.setLogsConsumer(next) + return c.receiver, nil +} + func (c *ReceiverCache) setReceiver( params receiver.CreateSettings, rConf component.Config, ) error { diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 57661677a3..a19bb1d9b2 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -31,7 +31,6 @@ import ( "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" - "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/receiver" semconv "go.opentelemetry.io/collector/semconv/v1.22.0" @@ -75,6 +74,8 @@ type telemetryAPIReceiver struct { metricFailures metric.Int64Counter metricTimeouts metric.Int64Counter metricMemoryUsages metric.Int64Histogram + // LOGS + nextLogsConsumer consumer.Logs } func newTelemetryAPIReceiver( @@ -159,33 +160,44 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { metric.WithDescription("The duration of the function's initialization."), metric.WithUnit("s"), ) + if r.cfg.Metrics.IncludeBilledDuration { r.metricBilledDuration, err = meter.Float64Counter( "faas.billed_duration", metric.WithDescription("The duration for which the function was billed."), metric.WithUnit("s"), ) + r.metricBilledDuration.Add(context.Background(), 0) } + r.metricColdstarts, err = meter.Int64Counter( "faas.coldstarts", metric.WithDescription("Number of invocation cold starts."), metric.WithUnit("1"), ) + r.metricColdstarts.Add(context.Background(), 0) + r.metricSuccesses, err = meter.Int64Counter( "faas.invocations", metric.WithDescription("Number of successful invocations."), metric.WithUnit("1"), ) + r.metricSuccesses.Add(context.Background(), 0) + r.metricFailures, err = meter.Int64Counter( "faas.errors", metric.WithDescription("Number of invocation errors."), metric.WithUnit("1"), ) + r.metricFailures.Add(context.Background(), 0) + r.metricTimeouts, err = meter.Int64Counter( "faas.timeouts", metric.WithDescription("Number of invocation timeouts."), metric.WithUnit("1"), ) + r.metricTimeouts.Add(context.Background(), 0) + r.metricMemoryUsages, err = meter.Int64Histogram( "faas.mem_usage", metric.WithDescription("Max memory usage per invocation."), @@ -194,6 +206,10 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { return err } +func (r *telemetryAPIReceiver) setLogsConsumer(next consumer.Logs) { + r.nextLogsConsumer = next +} + /* ------------------------------------ COMPONENT INTERFACE ------------------------------------ */ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) error { @@ -382,17 +398,25 @@ func (r *telemetryAPIReceiver) forwardMetrics() { } } - rr := pmetricotlp.NewExportRequestFromMetrics(metricData) - json, err := rr.MarshalJSON() - fmt.Printf("JSON: %s\n", string(json)) - fmt.Printf("Error: %s\n", err) - // Eventually, forward the metrics to the consumer if err := r.nextMetricsConsumer.ConsumeMetrics(context.Background(), metricData); err != nil { r.logger.Error("error receiving metrics", zap.Error(err)) } } +// func (r *telemetryAPIReceiver) forwardLogLine(line string) { +// logData := plog.NewLogs() +// rs := logData.ResourceLogs().AppendEmpty() +// r.resource.CopyTo(rs.Resource()) + +// scopeLog := rs.ScopeLogs().AppendEmpty() +// scopeLog.Scope().SetName(instrumentationScope) + +// log := scopeLog.LogRecords().AppendEmpty() +// log.SetSeverityNumber(plog.SeverityNumberDebug) +// log.Body() +// } + /* ------------------------------------------- TRACES ------------------------------------------ */ func newSpanID() pcommon.SpanID { @@ -440,6 +464,8 @@ func (r *telemetryAPIReceiver) createPlatformInitSpan(start, end string) (ptrace return traceData, nil } +/* -------------------------------------------- LOGS ------------------------------------------- */ + /* ------------------------------------------- UTILS ------------------------------------------- */ func listenOnAddress() string { From a19b48dd0f22f7b67046c9970300a58252b23bba Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Wed, 27 Mar 2024 22:04:14 +0100 Subject: [PATCH 12/43] Fix timestamps --- .../receiver/telemetryapireceiver/receiver.go | 64 +++++++++++++++---- .../telemetryapireceiver/transform.go | 22 ++++--- 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index a19bb1d9b2..17370ef16f 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -19,6 +19,7 @@ import ( crand "crypto/rand" "encoding/binary" "encoding/json" + "errors" "fmt" "io" "math/rand" @@ -48,6 +49,8 @@ const ( instrumentationScope = "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapi" ) +var errUnknownMetric = errors.New("metric is unknown") + /* ------------------------------------------ CREATION ----------------------------------------- */ type telemetryAPIReceiver struct { @@ -64,16 +67,19 @@ type telemetryAPIReceiver struct { // METRICS // NOTE: We're using the OpenTelemetry SDK here as generating 'pmetric' structures entirely // manually is error-prone and would duplicate plenty of code available in the SDK. - nextMetricsConsumer consumer.Metrics - metricsReader *sdkmetric.ManualReader - metricInitDurations metric.Float64Histogram - metricInvokeDurations metric.Float64Histogram - metricColdstarts metric.Int64Counter - metricBilledDuration metric.Float64Counter - metricSuccesses metric.Int64Counter - metricFailures metric.Int64Counter - metricTimeouts metric.Int64Counter - metricMemoryUsages metric.Int64Histogram + nextMetricsConsumer consumer.Metrics + metricsReader *sdkmetric.ManualReader + metricInitDurations metric.Float64Histogram + metricInvokeDurations metric.Float64Histogram + metricColdstarts metric.Int64Counter + metricBilledDuration metric.Float64Counter + metricSuccesses metric.Int64Counter + metricFailures metric.Int64Counter + metricTimeouts metric.Int64Counter + metricMemoryUsages metric.Int64Histogram + lastPlatformInitReportTime string + lastPlatformRuntimeDoneTime string + lastPlatformReportTime string // LOGS nextLogsConsumer consumer.Logs } @@ -272,6 +278,7 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Concluding report on function initialization. case string(telemetryapi.PlatformInitReport): r.logger.Debug(fmt.Sprintf("Init report: %s", el.Time), zap.Any("event", el)) + r.lastPlatformReportTime = el.Time if r.metricsReader == nil { continue } @@ -286,6 +293,7 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Function invocation completed. case string(telemetryapi.PlatformRuntimeDone): r.logger.Debug(fmt.Sprintf("Invoke end: %s", el.Time), zap.Any("event", el)) + r.lastPlatformRuntimeDoneTime = el.Time if r.metricsReader == nil { continue } @@ -303,6 +311,7 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Concluding report on function invocation (after runtime freeze). case string(telemetryapi.PlatformReport): r.logger.Debug(fmt.Sprintf("Invoke report: %s", el.Time), zap.Any("event", el)) + r.lastPlatformReportTime = el.Time if r.metricsReader == nil { continue } @@ -390,8 +399,16 @@ func (r *telemetryAPIReceiver) forwardMetrics() { scopeMetrics := resourceMetricData.ScopeMetrics().AppendEmpty() scopeMetrics.Scope().SetName(scope.Scope.Name) for _, metric := range scope.Metrics { + ts, err := r.metricTimestamp(metric.Name) + if err != nil { + r.logger.Error( + fmt.Sprintf("failed to obtain last timestamp for metric '%s'", metric.Name), + zap.Error(err), + ) + continue + } innerMetric := scopeMetrics.Metrics().AppendEmpty() - if err := transformMetric(metric, innerMetric); err != nil { + if err := transformMetric(metric, innerMetric, ts); err != nil { r.logger.Error("error parsing collected metrics", zap.Error(err)) return } @@ -450,13 +467,12 @@ func (r *telemetryAPIReceiver) createPlatformInitSpan(start, end string) (ptrace span.SetName("platform.initRuntimeDone") span.SetKind(ptrace.SpanKindInternal) span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) - layout := "2006-01-02T15:04:05.000Z" - startTime, err := time.Parse(layout, start) + startTime, err := parseTime(start) if err != nil { return ptrace.Traces{}, err } span.SetStartTimestamp(pcommon.NewTimestampFromTime(startTime)) - endTime, err := time.Parse(layout, end) + endTime, err := parseTime(end) if err != nil { return ptrace.Traces{}, err } @@ -464,10 +480,30 @@ func (r *telemetryAPIReceiver) createPlatformInitSpan(start, end string) (ptrace return traceData, nil } +/* ------------------------------------------ METRICS ------------------------------------------ */ + +func (r *telemetryAPIReceiver) metricTimestamp(metricName string) (time.Time, error) { + switch metricName { + case "faas.coldstarts", "faas.init_durations": + return parseTime(r.lastPlatformInitReportTime) + case "faas.invoke_duration", "faas.invocations", "faas.errors", "faas.timeouts": + return parseTime(r.lastPlatformRuntimeDoneTime) + case "faas.billed_duration", "faas.mem_usage": + return parseTime(r.lastPlatformReportTime) + default: + return time.Time{}, errUnknownMetric + } +} + /* -------------------------------------------- LOGS ------------------------------------------- */ /* ------------------------------------------- UTILS ------------------------------------------- */ +func parseTime(t string) (time.Time, error) { + layout := "2006-01-02T15:04:05.000Z" + return time.Parse(layout, t) +} + func listenOnAddress() string { envAwsLocal, ok := os.LookupEnv("AWS_SAM_LOCAL") var addr string diff --git a/collector/receiver/telemetryapireceiver/transform.go b/collector/receiver/telemetryapireceiver/transform.go index 603bc1ff85..770d1d8f46 100644 --- a/collector/receiver/telemetryapireceiver/transform.go +++ b/collector/receiver/telemetryapireceiver/transform.go @@ -2,6 +2,7 @@ package telemetryapireceiver import ( "errors" + "time" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" @@ -13,23 +14,23 @@ import ( var errUnsupportedInstrumentType = errors.New("instrument type is currently unsupported") -func transformMetric(src metricdata.Metrics, dst pmetric.Metric) error { +func transformMetric(src metricdata.Metrics, dst pmetric.Metric, timestamp time.Time) error { dst.SetName(src.Name) dst.SetDescription(src.Description) dst.SetUnit(src.Unit) switch data := src.Data.(type) { case metricdata.ExponentialHistogram[float64]: instrument := dst.SetEmptyExponentialHistogram() - transformExponentialHistogram(data, instrument) + transformExponentialHistogram(data, instrument, timestamp) case metricdata.ExponentialHistogram[int64]: instrument := dst.SetEmptyExponentialHistogram() - transformExponentialHistogram(data, instrument) + transformExponentialHistogram(data, instrument, timestamp) case metricdata.Sum[int64]: instrument := dst.SetEmptySum() - transformCounterInt(data, instrument) + transformCounterInt(data, instrument, timestamp) case metricdata.Sum[float64]: instrument := dst.SetEmptySum() - transformCounterFloat(data, instrument) + transformCounterFloat(data, instrument, timestamp) default: return errUnsupportedInstrumentType } @@ -41,6 +42,7 @@ func transformMetric(src metricdata.Metrics, dst pmetric.Metric) error { func transformExponentialHistogram[N int64 | float64]( src metricdata.ExponentialHistogram[N], dst pmetric.ExponentialHistogram, + timestamp time.Time, ) { dst.SetAggregationTemporality(mapTemporality(src.Temporality)) for _, datapoint := range src.DataPoints { @@ -55,7 +57,7 @@ func transformExponentialHistogram[N int64 | float64]( dp.SetScale(datapoint.Scale) dp.SetStartTimestamp(pcommon.NewTimestampFromTime(datapoint.StartTime)) dp.SetSum(float64(datapoint.Sum)) - dp.SetTimestamp(pcommon.NewTimestampFromTime(datapoint.Time)) + dp.SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) dp.SetZeroCount(datapoint.ZeroCount) dp.SetZeroThreshold(datapoint.ZeroThreshold) dp.Negative().SetOffset(datapoint.NegativeBucket.Offset) @@ -65,25 +67,25 @@ func transformExponentialHistogram[N int64 | float64]( } } -func transformCounterInt(src metricdata.Sum[int64], dst pmetric.Sum) { +func transformCounterInt(src metricdata.Sum[int64], dst pmetric.Sum, timestamp time.Time) { dst.SetAggregationTemporality(mapTemporality(src.Temporality)) dst.SetIsMonotonic(src.IsMonotonic) for _, datapoint := range src.DataPoints { dp := dst.DataPoints().AppendEmpty() dp.SetIntValue(datapoint.Value) dp.SetStartTimestamp(pcommon.NewTimestampFromTime(datapoint.StartTime)) - dp.SetTimestamp(pcommon.NewTimestampFromTime(datapoint.Time)) + dp.SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) } } -func transformCounterFloat(src metricdata.Sum[float64], dst pmetric.Sum) { +func transformCounterFloat(src metricdata.Sum[float64], dst pmetric.Sum, timestamp time.Time) { dst.SetAggregationTemporality(mapTemporality(src.Temporality)) dst.SetIsMonotonic(src.IsMonotonic) for _, datapoint := range src.DataPoints { dp := dst.DataPoints().AppendEmpty() dp.SetDoubleValue(datapoint.Value) dp.SetStartTimestamp(pcommon.NewTimestampFromTime(datapoint.StartTime)) - dp.SetTimestamp(pcommon.NewTimestampFromTime(datapoint.Time)) + dp.SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) } } From 20ed49ddf40aafbb305c2a1ca451f0f64d87c771 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Wed, 27 Mar 2024 22:09:17 +0100 Subject: [PATCH 13/43] Fix? --- collector/receiver/telemetryapireceiver/receiver.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 17370ef16f..11f0c4dcf3 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -278,7 +278,7 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Concluding report on function initialization. case string(telemetryapi.PlatformInitReport): r.logger.Debug(fmt.Sprintf("Init report: %s", el.Time), zap.Any("event", el)) - r.lastPlatformReportTime = el.Time + r.lastPlatformInitReportTime = el.Time if r.metricsReader == nil { continue } @@ -484,7 +484,7 @@ func (r *telemetryAPIReceiver) createPlatformInitSpan(start, end string) (ptrace func (r *telemetryAPIReceiver) metricTimestamp(metricName string) (time.Time, error) { switch metricName { - case "faas.coldstarts", "faas.init_durations": + case "faas.coldstarts", "faas.init_duration": return parseTime(r.lastPlatformInitReportTime) case "faas.invoke_duration", "faas.invocations", "faas.errors", "faas.timeouts": return parseTime(r.lastPlatformRuntimeDoneTime) From 8b6d1ef07cd7858e4d923dfa9f490211db090289 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Wed, 27 Mar 2024 22:14:36 +0100 Subject: [PATCH 14/43] try without 0 --- collector/receiver/telemetryapireceiver/receiver.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 11f0c4dcf3..2825111988 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -173,7 +173,7 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { metric.WithDescription("The duration for which the function was billed."), metric.WithUnit("s"), ) - r.metricBilledDuration.Add(context.Background(), 0) + // r.metricBilledDuration.Add(context.Background(), 0) } r.metricColdstarts, err = meter.Int64Counter( @@ -181,28 +181,28 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { metric.WithDescription("Number of invocation cold starts."), metric.WithUnit("1"), ) - r.metricColdstarts.Add(context.Background(), 0) + // r.metricColdstarts.Add(context.Background(), 0) r.metricSuccesses, err = meter.Int64Counter( "faas.invocations", metric.WithDescription("Number of successful invocations."), metric.WithUnit("1"), ) - r.metricSuccesses.Add(context.Background(), 0) + // r.metricSuccesses.Add(context.Background(), 0) r.metricFailures, err = meter.Int64Counter( "faas.errors", metric.WithDescription("Number of invocation errors."), metric.WithUnit("1"), ) - r.metricFailures.Add(context.Background(), 0) + // r.metricFailures.Add(context.Background(), 0) r.metricTimeouts, err = meter.Int64Counter( "faas.timeouts", metric.WithDescription("Number of invocation timeouts."), metric.WithUnit("1"), ) - r.metricTimeouts.Add(context.Background(), 0) + // r.metricTimeouts.Add(context.Background(), 0) r.metricMemoryUsages, err = meter.Int64Histogram( "faas.mem_usage", From 044f053d0316674780e0a16f8a2075a9c8370d1c Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Thu, 28 Mar 2024 00:52:56 +0100 Subject: [PATCH 15/43] Try zero-init --- .../receiver/telemetryapireceiver/config.go | 1 - .../receiver/telemetryapireceiver/receiver.go | 34 ++++++++----------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/config.go b/collector/receiver/telemetryapireceiver/config.go index 0f1ada5c75..9173b51720 100644 --- a/collector/receiver/telemetryapireceiver/config.go +++ b/collector/receiver/telemetryapireceiver/config.go @@ -23,7 +23,6 @@ type Config struct { // MetricsConfig defines configuration for the collection of metrics from the Telemetry API. type MetricsConfig struct { UseExponentialHistograms bool `mapstructure:"use_exponential_histograms"` - IncludeBilledDuration bool `mapstructure:"include_billed_duration"` } // Validate validates the configuration by checking for missing or invalid fields diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 2825111988..c7670415f2 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -72,7 +72,6 @@ type telemetryAPIReceiver struct { metricInitDurations metric.Float64Histogram metricInvokeDurations metric.Float64Histogram metricColdstarts metric.Int64Counter - metricBilledDuration metric.Float64Counter metricSuccesses metric.Int64Counter metricFailures metric.Int64Counter metricTimeouts metric.Int64Counter @@ -151,10 +150,12 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { ) meter := provider.Meter(instrumentationScope) - // Build the metrics and propagate the last error + // Build the metrics and propagate the last error. For all counters, we push a value of + // zero to properly indicate the start of the counter. This is particularly important if the + // Lambda function is called rarely. Unfortunately, histograms cannot easily be + // zero-initialized. // NOTE: The metrics defined here follow the semantic conventions for FaaS Metrics: // https://opentelemetry.io/docs/specs/semconv/faas/faas-metrics/ - // The only exception is `faas.billed_duration` which can be enabled via config. var err error r.metricInvokeDurations, err = meter.Float64Histogram( "faas.invoke_duration", @@ -167,48 +168,44 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { metric.WithUnit("s"), ) - if r.cfg.Metrics.IncludeBilledDuration { - r.metricBilledDuration, err = meter.Float64Counter( - "faas.billed_duration", - metric.WithDescription("The duration for which the function was billed."), - metric.WithUnit("s"), - ) - // r.metricBilledDuration.Add(context.Background(), 0) - } - r.metricColdstarts, err = meter.Int64Counter( "faas.coldstarts", metric.WithDescription("Number of invocation cold starts."), metric.WithUnit("1"), ) - // r.metricColdstarts.Add(context.Background(), 0) + r.metricColdstarts.Add(context.Background(), 0) r.metricSuccesses, err = meter.Int64Counter( "faas.invocations", metric.WithDescription("Number of successful invocations."), metric.WithUnit("1"), ) - // r.metricSuccesses.Add(context.Background(), 0) + r.metricSuccesses.Add(context.Background(), 0) r.metricFailures, err = meter.Int64Counter( "faas.errors", metric.WithDescription("Number of invocation errors."), metric.WithUnit("1"), ) - // r.metricFailures.Add(context.Background(), 0) + r.metricFailures.Add(context.Background(), 0) r.metricTimeouts, err = meter.Int64Counter( "faas.timeouts", metric.WithDescription("Number of invocation timeouts."), metric.WithUnit("1"), ) - // r.metricTimeouts.Add(context.Background(), 0) + r.metricTimeouts.Add(context.Background(), 0) r.metricMemoryUsages, err = meter.Int64Histogram( "faas.mem_usage", metric.WithDescription("Max memory usage per invocation."), metric.WithUnit("By"), ) + + if err == nil { + // Make sure to push zero-initialized metrics early + r.forwardMetrics() + } return err } @@ -316,9 +313,6 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ continue } if record, err := parseRecord[platformReport](el, r.logger); err == nil { - if r.metricBilledDuration != nil { // conditionally initialized - r.metricBilledDuration.Add(ctx, record.Metrics.BilledDurationMs/1000.0) - } r.metricMemoryUsages.Record(ctx, record.Metrics.MaxMemoryUsedMb*1024*1024) } // Log record emitted by function. @@ -488,7 +482,7 @@ func (r *telemetryAPIReceiver) metricTimestamp(metricName string) (time.Time, er return parseTime(r.lastPlatformInitReportTime) case "faas.invoke_duration", "faas.invocations", "faas.errors", "faas.timeouts": return parseTime(r.lastPlatformRuntimeDoneTime) - case "faas.billed_duration", "faas.mem_usage": + case "faas.mem_usage": return parseTime(r.lastPlatformReportTime) default: return time.Time{}, errUnknownMetric From 17b69763e78476afea1948aca92c6d469cd1faf7 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Thu, 28 Mar 2024 00:55:27 +0100 Subject: [PATCH 16/43] Do not send early --- collector/receiver/telemetryapireceiver/receiver.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index c7670415f2..4521b8cf91 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -201,11 +201,6 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { metric.WithDescription("Max memory usage per invocation."), metric.WithUnit("By"), ) - - if err == nil { - // Make sure to push zero-initialized metrics early - r.forwardMetrics() - } return err } From 858a060467acf157bb3f4d2a1daf83c960c829e2 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Thu, 28 Mar 2024 01:08:56 +0100 Subject: [PATCH 17/43] No add zero --- collector/receiver/telemetryapireceiver/README.md | 1 - .../receiver/telemetryapireceiver/receiver.go | 14 +------------- collector/receiver/telemetryapireceiver/types.go | 3 +-- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/README.md b/collector/receiver/telemetryapireceiver/README.md index 414abda1d8..2306ba5454 100644 --- a/collector/receiver/telemetryapireceiver/README.md +++ b/collector/receiver/telemetryapireceiver/README.md @@ -29,7 +29,6 @@ receivers: telemetryapi: metrics: useExponentialHistograms: true - includeBilledDuration: true ``` [in development]: https://github.com/open-telemetry/opentelemetry-collector#development diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 4521b8cf91..d286ff999b 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -150,10 +150,7 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { ) meter := provider.Meter(instrumentationScope) - // Build the metrics and propagate the last error. For all counters, we push a value of - // zero to properly indicate the start of the counter. This is particularly important if the - // Lambda function is called rarely. Unfortunately, histograms cannot easily be - // zero-initialized. + // Build the metrics and propagate the last error. // NOTE: The metrics defined here follow the semantic conventions for FaaS Metrics: // https://opentelemetry.io/docs/specs/semconv/faas/faas-metrics/ var err error @@ -167,35 +164,26 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { metric.WithDescription("The duration of the function's initialization."), metric.WithUnit("s"), ) - r.metricColdstarts, err = meter.Int64Counter( "faas.coldstarts", metric.WithDescription("Number of invocation cold starts."), metric.WithUnit("1"), ) - r.metricColdstarts.Add(context.Background(), 0) - r.metricSuccesses, err = meter.Int64Counter( "faas.invocations", metric.WithDescription("Number of successful invocations."), metric.WithUnit("1"), ) - r.metricSuccesses.Add(context.Background(), 0) - r.metricFailures, err = meter.Int64Counter( "faas.errors", metric.WithDescription("Number of invocation errors."), metric.WithUnit("1"), ) - r.metricFailures.Add(context.Background(), 0) - r.metricTimeouts, err = meter.Int64Counter( "faas.timeouts", metric.WithDescription("Number of invocation timeouts."), metric.WithUnit("1"), ) - r.metricTimeouts.Add(context.Background(), 0) - r.metricMemoryUsages, err = meter.Int64Histogram( "faas.mem_usage", metric.WithDescription("Max memory usage per invocation."), diff --git a/collector/receiver/telemetryapireceiver/types.go b/collector/receiver/telemetryapireceiver/types.go index 54ec212a5b..e8c67d4b29 100644 --- a/collector/receiver/telemetryapireceiver/types.go +++ b/collector/receiver/telemetryapireceiver/types.go @@ -44,8 +44,7 @@ type platformRuntimeDoneRecord struct { type platformReport struct { Metrics struct { - BilledDurationMs float64 `mapstructure:"billedDurationMs"` - MaxMemoryUsedMb int64 `mapstructure:"maxMemoryUsedMB"` + MaxMemoryUsedMb int64 `mapstructure:"maxMemoryUsedMB"` } `mapstructure:"metrics"` } From eae2acf4702201915c557e0b054dc49b70950a89 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Thu, 28 Mar 2024 01:55:06 +0100 Subject: [PATCH 18/43] Try --- .../receiver/telemetryapireceiver/receiver.go | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index d286ff999b..5122406d23 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -150,7 +150,10 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { ) meter := provider.Meter(instrumentationScope) - // Build the metrics and propagate the last error. + // Build the metrics and propagate the last error. For all counters, we push a value of + // zero to properly indicate the start of the counter. This is particularly important if the + // Lambda function is called rarely. Unfortunately, histograms cannot easily be + // zero-initialized. // NOTE: The metrics defined here follow the semantic conventions for FaaS Metrics: // https://opentelemetry.io/docs/specs/semconv/faas/faas-metrics/ var err error @@ -164,31 +167,45 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { metric.WithDescription("The duration of the function's initialization."), metric.WithUnit("s"), ) + r.metricColdstarts, err = meter.Int64Counter( "faas.coldstarts", metric.WithDescription("Number of invocation cold starts."), metric.WithUnit("1"), ) + r.metricColdstarts.Add(context.Background(), 0) + r.metricSuccesses, err = meter.Int64Counter( "faas.invocations", metric.WithDescription("Number of successful invocations."), metric.WithUnit("1"), ) + r.metricSuccesses.Add(context.Background(), 0) + r.metricFailures, err = meter.Int64Counter( "faas.errors", metric.WithDescription("Number of invocation errors."), metric.WithUnit("1"), ) + r.metricFailures.Add(context.Background(), 0) + r.metricTimeouts, err = meter.Int64Counter( "faas.timeouts", metric.WithDescription("Number of invocation timeouts."), metric.WithUnit("1"), ) + r.metricTimeouts.Add(context.Background(), 0) + r.metricMemoryUsages, err = meter.Int64Histogram( "faas.mem_usage", metric.WithDescription("Max memory usage per invocation."), metric.WithUnit("By"), ) + + if err == nil { + // Make sure to push zero-initialized metrics early + r.forwardMetrics() + } return err } @@ -478,7 +495,11 @@ func (r *telemetryAPIReceiver) metricTimestamp(metricName string) (time.Time, er func parseTime(t string) (time.Time, error) { layout := "2006-01-02T15:04:05.000Z" - return time.Parse(layout, t) + out, err := time.Parse(layout, t) + if err != nil { + return time.Now(), nil + } + return out, nil } func listenOnAddress() string { From 6ae04f06819c25cb757f9390c7b2634e8524cd61 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Thu, 28 Mar 2024 02:13:27 +0100 Subject: [PATCH 19/43] zero-init --- .../receiver/telemetryapireceiver/receiver.go | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 5122406d23..e1dc41c3e9 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -150,62 +150,56 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { ) meter := provider.Meter(instrumentationScope) - // Build the metrics and propagate the last error. For all counters, we push a value of - // zero to properly indicate the start of the counter. This is particularly important if the - // Lambda function is called rarely. Unfortunately, histograms cannot easily be - // zero-initialized. + // Build the metrics and propagate the last error. // NOTE: The metrics defined here follow the semantic conventions for FaaS Metrics: // https://opentelemetry.io/docs/specs/semconv/faas/faas-metrics/ var err error - r.metricInvokeDurations, err = meter.Float64Histogram( - "faas.invoke_duration", - metric.WithDescription("The duration of the function's logic execution."), - metric.WithUnit("s"), - ) - r.metricInitDurations, err = meter.Float64Histogram( - "faas.init_duration", - metric.WithDescription("The duration of the function's initialization."), - metric.WithUnit("s"), - ) + // COUNTERS r.metricColdstarts, err = meter.Int64Counter( "faas.coldstarts", metric.WithDescription("Number of invocation cold starts."), metric.WithUnit("1"), ) - r.metricColdstarts.Add(context.Background(), 0) - r.metricSuccesses, err = meter.Int64Counter( "faas.invocations", metric.WithDescription("Number of successful invocations."), metric.WithUnit("1"), ) - r.metricSuccesses.Add(context.Background(), 0) - r.metricFailures, err = meter.Int64Counter( "faas.errors", metric.WithDescription("Number of invocation errors."), metric.WithUnit("1"), ) - r.metricFailures.Add(context.Background(), 0) - r.metricTimeouts, err = meter.Int64Counter( "faas.timeouts", metric.WithDescription("Number of invocation timeouts."), metric.WithUnit("1"), ) + + // For all counters, we push a value of zero to properly indicate the start of the + // counter. This is particularly important if the Lambda function is called rarely. + r.metricColdstarts.Add(context.Background(), 0) + r.metricSuccesses.Add(context.Background(), 0) + r.metricFailures.Add(context.Background(), 0) r.metricTimeouts.Add(context.Background(), 0) + // HISTOGRAMS + r.metricInvokeDurations, err = meter.Float64Histogram( + "faas.invoke_duration", + metric.WithDescription("The duration of the function's logic execution."), + metric.WithUnit("s"), + ) + r.metricInitDurations, err = meter.Float64Histogram( + "faas.init_duration", + metric.WithDescription("The duration of the function's initialization."), + metric.WithUnit("s"), + ) r.metricMemoryUsages, err = meter.Int64Histogram( "faas.mem_usage", metric.WithDescription("Max memory usage per invocation."), metric.WithUnit("By"), ) - - if err == nil { - // Make sure to push zero-initialized metrics early - r.forwardMetrics() - } return err } @@ -479,8 +473,16 @@ func (r *telemetryAPIReceiver) createPlatformInitSpan(start, end string) (ptrace func (r *telemetryAPIReceiver) metricTimestamp(metricName string) (time.Time, error) { switch metricName { case "faas.coldstarts", "faas.init_duration": + if r.lastPlatformInitReportTime == "" { + // If the time is not set, the faas.coldstarts counter is being zero-initialized + return time.Now(), nil + } return parseTime(r.lastPlatformInitReportTime) case "faas.invoke_duration", "faas.invocations", "faas.errors", "faas.timeouts": + if r.lastPlatformInitReportTime == "" { + // If the time is not set, some counter is being zero-initialized + return time.Now(), nil + } return parseTime(r.lastPlatformRuntimeDoneTime) case "faas.mem_usage": return parseTime(r.lastPlatformReportTime) @@ -495,11 +497,7 @@ func (r *telemetryAPIReceiver) metricTimestamp(metricName string) (time.Time, er func parseTime(t string) (time.Time, error) { layout := "2006-01-02T15:04:05.000Z" - out, err := time.Parse(layout, t) - if err != nil { - return time.Now(), nil - } - return out, nil + return time.Parse(layout, t) } func listenOnAddress() string { From 0583116e33624b2c3654003af395699db7df225f Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 02:42:09 +0100 Subject: [PATCH 20/43] Better tracing --- collector/go.mod | 4 +- collector/lambdacomponents/default.go | 4 +- collector/lambdacomponents/go.mod | 22 +- collector/lambdacomponents/go.sum | 38 +- .../processor/coldstartprocessor/processor.go | 112 ---- .../coldstartprocessor/processor_test.go | 607 ------------------ .../Makefile | 0 .../README.md | 0 .../config.go | 2 +- .../config_test.go | 3 +- .../doc.go | 4 +- .../factory.go | 7 +- .../factory_test.go | 2 +- .../go.mod | 10 +- .../go.sum | 34 +- .../processor/faasprocessor/processor.go | 146 +++++ .../processor/faasprocessor/processor_test.go | 607 ++++++++++++++++++ .../receiver/telemetryapireceiver/receiver.go | 121 ++-- 18 files changed, 912 insertions(+), 811 deletions(-) delete mode 100644 collector/processor/coldstartprocessor/processor.go delete mode 100644 collector/processor/coldstartprocessor/processor_test.go rename collector/processor/{coldstartprocessor => faasprocessor}/Makefile (100%) rename collector/processor/{coldstartprocessor => faasprocessor}/README.md (100%) rename collector/processor/{coldstartprocessor => faasprocessor}/config.go (86%) rename collector/processor/{coldstartprocessor => faasprocessor}/config_test.go (90%) rename collector/processor/{coldstartprocessor => faasprocessor}/doc.go (85%) rename collector/processor/{coldstartprocessor => faasprocessor}/factory.go (89%) rename collector/processor/{coldstartprocessor => faasprocessor}/factory_test.go (93%) rename collector/processor/{coldstartprocessor => faasprocessor}/go.mod (93%) rename collector/processor/{coldstartprocessor => faasprocessor}/go.sum (88%) create mode 100644 collector/processor/faasprocessor/processor.go create mode 100644 collector/processor/faasprocessor/processor_test.go diff --git a/collector/go.mod b/collector/go.mod index a1a0efcc1d..7b7925ee7c 100644 --- a/collector/go.mod +++ b/collector/go.mod @@ -6,7 +6,7 @@ replace github.com/open-telemetry/opentelemetry-lambda/collector/lambdacomponent replace github.com/open-telemetry/opentelemetry-lambda/collector/lambdalifecycle => ./lambdalifecycle -replace github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor => ./processor/coldstartprocessor +replace github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor => ./processor/faasprocessor replace github.com/open-telemetry/opentelemetry-lambda/collector/processor/decoupleprocessor => ./processor/decoupleprocessor @@ -102,7 +102,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.92.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourceprocessor v0.92.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/processor/spanprocessor v0.92.0 // indirect - github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor v0.92.0 // indirect + github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor v0.92.0 // indirect github.com/open-telemetry/opentelemetry-lambda/collector/processor/decoupleprocessor v0.0.0-00010101000000-000000000000 // indirect github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver v0.92.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/collector/lambdacomponents/default.go b/collector/lambdacomponents/default.go index 7beaf3ece1..a096cb22d3 100644 --- a/collector/lambdacomponents/default.go +++ b/collector/lambdacomponents/default.go @@ -36,7 +36,7 @@ import ( "go.opentelemetry.io/collector/receiver/otlpreceiver" "go.uber.org/multierr" - "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" + "github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor" "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver" ) @@ -68,7 +68,7 @@ func Components(extensionID string) (otelcol.Factories, error) { probabilisticsamplerprocessor.NewFactory(), resourceprocessor.NewFactory(), spanprocessor.NewFactory(), - coldstartprocessor.NewFactory(), + faasprocessor.NewFactory(), decoupleprocessor.NewFactory(), batchprocessor.NewFactory(), ) diff --git a/collector/lambdacomponents/go.mod b/collector/lambdacomponents/go.mod index e2ba5ebc40..7a8e52cd6a 100644 --- a/collector/lambdacomponents/go.mod +++ b/collector/lambdacomponents/go.mod @@ -10,8 +10,8 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.92.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourceprocessor v0.92.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/spanprocessor v0.92.0 - github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor v0.92.0 github.com/open-telemetry/opentelemetry-lambda/collector/processor/decoupleprocessor v0.0.0-00010101000000-000000000000 + github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor v0.92.0 github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver v0.92.0 go.opentelemetry.io/collector/exporter v0.92.0 go.opentelemetry.io/collector/exporter/loggingexporter v0.92.0 @@ -51,7 +51,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/gobwas/glob v0.2.3 // indirect @@ -133,7 +133,7 @@ require ( go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.21.1 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/bridge/opencensus v0.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 // indirect @@ -143,21 +143,21 @@ require ( go.opentelemetry.io/otel/exporters/prometheus v0.44.1-0.20231201153405-6027c1ae76f2 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.44.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/otel/sdk v1.21.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/sdk v1.24.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect - go.uber.org/zap v1.26.0 // indirect + go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect gonum.org/v1/gonum v0.14.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect google.golang.org/grpc v1.60.1 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) @@ -172,7 +172,7 @@ replace github.com/open-telemetry/opentelemetry-lambda/collector => ../ replace github.com/open-telemetry/opentelemetry-lambda/collector/lambdalifecycle => ../lambdalifecycle -replace github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor => ../processor/coldstartprocessor +replace github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor => ../processor/faasprocessor replace github.com/open-telemetry/opentelemetry-lambda/collector/processor/decoupleprocessor => ../processor/decoupleprocessor diff --git a/collector/lambdacomponents/go.sum b/collector/lambdacomponents/go.sum index 0729cce43c..42947eb986 100644 --- a/collector/lambdacomponents/go.sum +++ b/collector/lambdacomponents/go.sum @@ -319,8 +319,8 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= @@ -555,8 +555,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo= github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -653,8 +653,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1: go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= go.opentelemetry.io/contrib/zpages v0.46.1 h1:U8Hh84dc+vJTVgRnL+QKWtWD2iqTSKibrQ85EeQqsNg= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/bridge/opencensus v0.44.0 h1:/inELPJztkn6Xx3ap9qw8i8XdeWF0B/OjGHOdRTePZ8= go.opentelemetry.io/otel/bridge/opencensus v0.44.0/go.mod h1:dQTBJVBx1xahrXEFBV1BGPAnGuXC92LCj55fxIrtj7I= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI= @@ -673,22 +673,22 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.44.0 h1:dEZWPjVN22urgY go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.44.0/go.mod h1:sTt30Evb7hJB/gEk27qLb1+l9n4Tb8HvHkR0Wx3S6CU= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYfrPk5SOryw1e9LDDTZCbIPFrho0ec= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= -go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= -go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/sdk/metric v1.24.0 h1:yyMQrPzF+k88/DbH7o4FMAs80puqd+9osbiBrJrz/w8= +go.opentelemetry.io/otel/sdk/metric v1.24.0/go.mod h1:I6Y5FjH6rvEnTTAYQz3Mmv2kl6Ek5IIrmwTLqMrrOE0= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -815,8 +815,8 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -969,8 +969,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/collector/processor/coldstartprocessor/processor.go b/collector/processor/coldstartprocessor/processor.go deleted file mode 100644 index 4dd0a0ce1a..0000000000 --- a/collector/processor/coldstartprocessor/processor.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" - -import ( - "context" - - "go.opentelemetry.io/collector/consumer" - "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/ptrace" - "go.opentelemetry.io/collector/processor" - "go.opentelemetry.io/collector/processor/processorhelper" - semconv "go.opentelemetry.io/collector/semconv/v1.5.0" - "go.uber.org/zap" -) - -type faasExecution struct { - span ptrace.Span - scope pcommon.InstrumentationScope - resource pcommon.Resource -} - -type coldstartProcessor struct { - coldstartSpan *ptrace.Span - faasExecution *faasExecution - logger *zap.Logger - nextConsumer consumer.Traces - reported bool // whether the cold start has already been reported -} - -func (p *coldstartProcessor) processTraces(ctx context.Context, td ptrace.Traces) (ptrace.Traces, error) { - if p.reported { - return td, nil - } - td.ResourceSpans().RemoveIf(func(rs ptrace.ResourceSpans) bool { - resource := rs.Resource() - rs.ScopeSpans().RemoveIf(func(ss ptrace.ScopeSpans) bool { - scope := ss.Scope() - ss.Spans().RemoveIf(func(span ptrace.Span) bool { - if p.reported { - return false - } - if attr, ok := span.Attributes().Get(semconv.AttributeFaaSColdstart); ok && attr.Bool() { - if p.faasExecution == nil { - sp := ptrace.NewSpan() - p.coldstartSpan = &sp - span.CopyTo(*p.coldstartSpan) - return true - } else { - p.faasExecution.scope.CopyTo(scope) - p.faasExecution.resource.CopyTo(resource) - span.SetParentSpanID(p.faasExecution.span.ParentSpanID()) - span.SetTraceID(p.faasExecution.span.TraceID()) - p.reported = true - return false - } - } - if _, ok := span.Attributes().Get(semconv.AttributeFaaSExecution); ok { - if p.coldstartSpan == nil { - p.faasExecution = &faasExecution{ - span: ptrace.NewSpan(), - scope: pcommon.NewInstrumentationScope(), - resource: pcommon.NewResource(), - } - - scope.CopyTo(p.faasExecution.scope) - resource.CopyTo(p.faasExecution.resource) - span.CopyTo(p.faasExecution.span) - } else { - s := ss.Spans().AppendEmpty() - p.coldstartSpan.CopyTo(s) - s.SetParentSpanID(span.ParentSpanID()) - s.SetTraceID(span.TraceID()) - p.reported = true - p.coldstartSpan = nil - } - } - return false - }) - return ss.Spans().Len() == 0 - }) - return rs.ScopeSpans().Len() == 0 - }) - - if td.ResourceSpans().Len() == 0 { - return td, processorhelper.ErrSkipProcessingData - } - return td, nil -} - -func newColdstartProcessor( - cfg *Config, - next consumer.Traces, - set processor.CreateSettings, -) (*coldstartProcessor, error) { - return &coldstartProcessor{ - nextConsumer: next, - logger: set.Logger, - }, nil -} diff --git a/collector/processor/coldstartprocessor/processor_test.go b/collector/processor/coldstartprocessor/processor_test.go deleted file mode 100644 index fb0f8fc48a..0000000000 --- a/collector/processor/coldstartprocessor/processor_test.go +++ /dev/null @@ -1,607 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" - -import ( - "bytes" - "context" - crand "crypto/rand" - "encoding/binary" - "fmt" - "hash" - "math" - "math/rand" - "reflect" - "sort" - "testing" - - "github.com/cespare/xxhash" - "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/ptrace" - "go.opentelemetry.io/collector/processor/processorhelper" - "go.opentelemetry.io/collector/processor/processortest" - semconv "go.opentelemetry.io/collector/semconv/v1.5.0" - "go.uber.org/multierr" -) - -func TestProcessor(t *testing.T) { - executionTraceID := getTraceID() - testCases := []struct { - desc string - input ptrace.Traces - expected ptrace.Traces - expectedError error - reported bool - }{ - { - desc: "no traces", - input: ptrace.NewTraces(), - expected: ptrace.NewTraces(), - expectedError: processorhelper.ErrSkipProcessingData, - }, - { - desc: "coldstart without execution", - input: func() ptrace.Traces { - td := ptrace.NewTraces() - span := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() - span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) - return td - }(), - expected: ptrace.NewTraces(), - expectedError: processorhelper.ErrSkipProcessingData, - }, - { - desc: "execution without coldstart", - input: func() ptrace.Traces { - td := ptrace.NewTraces() - addExecutionSpan(td, executionTraceID) - return td - }(), - expected: func() ptrace.Traces { - td := ptrace.NewTraces() - addExecutionSpan(td, executionTraceID) - return td - }(), - }, - { - desc: "faas.execution and faas.coldstart with coldstart is first", - input: func() ptrace.Traces { - td := ptrace.NewTraces() - span := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() - span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) - span.Attributes().PutBool("faas.initialization", true) - addExecutionSpan(td, executionTraceID) - return td - }(), - expected: func() ptrace.Traces { - td := ptrace.NewTraces() - rs := td.ResourceSpans().AppendEmpty() - ss := rs.ScopeSpans().AppendEmpty() - - rs.Resource().Attributes().PutStr("resource-attr", "faas-execution") - ss.Scope().SetName("app/execution") - executionSpan(ss.Spans().AppendEmpty(), executionTraceID) - initializationSpan(ss.Spans().AppendEmpty(), executionTraceID) - return td - }(), - reported: true, - }, - { - desc: "faas.execution and faas.coldstart with execution is first", - input: func() ptrace.Traces { - td := ptrace.NewTraces() - addExecutionSpan(td, executionTraceID) - span := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() - span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) - span.Attributes().PutBool("faas.initialization", true) - return td - }(), - expected: func() ptrace.Traces { - td := ptrace.NewTraces() - rs := td.ResourceSpans().AppendEmpty() - ss := rs.ScopeSpans().AppendEmpty() - rs.Resource().Attributes().PutStr("resource-attr", "faas-execution") - ss.Scope().SetName("app/execution") - executionSpan(ss.Spans().AppendEmpty(), executionTraceID) - rs = td.ResourceSpans().AppendEmpty() - ss = rs.ScopeSpans().AppendEmpty() - rs.Resource().Attributes().PutStr("resource-attr", "faas-execution") - ss.Scope().SetName("app/execution") - initializationSpan(ss.Spans().AppendEmpty(), executionTraceID) - return td - }(), - reported: true, - }, - } - for _, tc := range testCases { - t.Run(tc.desc, func(t *testing.T) { - c, err := newColdstartProcessor( - nil, - nil, - processortest.NewNopCreateSettings(), - ) - require.NoError(t, err) - td, err := c.processTraces(context.Background(), tc.input) - require.Equal(t, tc.expectedError, err) - - require.Equal(t, tc.expected.SpanCount(), td.SpanCount()) - require.Equal(t, tc.reported, c.reported) - require.NoError(t, compareTraces(tc.expected, td)) - }) - } -} - -func TestMultipleProcessTraces(t *testing.T) { - c, err := newColdstartProcessor( - nil, - nil, - processortest.NewNopCreateSettings(), - ) - require.NoError(t, err) - expected := ptrace.NewTraces() - input := ptrace.NewTraces() - addExecutionSpan(input, getTraceID()) - input.CopyTo(expected) - output, err := c.processTraces(context.Background(), input) - require.NoError(t, err) - require.Equal(t, 1, output.SpanCount()) - require.NoError(t, compareTraces(expected, output)) - require.False(t, c.reported) - - input = ptrace.NewTraces() - expected = ptrace.NewTraces() - span := input.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() - span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) - span.Attributes().PutBool("faas.initialization", true) - input.CopyTo(expected) - output, err = c.processTraces(context.Background(), input) - require.NoError(t, err) - require.Equal(t, expected.SpanCount(), output.SpanCount()) - require.Error(t, compareTraces(expected, output)) - attr, ok := output.ResourceSpans().At(0).Resource().Attributes().Get("resource-attr") - require.True(t, ok) - require.Equal(t, "faas-execution", attr.AsString()) - require.Equal(t, "app/execution", output.ResourceSpans().At(0).ScopeSpans().At(0).Scope().Name()) - require.True(t, c.reported) - - c, err = newColdstartProcessor( - nil, - nil, - processortest.NewNopCreateSettings(), - ) - require.NoError(t, err) - input = ptrace.NewTraces() - expected = ptrace.NewTraces() - span = input.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() - span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) - span.Attributes().PutBool("faas.initialization", true) - input.CopyTo(expected) - output, err = c.processTraces(context.Background(), input) - require.Error(t, err) - require.Equal(t, 0, output.SpanCount()) - require.False(t, c.reported) - - expected = ptrace.NewTraces() - input = ptrace.NewTraces() - addExecutionSpan(input, getTraceID()) - input.CopyTo(expected) - output, err = c.processTraces(context.Background(), input) - require.NoError(t, err) - require.Equal(t, 2, output.SpanCount()) - require.Error(t, compareTraces(expected, output)) - attr, ok = output.ResourceSpans().At(0).Resource().Attributes().Get("resource-attr") - require.True(t, ok) - require.Equal(t, "faas-execution", attr.AsString()) - require.Equal(t, "app/execution", output.ResourceSpans().At(0).ScopeSpans().At(0).Scope().Name()) - require.True(t, c.reported) -} - -func getTraceID() pcommon.TraceID { - var rngSeed int64 - _ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) - randSource := rand.New(rand.NewSource(rngSeed)) - tid := pcommon.TraceID{} - _, _ = randSource.Read(tid[:]) - return tid -} - -func addExecutionSpan(td ptrace.Traces, id pcommon.TraceID) { - rs := td.ResourceSpans().AppendEmpty() - rs.Resource().Attributes().PutStr("resource-attr", "faas-execution") - ss := rs.ScopeSpans().AppendEmpty() - ss.Scope().SetName("app/execution") - span := ss.Spans().AppendEmpty() - span.SetTraceID(id) - span.Attributes().PutStr(semconv.AttributeFaaSExecution, "af9d5aa4-a685-4c5f-a22b-444f80b3cc28") -} - -func executionSpan(span ptrace.Span, id pcommon.TraceID) { - span.SetTraceID(id) - span.Attributes().PutStr(semconv.AttributeFaaSExecution, "af9d5aa4-a685-4c5f-a22b-444f80b3cc28") -} - -func initializationSpan(span ptrace.Span, id pcommon.TraceID) { - span.SetTraceID(id) - span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) - span.Attributes().PutBool("faas.initialization", true) -} - -var ( - extraByte = []byte{'\xf3'} - keyPrefix = []byte{'\xf4'} - valEmpty = []byte{'\xf5'} - valBytesPrefix = []byte{'\xf6'} - valStrPrefix = []byte{'\xf7'} - valBoolTrue = []byte{'\xf8'} - valBoolFalse = []byte{'\xf9'} - valIntPrefix = []byte{'\xfa'} - valDoublePrefix = []byte{'\xfb'} - valMapPrefix = []byte{'\xfc'} - valMapSuffix = []byte{'\xfd'} - valSlicePrefix = []byte{'\xfe'} - valSliceSuffix = []byte{'\xff'} -) - -// mapHash return a hash for the provided map. -// Maps with the same underlying key/value pairs in different order produce the same deterministic hash value. -func mapHash(m pcommon.Map) [16]byte { - h := xxhash.New() - writeMapHash(h, m) - return hashSum128(h) -} - -func writeMapHash(h hash.Hash, m pcommon.Map) { - keys := make([]string, 0, m.Len()) - m.Range(func(k string, v pcommon.Value) bool { - keys = append(keys, k) - return true - }) - sort.Strings(keys) - for _, k := range keys { - v, _ := m.Get(k) - h.Write(keyPrefix) - h.Write([]byte(k)) - writeValueHash(h, v) - } -} - -func writeSliceHash(h hash.Hash, sl pcommon.Slice) { - for i := 0; i < sl.Len(); i++ { - writeValueHash(h, sl.At(i)) - } -} - -func writeValueHash(h hash.Hash, v pcommon.Value) { - switch v.Type() { - case pcommon.ValueTypeStr: - h.Write(valStrPrefix) - h.Write([]byte(v.Str())) - case pcommon.ValueTypeBool: - if v.Bool() { - h.Write(valBoolTrue) - } else { - h.Write(valBoolFalse) - } - case pcommon.ValueTypeInt: - h.Write(valIntPrefix) - b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, uint64(v.Int())) - h.Write(b) - case pcommon.ValueTypeDouble: - h.Write(valDoublePrefix) - b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, math.Float64bits(v.Double())) - h.Write(b) - case pcommon.ValueTypeMap: - h.Write(valMapPrefix) - writeMapHash(h, v.Map()) - h.Write(valMapSuffix) - case pcommon.ValueTypeSlice: - h.Write(valSlicePrefix) - writeSliceHash(h, v.Slice()) - h.Write(valSliceSuffix) - case pcommon.ValueTypeBytes: - h.Write(valBytesPrefix) - h.Write(v.Bytes().AsRaw()) - case pcommon.ValueTypeEmpty: - h.Write(valEmpty) - } -} - -// hashSum128 returns a [16]byte hash sum. -func hashSum128(h hash.Hash) [16]byte { - b := make([]byte, 0, 16) - b = h.Sum(b) - - // Append an extra byte to generate another part of the hash sum - _, _ = h.Write(extraByte) - b = h.Sum(b) - - res := [16]byte{} - copy(res[:], b) - return res -} - -func sortResourceSpans(a, b ptrace.ResourceSpans) bool { - if a.SchemaUrl() < b.SchemaUrl() { - return true - } - aAttrs := mapHash(a.Resource().Attributes()) - bAttrs := mapHash(b.Resource().Attributes()) - return bytes.Compare(aAttrs[:], bAttrs[:]) < 0 -} - -func sortSpansInstrumentationLibrary(a, b ptrace.ScopeSpans) bool { - if a.SchemaUrl() < b.SchemaUrl() { - return true - } - if a.Scope().Name() < b.Scope().Name() { - return true - } - if a.Scope().Version() < b.Scope().Version() { - return true - } - return false -} - -func sortSpanSlice(a, b ptrace.Span) bool { - aAttrs := mapHash(a.Attributes()) - bAttrs := mapHash(b.Attributes()) - return bytes.Compare(aAttrs[:], bAttrs[:]) < 0 -} - -// CompareTraces compares each part of two given Traces and returns -// an error if they don't match. The error describes what didn't match. -func compareTraces(expected, actual ptrace.Traces) error { - exp, act := ptrace.NewTraces(), ptrace.NewTraces() - expected.CopyTo(exp) - actual.CopyTo(act) - - expectedSpans, actualSpans := exp.ResourceSpans(), act.ResourceSpans() - if expectedSpans.Len() != actualSpans.Len() { - return fmt.Errorf("amount of ResourceSpans between Traces are not equal expected: %d, actual: %d", - expectedSpans.Len(), - actualSpans.Len()) - } - - // sort ResourceSpans - expectedSpans.Sort(sortResourceSpans) - actualSpans.Sort(sortResourceSpans) - - numResources := expectedSpans.Len() - - // Keep track of matching resources so that each can only be matched once - matchingResources := make(map[ptrace.ResourceSpans]ptrace.ResourceSpans, numResources) - - var errs error - for e := 0; e < numResources; e++ { - er := expectedSpans.At(e) - var foundMatch bool - for a := 0; a < numResources; a++ { - ar := actualSpans.At(a) - if _, ok := matchingResources[ar]; ok { - continue - } - if reflect.DeepEqual(er.Resource().Attributes().AsRaw(), ar.Resource().Attributes().AsRaw()) { - foundMatch = true - matchingResources[ar] = er - break - } - } - if !foundMatch { - errs = multierr.Append(errs, fmt.Errorf("missing expected resource with attributes: %v", er.Resource().Attributes().AsRaw())) - } - } - - for i := 0; i < numResources; i++ { - if _, ok := matchingResources[actualSpans.At(i)]; !ok { - errs = multierr.Append(errs, fmt.Errorf("extra resource with attributes: %v", actualSpans.At(i).Resource().Attributes().AsRaw())) - } - } - - if errs != nil { - return errs - } - - for ar, er := range matchingResources { - if err := CompareResourceSpans(er, ar); err != nil { - return err - } - } - - return nil -} - -// CompareResourceSpans compares each part of two given ResourceSpans and returns -// an error if they don't match. The error describes what didn't match. -func CompareResourceSpans(expected, actual ptrace.ResourceSpans) error { - eilms := expected.ScopeSpans() - ailms := actual.ScopeSpans() - - if eilms.Len() != ailms.Len() { - return fmt.Errorf("number of instrumentation libraries does not match expected: %d, actual: %d", eilms.Len(), - ailms.Len()) - } - - // sort InstrumentationLibrary - eilms.Sort(sortSpansInstrumentationLibrary) - ailms.Sort(sortSpansInstrumentationLibrary) - - for i := 0; i < eilms.Len(); i++ { - eilm, ailm := eilms.At(i), ailms.At(i) - eil, ail := eilm.Scope(), ailm.Scope() - - if eil.Name() != ail.Name() { - return fmt.Errorf("instrumentation library Name does not match expected: %s, actual: %s", eil.Name(), ail.Name()) - } - if eil.Version() != ail.Version() { - return fmt.Errorf("instrumentation library Version does not match expected: %s, actual: %s", eil.Version(), ail.Version()) - } - if err := CompareSpanSlices(eilm.Spans(), ailm.Spans()); err != nil { - return err - } - } - return nil -} - -// CompareSpanSlices compares each part of two given SpanSlices and returns -// an error if they don't match. The error describes what didn't match. -func CompareSpanSlices(expected, actual ptrace.SpanSlice) error { - if expected.Len() != actual.Len() { - return fmt.Errorf("number of spans does not match expected: %d, actual: %d", expected.Len(), actual.Len()) - } - - expected.Sort(sortSpanSlice) - actual.Sort(sortSpanSlice) - - numSpans := expected.Len() - - // Keep track of matching spans so that each span can only be matched once - matchingSpans := make(map[ptrace.Span]ptrace.Span, numSpans) - - var errs error - for e := 0; e < numSpans; e++ { - elr := expected.At(e) - var foundMatch bool - for a := 0; a < numSpans; a++ { - alr := actual.At(a) - if _, ok := matchingSpans[alr]; ok { - continue - } - if reflect.DeepEqual(elr.Attributes().AsRaw(), alr.Attributes().AsRaw()) { - foundMatch = true - matchingSpans[alr] = elr - break - } - } - if !foundMatch { - errs = multierr.Append(errs, fmt.Errorf("span missing expected resource with attributes: %v", elr.Attributes().AsRaw())) - } - } - - for i := 0; i < numSpans; i++ { - if _, ok := matchingSpans[actual.At(i)]; !ok { - errs = multierr.Append(errs, fmt.Errorf("span has extra record with attributes: %v", actual.At(i).Attributes().AsRaw())) - } - } - - if errs != nil { - return errs - } - - for alr, elr := range matchingSpans { - if err := CompareSpans(alr, elr); err != nil { - return multierr.Combine(fmt.Errorf("span with attributes: %v, does not match expected %v", alr.Attributes().AsRaw(), elr.Attributes().AsRaw()), err) - } - } - return nil -} - -// CompareSpans compares each part of two given Span and returns -// an error if they don't match. The error describes what didn't match. -func CompareSpans(expected, actual ptrace.Span) error { - if expected.TraceID() != actual.TraceID() { - return fmt.Errorf("span TraceID doesn't match expected: %d, actual: %d", - expected.TraceID(), - actual.TraceID()) - } - - if expected.SpanID() != actual.SpanID() { - return fmt.Errorf("span SpanID doesn't match expected: %d, actual: %d", - expected.SpanID(), - actual.SpanID()) - } - - if expected.TraceState().AsRaw() != actual.TraceState().AsRaw() { - return fmt.Errorf("span TraceState doesn't match expected: %s, actual: %s", - expected.TraceState().AsRaw(), - actual.TraceState().AsRaw()) - } - - if expected.ParentSpanID() != actual.ParentSpanID() { - return fmt.Errorf("span ParentSpanID doesn't match expected: %d, actual: %d", - expected.ParentSpanID(), - actual.ParentSpanID()) - } - - if expected.Name() != actual.Name() { - return fmt.Errorf("span Name doesn't match expected: %s, actual: %s", - expected.Name(), - actual.Name()) - } - - if expected.Kind() != actual.Kind() { - return fmt.Errorf("span Kind doesn't match expected: %d, actual: %d", - expected.Kind(), - actual.Kind()) - } - - if expected.StartTimestamp() != actual.StartTimestamp() { - return fmt.Errorf("span StartTimestamp doesn't match expected: %d, actual: %d", - expected.StartTimestamp(), - actual.StartTimestamp()) - } - - if expected.EndTimestamp() != actual.EndTimestamp() { - return fmt.Errorf("span EndTimestamp doesn't match expected: %d, actual: %d", - expected.EndTimestamp(), - actual.EndTimestamp()) - } - - if !reflect.DeepEqual(expected.Attributes().AsRaw(), actual.Attributes().AsRaw()) { - return fmt.Errorf("span Attributes doesn't match expected: %s, actual: %s", - expected.Attributes().AsRaw(), - actual.Attributes().AsRaw()) - } - - if expected.DroppedAttributesCount() != actual.DroppedAttributesCount() { - return fmt.Errorf("span DroppedAttributesCount doesn't match expected: %d, actual: %d", - expected.DroppedAttributesCount(), - actual.DroppedAttributesCount()) - } - - if !reflect.DeepEqual(expected.Events(), actual.Events()) { - return fmt.Errorf("span Events doesn't match expected: %v, actual: %v", - expected.Events(), - actual.Events()) - } - - if expected.DroppedEventsCount() != actual.DroppedEventsCount() { - return fmt.Errorf("span DroppedEventsCount doesn't match expected: %d, actual: %d", - expected.DroppedEventsCount(), - actual.DroppedEventsCount()) - } - - if !reflect.DeepEqual(expected.Links(), actual.Links()) { - return fmt.Errorf("span Links doesn't match expected: %v, actual: %v", - expected.Links(), - actual.Links()) - } - - if expected.DroppedLinksCount() != actual.DroppedLinksCount() { - return fmt.Errorf("span DroppedLinksCount doesn't match expected: %d, actual: %d", - expected.DroppedLinksCount(), - actual.DroppedLinksCount()) - } - - if !reflect.DeepEqual(expected.Status(), actual.Status()) { - return fmt.Errorf("span Status doesn't match expected: %v, actual: %v", - expected.Status(), - actual.Status()) - } - - return nil -} diff --git a/collector/processor/coldstartprocessor/Makefile b/collector/processor/faasprocessor/Makefile similarity index 100% rename from collector/processor/coldstartprocessor/Makefile rename to collector/processor/faasprocessor/Makefile diff --git a/collector/processor/coldstartprocessor/README.md b/collector/processor/faasprocessor/README.md similarity index 100% rename from collector/processor/coldstartprocessor/README.md rename to collector/processor/faasprocessor/README.md diff --git a/collector/processor/coldstartprocessor/config.go b/collector/processor/faasprocessor/config.go similarity index 86% rename from collector/processor/coldstartprocessor/config.go rename to collector/processor/faasprocessor/config.go index ee46e16b56..83044041f1 100644 --- a/collector/processor/coldstartprocessor/config.go +++ b/collector/processor/faasprocessor/config.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" +package faasprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor" // Config defines the configuration for the various elements of the processor. type Config struct{} diff --git a/collector/processor/coldstartprocessor/config_test.go b/collector/processor/faasprocessor/config_test.go similarity index 90% rename from collector/processor/coldstartprocessor/config_test.go rename to collector/processor/faasprocessor/config_test.go index 6ea2423c41..65928bd5fc 100644 --- a/collector/processor/coldstartprocessor/config_test.go +++ b/collector/processor/faasprocessor/config_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" +package faasprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor" import ( "testing" @@ -41,7 +41,6 @@ func TestValidate(t *testing.T) { } else { require.NoError(t, actualErr) } - }) } } diff --git a/collector/processor/coldstartprocessor/doc.go b/collector/processor/faasprocessor/doc.go similarity index 85% rename from collector/processor/coldstartprocessor/doc.go rename to collector/processor/faasprocessor/doc.go index 445abb573b..c0b89e1f3d 100644 --- a/collector/processor/coldstartprocessor/doc.go +++ b/collector/processor/faasprocessor/doc.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package coldstartprocessor correlates cold start information generated by the telemetryapireceiver +// Package faasprocessor correlates cold start information generated by the telemetryapireceiver // with incoming span data. // // It reads the following of incoming Lambda execution spans identified by the faas.execution attribute: @@ -28,4 +28,4 @@ // the span scope and resource attributes of the span scope containing the coldstart span // are replaced with the span scope and resource attributes of the execution span as // they contain more details. -package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" +package faasprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor" diff --git a/collector/processor/coldstartprocessor/factory.go b/collector/processor/faasprocessor/factory.go similarity index 89% rename from collector/processor/coldstartprocessor/factory.go rename to collector/processor/faasprocessor/factory.go index ec7c68af61..9426810320 100644 --- a/collector/processor/coldstartprocessor/factory.go +++ b/collector/processor/faasprocessor/factory.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" +package faasprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor" import ( "context" @@ -25,7 +25,7 @@ import ( ) const ( - typeStr = "coldstart" + typeStr = "faas" stability = component.StabilityLevelDevelopment ) @@ -52,7 +52,7 @@ func createTracesProcessor(ctx context.Context, params processor.CreateSettings, return nil, errConfigNotColdstart } - cp, err := newColdstartProcessor(cfg, next, params) + cp, err := newFaasProcessor(cfg, next, params) if err != nil { return nil, err } @@ -64,5 +64,4 @@ func createTracesProcessor(ctx context.Context, params processor.CreateSettings, cp.processTraces, processorhelper.WithCapabilities(processorCapabilities), ) - } diff --git a/collector/processor/coldstartprocessor/factory_test.go b/collector/processor/faasprocessor/factory_test.go similarity index 93% rename from collector/processor/coldstartprocessor/factory_test.go rename to collector/processor/faasprocessor/factory_test.go index cede4e4bf1..d65defa646 100644 --- a/collector/processor/coldstartprocessor/factory_test.go +++ b/collector/processor/faasprocessor/factory_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" +package faasprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor" import ( "context" diff --git a/collector/processor/coldstartprocessor/go.mod b/collector/processor/faasprocessor/go.mod similarity index 93% rename from collector/processor/coldstartprocessor/go.mod rename to collector/processor/faasprocessor/go.mod index 91d12e6bce..e7b5575fde 100644 --- a/collector/processor/coldstartprocessor/go.mod +++ b/collector/processor/faasprocessor/go.mod @@ -1,15 +1,17 @@ -module github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor +module github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor -go 1.20 +go 1.21 + +toolchain go1.21.5 require ( github.com/cespare/xxhash v1.1.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 go.opentelemetry.io/collector/component v0.91.0 go.opentelemetry.io/collector/consumer v0.91.0 go.opentelemetry.io/collector/pdata v1.0.0 go.opentelemetry.io/collector/processor v0.91.0 - go.opentelemetry.io/collector/semconv v0.91.0 + go.opentelemetry.io/collector/semconv v0.97.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.26.0 ) diff --git a/collector/processor/coldstartprocessor/go.sum b/collector/processor/faasprocessor/go.sum similarity index 88% rename from collector/processor/coldstartprocessor/go.sum rename to collector/processor/faasprocessor/go.sum index b3ce6155f9..07dab896a9 100644 --- a/collector/processor/coldstartprocessor/go.sum +++ b/collector/processor/faasprocessor/go.sum @@ -1,13 +1,16 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= +contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -18,14 +21,19 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -47,6 +55,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= @@ -62,8 +71,11 @@ github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g= github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY= @@ -78,12 +90,18 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= +github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= +github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -93,8 +111,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= @@ -115,18 +133,22 @@ go.opentelemetry.io/collector/pdata v1.0.0 h1:ECP2jnLztewsHmL1opL8BeMtWVc7/oSlKN go.opentelemetry.io/collector/pdata v1.0.0/go.mod h1:TsDFgs4JLNG7t6x9D8kGswXUz4mme+MyNChHx8zSF6k= go.opentelemetry.io/collector/processor v0.91.0 h1:Xi52gYMXTG4zYmNhsqJ8ly/9f7b0n0crMhKxVVI9HpY= go.opentelemetry.io/collector/processor v0.91.0/go.mod h1:naTuusZNfzM5MSqoTVzkKbR1MaJ8oD8v5ginR5JreDE= -go.opentelemetry.io/collector/semconv v0.91.0 h1:TRd+yDDfKQl+aNtS24wmEbJp1/QE/xAFV9SB5zWGxpE= -go.opentelemetry.io/collector/semconv v0.91.0/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw= +go.opentelemetry.io/collector/semconv v0.97.0 h1:iF3nTfThbiOwz7o5Pocn0dDnDoffd18ijDuf6Mwzi1s= +go.opentelemetry.io/collector/semconv v0.97.0/go.mod h1:8ElcRZ8Cdw5JnvhTOQOdYizkJaQ10Z2fS+R6djOnj6A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/prometheus v0.44.1-0.20231201153405-6027c1ae76f2 h1:TnhkxGJ5qPHAMIMI4r+HPT/BbpoHxqn4xONJrok054o= +go.opentelemetry.io/otel/exporters/prometheus v0.44.1-0.20231201153405-6027c1ae76f2/go.mod h1:ERL2uIeBtg4TxZdojHUwzZfIFlUIjZtxubT5p4h1Gjg= go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= +go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -208,7 +230,9 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/collector/processor/faasprocessor/processor.go b/collector/processor/faasprocessor/processor.go new file mode 100644 index 0000000000..0f76aa5a51 --- /dev/null +++ b/collector/processor/faasprocessor/processor.go @@ -0,0 +1,146 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package faasprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor" + +import ( + "context" + + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/ptrace" + "go.opentelemetry.io/collector/processor" + "go.opentelemetry.io/collector/processor/processorhelper" + semconv "go.opentelemetry.io/collector/semconv/v1.22.0" + "go.uber.org/zap" +) + +const ( + telemetryAPIScope = "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapi" +) + +type faasProcessor struct { + telemetryAPIRuntimeSpans map[string]cachedSpan + telemetryAPIInitSpans map[string]cachedSpan + invocationSpans map[string]cachedSpan + logger *zap.Logger + nextConsumer consumer.Traces +} + +func (p *faasProcessor) processTraces(ctx context.Context, td ptrace.Traces) (ptrace.Traces, error) { + // Remove spans which ought to be matched on the request ID + td.ResourceSpans().RemoveIf(func(rs ptrace.ResourceSpans) bool { + resource := rs.Resource() + rs.ScopeSpans().RemoveIf(func(ss ptrace.ScopeSpans) bool { + scope := ss.Scope() + ss.Spans().RemoveIf(func(span ptrace.Span) bool { + if scope.Name() == telemetryAPIScope { + if requestID, ok := span.Attributes().Get(semconv.AttributeFaaSInvocationID); ok { + // This span was issued from the telemetry api, let's cache it for later + cached := cachedSpan{ + resource: resource, + scope: scope, + span: span, + } + if _, ok := span.Attributes().Get(semconv.AttributeFaaSColdstart); ok { + // This is the "root" runtime span + p.telemetryAPIRuntimeSpans[requestID.Str()] = cached + } else { + // This is the init span that is a child of the "root" span + p.telemetryAPIInitSpans[requestID.Str()] = cached + } + return true + } + } else { + if requestID, ok := span.Attributes().Get(semconv.AttributeFaaSInvocationID); ok { + // This span was created by the invoked code, let's cache it and don't + // process it further here. + p.invocationSpans[requestID.Str()] = cachedSpan{ + resource: resource, + scope: scope, + span: span, + } + return true + } + } + return false + }) + return ss.Spans().Len() == 0 + }) + return rs.ScopeSpans().Len() == 0 + }) + + // Check for matches on the request ID and add new spans + for requestID, telemetryApiSpan := range p.telemetryAPIRuntimeSpans { + if invocationSpan, ok := p.invocationSpans[requestID]; ok { + // Augment the spans as required + telemetryApiSpan.span.SetParentSpanID(invocationSpan.span.ParentSpanID()) + invocationSpan.span.SetParentSpanID(telemetryApiSpan.span.SpanID()) + telemetryApiSpan.span.SetTraceID(invocationSpan.span.TraceID()) + + // Add spans to the output + telemetryApiSpan.addToTraces(td) + invocationSpan.addToTraces(td) + + // Clean up our cache + delete(p.telemetryAPIRuntimeSpans, requestID) + delete(p.invocationSpans, requestID) + + // Optionally, there is also an init span. We need to augment its trace ID + if initSpan, ok := p.telemetryAPIInitSpans[requestID]; ok { + initSpan.span.SetTraceID(invocationSpan.span.TraceID()) + initSpan.addToTraces(td) + delete(p.telemetryAPIInitSpans, requestID) + } + } + } + + if td.ResourceSpans().Len() == 0 { + return td, processorhelper.ErrSkipProcessingData + } + return td, nil +} + +func newFaasProcessor( + cfg *Config, + next consumer.Traces, + set processor.CreateSettings, +) (*faasProcessor, error) { + return &faasProcessor{ + telemetryAPIRuntimeSpans: make(map[string]cachedSpan), + telemetryAPIInitSpans: make(map[string]cachedSpan), + invocationSpans: make(map[string]cachedSpan), + nextConsumer: next, + logger: set.Logger, + }, nil +} + +/* ---------------------------------------- CACHED SPAN ---------------------------------------- */ + +type cachedSpan struct { + resource pcommon.Resource + scope pcommon.InstrumentationScope + span ptrace.Span +} + +func (s cachedSpan) addToTraces(td ptrace.Traces) { + resourceSpans := td.ResourceSpans().AppendEmpty() + s.resource.CopyTo(resourceSpans.Resource()) + + scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() + s.scope.CopyTo(scopeSpans.Scope()) + + span := scopeSpans.Spans().AppendEmpty() + s.span.CopyTo(span) +} diff --git a/collector/processor/faasprocessor/processor_test.go b/collector/processor/faasprocessor/processor_test.go new file mode 100644 index 0000000000..7e3a9037ae --- /dev/null +++ b/collector/processor/faasprocessor/processor_test.go @@ -0,0 +1,607 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package faasprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor" + +// import ( +// "bytes" +// "context" +// crand "crypto/rand" +// "encoding/binary" +// "fmt" +// "hash" +// "math" +// "math/rand" +// "reflect" +// "sort" +// "testing" + +// "github.com/cespare/xxhash" +// "github.com/stretchr/testify/require" +// "go.opentelemetry.io/collector/pdata/pcommon" +// "go.opentelemetry.io/collector/pdata/ptrace" +// "go.opentelemetry.io/collector/processor/processorhelper" +// "go.opentelemetry.io/collector/processor/processortest" +// semconv "go.opentelemetry.io/collector/semconv/v1.5.0" +// "go.uber.org/multierr" +// ) + +// func TestProcessor(t *testing.T) { +// executionTraceID := getTraceID() +// testCases := []struct { +// desc string +// input ptrace.Traces +// expected ptrace.Traces +// expectedError error +// reported bool +// }{ +// { +// desc: "no traces", +// input: ptrace.NewTraces(), +// expected: ptrace.NewTraces(), +// expectedError: processorhelper.ErrSkipProcessingData, +// }, +// { +// desc: "coldstart without execution", +// input: func() ptrace.Traces { +// td := ptrace.NewTraces() +// span := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() +// span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) +// return td +// }(), +// expected: ptrace.NewTraces(), +// expectedError: processorhelper.ErrSkipProcessingData, +// }, +// { +// desc: "execution without coldstart", +// input: func() ptrace.Traces { +// td := ptrace.NewTraces() +// addExecutionSpan(td, executionTraceID) +// return td +// }(), +// expected: func() ptrace.Traces { +// td := ptrace.NewTraces() +// addExecutionSpan(td, executionTraceID) +// return td +// }(), +// }, +// { +// desc: "faas.execution and faas.coldstart with coldstart is first", +// input: func() ptrace.Traces { +// td := ptrace.NewTraces() +// span := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() +// span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) +// span.Attributes().PutBool("faas.initialization", true) +// addExecutionSpan(td, executionTraceID) +// return td +// }(), +// expected: func() ptrace.Traces { +// td := ptrace.NewTraces() +// rs := td.ResourceSpans().AppendEmpty() +// ss := rs.ScopeSpans().AppendEmpty() + +// rs.Resource().Attributes().PutStr("resource-attr", "faas-execution") +// ss.Scope().SetName("app/execution") +// executionSpan(ss.Spans().AppendEmpty(), executionTraceID) +// initializationSpan(ss.Spans().AppendEmpty(), executionTraceID) +// return td +// }(), +// reported: true, +// }, +// { +// desc: "faas.execution and faas.coldstart with execution is first", +// input: func() ptrace.Traces { +// td := ptrace.NewTraces() +// addExecutionSpan(td, executionTraceID) +// span := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() +// span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) +// span.Attributes().PutBool("faas.initialization", true) +// return td +// }(), +// expected: func() ptrace.Traces { +// td := ptrace.NewTraces() +// rs := td.ResourceSpans().AppendEmpty() +// ss := rs.ScopeSpans().AppendEmpty() +// rs.Resource().Attributes().PutStr("resource-attr", "faas-execution") +// ss.Scope().SetName("app/execution") +// executionSpan(ss.Spans().AppendEmpty(), executionTraceID) +// rs = td.ResourceSpans().AppendEmpty() +// ss = rs.ScopeSpans().AppendEmpty() +// rs.Resource().Attributes().PutStr("resource-attr", "faas-execution") +// ss.Scope().SetName("app/execution") +// initializationSpan(ss.Spans().AppendEmpty(), executionTraceID) +// return td +// }(), +// reported: true, +// }, +// } +// for _, tc := range testCases { +// t.Run(tc.desc, func(t *testing.T) { +// c, err := newFaasProcessor( +// nil, +// nil, +// processortest.NewNopCreateSettings(), +// ) +// require.NoError(t, err) +// td, err := c.processTraces(context.Background(), tc.input) +// require.Equal(t, tc.expectedError, err) + +// require.Equal(t, tc.expected.SpanCount(), td.SpanCount()) +// require.Equal(t, tc.reported, c.reported) +// require.NoError(t, compareTraces(tc.expected, td)) +// }) +// } +// } + +// func TestMultipleProcessTraces(t *testing.T) { +// c, err := newFaasProcessor( +// nil, +// nil, +// processortest.NewNopCreateSettings(), +// ) +// require.NoError(t, err) +// expected := ptrace.NewTraces() +// input := ptrace.NewTraces() +// addExecutionSpan(input, getTraceID()) +// input.CopyTo(expected) +// output, err := c.processTraces(context.Background(), input) +// require.NoError(t, err) +// require.Equal(t, 1, output.SpanCount()) +// require.NoError(t, compareTraces(expected, output)) +// require.False(t, c.reported) + +// input = ptrace.NewTraces() +// expected = ptrace.NewTraces() +// span := input.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() +// span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) +// span.Attributes().PutBool("faas.initialization", true) +// input.CopyTo(expected) +// output, err = c.processTraces(context.Background(), input) +// require.NoError(t, err) +// require.Equal(t, expected.SpanCount(), output.SpanCount()) +// require.Error(t, compareTraces(expected, output)) +// attr, ok := output.ResourceSpans().At(0).Resource().Attributes().Get("resource-attr") +// require.True(t, ok) +// require.Equal(t, "faas-execution", attr.AsString()) +// require.Equal(t, "app/execution", output.ResourceSpans().At(0).ScopeSpans().At(0).Scope().Name()) +// require.True(t, c.reported) + +// c, err = newFaasProcessor( +// nil, +// nil, +// processortest.NewNopCreateSettings(), +// ) +// require.NoError(t, err) +// input = ptrace.NewTraces() +// expected = ptrace.NewTraces() +// span = input.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() +// span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) +// span.Attributes().PutBool("faas.initialization", true) +// input.CopyTo(expected) +// output, err = c.processTraces(context.Background(), input) +// require.Error(t, err) +// require.Equal(t, 0, output.SpanCount()) +// require.False(t, c.reported) + +// expected = ptrace.NewTraces() +// input = ptrace.NewTraces() +// addExecutionSpan(input, getTraceID()) +// input.CopyTo(expected) +// output, err = c.processTraces(context.Background(), input) +// require.NoError(t, err) +// require.Equal(t, 2, output.SpanCount()) +// require.Error(t, compareTraces(expected, output)) +// attr, ok = output.ResourceSpans().At(0).Resource().Attributes().Get("resource-attr") +// require.True(t, ok) +// require.Equal(t, "faas-execution", attr.AsString()) +// require.Equal(t, "app/execution", output.ResourceSpans().At(0).ScopeSpans().At(0).Scope().Name()) +// require.True(t, c.reported) +// } + +// func getTraceID() pcommon.TraceID { +// var rngSeed int64 +// _ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) +// randSource := rand.New(rand.NewSource(rngSeed)) +// tid := pcommon.TraceID{} +// _, _ = randSource.Read(tid[:]) +// return tid +// } + +// func addExecutionSpan(td ptrace.Traces, id pcommon.TraceID) { +// rs := td.ResourceSpans().AppendEmpty() +// rs.Resource().Attributes().PutStr("resource-attr", "faas-execution") +// ss := rs.ScopeSpans().AppendEmpty() +// ss.Scope().SetName("app/execution") +// span := ss.Spans().AppendEmpty() +// span.SetTraceID(id) +// span.Attributes().PutStr(semconv.AttributeFaaSExecution, "af9d5aa4-a685-4c5f-a22b-444f80b3cc28") +// } + +// func executionSpan(span ptrace.Span, id pcommon.TraceID) { +// span.SetTraceID(id) +// span.Attributes().PutStr(semconv.AttributeFaaSExecution, "af9d5aa4-a685-4c5f-a22b-444f80b3cc28") +// } + +// func initializationSpan(span ptrace.Span, id pcommon.TraceID) { +// span.SetTraceID(id) +// span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) +// span.Attributes().PutBool("faas.initialization", true) +// } + +// var ( +// extraByte = []byte{'\xf3'} +// keyPrefix = []byte{'\xf4'} +// valEmpty = []byte{'\xf5'} +// valBytesPrefix = []byte{'\xf6'} +// valStrPrefix = []byte{'\xf7'} +// valBoolTrue = []byte{'\xf8'} +// valBoolFalse = []byte{'\xf9'} +// valIntPrefix = []byte{'\xfa'} +// valDoublePrefix = []byte{'\xfb'} +// valMapPrefix = []byte{'\xfc'} +// valMapSuffix = []byte{'\xfd'} +// valSlicePrefix = []byte{'\xfe'} +// valSliceSuffix = []byte{'\xff'} +// ) + +// // mapHash return a hash for the provided map. +// // Maps with the same underlying key/value pairs in different order produce the same deterministic hash value. +// func mapHash(m pcommon.Map) [16]byte { +// h := xxhash.New() +// writeMapHash(h, m) +// return hashSum128(h) +// } + +// func writeMapHash(h hash.Hash, m pcommon.Map) { +// keys := make([]string, 0, m.Len()) +// m.Range(func(k string, v pcommon.Value) bool { +// keys = append(keys, k) +// return true +// }) +// sort.Strings(keys) +// for _, k := range keys { +// v, _ := m.Get(k) +// h.Write(keyPrefix) +// h.Write([]byte(k)) +// writeValueHash(h, v) +// } +// } + +// func writeSliceHash(h hash.Hash, sl pcommon.Slice) { +// for i := 0; i < sl.Len(); i++ { +// writeValueHash(h, sl.At(i)) +// } +// } + +// func writeValueHash(h hash.Hash, v pcommon.Value) { +// switch v.Type() { +// case pcommon.ValueTypeStr: +// h.Write(valStrPrefix) +// h.Write([]byte(v.Str())) +// case pcommon.ValueTypeBool: +// if v.Bool() { +// h.Write(valBoolTrue) +// } else { +// h.Write(valBoolFalse) +// } +// case pcommon.ValueTypeInt: +// h.Write(valIntPrefix) +// b := make([]byte, 8) +// binary.LittleEndian.PutUint64(b, uint64(v.Int())) +// h.Write(b) +// case pcommon.ValueTypeDouble: +// h.Write(valDoublePrefix) +// b := make([]byte, 8) +// binary.LittleEndian.PutUint64(b, math.Float64bits(v.Double())) +// h.Write(b) +// case pcommon.ValueTypeMap: +// h.Write(valMapPrefix) +// writeMapHash(h, v.Map()) +// h.Write(valMapSuffix) +// case pcommon.ValueTypeSlice: +// h.Write(valSlicePrefix) +// writeSliceHash(h, v.Slice()) +// h.Write(valSliceSuffix) +// case pcommon.ValueTypeBytes: +// h.Write(valBytesPrefix) +// h.Write(v.Bytes().AsRaw()) +// case pcommon.ValueTypeEmpty: +// h.Write(valEmpty) +// } +// } + +// // hashSum128 returns a [16]byte hash sum. +// func hashSum128(h hash.Hash) [16]byte { +// b := make([]byte, 0, 16) +// b = h.Sum(b) + +// // Append an extra byte to generate another part of the hash sum +// _, _ = h.Write(extraByte) +// b = h.Sum(b) + +// res := [16]byte{} +// copy(res[:], b) +// return res +// } + +// func sortResourceSpans(a, b ptrace.ResourceSpans) bool { +// if a.SchemaUrl() < b.SchemaUrl() { +// return true +// } +// aAttrs := mapHash(a.Resource().Attributes()) +// bAttrs := mapHash(b.Resource().Attributes()) +// return bytes.Compare(aAttrs[:], bAttrs[:]) < 0 +// } + +// func sortSpansInstrumentationLibrary(a, b ptrace.ScopeSpans) bool { +// if a.SchemaUrl() < b.SchemaUrl() { +// return true +// } +// if a.Scope().Name() < b.Scope().Name() { +// return true +// } +// if a.Scope().Version() < b.Scope().Version() { +// return true +// } +// return false +// } + +// func sortSpanSlice(a, b ptrace.Span) bool { +// aAttrs := mapHash(a.Attributes()) +// bAttrs := mapHash(b.Attributes()) +// return bytes.Compare(aAttrs[:], bAttrs[:]) < 0 +// } + +// // CompareTraces compares each part of two given Traces and returns +// // an error if they don't match. The error describes what didn't match. +// func compareTraces(expected, actual ptrace.Traces) error { +// exp, act := ptrace.NewTraces(), ptrace.NewTraces() +// expected.CopyTo(exp) +// actual.CopyTo(act) + +// expectedSpans, actualSpans := exp.ResourceSpans(), act.ResourceSpans() +// if expectedSpans.Len() != actualSpans.Len() { +// return fmt.Errorf("amount of ResourceSpans between Traces are not equal expected: %d, actual: %d", +// expectedSpans.Len(), +// actualSpans.Len()) +// } + +// // sort ResourceSpans +// expectedSpans.Sort(sortResourceSpans) +// actualSpans.Sort(sortResourceSpans) + +// numResources := expectedSpans.Len() + +// // Keep track of matching resources so that each can only be matched once +// matchingResources := make(map[ptrace.ResourceSpans]ptrace.ResourceSpans, numResources) + +// var errs error +// for e := 0; e < numResources; e++ { +// er := expectedSpans.At(e) +// var foundMatch bool +// for a := 0; a < numResources; a++ { +// ar := actualSpans.At(a) +// if _, ok := matchingResources[ar]; ok { +// continue +// } +// if reflect.DeepEqual(er.Resource().Attributes().AsRaw(), ar.Resource().Attributes().AsRaw()) { +// foundMatch = true +// matchingResources[ar] = er +// break +// } +// } +// if !foundMatch { +// errs = multierr.Append(errs, fmt.Errorf("missing expected resource with attributes: %v", er.Resource().Attributes().AsRaw())) +// } +// } + +// for i := 0; i < numResources; i++ { +// if _, ok := matchingResources[actualSpans.At(i)]; !ok { +// errs = multierr.Append(errs, fmt.Errorf("extra resource with attributes: %v", actualSpans.At(i).Resource().Attributes().AsRaw())) +// } +// } + +// if errs != nil { +// return errs +// } + +// for ar, er := range matchingResources { +// if err := CompareResourceSpans(er, ar); err != nil { +// return err +// } +// } + +// return nil +// } + +// // CompareResourceSpans compares each part of two given ResourceSpans and returns +// // an error if they don't match. The error describes what didn't match. +// func CompareResourceSpans(expected, actual ptrace.ResourceSpans) error { +// eilms := expected.ScopeSpans() +// ailms := actual.ScopeSpans() + +// if eilms.Len() != ailms.Len() { +// return fmt.Errorf("number of instrumentation libraries does not match expected: %d, actual: %d", eilms.Len(), +// ailms.Len()) +// } + +// // sort InstrumentationLibrary +// eilms.Sort(sortSpansInstrumentationLibrary) +// ailms.Sort(sortSpansInstrumentationLibrary) + +// for i := 0; i < eilms.Len(); i++ { +// eilm, ailm := eilms.At(i), ailms.At(i) +// eil, ail := eilm.Scope(), ailm.Scope() + +// if eil.Name() != ail.Name() { +// return fmt.Errorf("instrumentation library Name does not match expected: %s, actual: %s", eil.Name(), ail.Name()) +// } +// if eil.Version() != ail.Version() { +// return fmt.Errorf("instrumentation library Version does not match expected: %s, actual: %s", eil.Version(), ail.Version()) +// } +// if err := CompareSpanSlices(eilm.Spans(), ailm.Spans()); err != nil { +// return err +// } +// } +// return nil +// } + +// // CompareSpanSlices compares each part of two given SpanSlices and returns +// // an error if they don't match. The error describes what didn't match. +// func CompareSpanSlices(expected, actual ptrace.SpanSlice) error { +// if expected.Len() != actual.Len() { +// return fmt.Errorf("number of spans does not match expected: %d, actual: %d", expected.Len(), actual.Len()) +// } + +// expected.Sort(sortSpanSlice) +// actual.Sort(sortSpanSlice) + +// numSpans := expected.Len() + +// // Keep track of matching spans so that each span can only be matched once +// matchingSpans := make(map[ptrace.Span]ptrace.Span, numSpans) + +// var errs error +// for e := 0; e < numSpans; e++ { +// elr := expected.At(e) +// var foundMatch bool +// for a := 0; a < numSpans; a++ { +// alr := actual.At(a) +// if _, ok := matchingSpans[alr]; ok { +// continue +// } +// if reflect.DeepEqual(elr.Attributes().AsRaw(), alr.Attributes().AsRaw()) { +// foundMatch = true +// matchingSpans[alr] = elr +// break +// } +// } +// if !foundMatch { +// errs = multierr.Append(errs, fmt.Errorf("span missing expected resource with attributes: %v", elr.Attributes().AsRaw())) +// } +// } + +// for i := 0; i < numSpans; i++ { +// if _, ok := matchingSpans[actual.At(i)]; !ok { +// errs = multierr.Append(errs, fmt.Errorf("span has extra record with attributes: %v", actual.At(i).Attributes().AsRaw())) +// } +// } + +// if errs != nil { +// return errs +// } + +// for alr, elr := range matchingSpans { +// if err := CompareSpans(alr, elr); err != nil { +// return multierr.Combine(fmt.Errorf("span with attributes: %v, does not match expected %v", alr.Attributes().AsRaw(), elr.Attributes().AsRaw()), err) +// } +// } +// return nil +// } + +// // CompareSpans compares each part of two given Span and returns +// // an error if they don't match. The error describes what didn't match. +// func CompareSpans(expected, actual ptrace.Span) error { +// if expected.TraceID() != actual.TraceID() { +// return fmt.Errorf("span TraceID doesn't match expected: %d, actual: %d", +// expected.TraceID(), +// actual.TraceID()) +// } + +// if expected.SpanID() != actual.SpanID() { +// return fmt.Errorf("span SpanID doesn't match expected: %d, actual: %d", +// expected.SpanID(), +// actual.SpanID()) +// } + +// if expected.TraceState().AsRaw() != actual.TraceState().AsRaw() { +// return fmt.Errorf("span TraceState doesn't match expected: %s, actual: %s", +// expected.TraceState().AsRaw(), +// actual.TraceState().AsRaw()) +// } + +// if expected.ParentSpanID() != actual.ParentSpanID() { +// return fmt.Errorf("span ParentSpanID doesn't match expected: %d, actual: %d", +// expected.ParentSpanID(), +// actual.ParentSpanID()) +// } + +// if expected.Name() != actual.Name() { +// return fmt.Errorf("span Name doesn't match expected: %s, actual: %s", +// expected.Name(), +// actual.Name()) +// } + +// if expected.Kind() != actual.Kind() { +// return fmt.Errorf("span Kind doesn't match expected: %d, actual: %d", +// expected.Kind(), +// actual.Kind()) +// } + +// if expected.StartTimestamp() != actual.StartTimestamp() { +// return fmt.Errorf("span StartTimestamp doesn't match expected: %d, actual: %d", +// expected.StartTimestamp(), +// actual.StartTimestamp()) +// } + +// if expected.EndTimestamp() != actual.EndTimestamp() { +// return fmt.Errorf("span EndTimestamp doesn't match expected: %d, actual: %d", +// expected.EndTimestamp(), +// actual.EndTimestamp()) +// } + +// if !reflect.DeepEqual(expected.Attributes().AsRaw(), actual.Attributes().AsRaw()) { +// return fmt.Errorf("span Attributes doesn't match expected: %s, actual: %s", +// expected.Attributes().AsRaw(), +// actual.Attributes().AsRaw()) +// } + +// if expected.DroppedAttributesCount() != actual.DroppedAttributesCount() { +// return fmt.Errorf("span DroppedAttributesCount doesn't match expected: %d, actual: %d", +// expected.DroppedAttributesCount(), +// actual.DroppedAttributesCount()) +// } + +// if !reflect.DeepEqual(expected.Events(), actual.Events()) { +// return fmt.Errorf("span Events doesn't match expected: %v, actual: %v", +// expected.Events(), +// actual.Events()) +// } + +// if expected.DroppedEventsCount() != actual.DroppedEventsCount() { +// return fmt.Errorf("span DroppedEventsCount doesn't match expected: %d, actual: %d", +// expected.DroppedEventsCount(), +// actual.DroppedEventsCount()) +// } + +// if !reflect.DeepEqual(expected.Links(), actual.Links()) { +// return fmt.Errorf("span Links doesn't match expected: %v, actual: %v", +// expected.Links(), +// actual.Links()) +// } + +// if expected.DroppedLinksCount() != actual.DroppedLinksCount() { +// return fmt.Errorf("span DroppedLinksCount doesn't match expected: %d, actual: %d", +// expected.DroppedLinksCount(), +// actual.DroppedLinksCount()) +// } + +// if !reflect.DeepEqual(expected.Status(), actual.Status()) { +// return fmt.Errorf("span Status doesn't match expected: %v, actual: %v", +// expected.Status(), +// actual.Status()) +// } + +// return nil +// } diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index e1dc41c3e9..a443350c6e 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -49,7 +49,10 @@ const ( instrumentationScope = "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapi" ) -var errUnknownMetric = errors.New("metric is unknown") +var ( + errUnknownMetric = errors.New("metric is unknown") + errMissingServiceName = errors.New("service name is missing") +) /* ------------------------------------------ CREATION ----------------------------------------- */ @@ -61,24 +64,26 @@ type telemetryAPIReceiver struct { resource pcommon.Resource cfg *Config // TRACES - nextTracesConsumer consumer.Traces - lastPlatformInitStartTime string - lastPlatformInitEndTime string + nextTracesConsumer consumer.Traces + lastRequestID string + lastPlatformInitStartTime string + lastPlatformInitEndTime string + lastPlatformRuntimeStartTime string + lastPlatformRuntimeDoneTime string // METRICS // NOTE: We're using the OpenTelemetry SDK here as generating 'pmetric' structures entirely // manually is error-prone and would duplicate plenty of code available in the SDK. - nextMetricsConsumer consumer.Metrics - metricsReader *sdkmetric.ManualReader - metricInitDurations metric.Float64Histogram - metricInvokeDurations metric.Float64Histogram - metricColdstarts metric.Int64Counter - metricSuccesses metric.Int64Counter - metricFailures metric.Int64Counter - metricTimeouts metric.Int64Counter - metricMemoryUsages metric.Int64Histogram - lastPlatformInitReportTime string - lastPlatformRuntimeDoneTime string - lastPlatformReportTime string + nextMetricsConsumer consumer.Metrics + metricsReader *sdkmetric.ManualReader + metricInitDurations metric.Float64Histogram + metricInvokeDurations metric.Float64Histogram + metricColdstarts metric.Int64Counter + metricSuccesses metric.Int64Counter + metricFailures metric.Int64Counter + metricTimeouts metric.Int64Counter + metricMemoryUsages metric.Int64Histogram + lastPlatformInitReportTime string + lastPlatformReportTime string // LOGS nextLogsConsumer consumer.Logs } @@ -280,7 +285,7 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Function invocation started. case string(telemetryapi.PlatformStart): r.logger.Debug(fmt.Sprintf("Invoke start: %s", el.Time), zap.Any("event", el)) - continue + r.lastPlatformRuntimeStartTime = el.Time // Function invocation completed. case string(telemetryapi.PlatformRuntimeDone): r.logger.Debug(fmt.Sprintf("Invoke end: %s", el.Time), zap.Any("event", el)) @@ -289,6 +294,7 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ continue } if record, err := parseRecord[platformRuntimeDoneRecord](el, r.logger); err == nil { + r.lastRequestID = record.RequestID r.metricInvokeDurations.Record(ctx, record.Metrics.DurationMs/1000.0) switch record.Status { case statusSuccess: @@ -326,8 +332,9 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Lambda dropped log entries. // case "platform.logsDropped": } - r.forwardTraces() + // NOTE: Forward metrics first as trace forwarding clears timestamps r.forwardMetrics() + r.forwardTraces() slice = nil } @@ -346,13 +353,14 @@ func parseRecord[T any](el event, logger *zap.Logger) (T, error) { /* ----------------------------------------- FORWARDING ---------------------------------------- */ func (r *telemetryAPIReceiver) forwardTraces() { - // Create trace for init span - if len(r.lastPlatformInitStartTime) > 0 && len(r.lastPlatformInitEndTime) > 0 { - if td, err := r.createPlatformInitSpan(r.lastPlatformInitStartTime, r.lastPlatformInitEndTime); err == nil { + if r.lastPlatformRuntimeDoneTime != "" { + if td, err := r.createPlatformRuntimeSpan(); err == nil { err := r.nextTracesConsumer.ConsumeTraces(context.Background(), td) if err == nil { r.lastPlatformInitEndTime = "" r.lastPlatformInitStartTime = "" + r.lastPlatformRuntimeStartTime = "" + r.lastPlatformRuntimeDoneTime = "" } else { r.logger.Error("error receiving traces", zap.Error(err)) } @@ -387,7 +395,7 @@ func (r *telemetryAPIReceiver) forwardMetrics() { scopeMetrics := resourceMetricData.ScopeMetrics().AppendEmpty() scopeMetrics.Scope().SetName(scope.Scope.Name) for _, metric := range scope.Metrics { - ts, err := r.metricTimestamp(metric.Name) + ts, err := r.getMetricTimestamp(metric.Name) if err != nil { r.logger.Error( fmt.Sprintf("failed to obtain last timestamp for metric '%s'", metric.Name), @@ -424,6 +432,53 @@ func (r *telemetryAPIReceiver) forwardMetrics() { /* ------------------------------------------- TRACES ------------------------------------------ */ +func (r *telemetryAPIReceiver) createPlatformRuntimeSpan() (ptrace.Traces, error) { + serviceName, ok := r.resource.Attributes().Get(semconv.AttributeServiceName) + if !ok { + return ptrace.Traces{}, errMissingServiceName + } + + // Build trace data + traceData := ptrace.NewTraces() + rs := traceData.ResourceSpans().AppendEmpty() + r.resource.CopyTo(rs.Resource()) + + ss := rs.ScopeSpans().AppendEmpty() + ss.Scope().SetName(instrumentationScope) + + // Create root span for the entire runtime invocation + traceID := newTraceID() + rootSpan := ss.Spans().AppendEmpty() + rootSpan.SetTraceID(traceID) + rootSpan.SetSpanID(newSpanID()) + rootSpan.SetName(serviceName.Str()) + rootSpan.SetKind(ptrace.SpanKindServer) + rootSpan.Attributes().PutBool(semconv.AttributeFaaSColdstart, r.lastPlatformInitEndTime != "") + rootSpan.Attributes().PutStr(semconv.AttributeFaaSInvocationID, r.lastRequestID) + rootStartTime := r.lastPlatformRuntimeStartTime + if r.lastPlatformInitStartTime != "" { + rootStartTime = r.lastPlatformInitStartTime + } + if err := setSpanTimestamps(rootSpan, rootStartTime, r.lastPlatformRuntimeDoneTime); err != nil { + return ptrace.Traces{}, err + } + + // Optionally create an additional span for the init span + if r.lastPlatformInitEndTime != "" { + initSpan := ss.Spans().AppendEmpty() + initSpan.SetTraceID(traceID) + initSpan.SetSpanID(newSpanID()) + initSpan.SetParentSpanID(rootSpan.SpanID()) + initSpan.SetName("faas.runtimeInit") + initSpan.SetKind(ptrace.SpanKindInternal) + initSpan.Attributes().PutStr(semconv.AttributeFaaSInvocationID, r.lastRequestID) + if err := setSpanTimestamps(initSpan, r.lastPlatformInitStartTime, r.lastPlatformInitEndTime); err != nil { + return ptrace.Traces{}, err + } + } + return ptrace.Traces{}, nil +} + func newSpanID() pcommon.SpanID { var rngSeed int64 _ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) @@ -442,35 +497,23 @@ func newTraceID() pcommon.TraceID { return tid } -func (r *telemetryAPIReceiver) createPlatformInitSpan(start, end string) (ptrace.Traces, error) { - traceData := ptrace.NewTraces() - rs := traceData.ResourceSpans().AppendEmpty() - r.resource.CopyTo(rs.Resource()) - - ss := rs.ScopeSpans().AppendEmpty() - ss.Scope().SetName(instrumentationScope) - span := ss.Spans().AppendEmpty() - span.SetTraceID(newTraceID()) - span.SetSpanID(newSpanID()) - span.SetName("platform.initRuntimeDone") - span.SetKind(ptrace.SpanKindInternal) - span.Attributes().PutBool(semconv.AttributeFaaSColdstart, true) +func setSpanTimestamps(span ptrace.Span, start, end string) error { startTime, err := parseTime(start) if err != nil { - return ptrace.Traces{}, err + return err } span.SetStartTimestamp(pcommon.NewTimestampFromTime(startTime)) endTime, err := parseTime(end) if err != nil { - return ptrace.Traces{}, err + return err } span.SetEndTimestamp(pcommon.NewTimestampFromTime(endTime)) - return traceData, nil + return nil } /* ------------------------------------------ METRICS ------------------------------------------ */ -func (r *telemetryAPIReceiver) metricTimestamp(metricName string) (time.Time, error) { +func (r *telemetryAPIReceiver) getMetricTimestamp(metricName string) (time.Time, error) { switch metricName { case "faas.coldstarts", "faas.init_duration": if r.lastPlatformInitReportTime == "" { From 23a6c7601c69e97587fea2ab3961c7dc39d53287 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 02:43:50 +0100 Subject: [PATCH 21/43] Fix --- collector/go.mod | 8 +++++--- collector/go.sum | 24 +++++++++++++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/collector/go.mod b/collector/go.mod index 7b7925ee7c..0b7aa56981 100644 --- a/collector/go.mod +++ b/collector/go.mod @@ -1,6 +1,8 @@ module github.com/open-telemetry/opentelemetry-lambda/collector -go 1.20 +go 1.21 + +toolchain go1.21.5 replace github.com/open-telemetry/opentelemetry-lambda/collector/lambdacomponents => ./lambdacomponents @@ -102,8 +104,8 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.92.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourceprocessor v0.92.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/processor/spanprocessor v0.92.0 // indirect - github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor v0.92.0 // indirect github.com/open-telemetry/opentelemetry-lambda/collector/processor/decoupleprocessor v0.0.0-00010101000000-000000000000 // indirect + github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor v0.92.0 // indirect github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver v0.92.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect @@ -153,7 +155,7 @@ require ( go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.92.0 // indirect go.opentelemetry.io/collector/receiver v0.92.0 // indirect go.opentelemetry.io/collector/receiver/otlpreceiver v0.92.0 // indirect - go.opentelemetry.io/collector/semconv v0.92.0 // indirect + go.opentelemetry.io/collector/semconv v0.97.0 // indirect go.opentelemetry.io/collector/service v0.92.0 // indirect go.opentelemetry.io/contrib/config v0.1.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect diff --git a/collector/go.sum b/collector/go.sum index 20112e9fb0..e5574fa0b6 100644 --- a/collector/go.sum +++ b/collector/go.sum @@ -52,9 +52,11 @@ cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOt cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68 h1:aRVqY1p2IJaBGStWMsQMpkAa83cPkCDLl80eOj0Rbz4= +cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68/go.mod h1:1a3eRNYX12fs5UABBIXS8HXVvQbX9hRB/RkEBPORpe8= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= @@ -226,9 +228,11 @@ contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0= +github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= +github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -279,7 +283,6 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -295,6 +298,7 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -310,6 +314,7 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/expr-lang/expr v1.15.8 h1:FL8+d3rSSP4tmK9o+vKfSMqqpGL8n15pEPiHcnBpxoI= github.com/expr-lang/expr v1.15.8/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -410,6 +415,7 @@ github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -437,9 +443,11 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -469,6 +477,7 @@ github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusrem github.com/open-telemetry/opentelemetry-collector-contrib/extension/sigv4authextension v0.92.0 h1:bxyNu6cZkv5GTWFmcWGPFIThwFvmjVe6h/X+Gt07udI= github.com/open-telemetry/opentelemetry-collector-contrib/extension/sigv4authextension v0.92.0/go.mod h1:jvGTAwfXP5F5NPZRHi1ZMufUs2266V1Tpsmg6rbn/B8= github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.92.0 h1:x36ZvOy+ad363p3viPF2FZnaxcM2yoUPQpg9VX89unw= +github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.92.0/go.mod h1:qELp3+4I6DZUAbv5S3oyzxKGZHhwC82A0oOutosMtYg= github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.92.0 h1:1UF2MF9boARNt/3L9SExlIMggp8htU4OiPz050CS6SM= github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.92.0/go.mod h1:MwTANoi8W1PxCOR3VcRNjPvoDpCLe98tzjFTU55jXhQ= github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter v0.92.0 h1:8ULgM2gWQYl9jq5uX2KqtQPFeBIM4TufAL91fFG2e5g= @@ -476,6 +485,7 @@ github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter v0.92. github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl v0.92.0 h1:hYDw9amC8zJl9uik4zkaPqPHogZ7PMhoY5qaBwMSRQ4= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl v0.92.0/go.mod h1:6V4eg/9WNeiAJ1bqUyHE7t5wP03L/1ecB1dRk7jWm0Q= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.92.0 h1:2cjUFC0jNSqAYcO+ZWUQ8sqPZdAX03Bd90SpsGcnrNY= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.92.0/go.mod h1:SOBg+bs2hOmckkRr/yURA78AuMePwRYIpao4EmI6xdw= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.92.0 h1:sqs1y0Exyxons2mWMAmBSdcdl2UizUgOmoibEBRX/4I= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.92.0/go.mod h1:me0dUlXvkVpDA6bN2z+qAggsXqOBEcm/dFFPw2mp7n8= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry v0.92.0 h1:WSWc/55tE3tHQpWZFjkeokZNUwjyZTqyPcUaXx3tuWg= @@ -539,6 +549,7 @@ github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -639,6 +650,7 @@ go.opentelemetry.io/collector/extension v0.92.0/go.mod h1:5EYwiaGU6deSY8YWqT5gvl go.opentelemetry.io/collector/extension/auth v0.92.0 h1:FlCObeiYXsVStltFivg+gD5PSFUM6dXHigkgkUMitv0= go.opentelemetry.io/collector/extension/auth v0.92.0/go.mod h1:fqCblNQV8Iz5w7Nrp1B865EJzKlVWS0aRgrr/c2HDDg= go.opentelemetry.io/collector/extension/zpagesextension v0.92.0 h1:n2W8Lla4P22P88WJ+e1n/AtcAEO47WnSYXlUUideU8g= +go.opentelemetry.io/collector/extension/zpagesextension v0.92.0/go.mod h1:oZwtuGVYK8C3Uh4exR0v0KQSkIUkngA3h9qutnmn7Qo= go.opentelemetry.io/collector/featuregate v1.0.1 h1:ok//hLSXttBbyu4sSV1pTx1nKdr5udSmrWy5sFMIIbM= go.opentelemetry.io/collector/featuregate v1.0.1/go.mod h1:QQXjP4etmJQhkQ20j4P/rapWuItYxoFozg/iIwuKnYg= go.opentelemetry.io/collector/otelcol v0.92.0 h1:F2plXKY8/ULnVOvQPHrSOEUE8OSGEcBhJIntzT+BRKI= @@ -655,8 +667,8 @@ go.opentelemetry.io/collector/receiver v0.92.0 h1:TRz4ufr5bFEszpAWgYVEx/b7VPZzEc go.opentelemetry.io/collector/receiver v0.92.0/go.mod h1:bYAAYbMuUVj3wx7ave2iyyJ+aGUpACliYOQ5xI92I7k= go.opentelemetry.io/collector/receiver/otlpreceiver v0.92.0 h1:77oFMYYJfRu4yqlRkExMHDieg9gPv38UsMtK/0cu5kU= go.opentelemetry.io/collector/receiver/otlpreceiver v0.92.0/go.mod h1:eZIrA6CY6xcm9uu3hmycS+L9kmBzyXE66Ci8FwkJpmI= -go.opentelemetry.io/collector/semconv v0.92.0 h1:3+OGPPuVu4rtrz8qGbpbiw7eKKULj4iJaSDTV52HM40= -go.opentelemetry.io/collector/semconv v0.92.0/go.mod h1:gZ0uzkXsN+J5NpiRcdp9xOhNGQDDui8Y62p15sKrlzo= +go.opentelemetry.io/collector/semconv v0.97.0 h1:iF3nTfThbiOwz7o5Pocn0dDnDoffd18ijDuf6Mwzi1s= +go.opentelemetry.io/collector/semconv v0.97.0/go.mod h1:8ElcRZ8Cdw5JnvhTOQOdYizkJaQ10Z2fS+R6djOnj6A= go.opentelemetry.io/collector/service v0.92.0 h1:KhicjajrbhEpjzSYCHvVZBYW5Qvd/UXi88oCegSanZI= go.opentelemetry.io/collector/service v0.92.0/go.mod h1:hlq/Vyj0un+HKx8nAI77eaK/mABNL8hhPH7rKh9SOu4= go.opentelemetry.io/contrib/config v0.1.1 h1:lIUTrMWkfDE0GvzBLhwv6ATDB1vntrnTsRvUMkZKnfQ= @@ -668,6 +680,7 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1: go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= go.opentelemetry.io/contrib/zpages v0.46.1 h1:U8Hh84dc+vJTVgRnL+QKWtWD2iqTSKibrQ85EeQqsNg= +go.opentelemetry.io/contrib/zpages v0.46.1/go.mod h1:1Wq9YTzkhr3Jkyi/sVrasFSppVzJQcvFf2Vc2ExZd6c= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/bridge/opencensus v0.44.0 h1:/inELPJztkn6Xx3ap9qw8i8XdeWF0B/OjGHOdRTePZ8= @@ -700,6 +713,7 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -774,6 +788,7 @@ golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -891,6 +906,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -942,6 +958,7 @@ google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnp google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f h1:Vn+VyHU5guc9KjB5KrjI2q0wCOWEOIh0OEsleqakHJg= +google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE= @@ -990,6 +1007,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From 94036e024fbaced3b22b3e78feef8d812bf2e90c Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 02:59:01 +0100 Subject: [PATCH 22/43] fix --- collector/receiver/telemetryapireceiver/receiver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index a443350c6e..94180ac5fd 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -476,7 +476,7 @@ func (r *telemetryAPIReceiver) createPlatformRuntimeSpan() (ptrace.Traces, error return ptrace.Traces{}, err } } - return ptrace.Traces{}, nil + return traceData, nil } func newSpanID() pcommon.SpanID { From 74588569b116881a6e9051ed002814ead41f4f64 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 18:13:46 +0100 Subject: [PATCH 23/43] Parse logs --- collector/lambdacomponents/go.mod | 6 +- collector/lambdacomponents/go.sum | 27 +- collector/processor/faasprocessor/go.mod | 3 +- collector/processor/faasprocessor/go.sum | 6 - .../receiver/telemetryapireceiver/config.go | 12 +- .../receiver/telemetryapireceiver/go.mod | 8 +- .../receiver/telemetryapireceiver/go.sum | 15 +- .../receiver/telemetryapireceiver/receiver.go | 263 +++++++++++++----- .../receiver/telemetryapireceiver/types.go | 6 +- 9 files changed, 244 insertions(+), 102 deletions(-) diff --git a/collector/lambdacomponents/go.mod b/collector/lambdacomponents/go.mod index 7a8e52cd6a..c7169b40d5 100644 --- a/collector/lambdacomponents/go.mod +++ b/collector/lambdacomponents/go.mod @@ -1,6 +1,8 @@ module github.com/open-telemetry/opentelemetry-lambda/collector/lambdacomponents -go 1.20 +go 1.21 + +toolchain go1.21.5 require ( github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusremotewriteexporter v0.92.0 @@ -127,7 +129,7 @@ require ( go.opentelemetry.io/collector/extension/auth v0.92.0 // indirect go.opentelemetry.io/collector/featuregate v1.0.1 // indirect go.opentelemetry.io/collector/pdata v1.0.1 // indirect - go.opentelemetry.io/collector/semconv v0.92.0 // indirect + go.opentelemetry.io/collector/semconv v0.97.0 // indirect go.opentelemetry.io/collector/service v0.92.0 // indirect go.opentelemetry.io/contrib/config v0.1.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect diff --git a/collector/lambdacomponents/go.sum b/collector/lambdacomponents/go.sum index 42947eb986..f633b16af6 100644 --- a/collector/lambdacomponents/go.sum +++ b/collector/lambdacomponents/go.sum @@ -52,9 +52,11 @@ cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOt cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68 h1:aRVqY1p2IJaBGStWMsQMpkAa83cPkCDLl80eOj0Rbz4= +cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68/go.mod h1:1a3eRNYX12fs5UABBIXS8HXVvQbX9hRB/RkEBPORpe8= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= @@ -226,9 +228,11 @@ contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0= +github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= +github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -269,7 +273,6 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -285,10 +288,12 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -299,6 +304,7 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/expr-lang/expr v1.15.8 h1:FL8+d3rSSP4tmK9o+vKfSMqqpGL8n15pEPiHcnBpxoI= github.com/expr-lang/expr v1.15.8/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -399,6 +405,7 @@ github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -426,9 +433,11 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -456,6 +465,7 @@ github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusrem github.com/open-telemetry/opentelemetry-collector-contrib/extension/sigv4authextension v0.92.0 h1:bxyNu6cZkv5GTWFmcWGPFIThwFvmjVe6h/X+Gt07udI= github.com/open-telemetry/opentelemetry-collector-contrib/extension/sigv4authextension v0.92.0/go.mod h1:jvGTAwfXP5F5NPZRHi1ZMufUs2266V1Tpsmg6rbn/B8= github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.92.0 h1:x36ZvOy+ad363p3viPF2FZnaxcM2yoUPQpg9VX89unw= +github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.92.0/go.mod h1:qELp3+4I6DZUAbv5S3oyzxKGZHhwC82A0oOutosMtYg= github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.92.0 h1:1UF2MF9boARNt/3L9SExlIMggp8htU4OiPz050CS6SM= github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.92.0/go.mod h1:MwTANoi8W1PxCOR3VcRNjPvoDpCLe98tzjFTU55jXhQ= github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter v0.92.0 h1:8ULgM2gWQYl9jq5uX2KqtQPFeBIM4TufAL91fFG2e5g= @@ -463,6 +473,7 @@ github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter v0.92. github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl v0.92.0 h1:hYDw9amC8zJl9uik4zkaPqPHogZ7PMhoY5qaBwMSRQ4= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl v0.92.0/go.mod h1:6V4eg/9WNeiAJ1bqUyHE7t5wP03L/1ecB1dRk7jWm0Q= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.92.0 h1:2cjUFC0jNSqAYcO+ZWUQ8sqPZdAX03Bd90SpsGcnrNY= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.92.0/go.mod h1:SOBg+bs2hOmckkRr/yURA78AuMePwRYIpao4EmI6xdw= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.92.0 h1:sqs1y0Exyxons2mWMAmBSdcdl2UizUgOmoibEBRX/4I= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.92.0/go.mod h1:me0dUlXvkVpDA6bN2z+qAggsXqOBEcm/dFFPw2mp7n8= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry v0.92.0 h1:WSWc/55tE3tHQpWZFjkeokZNUwjyZTqyPcUaXx3tuWg= @@ -486,6 +497,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -525,6 +537,7 @@ github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -557,6 +570,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo= github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -624,6 +638,7 @@ go.opentelemetry.io/collector/extension v0.92.0/go.mod h1:5EYwiaGU6deSY8YWqT5gvl go.opentelemetry.io/collector/extension/auth v0.92.0 h1:FlCObeiYXsVStltFivg+gD5PSFUM6dXHigkgkUMitv0= go.opentelemetry.io/collector/extension/auth v0.92.0/go.mod h1:fqCblNQV8Iz5w7Nrp1B865EJzKlVWS0aRgrr/c2HDDg= go.opentelemetry.io/collector/extension/zpagesextension v0.92.0 h1:n2W8Lla4P22P88WJ+e1n/AtcAEO47WnSYXlUUideU8g= +go.opentelemetry.io/collector/extension/zpagesextension v0.92.0/go.mod h1:oZwtuGVYK8C3Uh4exR0v0KQSkIUkngA3h9qutnmn7Qo= go.opentelemetry.io/collector/featuregate v1.0.1 h1:ok//hLSXttBbyu4sSV1pTx1nKdr5udSmrWy5sFMIIbM= go.opentelemetry.io/collector/featuregate v1.0.1/go.mod h1:QQXjP4etmJQhkQ20j4P/rapWuItYxoFozg/iIwuKnYg= go.opentelemetry.io/collector/otelcol v0.92.0 h1:F2plXKY8/ULnVOvQPHrSOEUE8OSGEcBhJIntzT+BRKI= @@ -640,8 +655,8 @@ go.opentelemetry.io/collector/receiver v0.92.0 h1:TRz4ufr5bFEszpAWgYVEx/b7VPZzEc go.opentelemetry.io/collector/receiver v0.92.0/go.mod h1:bYAAYbMuUVj3wx7ave2iyyJ+aGUpACliYOQ5xI92I7k= go.opentelemetry.io/collector/receiver/otlpreceiver v0.92.0 h1:77oFMYYJfRu4yqlRkExMHDieg9gPv38UsMtK/0cu5kU= go.opentelemetry.io/collector/receiver/otlpreceiver v0.92.0/go.mod h1:eZIrA6CY6xcm9uu3hmycS+L9kmBzyXE66Ci8FwkJpmI= -go.opentelemetry.io/collector/semconv v0.92.0 h1:3+OGPPuVu4rtrz8qGbpbiw7eKKULj4iJaSDTV52HM40= -go.opentelemetry.io/collector/semconv v0.92.0/go.mod h1:gZ0uzkXsN+J5NpiRcdp9xOhNGQDDui8Y62p15sKrlzo= +go.opentelemetry.io/collector/semconv v0.97.0 h1:iF3nTfThbiOwz7o5Pocn0dDnDoffd18ijDuf6Mwzi1s= +go.opentelemetry.io/collector/semconv v0.97.0/go.mod h1:8ElcRZ8Cdw5JnvhTOQOdYizkJaQ10Z2fS+R6djOnj6A= go.opentelemetry.io/collector/service v0.92.0 h1:KhicjajrbhEpjzSYCHvVZBYW5Qvd/UXi88oCegSanZI= go.opentelemetry.io/collector/service v0.92.0/go.mod h1:hlq/Vyj0un+HKx8nAI77eaK/mABNL8hhPH7rKh9SOu4= go.opentelemetry.io/contrib/config v0.1.1 h1:lIUTrMWkfDE0GvzBLhwv6ATDB1vntrnTsRvUMkZKnfQ= @@ -653,6 +668,7 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1: go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= go.opentelemetry.io/contrib/zpages v0.46.1 h1:U8Hh84dc+vJTVgRnL+QKWtWD2iqTSKibrQ85EeQqsNg= +go.opentelemetry.io/contrib/zpages v0.46.1/go.mod h1:1Wq9YTzkhr3Jkyi/sVrasFSppVzJQcvFf2Vc2ExZd6c= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/bridge/opencensus v0.44.0 h1:/inELPJztkn6Xx3ap9qw8i8XdeWF0B/OjGHOdRTePZ8= @@ -685,6 +701,7 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -759,6 +776,7 @@ golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -876,6 +894,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -927,6 +946,7 @@ google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnp google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f h1:Vn+VyHU5guc9KjB5KrjI2q0wCOWEOIh0OEsleqakHJg= +google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE= @@ -975,6 +995,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/collector/processor/faasprocessor/go.mod b/collector/processor/faasprocessor/go.mod index e7b5575fde..6a0f0544d4 100644 --- a/collector/processor/faasprocessor/go.mod +++ b/collector/processor/faasprocessor/go.mod @@ -5,14 +5,12 @@ go 1.21 toolchain go1.21.5 require ( - github.com/cespare/xxhash v1.1.0 github.com/stretchr/testify v1.9.0 go.opentelemetry.io/collector/component v0.91.0 go.opentelemetry.io/collector/consumer v0.91.0 go.opentelemetry.io/collector/pdata v1.0.0 go.opentelemetry.io/collector/processor v0.91.0 go.opentelemetry.io/collector/semconv v0.97.0 - go.uber.org/multierr v1.11.0 go.uber.org/zap v1.26.0 ) @@ -39,6 +37,7 @@ require ( go.opentelemetry.io/otel v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.18.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/collector/processor/faasprocessor/go.sum b/collector/processor/faasprocessor/go.sum index 07dab896a9..36858b1031 100644 --- a/collector/processor/faasprocessor/go.sum +++ b/collector/processor/faasprocessor/go.sum @@ -2,13 +2,9 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -102,8 +98,6 @@ github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/collector/receiver/telemetryapireceiver/config.go b/collector/receiver/telemetryapireceiver/config.go index 9173b51720..4d7616b6ed 100644 --- a/collector/receiver/telemetryapireceiver/config.go +++ b/collector/receiver/telemetryapireceiver/config.go @@ -17,12 +17,12 @@ package telemetryapireceiver // import "github.com/open-telemetry/opentelemetry- // Config defines the configuration for the various elements of the receiver agent. type Config struct { extensionID string - Metrics MetricsConfig `mapstructure:"metrics"` -} - -// MetricsConfig defines configuration for the collection of metrics from the Telemetry API. -type MetricsConfig struct { - UseExponentialHistograms bool `mapstructure:"use_exponential_histograms"` + Metrics struct { + UseExponentialHistograms bool `mapstructure:"use_exponential_histograms"` + } `mapstructure:"metrics"` + Logs struct { + BodyKey string `mapstructure:"body_key"` + } `mapstructure:"logs"` } // Validate validates the configuration by checking for missing or invalid fields diff --git a/collector/receiver/telemetryapireceiver/go.mod b/collector/receiver/telemetryapireceiver/go.mod index 73a6463385..bde6dddb3a 100644 --- a/collector/receiver/telemetryapireceiver/go.mod +++ b/collector/receiver/telemetryapireceiver/go.mod @@ -1,6 +1,8 @@ module github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver -go 1.20 +go 1.21 + +toolchain go1.21.5 replace github.com/open-telemetry/opentelemetry-lambda/collector => ../../ @@ -12,7 +14,7 @@ require ( go.opentelemetry.io/collector/consumer v0.92.0 go.opentelemetry.io/collector/pdata v1.0.1 go.opentelemetry.io/collector/receiver v0.92.0 - go.opentelemetry.io/collector/semconv v0.92.0 + go.opentelemetry.io/collector/semconv v0.97.0 go.opentelemetry.io/otel/metric v1.24.0 go.opentelemetry.io/otel/sdk/metric v1.24.0 go.uber.org/zap v1.27.0 @@ -43,7 +45,7 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect google.golang.org/grpc v1.60.1 // indirect diff --git a/collector/receiver/telemetryapireceiver/go.sum b/collector/receiver/telemetryapireceiver/go.sum index 9dac2c4688..ae962974be 100644 --- a/collector/receiver/telemetryapireceiver/go.sum +++ b/collector/receiver/telemetryapireceiver/go.sum @@ -16,6 +16,7 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -30,7 +31,9 @@ github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g= github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY= @@ -46,6 +49,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= @@ -53,6 +57,7 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/collector v0.92.0 h1:XiC0ptaT1EmOkK2RI0gt3n2tkzLAkNQGf0E7hrGdyeA= +go.opentelemetry.io/collector v0.92.0/go.mod h1:wbksjM63DTKA1BbdUVS7gAFzAngCZTWb46RBpKdtsPw= go.opentelemetry.io/collector/component v0.92.0 h1:/tRgPT1hr4KNB8ABHa0oJsjJFRZ5oiCIYHcTpZGwm9s= go.opentelemetry.io/collector/component v0.92.0/go.mod h1:C2JwPTjauu36UCAzwX71/glNnOc5BR18p8FVccCFsqc= go.opentelemetry.io/collector/config/configtelemetry v0.92.0 h1:iCfxJ2DhWVOAHpGgkWUZRfUvUPyWGhpVRCqjPQ2D87Y= @@ -67,8 +72,8 @@ go.opentelemetry.io/collector/pdata v1.0.1 h1:dGX2h7maA6zHbl5D3AsMnF1c3Nn+3EUftb go.opentelemetry.io/collector/pdata v1.0.1/go.mod h1:jutXeu0QOXYY8wcZ/hege+YAnSBP3+jpTqYU1+JTI5Y= go.opentelemetry.io/collector/receiver v0.92.0 h1:TRz4ufr5bFEszpAWgYVEx/b7VPZzEcECsyMzztf5PsQ= go.opentelemetry.io/collector/receiver v0.92.0/go.mod h1:bYAAYbMuUVj3wx7ave2iyyJ+aGUpACliYOQ5xI92I7k= -go.opentelemetry.io/collector/semconv v0.92.0 h1:3+OGPPuVu4rtrz8qGbpbiw7eKKULj4iJaSDTV52HM40= -go.opentelemetry.io/collector/semconv v0.92.0/go.mod h1:gZ0uzkXsN+J5NpiRcdp9xOhNGQDDui8Y62p15sKrlzo= +go.opentelemetry.io/collector/semconv v0.97.0 h1:iF3nTfThbiOwz7o5Pocn0dDnDoffd18ijDuf6Mwzi1s= +go.opentelemetry.io/collector/semconv v0.97.0/go.mod h1:8ElcRZ8Cdw5JnvhTOQOdYizkJaQ10Z2fS+R6djOnj6A= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= @@ -80,6 +85,7 @@ go.opentelemetry.io/otel/sdk/metric v1.24.0/go.mod h1:I6Y5FjH6rvEnTTAYQz3Mmv2kl6 go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -101,8 +107,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -125,5 +131,6 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 94180ac5fd..f3eb646e93 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -25,12 +25,15 @@ import ( "math/rand" "net/http" "os" + "reflect" "strconv" + "sync" "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/receiver" @@ -51,6 +54,7 @@ const ( var ( errUnknownMetric = errors.New("metric is unknown") + errMissingTimestamp = errors.New("expected timestamp is missing") errMissingServiceName = errors.New("service name is missing") ) @@ -63,29 +67,45 @@ type telemetryAPIReceiver struct { extensionID string resource pcommon.Resource cfg *Config + mutex sync.Mutex // TRACES - nextTracesConsumer consumer.Traces - lastRequestID string - lastPlatformInitStartTime string - lastPlatformInitEndTime string - lastPlatformRuntimeStartTime string - lastPlatformRuntimeDoneTime string + nextTracesConsumer consumer.Traces + lastRequestID string + lastTraceTimestamps traceTimestamps // METRICS // NOTE: We're using the OpenTelemetry SDK here as generating 'pmetric' structures entirely // manually is error-prone and would duplicate plenty of code available in the SDK. - nextMetricsConsumer consumer.Metrics - metricsReader *sdkmetric.ManualReader - metricInitDurations metric.Float64Histogram - metricInvokeDurations metric.Float64Histogram - metricColdstarts metric.Int64Counter - metricSuccesses metric.Int64Counter - metricFailures metric.Int64Counter - metricTimeouts metric.Int64Counter - metricMemoryUsages metric.Int64Histogram - lastPlatformInitReportTime string - lastPlatformReportTime string + nextMetricsConsumer consumer.Metrics + metricsReader *sdkmetric.ManualReader + metricInitDurations metric.Float64Histogram + metricInvokeDurations metric.Float64Histogram + metricColdstarts metric.Int64Counter + metricSuccesses metric.Int64Counter + metricFailures metric.Int64Counter + metricTimeouts metric.Int64Counter + metricMemoryUsages metric.Int64Histogram + lastMetricTimestamps metricTimestamps // LOGS nextLogsConsumer consumer.Logs + logsCache []logLine +} + +type traceTimestamps struct { + platformInitStartTime *time.Time + platformInitEndTime *time.Time + platformRuntimeStartTime *time.Time + platformRuntimeEndTime *time.Time +} + +type metricTimestamps struct { + platformInitReportTime *time.Time + platformRuntimeEndTime *time.Time + platformReportTime *time.Time +} + +type logLine struct { + timestamp time.Time + log any } func newTelemetryAPIReceiver( @@ -248,6 +268,13 @@ func (r *telemetryAPIReceiver) Shutdown(ctx context.Context) error { // receive extension logs. Otherwise, logging here will cause Telemetry API to send new logs for // the printed lines which may create an infinite loop. func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Request) { + // We should not run HTTP handlers in parallel, this would cause all kinds of issues. Let's + // just lock very coarsely here for simplicity. The TelemetryAPI should not send concurrent + // requests anyway as it should not send requests more often than every 25ms unless a LOT of + // logs are generated (see configuration in `telemetryClient.Subscribe` above). + r.mutex.Lock() + defer r.mutex.Unlock() + body, err := io.ReadAll(req.Body) if err != nil { r.logger.Error("error reading body", zap.Error(err)) @@ -266,15 +293,27 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Function initialization started. case string(telemetryapi.PlatformInitStart): r.logger.Debug(fmt.Sprintf("Init start: %s", el.Time), zap.Any("event", el)) - r.lastPlatformInitStartTime = el.Time + if time, err := parseTime(el.Time); err != nil { + r.lastTraceTimestamps.platformInitStartTime = &time + } else { + r.lastTraceTimestamps.platformInitStartTime = nil + } // Function initialization completed. case string(telemetryapi.PlatformInitRuntimeDone): r.logger.Debug(fmt.Sprintf("Init end: %s", el.Time), zap.Any("event", el)) - r.lastPlatformInitEndTime = el.Time + if time, err := parseTime(el.Time); err != nil { + r.lastTraceTimestamps.platformInitEndTime = &time + } else { + r.lastTraceTimestamps.platformInitEndTime = nil + } // Concluding report on function initialization. case string(telemetryapi.PlatformInitReport): r.logger.Debug(fmt.Sprintf("Init report: %s", el.Time), zap.Any("event", el)) - r.lastPlatformInitReportTime = el.Time + if time, err := parseTime(el.Time); err != nil { + r.lastMetricTimestamps.platformInitReportTime = &time + } else { + r.lastMetricTimestamps.platformInitReportTime = nil + } if r.metricsReader == nil { continue } @@ -285,11 +324,21 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Function invocation started. case string(telemetryapi.PlatformStart): r.logger.Debug(fmt.Sprintf("Invoke start: %s", el.Time), zap.Any("event", el)) - r.lastPlatformRuntimeStartTime = el.Time + if time, err := parseTime(el.Time); err != nil { + r.lastTraceTimestamps.platformRuntimeStartTime = &time + } else { + r.lastTraceTimestamps.platformRuntimeStartTime = nil + } // Function invocation completed. case string(telemetryapi.PlatformRuntimeDone): r.logger.Debug(fmt.Sprintf("Invoke end: %s", el.Time), zap.Any("event", el)) - r.lastPlatformRuntimeDoneTime = el.Time + if time, err := parseTime(el.Time); err != nil { + r.lastTraceTimestamps.platformRuntimeEndTime = &time + r.lastMetricTimestamps.platformRuntimeEndTime = &time + } else { + r.lastTraceTimestamps.platformRuntimeEndTime = nil + r.lastMetricTimestamps.platformRuntimeEndTime = nil + } if r.metricsReader == nil { continue } @@ -308,7 +357,11 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Concluding report on function invocation (after runtime freeze). case string(telemetryapi.PlatformReport): r.logger.Debug(fmt.Sprintf("Invoke report: %s", el.Time), zap.Any("event", el)) - r.lastPlatformReportTime = el.Time + if time, err := parseTime(el.Time); err != nil { + r.lastMetricTimestamps.platformReportTime = &time + } else { + r.lastMetricTimestamps.platformReportTime = nil + } if r.metricsReader == nil { continue } @@ -318,7 +371,15 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Log record emitted by function. case string(telemetryapi.Function): r.logger.Debug(fmt.Sprintf("Log entry: %s", el.Time), zap.Any("event", el)) - continue + time, err := parseTime(el.Time) + if err != nil { + r.logger.Warn("Dropping log line as time cannot be parsed", zap.Error(err)) + } else { + r.logsCache = append(r.logsCache, logLine{ + timestamp: time, + log: el.Record, + }) + } } // TODO: potentially add support for additional events, see https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api.html // Runtime restore started (reserved for future use) @@ -335,6 +396,7 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // NOTE: Forward metrics first as trace forwarding clears timestamps r.forwardMetrics() r.forwardTraces() + r.forwardLogs() slice = nil } @@ -353,14 +415,15 @@ func parseRecord[T any](el event, logger *zap.Logger) (T, error) { /* ----------------------------------------- FORWARDING ---------------------------------------- */ func (r *telemetryAPIReceiver) forwardTraces() { - if r.lastPlatformRuntimeDoneTime != "" { + if r.lastTraceTimestamps.platformRuntimeStartTime != nil && r.lastTraceTimestamps.platformRuntimeEndTime != nil { if td, err := r.createPlatformRuntimeSpan(); err == nil { err := r.nextTracesConsumer.ConsumeTraces(context.Background(), td) if err == nil { - r.lastPlatformInitEndTime = "" - r.lastPlatformInitStartTime = "" - r.lastPlatformRuntimeStartTime = "" - r.lastPlatformRuntimeDoneTime = "" + // Clear for next invocation + r.lastTraceTimestamps.platformInitStartTime = nil + r.lastTraceTimestamps.platformInitEndTime = nil + r.lastTraceTimestamps.platformRuntimeStartTime = nil + r.lastTraceTimestamps.platformRuntimeEndTime = nil } else { r.logger.Error("error receiving traces", zap.Error(err)) } @@ -417,18 +480,24 @@ func (r *telemetryAPIReceiver) forwardMetrics() { } } -// func (r *telemetryAPIReceiver) forwardLogLine(line string) { -// logData := plog.NewLogs() -// rs := logData.ResourceLogs().AppendEmpty() -// r.resource.CopyTo(rs.Resource()) +func (r *telemetryAPIReceiver) forwardLogs() { + if len(r.logsCache) == 0 { + return + } -// scopeLog := rs.ScopeLogs().AppendEmpty() -// scopeLog.Scope().SetName(instrumentationScope) + logData := plog.NewLogs() + rs := logData.ResourceLogs().AppendEmpty() + r.resource.CopyTo(rs.Resource()) -// log := scopeLog.LogRecords().AppendEmpty() -// log.SetSeverityNumber(plog.SeverityNumberDebug) -// log.Body() -// } + scopeLog := rs.ScopeLogs().AppendEmpty() + scopeLog.Scope().SetName(instrumentationScope) + + for _, item := range r.logsCache { + log := scopeLog.LogRecords().AppendEmpty() + r.populateLogRecord(log, item.log, item.timestamp) + } + r.logsCache = nil +} /* ------------------------------------------- TRACES ------------------------------------------ */ @@ -438,6 +507,8 @@ func (r *telemetryAPIReceiver) createPlatformRuntimeSpan() (ptrace.Traces, error return ptrace.Traces{}, errMissingServiceName } + buildInitSpan := r.lastTraceTimestamps.platformInitStartTime != nil && r.lastTraceTimestamps.platformInitEndTime != nil + // Build trace data traceData := ptrace.NewTraces() rs := traceData.ResourceSpans().AppendEmpty() @@ -453,18 +524,17 @@ func (r *telemetryAPIReceiver) createPlatformRuntimeSpan() (ptrace.Traces, error rootSpan.SetSpanID(newSpanID()) rootSpan.SetName(serviceName.Str()) rootSpan.SetKind(ptrace.SpanKindServer) - rootSpan.Attributes().PutBool(semconv.AttributeFaaSColdstart, r.lastPlatformInitEndTime != "") + rootSpan.Attributes().PutBool(semconv.AttributeFaaSColdstart, buildInitSpan) rootSpan.Attributes().PutStr(semconv.AttributeFaaSInvocationID, r.lastRequestID) - rootStartTime := r.lastPlatformRuntimeStartTime - if r.lastPlatformInitStartTime != "" { - rootStartTime = r.lastPlatformInitStartTime - } - if err := setSpanTimestamps(rootSpan, rootStartTime, r.lastPlatformRuntimeDoneTime); err != nil { - return ptrace.Traces{}, err + rootStartTime := *r.lastTraceTimestamps.platformRuntimeStartTime + if r.lastTraceTimestamps.platformInitStartTime != nil { + rootStartTime = *r.lastTraceTimestamps.platformInitStartTime } + rootSpan.SetStartTimestamp(pcommon.NewTimestampFromTime(rootStartTime)) + rootSpan.SetEndTimestamp(pcommon.NewTimestampFromTime(*r.lastMetricTimestamps.platformRuntimeEndTime)) // Optionally create an additional span for the init span - if r.lastPlatformInitEndTime != "" { + if buildInitSpan { initSpan := ss.Spans().AppendEmpty() initSpan.SetTraceID(traceID) initSpan.SetSpanID(newSpanID()) @@ -472,9 +542,8 @@ func (r *telemetryAPIReceiver) createPlatformRuntimeSpan() (ptrace.Traces, error initSpan.SetName("faas.runtimeInit") initSpan.SetKind(ptrace.SpanKindInternal) initSpan.Attributes().PutStr(semconv.AttributeFaaSInvocationID, r.lastRequestID) - if err := setSpanTimestamps(initSpan, r.lastPlatformInitStartTime, r.lastPlatformInitEndTime); err != nil { - return ptrace.Traces{}, err - } + initSpan.SetStartTimestamp(pcommon.NewTimestampFromTime(*r.lastTraceTimestamps.platformInitStartTime)) + initSpan.SetEndTimestamp(pcommon.NewTimestampFromTime(*r.lastTraceTimestamps.platformInitEndTime)) } return traceData, nil } @@ -497,38 +566,27 @@ func newTraceID() pcommon.TraceID { return tid } -func setSpanTimestamps(span ptrace.Span, start, end string) error { - startTime, err := parseTime(start) - if err != nil { - return err - } - span.SetStartTimestamp(pcommon.NewTimestampFromTime(startTime)) - endTime, err := parseTime(end) - if err != nil { - return err - } - span.SetEndTimestamp(pcommon.NewTimestampFromTime(endTime)) - return nil -} - /* ------------------------------------------ METRICS ------------------------------------------ */ func (r *telemetryAPIReceiver) getMetricTimestamp(metricName string) (time.Time, error) { switch metricName { case "faas.coldstarts", "faas.init_duration": - if r.lastPlatformInitReportTime == "" { - // If the time is not set, the faas.coldstarts counter is being zero-initialized - return time.Now(), nil + if r.lastMetricTimestamps.platformInitReportTime != nil { + return *r.lastMetricTimestamps.platformInitReportTime, nil } - return parseTime(r.lastPlatformInitReportTime) + // If the time is not set, the faas.coldstarts counter is being zero-initialized + return time.Now(), nil case "faas.invoke_duration", "faas.invocations", "faas.errors", "faas.timeouts": - if r.lastPlatformInitReportTime == "" { - // If the time is not set, some counter is being zero-initialized - return time.Now(), nil + if r.lastMetricTimestamps.platformRuntimeEndTime != nil { + return *r.lastMetricTimestamps.platformRuntimeEndTime, nil } - return parseTime(r.lastPlatformRuntimeDoneTime) + // If the time is not set, some counter is being zero-initialized + return time.Now(), nil case "faas.mem_usage": - return parseTime(r.lastPlatformReportTime) + if r.lastMetricTimestamps.platformReportTime != nil { + return *r.lastMetricTimestamps.platformReportTime, nil + } + return time.Time{}, errMissingTimestamp default: return time.Time{}, errUnknownMetric } @@ -536,6 +594,65 @@ func (r *telemetryAPIReceiver) getMetricTimestamp(metricName string) (time.Time, /* -------------------------------------------- LOGS ------------------------------------------- */ +func (r *telemetryAPIReceiver) populateLogRecord(log plog.LogRecord, record any, timestamp time.Time) { + recordValue := reflect.ValueOf(record) + + // Set metadata + log.SetObservedTimestamp(pcommon.NewTimestampFromTime(timestamp)) + if recordValue.Kind() == reflect.Map { + levelKey := reflect.ValueOf("level") + levelValue := recordValue.MapIndex(levelKey) + if levelValue.Kind() == reflect.String { + log.SetSeverityText(levelValue.String()) + // Remove from map to not include severity in body + recordValue.SetMapIndex(levelKey, reflect.Value{}) + } + } + + // Populate body: if the receiver's configuration indicates that we should only add a "subkey", + // let's do so + if r.cfg.Logs.BodyKey != "" { + if recordValue.Kind() == reflect.Map { + bodyValue := recordValue.MapIndex(reflect.ValueOf(r.cfg.Logs.BodyKey)) + if !bodyValue.IsNil() { + r.populateLogValue(log.Body(), bodyValue) + return + } + } + } + // If we didn't return above, we just populate the entire body from the record + r.populateLogValue(log.Body(), recordValue) +} + +func (r *telemetryAPIReceiver) populateLogValue(value pcommon.Value, src reflect.Value) { + switch src.Kind() { + case reflect.String: + value.SetStr(src.String()) + case reflect.Bool: + value.SetBool(src.Bool()) + case reflect.Float32, reflect.Float64: + value.SetDouble(src.Float()) + case reflect.Int, reflect.Uint: + value.SetInt(src.Int()) + case reflect.Slice: + slice := value.SetEmptySlice() + for i := 0; i < src.Len(); i++ { + r.populateLogValue(slice.AppendEmpty(), src.Index(i)) + } + case reflect.Map: + m := value.SetEmptyMap() + iter := src.MapRange() + for iter.Next() { + r.populateLogValue(m.PutEmpty(iter.Key().String()), iter.Value()) + } + default: + r.logger.Warn( + "Encountered invalid value when parsing log", + zap.String("value", value.AsString()), + ) + } +} + /* ------------------------------------------- UTILS ------------------------------------------- */ func parseTime(t string) (time.Time, error) { diff --git a/collector/receiver/telemetryapireceiver/types.go b/collector/receiver/telemetryapireceiver/types.go index e8c67d4b29..d240abf7f8 100644 --- a/collector/receiver/telemetryapireceiver/types.go +++ b/collector/receiver/telemetryapireceiver/types.go @@ -15,9 +15,9 @@ package telemetryapireceiver // import "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver" type event struct { - Time string `json:"time"` - Type string `json:"type"` - Record map[string]any `json:"record"` + Time string `json:"time"` + Type string `json:"type"` + Record any `json:"record"` } // NOTE: Types defined here do not include all attributes sent by the Telemetry API but only those From c7af04bc34caf3934e6b5670d2fab643f01f01ae Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 18:21:45 +0100 Subject: [PATCH 24/43] Fix gomod --- collector/go.mod | 2 +- collector/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/collector/go.mod b/collector/go.mod index 0b7aa56981..91c582585b 100644 --- a/collector/go.mod +++ b/collector/go.mod @@ -178,7 +178,7 @@ require ( go.opentelemetry.io/proto/otlp v1.0.0 // indirect golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect gonum.org/v1/gonum v0.14.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect diff --git a/collector/go.sum b/collector/go.sum index e5574fa0b6..a5e94d30b3 100644 --- a/collector/go.sum +++ b/collector/go.sum @@ -845,8 +845,8 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 4180f2b3551b2498bede7d3c957bb8db8f47b436 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 18:29:15 +0100 Subject: [PATCH 25/43] Tidy --- collector/lambdacomponents/go.mod | 2 +- collector/lambdacomponents/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/collector/lambdacomponents/go.mod b/collector/lambdacomponents/go.mod index c7169b40d5..9008720bf7 100644 --- a/collector/lambdacomponents/go.mod +++ b/collector/lambdacomponents/go.mod @@ -153,7 +153,7 @@ require ( go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect gonum.org/v1/gonum v0.14.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect diff --git a/collector/lambdacomponents/go.sum b/collector/lambdacomponents/go.sum index f633b16af6..0a4867aaab 100644 --- a/collector/lambdacomponents/go.sum +++ b/collector/lambdacomponents/go.sum @@ -833,8 +833,8 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From a3665a36614ba49d48a7eab2f4acb3217161fe24 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 18:59:34 +0100 Subject: [PATCH 26/43] Fixes? --- collector/internal/lifecycle/manager.go | 9 ++++----- collector/internal/telemetryapi/client.go | 11 +++++++++-- collector/receiver/telemetryapireceiver/receiver.go | 10 ++++++++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/collector/internal/lifecycle/manager.go b/collector/internal/lifecycle/manager.go index 68f6939190..34b8b3f557 100644 --- a/collector/internal/lifecycle/manager.go +++ b/collector/internal/lifecycle/manager.go @@ -17,13 +17,14 @@ package lifecycle import ( "context" "fmt" - "github.com/open-telemetry/opentelemetry-lambda/collector/lambdalifecycle" "os" "os/signal" "path/filepath" "sync" "syscall" + "github.com/open-telemetry/opentelemetry-lambda/collector/lambdalifecycle" + "go.uber.org/multierr" "go.uber.org/zap" @@ -33,9 +34,7 @@ import ( "github.com/open-telemetry/opentelemetry-lambda/collector/lambdacomponents" ) -var ( - extensionName = filepath.Base(os.Args[0]) // extension name has to match the filename -) +var extensionName = filepath.Base(os.Args[0]) // extension name has to match the filename type collectorWrapper interface { Start(ctx context.Context) error @@ -75,7 +74,7 @@ func NewManager(ctx context.Context, logger *zap.Logger, version string) (contex } telemetryClient := telemetryapi.NewClient(logger) - _, err = telemetryClient.Subscribe(ctx, res.ExtensionID, addr) + _, err = telemetryClient.Subscribe(ctx, res.ExtensionID, addr, false) if err != nil { logger.Fatal("Cannot register Telemetry API client", zap.Error(err)) } diff --git a/collector/internal/telemetryapi/client.go b/collector/internal/telemetryapi/client.go index db57573fc2..f56ab1b289 100644 --- a/collector/internal/telemetryapi/client.go +++ b/collector/internal/telemetryapi/client.go @@ -46,12 +46,20 @@ func NewClient(logger *zap.Logger) *Client { } } -func (c *Client) Subscribe(ctx context.Context, extensionID string, listenerURI string) (string, error) { +func (c *Client) Subscribe( + ctx context.Context, + extensionID string, + listenerURI string, + functionLogs bool, +) (string, error) { eventTypes := []EventType{ Platform, // Function, // Extension, } + if functionLogs { + eventTypes = append(eventTypes, Function) + } bufferingConfig := BufferingCfg{ MaxItems: 1000, @@ -73,7 +81,6 @@ func (c *Client) Subscribe(ctx context.Context, extensionID string, listenerURI BufferingCfg: bufferingConfig, Destination: destination, }) - if err != nil { return "", fmt.Errorf("Failed to marshal SubscribeRequest: %w", err) } diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index f3eb646e93..c97230d67e 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -236,7 +236,11 @@ func (r *telemetryAPIReceiver) setLogsConsumer(next consumer.Logs) { func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) error { address := listenOnAddress() - r.logger.Info("Listening for requests", zap.String("address", address)) + r.logger.Info( + "Listening for requests", + zap.String("address", address), + zap.Bool("logs", r.nextLogsConsumer != nil), + ) mux := http.NewServeMux() mux.HandleFunc("/", r.httpHandler) @@ -246,7 +250,9 @@ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) e }() telemetryClient := telemetryapi.NewClient(r.logger) - _, err := telemetryClient.Subscribe(ctx, r.extensionID, fmt.Sprintf("http://%s/", address)) + _, err := telemetryClient.Subscribe( + ctx, r.extensionID, fmt.Sprintf("http://%s/", address), r.nextLogsConsumer != nil, + ) if err != nil { r.logger.Info( "Listening for requests", From 9e029d0e2439b14c3253abd19fd472da53e69690 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 19:49:05 +0100 Subject: [PATCH 27/43] Debug --- collector/receiver/telemetryapireceiver/receiver.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index c97230d67e..2794c42042 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -345,11 +345,11 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ r.lastTraceTimestamps.platformRuntimeEndTime = nil r.lastMetricTimestamps.platformRuntimeEndTime = nil } - if r.metricsReader == nil { - continue - } if record, err := parseRecord[platformRuntimeDoneRecord](el, r.logger); err == nil { r.lastRequestID = record.RequestID + if r.metricsReader == nil { + continue + } r.metricInvokeDurations.Record(ctx, record.Metrics.DurationMs/1000.0) switch record.Status { case statusSuccess: @@ -364,8 +364,10 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ case string(telemetryapi.PlatformReport): r.logger.Debug(fmt.Sprintf("Invoke report: %s", el.Time), zap.Any("event", el)) if time, err := parseTime(el.Time); err != nil { + r.logger.Debug("setting last report time to value") r.lastMetricTimestamps.platformReportTime = &time } else { + r.logger.Debug("setting last report time to nil") r.lastMetricTimestamps.platformReportTime = nil } if r.metricsReader == nil { From 93e9b249222271d9e08313240153f8dec0ec3650 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 20:04:34 +0100 Subject: [PATCH 28/43] Fix? --- collector/receiver/telemetryapireceiver/receiver.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 2794c42042..b236edb3f1 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -330,7 +330,7 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Function invocation started. case string(telemetryapi.PlatformStart): r.logger.Debug(fmt.Sprintf("Invoke start: %s", el.Time), zap.Any("event", el)) - if time, err := parseTime(el.Time); err != nil { + if time, err := parseTime(el.Time); err == nil { r.lastTraceTimestamps.platformRuntimeStartTime = &time } else { r.lastTraceTimestamps.platformRuntimeStartTime = nil @@ -338,7 +338,7 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Function invocation completed. case string(telemetryapi.PlatformRuntimeDone): r.logger.Debug(fmt.Sprintf("Invoke end: %s", el.Time), zap.Any("event", el)) - if time, err := parseTime(el.Time); err != nil { + if time, err := parseTime(el.Time); err == nil { r.lastTraceTimestamps.platformRuntimeEndTime = &time r.lastMetricTimestamps.platformRuntimeEndTime = &time } else { @@ -363,11 +363,12 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Concluding report on function invocation (after runtime freeze). case string(telemetryapi.PlatformReport): r.logger.Debug(fmt.Sprintf("Invoke report: %s", el.Time), zap.Any("event", el)) - if time, err := parseTime(el.Time); err != nil { + time, err := parseTime(el.Time) + if err == nil { r.logger.Debug("setting last report time to value") r.lastMetricTimestamps.platformReportTime = &time } else { - r.logger.Debug("setting last report time to nil") + r.logger.Debug("setting last report time to nil", zap.Error(err)) r.lastMetricTimestamps.platformReportTime = nil } if r.metricsReader == nil { From 82af05160c6840d624e4d39925935cea8cfba95e Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 20:06:29 +0100 Subject: [PATCH 29/43] Fix --- collector/receiver/telemetryapireceiver/receiver.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index b236edb3f1..ed8b4b75f3 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -506,6 +506,10 @@ func (r *telemetryAPIReceiver) forwardLogs() { r.populateLogRecord(log, item.log, item.timestamp) } r.logsCache = nil + + if err := r.nextLogsConsumer.ConsumeLogs(context.Background(), logData); err != nil { + r.logger.Error("error receiving logs", zap.Error(err)) + } } /* ------------------------------------------- TRACES ------------------------------------------ */ From f5dc219b302c89dbe71847fe5d07bda79ecb6622 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 20:26:57 +0100 Subject: [PATCH 30/43] fixes --- .../receiver/telemetryapireceiver/receiver.go | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index ed8b4b75f3..8bf7191935 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -61,13 +61,14 @@ var ( /* ------------------------------------------ CREATION ----------------------------------------- */ type telemetryAPIReceiver struct { + mutex sync.Mutex + didStartUp bool // SHARED httpServer *http.Server logger *zap.Logger extensionID string resource pcommon.Resource cfg *Config - mutex sync.Mutex // TRACES nextTracesConsumer consumer.Traces lastRequestID string @@ -235,6 +236,13 @@ func (r *telemetryAPIReceiver) setLogsConsumer(next consumer.Logs) { /* ------------------------------------ COMPONENT INTERFACE ------------------------------------ */ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) error { + r.mutex.Lock() + defer r.mutex.Unlock() + + if r.didStartUp { + return nil + } + address := listenOnAddress() r.logger.Info( "Listening for requests", @@ -260,6 +268,8 @@ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) e ) return err } + + r.didStartUp = true return nil } @@ -490,10 +500,6 @@ func (r *telemetryAPIReceiver) forwardMetrics() { } func (r *telemetryAPIReceiver) forwardLogs() { - if len(r.logsCache) == 0 { - return - } - logData := plog.NewLogs() rs := logData.ResourceLogs().AppendEmpty() r.resource.CopyTo(rs.Resource()) @@ -503,7 +509,18 @@ func (r *telemetryAPIReceiver) forwardLogs() { for _, item := range r.logsCache { log := scopeLog.LogRecords().AppendEmpty() - r.populateLogRecord(log, item.log, item.timestamp) + if line, ok := item.log.(string); ok { + var parsed any + // Log lines are delivered as raw strings, we try to parse them here + if err := json.Unmarshal([]byte(line), &parsed); err != nil { + r.populateLogRecord(log, parsed, item.timestamp) + } else { + // Otherwise, we process them as raw string + r.populateLogRecord(log, item.log, item.timestamp) + } + } else { + r.logger.Warn("received log line in a format other than a plain string, ignoring") + } } r.logsCache = nil From e208e2056d646d5bc240ac12aea06c8dfb672826 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 20:40:22 +0100 Subject: [PATCH 31/43] Some stuff --- .../receiver/telemetryapireceiver/receiver.go | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 8bf7191935..9fdc498a31 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -309,26 +309,32 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Function initialization started. case string(telemetryapi.PlatformInitStart): r.logger.Debug(fmt.Sprintf("Init start: %s", el.Time), zap.Any("event", el)) - if time, err := parseTime(el.Time); err != nil { - r.lastTraceTimestamps.platformInitStartTime = &time - } else { + time, err := parseTime(el.Time) + if err != nil { + r.logger.Error("unable to set last platform init start time", zap.Error(err)) r.lastTraceTimestamps.platformInitStartTime = nil + } else { + r.lastTraceTimestamps.platformInitStartTime = &time } // Function initialization completed. case string(telemetryapi.PlatformInitRuntimeDone): r.logger.Debug(fmt.Sprintf("Init end: %s", el.Time), zap.Any("event", el)) - if time, err := parseTime(el.Time); err != nil { - r.lastTraceTimestamps.platformInitEndTime = &time - } else { + time, err := parseTime(el.Time) + if err != nil { + r.logger.Error("unable to set last platform init end time", zap.Error(err)) r.lastTraceTimestamps.platformInitEndTime = nil + } else { + r.lastTraceTimestamps.platformInitEndTime = &time } // Concluding report on function initialization. case string(telemetryapi.PlatformInitReport): r.logger.Debug(fmt.Sprintf("Init report: %s", el.Time), zap.Any("event", el)) - if time, err := parseTime(el.Time); err != nil { - r.lastMetricTimestamps.platformInitReportTime = &time - } else { + time, err := parseTime(el.Time) + if err != nil { + r.logger.Error("unable to set last platform init report time", zap.Error(err)) r.lastMetricTimestamps.platformInitReportTime = nil + } else { + r.lastMetricTimestamps.platformInitReportTime = &time } if r.metricsReader == nil { continue @@ -340,20 +346,24 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // Function invocation started. case string(telemetryapi.PlatformStart): r.logger.Debug(fmt.Sprintf("Invoke start: %s", el.Time), zap.Any("event", el)) - if time, err := parseTime(el.Time); err == nil { - r.lastTraceTimestamps.platformRuntimeStartTime = &time - } else { + time, err := parseTime(el.Time) + if err != nil { + r.logger.Error("unable to set last platform runtime start time", zap.Error(err)) r.lastTraceTimestamps.platformRuntimeStartTime = nil + } else { + r.lastTraceTimestamps.platformRuntimeStartTime = &time } // Function invocation completed. case string(telemetryapi.PlatformRuntimeDone): r.logger.Debug(fmt.Sprintf("Invoke end: %s", el.Time), zap.Any("event", el)) - if time, err := parseTime(el.Time); err == nil { - r.lastTraceTimestamps.platformRuntimeEndTime = &time - r.lastMetricTimestamps.platformRuntimeEndTime = &time - } else { + time, err := parseTime(el.Time) + if err != nil { + r.logger.Error("unable to set last platform runtime end time", zap.Error(err)) r.lastTraceTimestamps.platformRuntimeEndTime = nil r.lastMetricTimestamps.platformRuntimeEndTime = nil + } else { + r.lastTraceTimestamps.platformRuntimeEndTime = &time + r.lastMetricTimestamps.platformRuntimeEndTime = &time } if record, err := parseRecord[platformRuntimeDoneRecord](el, r.logger); err == nil { r.lastRequestID = record.RequestID @@ -374,12 +384,11 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ case string(telemetryapi.PlatformReport): r.logger.Debug(fmt.Sprintf("Invoke report: %s", el.Time), zap.Any("event", el)) time, err := parseTime(el.Time) - if err == nil { - r.logger.Debug("setting last report time to value") - r.lastMetricTimestamps.platformReportTime = &time - } else { - r.logger.Debug("setting last report time to nil", zap.Error(err)) + if err != nil { + r.logger.Error("unable to set last platform report time", zap.Error(err)) r.lastMetricTimestamps.platformReportTime = nil + } else { + r.lastMetricTimestamps.platformReportTime = &time } if r.metricsReader == nil { continue @@ -513,9 +522,11 @@ func (r *telemetryAPIReceiver) forwardLogs() { var parsed any // Log lines are delivered as raw strings, we try to parse them here if err := json.Unmarshal([]byte(line), &parsed); err != nil { + r.logger.Debug("interpreting log line as JSON", zap.String("line", line)) r.populateLogRecord(log, parsed, item.timestamp) } else { // Otherwise, we process them as raw string + r.logger.Debug("interpreting log line as raw string", zap.String("line", line)) r.populateLogRecord(log, item.log, item.timestamp) } } else { From 563900a396470ead03a576fcdee5f45909c86dda Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 21:26:22 +0100 Subject: [PATCH 32/43] Debug --- .../receiver/telemetryapireceiver/receiver.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 9fdc498a31..39e482cb78 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -509,6 +509,11 @@ func (r *telemetryAPIReceiver) forwardMetrics() { } func (r *telemetryAPIReceiver) forwardLogs() { + if len(r.logsCache) == 0 { + // Return early if there are no logs + return + } + logData := plog.NewLogs() rs := logData.ResourceLogs().AppendEmpty() r.resource.CopyTo(rs.Resource()) @@ -517,12 +522,15 @@ func (r *telemetryAPIReceiver) forwardLogs() { scopeLog.Scope().SetName(instrumentationScope) for _, item := range r.logsCache { - log := scopeLog.LogRecords().AppendEmpty() if line, ok := item.log.(string); ok { + log := scopeLog.LogRecords().AppendEmpty() var parsed any // Log lines are delivered as raw strings, we try to parse them here if err := json.Unmarshal([]byte(line), &parsed); err != nil { - r.logger.Debug("interpreting log line as JSON", zap.String("line", line)) + r.logger.Debug( + "interpreting log line as JSON", + zap.String("line", line), zap.Error(err), + ) r.populateLogRecord(log, parsed, item.timestamp) } else { // Otherwise, we process them as raw string @@ -535,6 +543,10 @@ func (r *telemetryAPIReceiver) forwardLogs() { } r.logsCache = nil + if scopeLog.LogRecords().Len() == 0 { + // Return before forwarding if we couldn't process any logs + return + } if err := r.nextLogsConsumer.ConsumeLogs(context.Background(), logData); err != nil { r.logger.Error("error receiving logs", zap.Error(err)) } From 440c40dfa21e43574829e147c5a530c7eabe975a Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 21:32:17 +0100 Subject: [PATCH 33/43] Fix --- collector/receiver/telemetryapireceiver/receiver.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 39e482cb78..98f4bc7bfa 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -526,11 +526,8 @@ func (r *telemetryAPIReceiver) forwardLogs() { log := scopeLog.LogRecords().AppendEmpty() var parsed any // Log lines are delivered as raw strings, we try to parse them here - if err := json.Unmarshal([]byte(line), &parsed); err != nil { - r.logger.Debug( - "interpreting log line as JSON", - zap.String("line", line), zap.Error(err), - ) + if err := json.Unmarshal([]byte(line), &parsed); err == nil { + r.logger.Debug("interpreting log line as JSON", zap.String("line", line)) r.populateLogRecord(log, parsed, item.timestamp) } else { // Otherwise, we process them as raw string From da9e17fbcd04087a06aaa16455c4e70a2128b5e1 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 21:50:22 +0100 Subject: [PATCH 34/43] Debug --- collector/receiver/telemetryapireceiver/receiver.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 98f4bc7bfa..be77b088fa 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -698,7 +698,8 @@ func (r *telemetryAPIReceiver) populateLogValue(value pcommon.Value, src reflect default: r.logger.Warn( "Encountered invalid value when parsing log", - zap.String("value", value.AsString()), + zap.String("value", src.String()), + zap.String("kind", src.Kind().String()), ) } } From 3902ff8fff63e50b7c8f4ef0ea229001c52bbfd5 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 22:11:30 +0100 Subject: [PATCH 35/43] Try --- collector/receiver/telemetryapireceiver/receiver.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index be77b088fa..36d0a3e29b 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -649,10 +649,10 @@ func (r *telemetryAPIReceiver) populateLogRecord(log plog.LogRecord, record any, // Set metadata log.SetObservedTimestamp(pcommon.NewTimestampFromTime(timestamp)) - if recordValue.Kind() == reflect.Map { + if recordValue.Type().Kind() == reflect.Map { levelKey := reflect.ValueOf("level") levelValue := recordValue.MapIndex(levelKey) - if levelValue.Kind() == reflect.String { + if levelValue.Type().Kind() == reflect.String { log.SetSeverityText(levelValue.String()) // Remove from map to not include severity in body recordValue.SetMapIndex(levelKey, reflect.Value{}) @@ -662,7 +662,7 @@ func (r *telemetryAPIReceiver) populateLogRecord(log plog.LogRecord, record any, // Populate body: if the receiver's configuration indicates that we should only add a "subkey", // let's do so if r.cfg.Logs.BodyKey != "" { - if recordValue.Kind() == reflect.Map { + if recordValue.Type().Kind() == reflect.Map { bodyValue := recordValue.MapIndex(reflect.ValueOf(r.cfg.Logs.BodyKey)) if !bodyValue.IsNil() { r.populateLogValue(log.Body(), bodyValue) @@ -675,7 +675,7 @@ func (r *telemetryAPIReceiver) populateLogRecord(log plog.LogRecord, record any, } func (r *telemetryAPIReceiver) populateLogValue(value pcommon.Value, src reflect.Value) { - switch src.Kind() { + switch src.Type().Kind() { case reflect.String: value.SetStr(src.String()) case reflect.Bool: @@ -698,8 +698,7 @@ func (r *telemetryAPIReceiver) populateLogValue(value pcommon.Value, src reflect default: r.logger.Warn( "Encountered invalid value when parsing log", - zap.String("value", src.String()), - zap.String("kind", src.Kind().String()), + zap.String("kind", src.Type().Kind().String()), ) } } From b9af0e476382b3f453b1c95c3495ebfda1200b87 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Fri, 29 Mar 2024 23:10:52 +0100 Subject: [PATCH 36/43] Fix --- .../receiver/telemetryapireceiver/config.go | 4 +- .../receiver/telemetryapireceiver/receiver.go | 63 +++++++++---------- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/config.go b/collector/receiver/telemetryapireceiver/config.go index 4d7616b6ed..92e3087114 100644 --- a/collector/receiver/telemetryapireceiver/config.go +++ b/collector/receiver/telemetryapireceiver/config.go @@ -21,7 +21,9 @@ type Config struct { UseExponentialHistograms bool `mapstructure:"use_exponential_histograms"` } `mapstructure:"metrics"` Logs struct { - BodyKey string `mapstructure:"body_key"` + JSON struct { + BodyPath string `mapstructure:"body_path"` + } `mapstructure:"json"` } `mapstructure:"logs"` } diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 36d0a3e29b..07f2532800 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -645,60 +645,55 @@ func (r *telemetryAPIReceiver) getMetricTimestamp(metricName string) (time.Time, /* -------------------------------------------- LOGS ------------------------------------------- */ func (r *telemetryAPIReceiver) populateLogRecord(log plog.LogRecord, record any, timestamp time.Time) { - recordValue := reflect.ValueOf(record) - // Set metadata log.SetObservedTimestamp(pcommon.NewTimestampFromTime(timestamp)) - if recordValue.Type().Kind() == reflect.Map { - levelKey := reflect.ValueOf("level") - levelValue := recordValue.MapIndex(levelKey) - if levelValue.Type().Kind() == reflect.String { - log.SetSeverityText(levelValue.String()) - // Remove from map to not include severity in body - recordValue.SetMapIndex(levelKey, reflect.Value{}) + if m, ok := record.(map[string]any); ok { + if rawLevel, ok := m["level"]; ok { + if level, ok := rawLevel.(string); ok { + log.SetSeverityText(level) + // Remove from map to not include severity in body + delete(m, "level") + } } } // Populate body: if the receiver's configuration indicates that we should only add a "subkey", // let's do so - if r.cfg.Logs.BodyKey != "" { - if recordValue.Type().Kind() == reflect.Map { - bodyValue := recordValue.MapIndex(reflect.ValueOf(r.cfg.Logs.BodyKey)) - if !bodyValue.IsNil() { - r.populateLogValue(log.Body(), bodyValue) - return + if r.cfg.Logs.JSON.BodyPath != "" { + if m, ok := record.(map[string]any); ok { + if body, ok := m[r.cfg.Logs.JSON.BodyPath]; ok { + r.populateLogValue(log.Body(), body) } } } // If we didn't return above, we just populate the entire body from the record - r.populateLogValue(log.Body(), recordValue) + r.populateLogValue(log.Body(), record) } -func (r *telemetryAPIReceiver) populateLogValue(value pcommon.Value, src reflect.Value) { - switch src.Type().Kind() { - case reflect.String: - value.SetStr(src.String()) - case reflect.Bool: - value.SetBool(src.Bool()) - case reflect.Float32, reflect.Float64: - value.SetDouble(src.Float()) - case reflect.Int, reflect.Uint: - value.SetInt(src.Int()) - case reflect.Slice: +func (r *telemetryAPIReceiver) populateLogValue(value pcommon.Value, src any) { + switch v := src.(type) { + case string: + value.SetStr(v) + case bool: + value.SetBool(v) + case float64: + value.SetDouble(v) + case int64: + value.SetInt(v) + case []any: slice := value.SetEmptySlice() - for i := 0; i < src.Len(); i++ { - r.populateLogValue(slice.AppendEmpty(), src.Index(i)) + for _, item := range v { + r.populateLogValue(slice.AppendEmpty(), item) } - case reflect.Map: + case map[string]any: m := value.SetEmptyMap() - iter := src.MapRange() - for iter.Next() { - r.populateLogValue(m.PutEmpty(iter.Key().String()), iter.Value()) + for key, item := range v { + r.populateLogValue(m.PutEmpty(key), item) } default: r.logger.Warn( "Encountered invalid value when parsing log", - zap.String("kind", src.Type().Kind().String()), + zap.String("type", reflect.TypeOf(src).String()), ) } } From 0d86b00aa99b8b6505e826147afcfa098d441e16 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Sat, 30 Mar 2024 02:16:32 +0100 Subject: [PATCH 37/43] No logs --- collector/internal/lifecycle/manager.go | 2 +- collector/internal/telemetryapi/client.go | 4 - .../receiver/telemetryapireceiver/factory.go | 19 --- .../receiver/telemetryapireceiver/receiver.go | 137 +----------------- 4 files changed, 4 insertions(+), 158 deletions(-) diff --git a/collector/internal/lifecycle/manager.go b/collector/internal/lifecycle/manager.go index 34b8b3f557..a1d9788a0c 100644 --- a/collector/internal/lifecycle/manager.go +++ b/collector/internal/lifecycle/manager.go @@ -74,7 +74,7 @@ func NewManager(ctx context.Context, logger *zap.Logger, version string) (contex } telemetryClient := telemetryapi.NewClient(logger) - _, err = telemetryClient.Subscribe(ctx, res.ExtensionID, addr, false) + _, err = telemetryClient.Subscribe(ctx, res.ExtensionID, addr) if err != nil { logger.Fatal("Cannot register Telemetry API client", zap.Error(err)) } diff --git a/collector/internal/telemetryapi/client.go b/collector/internal/telemetryapi/client.go index f56ab1b289..2b80e7c125 100644 --- a/collector/internal/telemetryapi/client.go +++ b/collector/internal/telemetryapi/client.go @@ -50,16 +50,12 @@ func (c *Client) Subscribe( ctx context.Context, extensionID string, listenerURI string, - functionLogs bool, ) (string, error) { eventTypes := []EventType{ Platform, // Function, // Extension, } - if functionLogs { - eventTypes = append(eventTypes, Function) - } bufferingConfig := BufferingCfg{ MaxItems: 1000, diff --git a/collector/receiver/telemetryapireceiver/factory.go b/collector/receiver/telemetryapireceiver/factory.go index 47a69c60f0..16267f2528 100644 --- a/collector/receiver/telemetryapireceiver/factory.go +++ b/collector/receiver/telemetryapireceiver/factory.go @@ -43,7 +43,6 @@ func NewFactory(extensionID string) receiver.Factory { }, receiver.WithTraces(cache.createTracesReceiver, stability), receiver.WithMetrics(cache.createMetricsReceiver, stability), - receiver.WithLogs(cache.createLogsReceiver, stability), ) } @@ -90,24 +89,6 @@ func (c *ReceiverCache) createMetricsReceiver( return c.receiver, nil } -func (c *ReceiverCache) createLogsReceiver( - _ context.Context, - params receiver.CreateSettings, - rConf component.Config, - next consumer.Logs, -) (receiver.Logs, error) { - c.lock.Lock() - defer c.lock.Unlock() - - if c.receiver == nil { - if err := c.setReceiver(params, rConf); err != nil { - return nil, err - } - } - c.receiver.setLogsConsumer(next) - return c.receiver, nil -} - func (c *ReceiverCache) setReceiver( params receiver.CreateSettings, rConf component.Config, ) error { diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 07f2532800..690ebf37e1 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -25,7 +25,6 @@ import ( "math/rand" "net/http" "os" - "reflect" "strconv" "sync" "time" @@ -33,7 +32,6 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/receiver" @@ -86,9 +84,6 @@ type telemetryAPIReceiver struct { metricTimeouts metric.Int64Counter metricMemoryUsages metric.Int64Histogram lastMetricTimestamps metricTimestamps - // LOGS - nextLogsConsumer consumer.Logs - logsCache []logLine } type traceTimestamps struct { @@ -104,11 +99,6 @@ type metricTimestamps struct { platformReportTime *time.Time } -type logLine struct { - timestamp time.Time - log any -} - func newTelemetryAPIReceiver( cfg *Config, set receiver.CreateSettings, @@ -229,10 +219,6 @@ func (r *telemetryAPIReceiver) setMetricsConsumer(next consumer.Metrics) error { return err } -func (r *telemetryAPIReceiver) setLogsConsumer(next consumer.Logs) { - r.nextLogsConsumer = next -} - /* ------------------------------------ COMPONENT INTERFACE ------------------------------------ */ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) error { @@ -244,11 +230,7 @@ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) e } address := listenOnAddress() - r.logger.Info( - "Listening for requests", - zap.String("address", address), - zap.Bool("logs", r.nextLogsConsumer != nil), - ) + r.logger.Info("Listening for requests", zap.String("address", address)) mux := http.NewServeMux() mux.HandleFunc("/", r.httpHandler) @@ -258,9 +240,7 @@ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) e }() telemetryClient := telemetryapi.NewClient(r.logger) - _, err := telemetryClient.Subscribe( - ctx, r.extensionID, fmt.Sprintf("http://%s/", address), r.nextLogsConsumer != nil, - ) + _, err := telemetryClient.Subscribe(ctx, r.extensionID, fmt.Sprintf("http://%s/", address)) if err != nil { r.logger.Info( "Listening for requests", @@ -286,8 +266,7 @@ func (r *telemetryAPIReceiver) Shutdown(ctx context.Context) error { func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Request) { // We should not run HTTP handlers in parallel, this would cause all kinds of issues. Let's // just lock very coarsely here for simplicity. The TelemetryAPI should not send concurrent - // requests anyway as it should not send requests more often than every 25ms unless a LOT of - // logs are generated (see configuration in `telemetryClient.Subscribe` above). + // requests anyway. r.mutex.Lock() defer r.mutex.Unlock() @@ -396,18 +375,6 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ if record, err := parseRecord[platformReport](el, r.logger); err == nil { r.metricMemoryUsages.Record(ctx, record.Metrics.MaxMemoryUsedMb*1024*1024) } - // Log record emitted by function. - case string(telemetryapi.Function): - r.logger.Debug(fmt.Sprintf("Log entry: %s", el.Time), zap.Any("event", el)) - time, err := parseTime(el.Time) - if err != nil { - r.logger.Warn("Dropping log line as time cannot be parsed", zap.Error(err)) - } else { - r.logsCache = append(r.logsCache, logLine{ - timestamp: time, - log: el.Record, - }) - } } // TODO: potentially add support for additional events, see https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api.html // Runtime restore started (reserved for future use) @@ -424,7 +391,6 @@ func (r *telemetryAPIReceiver) httpHandler(w http.ResponseWriter, req *http.Requ // NOTE: Forward metrics first as trace forwarding clears timestamps r.forwardMetrics() r.forwardTraces() - r.forwardLogs() slice = nil } @@ -508,47 +474,6 @@ func (r *telemetryAPIReceiver) forwardMetrics() { } } -func (r *telemetryAPIReceiver) forwardLogs() { - if len(r.logsCache) == 0 { - // Return early if there are no logs - return - } - - logData := plog.NewLogs() - rs := logData.ResourceLogs().AppendEmpty() - r.resource.CopyTo(rs.Resource()) - - scopeLog := rs.ScopeLogs().AppendEmpty() - scopeLog.Scope().SetName(instrumentationScope) - - for _, item := range r.logsCache { - if line, ok := item.log.(string); ok { - log := scopeLog.LogRecords().AppendEmpty() - var parsed any - // Log lines are delivered as raw strings, we try to parse them here - if err := json.Unmarshal([]byte(line), &parsed); err == nil { - r.logger.Debug("interpreting log line as JSON", zap.String("line", line)) - r.populateLogRecord(log, parsed, item.timestamp) - } else { - // Otherwise, we process them as raw string - r.logger.Debug("interpreting log line as raw string", zap.String("line", line)) - r.populateLogRecord(log, item.log, item.timestamp) - } - } else { - r.logger.Warn("received log line in a format other than a plain string, ignoring") - } - } - r.logsCache = nil - - if scopeLog.LogRecords().Len() == 0 { - // Return before forwarding if we couldn't process any logs - return - } - if err := r.nextLogsConsumer.ConsumeLogs(context.Background(), logData); err != nil { - r.logger.Error("error receiving logs", zap.Error(err)) - } -} - /* ------------------------------------------- TRACES ------------------------------------------ */ func (r *telemetryAPIReceiver) createPlatformRuntimeSpan() (ptrace.Traces, error) { @@ -642,62 +567,6 @@ func (r *telemetryAPIReceiver) getMetricTimestamp(metricName string) (time.Time, } } -/* -------------------------------------------- LOGS ------------------------------------------- */ - -func (r *telemetryAPIReceiver) populateLogRecord(log plog.LogRecord, record any, timestamp time.Time) { - // Set metadata - log.SetObservedTimestamp(pcommon.NewTimestampFromTime(timestamp)) - if m, ok := record.(map[string]any); ok { - if rawLevel, ok := m["level"]; ok { - if level, ok := rawLevel.(string); ok { - log.SetSeverityText(level) - // Remove from map to not include severity in body - delete(m, "level") - } - } - } - - // Populate body: if the receiver's configuration indicates that we should only add a "subkey", - // let's do so - if r.cfg.Logs.JSON.BodyPath != "" { - if m, ok := record.(map[string]any); ok { - if body, ok := m[r.cfg.Logs.JSON.BodyPath]; ok { - r.populateLogValue(log.Body(), body) - } - } - } - // If we didn't return above, we just populate the entire body from the record - r.populateLogValue(log.Body(), record) -} - -func (r *telemetryAPIReceiver) populateLogValue(value pcommon.Value, src any) { - switch v := src.(type) { - case string: - value.SetStr(v) - case bool: - value.SetBool(v) - case float64: - value.SetDouble(v) - case int64: - value.SetInt(v) - case []any: - slice := value.SetEmptySlice() - for _, item := range v { - r.populateLogValue(slice.AppendEmpty(), item) - } - case map[string]any: - m := value.SetEmptyMap() - for key, item := range v { - r.populateLogValue(m.PutEmpty(key), item) - } - default: - r.logger.Warn( - "Encountered invalid value when parsing log", - zap.String("type", reflect.TypeOf(src).String()), - ) - } -} - /* ------------------------------------------- UTILS ------------------------------------------- */ func parseTime(t string) (time.Time, error) { From c9d7a673176700ecd32e84b937fd34b61cda0395 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Sat, 30 Mar 2024 02:43:53 +0100 Subject: [PATCH 38/43] More attributes --- collector/receiver/telemetryapireceiver/receiver.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 690ebf37e1..d25fd38846 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -103,7 +103,15 @@ func newTelemetryAPIReceiver( cfg *Config, set receiver.CreateSettings, ) (*telemetryAPIReceiver, error) { + // Resource attributes follow the OTEL semantiv conventions... r := pcommon.NewResource() + // Cloud Resource Attributes: https://opentelemetry.io/docs/specs/semconv/resource/cloud/ + r.Attributes().PutStr(semconv.AttributeCloudProvider, semconv.AttributeCloudProviderAWS) + r.Attributes().PutStr(semconv.AttributeCloudPlatform, semconv.AttributeCloudPlatformAWSLambda) + if val, ok := os.LookupEnv("AWS_REGION"); ok { + r.Attributes().PutStr(semconv.AttributeCloudRegion, val) + } + // FaaS Resource Attributes: https://opentelemetry.io/docs/specs/semconv/resource/faas/ if val, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_NAME"); ok { r.Attributes().PutStr(semconv.AttributeServiceName, val) r.Attributes().PutStr(semconv.AttributeFaaSName, val) @@ -122,8 +130,8 @@ func newTelemetryAPIReceiver( } } - // This telemetry API receiver is very minimal. We're lazily initializing most members as this - // receiver is requested in processing pipelines. + // This telemetry API receiver is very minimal. We're lazily initializing most members when + // this receiver is requested in processing pipelines. return &telemetryAPIReceiver{ logger: set.Logger, extensionID: cfg.extensionID, From 6c4932aac3d08a56ff9611dcab5a003c5e4a418b Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Sat, 30 Mar 2024 02:50:16 +0100 Subject: [PATCH 39/43] Remove config --- collector/receiver/telemetryapireceiver/config.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/collector/receiver/telemetryapireceiver/config.go b/collector/receiver/telemetryapireceiver/config.go index 92e3087114..8874193a6b 100644 --- a/collector/receiver/telemetryapireceiver/config.go +++ b/collector/receiver/telemetryapireceiver/config.go @@ -20,11 +20,6 @@ type Config struct { Metrics struct { UseExponentialHistograms bool `mapstructure:"use_exponential_histograms"` } `mapstructure:"metrics"` - Logs struct { - JSON struct { - BodyPath string `mapstructure:"body_path"` - } `mapstructure:"json"` - } `mapstructure:"logs"` } // Validate validates the configuration by checking for missing or invalid fields From 52b67ff2252e7b1f409b28f2f78a2b6c374221e0 Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Sun, 31 Mar 2024 03:07:52 +0200 Subject: [PATCH 40/43] Try --- collector/receiver/telemetryapireceiver/go.mod | 1 + collector/receiver/telemetryapireceiver/go.sum | 2 ++ collector/receiver/telemetryapireceiver/receiver.go | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/collector/receiver/telemetryapireceiver/go.mod b/collector/receiver/telemetryapireceiver/go.mod index bde6dddb3a..c5c4b3901b 100644 --- a/collector/receiver/telemetryapireceiver/go.mod +++ b/collector/receiver/telemetryapireceiver/go.mod @@ -7,6 +7,7 @@ toolchain go1.21.5 replace github.com/open-telemetry/opentelemetry-lambda/collector => ../../ require ( + github.com/google/uuid v1.5.0 github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 github.com/open-telemetry/opentelemetry-lambda/collector v0.91.0 github.com/stretchr/testify v1.9.0 diff --git a/collector/receiver/telemetryapireceiver/go.sum b/collector/receiver/telemetryapireceiver/go.sum index ae962974be..74b2f113c0 100644 --- a/collector/receiver/telemetryapireceiver/go.sum +++ b/collector/receiver/telemetryapireceiver/go.sum @@ -18,6 +18,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index d25fd38846..9ddd659ffd 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -41,6 +41,7 @@ import ( "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.uber.org/zap" + "github.com/google/uuid" "github.com/mitchellh/mapstructure" "github.com/open-telemetry/opentelemetry-lambda/collector/internal/telemetryapi" ) @@ -121,8 +122,12 @@ func newTelemetryAPIReceiver( if val, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_VERSION"); ok { r.Attributes().PutStr(semconv.AttributeFaaSVersion, val) } + // In order for metrics to adhere to the single-writer principle, faas.instance MUST be set: + // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/metrics/datamodel.md#single-writer if val, ok := os.LookupEnv("AWS_LAMBDA_LOG_STREAM_NAME"); ok { r.Attributes().PutStr(semconv.AttributeFaaSInstance, val) + } else { + r.Attributes().PutStr(semconv.AttributeFaaSInstance, uuid.New().String()) } if val, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE"); ok { if mb, err := strconv.Atoi(val); err == nil { From 53d1d7b0e7b375c66d60f1b410755c8283f4c58c Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Sun, 31 Mar 2024 03:40:00 +0200 Subject: [PATCH 41/43] Service instance id --- .../processor/faasprocessor/processor.go | 2 +- .../receiver/telemetryapireceiver/receiver.go | 28 +++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/collector/processor/faasprocessor/processor.go b/collector/processor/faasprocessor/processor.go index 0f76aa5a51..a853aff7d4 100644 --- a/collector/processor/faasprocessor/processor.go +++ b/collector/processor/faasprocessor/processor.go @@ -86,8 +86,8 @@ func (p *faasProcessor) processTraces(ctx context.Context, td ptrace.Traces) (pt if invocationSpan, ok := p.invocationSpans[requestID]; ok { // Augment the spans as required telemetryApiSpan.span.SetParentSpanID(invocationSpan.span.ParentSpanID()) - invocationSpan.span.SetParentSpanID(telemetryApiSpan.span.SpanID()) telemetryApiSpan.span.SetTraceID(invocationSpan.span.TraceID()) + invocationSpan.span.SetParentSpanID(telemetryApiSpan.span.SpanID()) // Add spans to the output telemetryApiSpan.addToTraces(td) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index 9ddd659ffd..ffddadc060 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -25,6 +25,7 @@ import ( "math/rand" "net/http" "os" + "os/signal" "strconv" "sync" "time" @@ -68,6 +69,7 @@ type telemetryAPIReceiver struct { extensionID string resource pcommon.Resource cfg *Config + shutdown chan struct{} // TRACES nextTracesConsumer consumer.Traces lastRequestID string @@ -112,22 +114,22 @@ func newTelemetryAPIReceiver( if val, ok := os.LookupEnv("AWS_REGION"); ok { r.Attributes().PutStr(semconv.AttributeCloudRegion, val) } - // FaaS Resource Attributes: https://opentelemetry.io/docs/specs/semconv/resource/faas/ + // Service attributes: https://opentelemetry.io/docs/specs/semconv/resource/#service if val, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_NAME"); ok { r.Attributes().PutStr(semconv.AttributeServiceName, val) r.Attributes().PutStr(semconv.AttributeFaaSName, val) } else { r.Attributes().PutStr(semconv.AttributeServiceName, "unknown_service") } + // In order for metrics to adhere to the single-writer principle, service.instance.id MUST be set: + // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/metrics/datamodel.md#single-writer + r.Attributes().PutStr(semconv.AttributeServiceInstanceID, uuid.New().String()) + // FaaS Resource Attributes: https://opentelemetry.io/docs/specs/semconv/resource/faas/ if val, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_VERSION"); ok { r.Attributes().PutStr(semconv.AttributeFaaSVersion, val) } - // In order for metrics to adhere to the single-writer principle, faas.instance MUST be set: - // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/metrics/datamodel.md#single-writer if val, ok := os.LookupEnv("AWS_LAMBDA_LOG_STREAM_NAME"); ok { r.Attributes().PutStr(semconv.AttributeFaaSInstance, val) - } else { - r.Attributes().PutStr(semconv.AttributeFaaSInstance, uuid.New().String()) } if val, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE"); ok { if mb, err := strconv.Atoi(val); err == nil { @@ -142,6 +144,7 @@ func newTelemetryAPIReceiver( extensionID: cfg.extensionID, resource: r, cfg: cfg, + shutdown: make(chan struct{}), }, nil } @@ -251,6 +254,13 @@ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) e go func() { _ = r.httpServer.ListenAndServe() }() + go func() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + _ = <-c + _ = r.httpServer.Shutdown(context.Background()) + close(r.shutdown) + }() telemetryClient := telemetryapi.NewClient(r.logger) _, err := telemetryClient.Subscribe(ctx, r.extensionID, fmt.Sprintf("http://%s/", address)) @@ -267,7 +277,13 @@ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) e } func (r *telemetryAPIReceiver) Shutdown(ctx context.Context) error { - return nil + r.httpServer.Shutdown(ctx) + select { + case <-ctx.Done(): + return nil + case <-r.shutdown: + return nil + } } /* --------------------------------------- EVENT HANDLER --------------------------------------- */ From bb6ccd15b60fdac504bec5fdd359e6bc882acf5a Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Sun, 31 Mar 2024 04:04:07 +0200 Subject: [PATCH 42/43] Fix? --- collector/receiver/telemetryapireceiver/receiver.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/collector/receiver/telemetryapireceiver/receiver.go b/collector/receiver/telemetryapireceiver/receiver.go index ffddadc060..5e96d2dad6 100644 --- a/collector/receiver/telemetryapireceiver/receiver.go +++ b/collector/receiver/telemetryapireceiver/receiver.go @@ -28,6 +28,7 @@ import ( "os/signal" "strconv" "sync" + "syscall" "time" "go.opentelemetry.io/collector/component" @@ -256,7 +257,7 @@ func (r *telemetryAPIReceiver) Start(ctx context.Context, host component.Host) e }() go func() { c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt) + signal.Notify(c, syscall.SIGTERM) _ = <-c _ = r.httpServer.Shutdown(context.Background()) close(r.shutdown) From e55593bae09cdb1eb70dc1690db0815154fe384a Mon Sep 17 00:00:00 2001 From: Oliver Borchert Date: Mon, 1 Apr 2024 00:08:08 +0200 Subject: [PATCH 43/43] Update docs --- collector/processor/faasprocessor/README.md | 43 +++++++------- collector/processor/faasprocessor/doc.go | 30 +++++----- collector/processor/faasprocessor/factory.go | 21 ++----- .../processor/faasprocessor/factory_test.go | 2 +- .../processor/faasprocessor/processor.go | 57 +++++++++++++------ .../receiver/telemetryapireceiver/README.md | 41 +++++++++---- 6 files changed, 117 insertions(+), 77 deletions(-) diff --git a/collector/processor/faasprocessor/README.md b/collector/processor/faasprocessor/README.md index 7aaa6cbd83..66c2e644e1 100644 --- a/collector/processor/faasprocessor/README.md +++ b/collector/processor/faasprocessor/README.md @@ -1,31 +1,34 @@ -# Coldstart Processor +# FaaS Processor -| Status | | -| ------------------------ |-----------------| -| Stability | [in development]| -| Supported pipeline types | traces | -| Distributions | [extension] | +| Status | | +| ------------------------ | ---------------- | +| Stability | [in development] | +| Supported pipeline types | traces | +| Distributions | [extension] | -This processor associates cold start information generated by the [telemetryapireceiver](../../receiver/telemetryapireceiver) with incoming span data processed by -the Collector extension. It reads the following of incoming Lambda execution spans identified by the `faas.execution` attribute: +This processor associates spans created by the [telemetryapireceiver](../../receiver/telemetryapireceiver) with +incoming span data processed by the Collector extension. To this end, it searches for a pair of spans with the same +value for the `faas.invocation_id` attribute: -- trace ID -- parent span ID -- span scope -- resource attributes +- The first span is created by the `telemetryapireceiver` and can easily be identified via its scope. +- The second span must be created by the user application and be received via the collector extension. -This information is stored until the first coldstart span identified by the `faas.coldstart` attribute -is received. That span's trace ID, parent span ID are updated to match the execution span. This -allows the coldstart span to be part of the same trace as the operation that triggered the cold start. Additionally, -the span scope and resource attributes of the span scope containing the coldstart span -are replaced with the span scope and resource attributes of the execution span as -they contain more details. +Once a matching pair is found, the span created by the `telemetryapireceiver` is updated to belong to the same trace as +the user-created span and is "inserted" into the span hierarchy: the span created by the `telemetryapireceiver` is set +as the parent span of the user-created span and is itself set as child of the previous user-created span's parent (if +any). If the `telemetryapireceiver` also created a span for the function initialization, it is simply updated to belong +to the same trace and remains a child of the created "FaaS invocation span". -There are currently no configuration parameters available for this processor. It can be enabled via the following configuration: +**Note:** If your application does not emit any spans with the `faas.invocation_id` attribute set, DO NOT use this +processor. It will store all traces trying to search for matches of this attribute and never emits them (until the +Lambda runtime shuts down in which case all unmatched spans are emitted). + +There are currently no configuration parameters available for this processor. It can be enabled via the following +configuration: ```yaml processors: - coldstart: + faas: ``` [in development]: https://github.com/open-telemetry/opentelemetry-collector#development diff --git a/collector/processor/faasprocessor/doc.go b/collector/processor/faasprocessor/doc.go index c0b89e1f3d..ef7b640a4c 100644 --- a/collector/processor/faasprocessor/doc.go +++ b/collector/processor/faasprocessor/doc.go @@ -12,20 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package faasprocessor correlates cold start information generated by the telemetryapireceiver -// with incoming span data. +// Package faasprocessor associates spans created by the telemetryapireceiver with incoming span +// data processed by the Collector extension. To this end, it searches for a pair of spans with +// the same value for the faas.invocation_id attribute: // -// It reads the following of incoming Lambda execution spans identified by the faas.execution attribute: +// - The first span is created by the telemetryapireceiver and can easily be identified via its +// scope. +// - The second span must be created by the user application and be received via the collector +// extension. // -// - trace ID -// - parent span ID -// - span scope -// - resource attributes +// Once a matching pair is found, the span created by the telemetryapireceiver is updated to +// belong to the same trace as the user-created span and is "inserted" into the span hierarchy: +// the span created by the telemetryapireceiver is set as the parent span of the user-created span +// and is itself set as child of the previous user-created span's parent (if any). If the +// telemetryapireceiver also created a span for the function initialization, it is simply updated +// to belong to the same trace and remains a child of the created "FaaS invocation span". // -// This information is stored until the first coldstart span identified by the faas.coldstart attribute -// is received. That span's trace ID, parent span ID are updated to match the execution span. This -// allows the coldstart span to be part of the same trace as the operation that triggered the cold start. Additionally, -// the span scope and resource attributes of the span scope containing the coldstart span -// are replaced with the span scope and resource attributes of the execution span as -// they contain more details. +// NOTE: If your application does not emit any spans with the faas.invocation_id attribute set, DO +// NOT use this processor. It will store all traces trying to search for matches of this attribute +// and never emits them (until the Lambda runtime shuts down in which case all unmatched spans are +// emitted). package faasprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/faasprocessor" diff --git a/collector/processor/faasprocessor/factory.go b/collector/processor/faasprocessor/factory.go index 9426810320..c3b1de373c 100644 --- a/collector/processor/faasprocessor/factory.go +++ b/collector/processor/faasprocessor/factory.go @@ -21,7 +21,6 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/processor" - "go.opentelemetry.io/collector/processor/processorhelper" ) const ( @@ -29,10 +28,7 @@ const ( stability = component.StabilityLevelDevelopment ) -var ( - errConfigNotColdstart = errors.New("config was not a Coldstart processor config") - processorCapabilities = consumer.Capabilities{MutatesData: true} -) +var errConfigNotFaas = errors.New("config was not a faas processor config") func NewFactory() processor.Factory { return processor.NewFactory( @@ -47,21 +43,14 @@ func createDefaultConfig() component.Config { } func createTracesProcessor(ctx context.Context, params processor.CreateSettings, rConf component.Config, next consumer.Traces) (processor.Traces, error) { - cfg, ok := rConf.(*Config) + _, ok := rConf.(*Config) if !ok { - return nil, errConfigNotColdstart + return nil, errConfigNotFaas } - cp, err := newFaasProcessor(cfg, next, params) + cp, err := newFaasProcessor(next, params) if err != nil { return nil, err } - return processorhelper.NewTracesProcessor( - ctx, - params, - cfg, - next, - cp.processTraces, - processorhelper.WithCapabilities(processorCapabilities), - ) + return cp, nil } diff --git a/collector/processor/faasprocessor/factory_test.go b/collector/processor/faasprocessor/factory_test.go index d65defa646..177c91283c 100644 --- a/collector/processor/faasprocessor/factory_test.go +++ b/collector/processor/faasprocessor/factory_test.go @@ -59,7 +59,7 @@ func TestNewFactory(t *testing.T) { nil, consumertest.NewNop(), ) - require.ErrorIs(t, err, errConfigNotColdstart) + require.ErrorIs(t, err, errConfigNotFaas) }, }, } diff --git a/collector/processor/faasprocessor/processor.go b/collector/processor/faasprocessor/processor.go index a853aff7d4..9d92016136 100644 --- a/collector/processor/faasprocessor/processor.go +++ b/collector/processor/faasprocessor/processor.go @@ -17,6 +17,7 @@ package faasprocessor // import "github.com/open-telemetry/opentelemetry-lambda/ import ( "context" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" @@ -38,7 +39,23 @@ type faasProcessor struct { nextConsumer consumer.Traces } -func (p *faasProcessor) processTraces(ctx context.Context, td ptrace.Traces) (ptrace.Traces, error) { +func newFaasProcessor(next consumer.Traces, set processor.CreateSettings) (*faasProcessor, error) { + return &faasProcessor{ + telemetryAPIRuntimeSpans: make(map[string]cachedSpan), + telemetryAPIInitSpans: make(map[string]cachedSpan), + invocationSpans: make(map[string]cachedSpan), + nextConsumer: next, + logger: set.Logger, + }, nil +} + +/* -------------------------------------- TRACES INTERFACE ------------------------------------- */ + +func (*faasProcessor) Capabilities() consumer.Capabilities { + return consumer.Capabilities{MutatesData: true} +} + +func (p *faasProcessor) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { // Remove spans which ought to be matched on the request ID td.ResourceSpans().RemoveIf(func(rs ptrace.ResourceSpans) bool { resource := rs.Resource() @@ -105,25 +122,33 @@ func (p *faasProcessor) processTraces(ctx context.Context, td ptrace.Traces) (pt } } } - if td.ResourceSpans().Len() == 0 { - return td, processorhelper.ErrSkipProcessingData + return processorhelper.ErrSkipProcessingData } - return td, nil + return p.nextConsumer.ConsumeTraces(ctx, td) } -func newFaasProcessor( - cfg *Config, - next consumer.Traces, - set processor.CreateSettings, -) (*faasProcessor, error) { - return &faasProcessor{ - telemetryAPIRuntimeSpans: make(map[string]cachedSpan), - telemetryAPIInitSpans: make(map[string]cachedSpan), - invocationSpans: make(map[string]cachedSpan), - nextConsumer: next, - logger: set.Logger, - }, nil +func (p *faasProcessor) Start(ctx context.Context, host component.Host) error { + return nil +} + +func (p *faasProcessor) Shutdown(ctx context.Context) error { + // If there are still any spans left, let's just forward them as-is. We don't want to lose any + // in our cache. + td := ptrace.NewTraces() + for _, item := range p.invocationSpans { + item.addToTraces(td) + } + for _, item := range p.telemetryAPIInitSpans { + item.addToTraces(td) + } + for _, item := range p.telemetryAPIRuntimeSpans { + item.addToTraces(td) + } + if td.ResourceSpans().Len() == 0 { + return nil + } + return p.nextConsumer.ConsumeTraces(ctx, td) } /* ---------------------------------------- CACHED SPAN ---------------------------------------- */ diff --git a/collector/receiver/telemetryapireceiver/README.md b/collector/receiver/telemetryapireceiver/README.md index 2306ba5454..e7cd1dfa99 100644 --- a/collector/receiver/telemetryapireceiver/README.md +++ b/collector/receiver/telemetryapireceiver/README.md @@ -8,27 +8,46 @@ This receiver generates telemetry in response to events from the [Telemetry API](https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api.html). It does this by setting up an -endpoint and registering itself with the Telemetry API on startup. +endpoint and registering itself with the Telemetry API on startup. Generated telemetry includes both traces and +metrics. -Supported events: +## Traces -- `platform.initStart` - The receiver uses this event to record the start time of the function initialization period. - Once both start and end times are recorded, the receiver generates a span named `platform.initRuntimeDone` to record - the event. -- `platform.initRuntimeDone` - The receiver uses this event to record the end time of the function initialization - period. Once both start and end times are recorded, the receiver generates a span named `platform.initRuntimeDone` to - record the event. +If used in a `traces` pipeline, this receiver currently creates two kinds of spans: + +- A "FaaS invocation" span following the + [semantic conventions for FaaS spans](https://opentelemetry.io/docs/specs/semconv/faas/faas-spans/). Unless the + function is being initialized for the invocation, the span runs from the `platform.start` event to the + `platform.runtimeDone` event. If the function is being initialized, the span's start timestamp is instead taken from + the `platform.initStart` event. +- If the function is being initialized, another span named `faas.runtimeInit` is created as a child of the "FaaS + invocation" span. This span runs from the `platform.initStart` to the `platform.initRuntimeDone` event. + +In order to associate these spans with traces created during function invocation, consider using the +[`faasprocessor`](../../processor/faasprocessor/). + +## Metrics + +If used in a `metrics` pipeline, this receiver currently generates a all metrics specified in the +[semantic conventions for FaaS metrics](https://opentelemetry.io/docs/specs/semconv/faas/faas-metrics/) (except for +`faas.cpu_usage` which is not provided by the Telemetry API). Timestamps of all metrics are set to the timestamps +provided by certain events emitted by the Telemetry API such that metrics ought to capture timing information well. + +Created metrics initialize counters to zero to prevent time series (such as `faas.coldstarts`) starting with a value +of 1. Otherwise, this would create issues for many systems (e.g. Prometheus) as the transition from value 0 to 1 would +never be observed. ## Configuration -There are currently no configuration parameters available for this receiver. It can be enabled via the following -configuration: +The receiver can be enabled via the following configuration: ```yaml receivers: telemetryapi: metrics: - useExponentialHistograms: true + # `use_exponential_histograms` allows to generate histogram metrics using exponential buckets rather than + # predefined ones. For Prometheus, exponential histograms currently requires enabling experimental features. + use_exponential_histograms: false ``` [in development]: https://github.com/open-telemetry/opentelemetry-collector#development