Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal/telemetry: revamp #2996

Open
wants to merge 57 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
7d9896d
setup internal/newtelemetry
eliottness Oct 18, 2024
f398276
setup newtelemetry package
eliottness Nov 27, 2024
34d2cf8
internal/newtelemetry: create all structs from schemas
eliottness Jan 13, 2025
f921f60
internal/newtelemetry/internal: created and implemented the Writer
eliottness Jan 15, 2025
160e1fb
end to end support for integration, product, client configuration cha…
eliottness Jan 15, 2025
f43bbdb
refactor config and implement NewClient()
eliottness Jan 15, 2025
a0f0d6b
wip
eliottness Jan 16, 2025
b8de6af
support for payload transformers
eliottness Jan 17, 2025
a9fc7bd
support for more configuration options
eliottness Jan 17, 2025
5159533
fix hostname resolution logic to match the previous telemetry client
eliottness Jan 17, 2025
5e90cb8
test the writer
eliottness Jan 20, 2025
9d9c3b8
support for disabling telemetry
eliottness Jan 20, 2025
72359f5
renamed transformers to mappers and added a heartbeat mapper, removed…
eliottness Jan 20, 2025
9eafa97
start testing the basic features of the client
eliottness Jan 20, 2025
1baad87
add more tests
eliottness Jan 22, 2025
f7e7ff7
add end 2 end tests and body unmarshaling for testing purposes
eliottness Jan 22, 2025
2b2e13b
add actionQueue for calls because NewClient() is done
eliottness Jan 23, 2025
70adebc
fix app-extended-heartbeat payload way of being sent each 24 hours
eliottness Jan 24, 2025
f52047b
support for app-dependencies-loaded payload
eliottness Jan 24, 2025
5f5b7ba
setup logging and the recorder for metrics. Change the api to remove …
eliottness Jan 27, 2025
712971b
tested logs API and added benchmarks for it
eliottness Jan 27, 2025
214c2a7
use internal.RecordWriter instead of the testWriter
eliottness Jan 28, 2025
f847631
refactor the writer and flush method to record more data that will th…
eliottness Jan 28, 2025
3ebfb63
added replay feature to the metrics function of the global client
eliottness Jan 28, 2025
f9dd56c
add internal package for known metrics from the backend
eliottness Jan 28, 2025
4cd8b71
rename metrics package to knownmetrics + added a new TypedSyncMap wra…
eliottness Jan 28, 2025
7487c90
moved the Origin type and Namespace type to the transport package, re…
eliottness Jan 28, 2025
651e8f6
support for distributions metrics
eliottness Jan 29, 2025
44eb960
add tests and fix issues with distributions
eliottness Jan 29, 2025
05b010c
reworked knownmetrics to include namespace and metric kind and added …
eliottness Jan 29, 2025
2cfb429
remove new dependencies that were introduced inadvertently
eliottness Jan 29, 2025
5380ba3
renamed several things added send failure tests and reworked the ring…
eliottness Jan 30, 2025
f654610
added mock telemetry client
eliottness Jan 30, 2025
21d0f01
add GlobalClient() function to mirror old package variable GlobalClient
eliottness Jan 30, 2025
29fc678
rename AddAppConfig to RegisterAppConfig and rename AddBulkConfig to …
eliottness Jan 30, 2025
c7e4928
support config sanitizing and rename some stuff to facilitate the tra…
eliottness Jan 30, 2025
6ba3e84
switch tags from map[string]string to []string
eliottness Jan 30, 2025
9cf1102
fix misc
eliottness Jan 30, 2025
cfe990a
rework telemetrytest to divide the mock client and the recorder client
eliottness Jan 31, 2025
091c522
rework logger to work without sync.Map.Clear() from go 1.23
eliottness Jan 31, 2025
8bc28bc
remove data race from telemetry metrics hot pointer
eliottness Jan 31, 2025
681eae1
flush app-started on StartApp()
eliottness Jan 31, 2025
cd86428
add new benchmarks to benchmarking platform
eliottness Feb 3, 2025
373e2fd
apply @RomainMuller suggestions
eliottness Feb 3, 2025
09cab87
fix bug found with the system-tests
eliottness Feb 3, 2025
352d7a5
increase retro compat with all sanitization config value code
eliottness Feb 4, 2025
e849e5e
starting to apply @RomainMuller suggestions
eliottness Feb 5, 2025
4798807
rework metrics
eliottness Feb 5, 2025
ecf313b
Merge branch 'main' into eliott.bouhana/newtelemetry
eliottness Feb 5, 2025
4fd7f2c
new metric implementation using atomic.Pointer and sync.Pool
eliottness Feb 6, 2025
a6a0bdb
removed mapper.wrapper type
eliottness Feb 6, 2025
c4080ec
simplify knownmetrics generator
eliottness Feb 6, 2025
0759137
added a new TypedSyncPool for use in the RingQueue to aggregate usage…
eliottness Feb 6, 2025
a5b0d0c
apply last suggestions from @RomainMuller
eliottness Feb 6, 2025
a62953e
Merge branch 'main' into eliott.bouhana/newtelemetry
eliottness Feb 6, 2025
90c9985
Merge branch 'main' into eliott.bouhana/newtelemetry
eliottness Feb 7, 2025
3dd727b
fix issue where reducing the value of DD_TELEMETRY_HEARTBEAT_INTERVAL…
eliottness Feb 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ variables:
INDEX_FILE: index.txt
KUBERNETES_SERVICE_ACCOUNT_OVERWRITE: dd-trace-go
FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY: "true"
BENCHMARK_TARGETS: "BenchmarkStartRequestSpan|BenchmarkHttpServeTrace|BenchmarkTracerAddSpans|BenchmarkStartSpan|BenchmarkSingleSpanRetention|BenchmarkOTelApiWithCustomTags|BenchmarkInjectW3C|BenchmarkExtractW3C|BenchmarkPartialFlushing|BenchmarkGraphQL|BenchmarkSampleWAFContext|BenchmarkCaptureStackTrace|BenchmarkSetTagString|BenchmarkSetTagStringPtr|BenchmarkSetTagMetric|BenchmarkSetTagStringer|BenchmarkSerializeSpanLinksInMeta"

BENCHMARK_TARGETS: "BenchmarkStartRequestSpan|BenchmarkHttpServeTrace|BenchmarkTracerAddSpans|BenchmarkStartSpan|BenchmarkSingleSpanRetention|BenchmarkOTelApiWithCustomTags|BenchmarkInjectW3C|BenchmarkExtractW3C|BenchmarkPartialFlushing|BenchmarkGraphQL|BenchmarkSampleWAFContext|BenchmarkCaptureStackTrace|BenchmarkSetTagString|BenchmarkSetTagStringPtr|BenchmarkSetTagMetric|BenchmarkSetTagStringer|BenchmarkSerializeSpanLinksInMeta|BenchmarkLogs|BenchmarkWorstCaseScenarioFloodLogging|BenchmarkMetrics|BenchmarkWorstCaseScenarioFloodMetrics"
include:
- ".gitlab/benchmarks.yml"
- ".gitlab/macrobenchmarks.yml"
Expand Down
16 changes: 16 additions & 0 deletions internal/globalconfig/globalconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package globalconfig

import (
"math"
"os"
"sync"

"gopkg.in/DataDog/dd-trace-go.v1/internal"
Expand Down Expand Up @@ -130,3 +131,18 @@ func HeaderTagsLen() int {
func ClearHeaderTags() {
cfg.headersAsTags.Clear()
}

// InstrumentationInstallID returns the install ID as described in DD_INSTRUMENTATION_INSTALL_ID
func InstrumentationInstallID() string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never considered just putting a getter in globalconfig. From APM perspective, typically we process the env var once, in a method like newUnstartedTracer, and set the value on the globalconfig. But your idea is a good one, provided we are not constantly spamming these InstrumentationInstall functions (such that we are not making tons of calls to os.Getenv instead of a single call)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was just a attempt to create something usable by everyone since I don't believe I have an easy access to those values

return os.Getenv("DD_INSTRUMENTATION_INSTALL_ID")
}

// InstrumentationInstallType returns the install type as described in DD_INSTRUMENTATION_INSTALL_TYPE
func InstrumentationInstallType() string {
return os.Getenv("DD_INSTRUMENTATION_INSTALL_TYPE")
}

// InstrumentationInstallTime returns the install time as described in DD_INSTRUMENTATION_INSTALL_TIME
func InstrumentationInstallTime() string {
return os.Getenv("DD_INSTRUMENTATION_INSTALL_TIME")
}
152 changes: 152 additions & 0 deletions internal/newtelemetry/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2024 Datadog, Inc.

package newtelemetry

import (
"io"

"gopkg.in/DataDog/dd-trace-go.v1/internal/newtelemetry/internal/transport"
)

// Namespace describes a product to distinguish telemetry coming from
// different products used by the same application
type Namespace = transport.Namespace

// Goland is having a hard time with the following const block, it keeps deleting the type
//
//goland:noinspection GoVarAndConstTypeMayBeOmitted
const (
NamespaceGeneral Namespace = transport.NamespaceGeneral
NamespaceTracers Namespace = transport.NamespaceTracers
NamespaceProfilers Namespace = transport.NamespaceProfilers
NamespaceAppSec Namespace = transport.NamespaceAppSec
NamespaceIAST Namespace = transport.NamespaceIAST
NamespaceCIVisibility Namespace = transport.NamespaceCIVisibility
NamespaceMLOps Namespace = transport.NamespaceMLOps
NamespaceRUM Namespace = transport.NamespaceRUM
)

// Origin describes the source of a configuration change
type Origin = transport.Origin

// Goland is having a hard time with the following const block, it keeps deleting the type
//
//goland:noinspection GoVarAndConstTypeMayBeOmitted
const (
OriginDefault Origin = transport.OriginDefault
OriginCode Origin = transport.OriginCode
OriginDDConfig Origin = transport.OriginDDConfig
OriginEnvVar Origin = transport.OriginEnvVar
OriginRemoteConfig Origin = transport.OriginRemoteConfig
)

// LogLevel describes the level of a log message
type LogLevel = transport.LogLevel

// Goland is having a hard time with the following const block, it keeps deleting the type
//
//goland:noinspection GoVarAndConstTypeMayBeOmitted
const (
LogDebug LogLevel = transport.LogLevelDebug
LogWarn LogLevel = transport.LogLevelWarn
LogError LogLevel = transport.LogLevelError
)

// MetricHandle can be used to submit different values for the same metric.
// MetricHandle is used to reduce lock contention when submitting metrics.
// This can also be used ephemerally to submit a single metric value like this:
//
// ```go
// telemetry.metric(telemetry.Appsec, "my-count", map[string]string{"tag1": "true", "tag2": "1.0"}).Submit(1.0)
// ```
type MetricHandle interface {
// Submit submits a value to the metric handle.
Submit(value float64)
// Get returns the last value submitted to the metric handle.
Get() float64
}

// Integration is an integration that is configured to be traced.
type Integration struct {
// Name is an arbitrary string that must stay constant for the integration.
Name string
// Version is the version of the integration/dependency that is being loaded.
Version string
// Error is the error that occurred while loading the integration. If this field is specified, the integration is
// considered to be having been forcefully disabled because of the error.
Error string
}

// Configuration is a key-value pair that is used to configure the application.
type Configuration struct {
// Key is the key of the configuration.
Name string
// Value is the value of the configuration. Need to be json serializable.
Value any
// Origin is the source of the configuration change.
Origin Origin
}

// LogOption is a function that modifies the log message that is sent to the telemetry.
type LogOption func(key *loggerKey, value *loggerValue)

// Client constitutes all the functions available concurrently for the telemetry users. All methods are thread-safe
// This is an interface for easier testing but all functions will be mirrored at the package level to call
// the global client.
type Client interface {
io.Closer

// Count obtains the metric handle for the given parameters, or creates a new one if none was created just yet.
// Tags cannot contain commas.
Count(namespace Namespace, name string, tags []string) MetricHandle

// Rate obtains the metric handle for the given parameters, or creates a new one if none was created just yet.
// Tags cannot contain commas.
Rate(namespace Namespace, name string, tags []string) MetricHandle

// Gauge obtains the metric handle for the given parameters, or creates a new one if none was created just yet.
// Tags cannot contain commas.
Gauge(namespace Namespace, name string, tags []string) MetricHandle

// Distribution obtains the metric handle for the given parameters, or creates a new one if none was created just yet.
// Tags cannot contain commas.
Distribution(namespace Namespace, name string, tags []string) MetricHandle

// Log sends a telemetry log at the desired level with the given text and options.
// Options include sending key-value pairs as tags, and a stack trace frozen from inside the Log function.
Log(level LogLevel, text string, options ...LogOption)
eliottness marked this conversation as resolved.
Show resolved Hide resolved

// ProductStarted declares a product to have started at the customer’s request
ProductStarted(product Namespace)

// ProductStopped declares a product to have being stopped by the customer
ProductStopped(product Namespace)

// ProductStartError declares that a product could not start because of the following error
ProductStartError(product Namespace, err error)
eliottness marked this conversation as resolved.
Show resolved Hide resolved

// RegisterAppConfig adds a key value pair to the app configuration and send the change to telemetry
// value has to be json serializable and the origin is the source of the change.
RegisterAppConfig(key string, value any, origin Origin)

// RegisterAppConfigs adds a list of key value pairs to the app configuration and sends the change to telemetry.
// Same as AddAppConfig but for multiple values.
eliottness marked this conversation as resolved.
Show resolved Hide resolved
RegisterAppConfigs(kvs ...Configuration)

// MarkIntegrationAsLoaded marks an integration as loaded in the telemetry
MarkIntegrationAsLoaded(integration Integration)

// Flush closes the client and flushes any remaining data.
Flush()
eliottness marked this conversation as resolved.
Show resolved Hide resolved

// AppStart sends the telemetry necessary to signal that the app is starting.
// Preferred use via StartApp package level function
eliottness marked this conversation as resolved.
Show resolved Hide resolved
AppStart()

// AppStop sends the telemetry necessary to signal that the app is stopping.
// Preferred use via StopApp package level function
eliottness marked this conversation as resolved.
Show resolved Hide resolved
AppStop()
}
Loading
Loading