Skip to content

Commit

Permalink
setup internal/newtelemetry
Browse files Browse the repository at this point in the history
Signed-off-by: Eliott Bouhana <eliott.bouhana@datadoghq.com>

wip

Signed-off-by: Eliott Bouhana <eliott.bouhana@datadoghq.com>
  • Loading branch information
eliottness committed Nov 27, 2024
1 parent 2f8b419 commit e723f13
Show file tree
Hide file tree
Showing 8 changed files with 692 additions and 0 deletions.
105 changes: 105 additions & 0 deletions internal/newtelemetry/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// 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 (
"net/http"
)

type ClientConfig struct {
// AgentlessURL is the full URL to the agentless telemetry endpoint.
// Defaults to https://instrumentation-telemetry-intake.datadoghq.com/api/v2/apmtelemetry
AgentlessURL string

// AgentURL is the url to the agent without the path
AgentURL string

// APIKey is the API key to use for sending telemetry, defaults to the env var DD_API_KEY.
APIKey string

// HTTPClient is the http client to use for sending telemetry, defaults to http.DefaultClient.
HTTPClient http.RoundTripper
}

// NewClient creates a new telemetry client with the given service, environment, and version and config.
func NewClient(service, env, version string, config ClientConfig) (Client, error) {
return nil, nil
}

// StartApp starts the telemetry client with the given client send the app-started telemetry and sets it as the global client.
func StartApp(client Client) error {
return nil
}

// StopApp creates the app-stopped telemetry, adding to the queue and flush all the queue before stopping the client.
func StopApp() {
}

// MetricHandle is used to reduce lock contention when submitting metrics.
// This can also be used ephemerally to submit a single metric value like this:
//
// telemetry.Metric(telemetry.Appsec, "my-count").Submit(1.0, []string{"tag1:true", "tag2:1.0"})
type MetricHandle interface {
Submit(value float64, tags []string)

flush()
}

// Logger is the interface i
type Logger interface {
// WithTags creates a new Logger which will send a comma-separated list of tags with the next logs
WithTags(tags string) Logger

// WithStackTrace creates a new Logger which will send a stack trace generated for each next log.
WithStackTrace(tags string) Logger

// Error sends a telemetry log at the ERROR level
Error(text string)

// Warn sends a telemetry log at the WARN level
Warn(text string)

// Debug sends a telemetry log at the DEBUG level
Debug(text string)
}

// Client constitutes all the functions available concurrently for the telemetry users.
type Client interface {
// Count creates a new metric handle for the given namespace and name that can be used to submit values.
Count(namespace Namespace, name string) MetricHandle

// Rate creates a new metric handle for the given namespace and name that can be used to submit values.
Rate(namespace Namespace, name string) MetricHandle

// Gauge creates a new metric handle for the given namespace and name that can be used to submit values.
Gauge(namespace Namespace, name string) MetricHandle

// Distribution creates a new metric handle for the given namespace and name that can be used to submit values.
Distribution(namespace Namespace, name string) MetricHandle

// Logger returns an implementation of the Logger interface which sends telemetry logs.
Logger() Logger

// ProductOnOff sent the telemetry necessary to signal that a product is enabled/disabled.
ProductOnOff(product Namespace, enabled bool)

// AddAppConfig 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.
AddAppConfig(key string, value any, origin Origin)

// AddBulkAppConfig adds a list of key value pairs to the app configuration and send the change to telemetry.
// Same as AddAppConfig but for multiple values.
AddBulkAppConfig(kvs []Configuration)

// flush closes the client and flushes any remaining data.
flush()

// appStart sends the telemetry necessary to signal that the app is starting.
appStart()

// appStop sends the telemetry necessary to signal that the app is stopping and calls Close()
appStop()
}
14 changes: 14 additions & 0 deletions internal/newtelemetry/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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

type InternalConfig struct {
Enabled bool
HeartbeatInterval int
DependencyCollectionEnabled bool
MetricsEnabled bool
LogsEnabled bool
}
40 changes: 40 additions & 0 deletions internal/newtelemetry/defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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 (
"net"
"net/http"
"time"
)

var (
// We copy the transport to avoid using the default one, as it might be
// augmented with tracing and we don't want these calls to be recorded.
// See https://golang.org/pkg/net/http/#DefaultTransport .
defaultHTTPClient = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
Timeout: 5 * time.Second,
}

// agentlessURL is the endpoint used to send telemetry in an agentless environment. It is
// also the default URL in case connecting to the agent URL fails.
agentlessURL = "https://instrumentation-telemetry-intake.datadoghq.com/api/v2/apmtelemetry"

// defaultHeartbeatInterval is the default interval at which the agent sends a heartbeat.
defaultHeartbeatInterval = 60.0
)
42 changes: 42 additions & 0 deletions internal/newtelemetry/hot_pointer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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 (
"sync"
)

// hotPointer is a type that allows for atomic swapping of a value while keeping the other on standby to prevent allocations.
type hotPointer[T any] struct {
// value is the current value that can be extracted.
value *T
// standby is the value that will be swapped in.
standby *T
// writeMu is used to lock the value.
writeMu sync.Mutex
// swapMu is used to lock the swap.
swapMu sync.Mutex
}

// Lock take the lock and return the current value
func (hp *hotPointer[T]) Lock() *T {
hp.writeMu.Lock()
return hp.value
}

// StandbyValue returns the standby value WITHOUT locking. Which means it cannot be used concurrently.
func (hp *hotPointer[T]) StandbyValue() *T {
return hp.standby
}

// Swap swaps the current value with the standby value and return the standby value using the lock.
// the value returned is NOT protected by the lock.
func (hp *hotPointer[T]) Swap() *T {
hp.Lock()
defer hp.Unlock()
hp.value, hp.standby = hp.standby, hp.value
return hp.standby
}
Loading

0 comments on commit e723f13

Please sign in to comment.