| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948 |
- // 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 2016 Datadog, Inc.
- package tracer
- import (
- "context"
- "encoding/json"
- "fmt"
- "math"
- "net"
- "net/http"
- "os"
- "path/filepath"
- "runtime"
- "strconv"
- "strings"
- "time"
- "gopkg.in/DataDog/dd-trace-go.v1/ddtrace"
- "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
- "gopkg.in/DataDog/dd-trace-go.v1/internal"
- "gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig"
- "gopkg.in/DataDog/dd-trace-go.v1/internal/log"
- "gopkg.in/DataDog/dd-trace-go.v1/internal/traceprof"
- "gopkg.in/DataDog/dd-trace-go.v1/internal/version"
- "github.com/DataDog/datadog-go/v5/statsd"
- )
- var (
- // defaultSocketAPM specifies the socket path to use for connecting to the trace-agent.
- // Replaced in tests
- defaultSocketAPM = "/var/run/datadog/apm.socket"
- // defaultSocketDSD specifies the socket path to use for connecting to the statsd server.
- // Replaced in tests
- defaultSocketDSD = "/var/run/datadog/dsd.socket"
- // defaultMaxTagsHeaderLen specifies the default maximum length of the X-Datadog-Tags header value.
- defaultMaxTagsHeaderLen = 128
- )
- // config holds the tracer configuration.
- type config struct {
- // debug, when true, writes details to logs.
- debug bool
- // agent holds the capabilities of the agent and determines some
- // of the behaviour of the tracer.
- agent agentFeatures
- // featureFlags specifies any enabled feature flags.
- featureFlags map[string]struct{}
- // logToStdout reports whether we should log all traces to the standard
- // output instead of using the agent. This is used in Lambda environments.
- logToStdout bool
- // logStartup, when true, causes various startup info to be written
- // when the tracer starts.
- logStartup bool
- // serviceName specifies the name of this application.
- serviceName string
- // universalVersion, reports whether span service name and config service name
- // should match to set application version tag. False by default
- universalVersion bool
- // version specifies the version of this application
- version string
- // env contains the environment that this application will run under.
- env string
- // sampler specifies the sampler that will be used for sampling traces.
- sampler Sampler
- // agentURL is the agent URL that receives traces from the tracer.
- agentURL string
- // serviceMappings holds a set of service mappings to dynamically rename services
- serviceMappings map[string]string
- // globalTags holds a set of tags that will be automatically applied to
- // all spans.
- globalTags map[string]interface{}
- // transport specifies the Transport interface which will be used to send data to the agent.
- transport transport
- // propagator propagates span context cross-process
- propagator Propagator
- // httpClient specifies the HTTP client to be used by the agent's transport.
- httpClient *http.Client
- // hostname is automatically assigned when the DD_TRACE_REPORT_HOSTNAME is set to true,
- // and is added as a special tag to the root span of traces.
- hostname string
- // logger specifies the logger to use when printing errors. If not specified, the "log" package
- // will be used.
- logger ddtrace.Logger
- // runtimeMetrics specifies whether collection of runtime metrics is enabled.
- runtimeMetrics bool
- // dogstatsdAddr specifies the address to connect for sending metrics to the
- // Datadog Agent. If not set, it defaults to "localhost:8125" or to the
- // combination of the environment variables DD_AGENT_HOST and DD_DOGSTATSD_PORT.
- dogstatsdAddr string
- // statsdClient is set when a user provides a custom statsd client for tracking metrics
- // associated with the runtime and the tracer.
- statsdClient statsdClient
- // spanRules contains user-defined rules to determine the sampling rate to apply
- // to trace spans.
- spanRules []SamplingRule
- // traceRules contains user-defined rules to determine the sampling rate to apply
- // to individual spans.
- traceRules []SamplingRule
- // tickChan specifies a channel which will receive the time every time the tracer must flush.
- // It defaults to time.Ticker; replaced in tests.
- tickChan <-chan time.Time
- // noDebugStack disables the collection of debug stack traces globally. No traces reporting
- // errors will record a stack trace when this option is set.
- noDebugStack bool
- // profilerHotspots specifies whether profiler Code Hotspots is enabled.
- profilerHotspots bool
- // profilerEndpoints specifies whether profiler endpoint filtering is enabled.
- profilerEndpoints bool
- // enabled reports whether tracing is enabled.
- enabled bool
- }
- // HasFeature reports whether feature f is enabled.
- func (c *config) HasFeature(f string) bool {
- _, ok := c.featureFlags[strings.TrimSpace(f)]
- return ok
- }
- // StartOption represents a function that can be provided as a parameter to Start.
- type StartOption func(*config)
- // forEachStringTag runs fn on every key:val pair encountered in str.
- // str may contain multiple key:val pairs separated by either space
- // or comma (but not a mixture of both).
- func forEachStringTag(str string, fn func(key string, val string)) {
- sep := " "
- if strings.Index(str, ",") > -1 {
- // falling back to comma as separator
- sep = ","
- }
- for _, tag := range strings.Split(str, sep) {
- tag = strings.TrimSpace(tag)
- if tag == "" {
- continue
- }
- kv := strings.SplitN(tag, ":", 2)
- key := strings.TrimSpace(kv[0])
- if key == "" {
- continue
- }
- var val string
- if len(kv) == 2 {
- val = strings.TrimSpace(kv[1])
- }
- fn(key, val)
- }
- }
- // maxPropagatedTagsLength limits the size of DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH to prevent HTTP 413 responses.
- const maxPropagatedTagsLength = 512
- // newConfig renders the tracer configuration based on defaults, environment variables
- // and passed user opts.
- func newConfig(opts ...StartOption) *config {
- c := new(config)
- c.sampler = NewAllSampler()
- c.agentURL = "http://" + resolveAgentAddr()
- c.httpClient = defaultHTTPClient()
- if url := internal.AgentURLFromEnv(); url != nil {
- if url.Scheme == "unix" {
- c.httpClient = udsClient(url.Path)
- } else {
- c.agentURL = url.String()
- }
- }
- if internal.BoolEnv("DD_TRACE_ANALYTICS_ENABLED", false) {
- globalconfig.SetAnalyticsRate(1.0)
- }
- if os.Getenv("DD_TRACE_REPORT_HOSTNAME") == "true" {
- var err error
- c.hostname, err = os.Hostname()
- if err != nil {
- log.Warn("unable to look up hostname: %v", err)
- }
- }
- if v := os.Getenv("DD_TRACE_SOURCE_HOSTNAME"); v != "" {
- c.hostname = v
- }
- if v := os.Getenv("DD_ENV"); v != "" {
- c.env = v
- }
- if v := os.Getenv("DD_TRACE_FEATURES"); v != "" {
- WithFeatureFlags(strings.FieldsFunc(v, func(r rune) bool {
- return r == ',' || r == ' '
- })...)(c)
- }
- if v := os.Getenv("DD_SERVICE"); v != "" {
- c.serviceName = v
- globalconfig.SetServiceName(v)
- }
- if ver := os.Getenv("DD_VERSION"); ver != "" {
- c.version = ver
- }
- if v := os.Getenv("DD_SERVICE_MAPPING"); v != "" {
- forEachStringTag(v, func(key, val string) { WithServiceMapping(key, val)(c) })
- }
- if v := os.Getenv("DD_TAGS"); v != "" {
- forEachStringTag(v, func(key, val string) { WithGlobalTag(key, val)(c) })
- }
- if _, ok := os.LookupEnv("AWS_LAMBDA_FUNCTION_NAME"); ok {
- // AWS_LAMBDA_FUNCTION_NAME being set indicates that we're running in an AWS Lambda environment.
- // See: https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html
- c.logToStdout = true
- }
- c.logStartup = internal.BoolEnv("DD_TRACE_STARTUP_LOGS", true)
- c.runtimeMetrics = internal.BoolEnv("DD_RUNTIME_METRICS_ENABLED", false)
- c.debug = internal.BoolEnv("DD_TRACE_DEBUG", false)
- c.enabled = internal.BoolEnv("DD_TRACE_ENABLED", true)
- c.profilerEndpoints = internal.BoolEnv(traceprof.EndpointEnvVar, true)
- c.profilerHotspots = internal.BoolEnv(traceprof.CodeHotspotsEnvVar, true)
- for _, fn := range opts {
- fn(c)
- }
- WithGlobalTag(ext.RuntimeID, globalconfig.RuntimeID())(c)
- if c.env == "" {
- if v, ok := c.globalTags["env"]; ok {
- if e, ok := v.(string); ok {
- c.env = e
- }
- }
- }
- if c.version == "" {
- if v, ok := c.globalTags["version"]; ok {
- if ver, ok := v.(string); ok {
- c.version = ver
- }
- }
- }
- if c.serviceName == "" {
- if v, ok := c.globalTags["service"]; ok {
- if s, ok := v.(string); ok {
- c.serviceName = s
- globalconfig.SetServiceName(s)
- }
- } else {
- c.serviceName = filepath.Base(os.Args[0])
- }
- }
- if c.transport == nil {
- c.transport = newHTTPTransport(c.agentURL, c.httpClient)
- }
- if c.propagator == nil {
- envKey := "DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH"
- max := internal.IntEnv(envKey, defaultMaxTagsHeaderLen)
- if max < 0 {
- log.Warn("Invalid value %d for %s. Setting to 0.", max, envKey)
- max = 0
- }
- if max > maxPropagatedTagsLength {
- log.Warn("Invalid value %d for %s. Maximum allowed is %d. Setting to %d.", max, envKey, maxPropagatedTagsLength, maxPropagatedTagsLength)
- max = maxPropagatedTagsLength
- }
- c.propagator = NewPropagator(&PropagatorConfig{
- MaxTagsHeaderLen: max,
- })
- }
- if c.logger != nil {
- log.UseLogger(c.logger)
- }
- if c.debug {
- log.SetLevel(log.LevelDebug)
- }
- c.loadAgentFeatures()
- if c.statsdClient == nil {
- // configure statsd client
- addr := c.dogstatsdAddr
- if addr == "" {
- // no config defined address; use defaults
- addr = defaultDogstatsdAddr()
- }
- if agentport := c.agent.StatsdPort; agentport > 0 {
- // the agent reported a non-standard port
- host, _, err := net.SplitHostPort(addr)
- if err == nil {
- // we have a valid host:port address; replace the port because
- // the agent knows better
- if host == "" {
- host = defaultHostname
- }
- addr = net.JoinHostPort(host, strconv.Itoa(agentport))
- }
- // not a valid TCP address, leave it as it is (could be a socket connection)
- }
- c.dogstatsdAddr = addr
- }
- return c
- }
- func newStatsdClient(c *config) (statsdClient, error) {
- if c.statsdClient != nil {
- return c.statsdClient, nil
- }
- client, err := statsd.New(c.dogstatsdAddr, statsd.WithMaxMessagesPerPayload(40), statsd.WithTags(statsTags(c)))
- if err != nil {
- return &statsd.NoOpClient{}, err
- }
- return client, nil
- }
- // defaultHTTPClient returns the default http.Client to start the tracer with.
- func defaultHTTPClient() *http.Client {
- if _, err := os.Stat(defaultSocketAPM); err == nil {
- // we have the UDS socket file, use it
- return udsClient(defaultSocketAPM)
- }
- return defaultClient
- }
- // udsClient returns a new http.Client which connects using the given UDS socket path.
- func udsClient(socketPath string) *http.Client {
- return &http.Client{
- Transport: &http.Transport{
- Proxy: http.ProxyFromEnvironment,
- DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
- return defaultDialer.DialContext(ctx, "unix", (&net.UnixAddr{
- Name: socketPath,
- Net: "unix",
- }).String())
- },
- MaxIdleConns: 100,
- IdleConnTimeout: 90 * time.Second,
- TLSHandshakeTimeout: 10 * time.Second,
- ExpectContinueTimeout: 1 * time.Second,
- },
- Timeout: defaultHTTPTimeout,
- }
- }
- // defaultDogstatsdAddr returns the default connection address for Dogstatsd.
- func defaultDogstatsdAddr() string {
- envHost, envPort := os.Getenv("DD_AGENT_HOST"), os.Getenv("DD_DOGSTATSD_PORT")
- if _, err := os.Stat(defaultSocketDSD); err == nil && envHost == "" && envPort == "" {
- // socket exists and user didn't specify otherwise via env vars
- return "unix://" + defaultSocketDSD
- }
- host, port := defaultHostname, "8125"
- if envHost != "" {
- host = envHost
- }
- if envPort != "" {
- port = envPort
- }
- return net.JoinHostPort(host, port)
- }
- // agentFeatures holds information about the trace-agent's capabilities.
- // When running WithLambdaMode, a zero-value of this struct will be used
- // as features.
- type agentFeatures struct {
- // DropP0s reports whether it's ok for the tracer to not send any
- // P0 traces to the agent.
- DropP0s bool
- // Stats reports whether the agent can receive client-computed stats on
- // the /v0.6/stats endpoint.
- Stats bool
- // StatsdPort specifies the Dogstatsd port as provided by the agent.
- // If it's the default, it will be 0, which means 8125.
- StatsdPort int
- // featureFlags specifies all the feature flags reported by the trace-agent.
- featureFlags map[string]struct{}
- }
- // HasFlag reports whether the agent has set the feat feature flag.
- func (a *agentFeatures) HasFlag(feat string) bool {
- _, ok := a.featureFlags[feat]
- return ok
- }
- // loadAgentFeatures queries the trace-agent for its capabilities and updates
- // the tracer's behaviour.
- func (c *config) loadAgentFeatures() {
- c.agent = agentFeatures{}
- if c.logToStdout {
- // there is no agent; all features off
- return
- }
- resp, err := c.httpClient.Get(fmt.Sprintf("%s/info", c.agentURL))
- if err != nil {
- log.Error("Loading features: %v", err)
- return
- }
- if resp.StatusCode == http.StatusNotFound {
- // agent is older than 7.28.0, features not discoverable
- return
- }
- defer resp.Body.Close()
- type infoResponse struct {
- Endpoints []string `json:"endpoints"`
- ClientDropP0s bool `json:"client_drop_p0s"`
- StatsdPort int `json:"statsd_port"`
- FeatureFlags []string `json:"feature_flags"`
- }
- var info infoResponse
- if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
- log.Error("Decoding features: %v", err)
- return
- }
- c.agent.DropP0s = info.ClientDropP0s
- c.agent.StatsdPort = info.StatsdPort
- for _, endpoint := range info.Endpoints {
- switch endpoint {
- case "/v0.6/stats":
- c.agent.Stats = true
- }
- }
- c.agent.featureFlags = make(map[string]struct{}, len(info.FeatureFlags))
- for _, flag := range info.FeatureFlags {
- c.agent.featureFlags[flag] = struct{}{}
- }
- }
- func (c *config) canComputeStats() bool {
- return c.agent.Stats && c.HasFeature("discovery")
- }
- func (c *config) canDropP0s() bool {
- return c.canComputeStats() && c.agent.DropP0s
- }
- func statsTags(c *config) []string {
- tags := []string{
- "lang:go",
- "version:" + version.Tag,
- "lang_version:" + runtime.Version(),
- }
- if c.serviceName != "" {
- tags = append(tags, "service:"+c.serviceName)
- }
- if c.env != "" {
- tags = append(tags, "env:"+c.env)
- }
- if c.hostname != "" {
- tags = append(tags, "host:"+c.hostname)
- }
- for k, v := range c.globalTags {
- if vstr, ok := v.(string); ok {
- tags = append(tags, k+":"+vstr)
- }
- }
- return tags
- }
- // withNoopStats is used for testing to disable statsd client
- func withNoopStats() StartOption {
- return func(c *config) {
- c.statsdClient = &statsd.NoOpClient{}
- }
- }
- // WithFeatureFlags specifies a set of feature flags to enable. Please take into account
- // that most, if not all features flags are considered to be experimental and result in
- // unexpected bugs.
- func WithFeatureFlags(feats ...string) StartOption {
- return func(c *config) {
- if c.featureFlags == nil {
- c.featureFlags = make(map[string]struct{}, len(feats))
- }
- for _, f := range feats {
- c.featureFlags[strings.TrimSpace(f)] = struct{}{}
- }
- log.Info("FEATURES enabled: %v", feats)
- }
- }
- // WithLogger sets logger as the tracer's error printer.
- func WithLogger(logger ddtrace.Logger) StartOption {
- return func(c *config) {
- c.logger = logger
- }
- }
- // WithPrioritySampling is deprecated, and priority sampling is enabled by default.
- // When using distributed tracing, the priority sampling value is propagated in order to
- // get all the parts of a distributed trace sampled.
- // To learn more about priority sampling, please visit:
- // https://docs.datadoghq.com/tracing/getting_further/trace_sampling_and_storage/#priority-sampling-for-distributed-tracing
- func WithPrioritySampling() StartOption {
- return func(c *config) {
- // This is now enabled by default.
- }
- }
- // WithDebugStack can be used to globally enable or disable the collection of stack traces when
- // spans finish with errors. It is enabled by default. This is a global version of the NoDebugStack
- // FinishOption.
- func WithDebugStack(enabled bool) StartOption {
- return func(c *config) {
- c.noDebugStack = !enabled
- }
- }
- // WithDebugMode enables debug mode on the tracer, resulting in more verbose logging.
- func WithDebugMode(enabled bool) StartOption {
- return func(c *config) {
- c.debug = enabled
- }
- }
- // WithLambdaMode enables lambda mode on the tracer, for use with AWS Lambda.
- func WithLambdaMode(enabled bool) StartOption {
- return func(c *config) {
- c.logToStdout = enabled
- }
- }
- // WithPropagator sets an alternative propagator to be used by the tracer.
- func WithPropagator(p Propagator) StartOption {
- return func(c *config) {
- c.propagator = p
- }
- }
- // WithServiceName is deprecated. Please use WithService.
- // If you are using an older version and you are upgrading from WithServiceName
- // to WithService, please note that WithService will determine the service name of
- // server and framework integrations.
- func WithServiceName(name string) StartOption {
- return func(c *config) {
- c.serviceName = name
- if globalconfig.ServiceName() != "" {
- log.Warn("ddtrace/tracer: deprecated config WithServiceName should not be used " +
- "with `WithService` or `DD_SERVICE`; integration service name will not be set.")
- }
- globalconfig.SetServiceName("")
- }
- }
- // WithService sets the default service name for the program.
- func WithService(name string) StartOption {
- return func(c *config) {
- c.serviceName = name
- globalconfig.SetServiceName(c.serviceName)
- }
- }
- // WithAgentAddr sets the address where the agent is located. The default is
- // localhost:8126. It should contain both host and port.
- func WithAgentAddr(addr string) StartOption {
- return func(c *config) {
- c.agentURL = "http://" + addr
- }
- }
- // WithEnv sets the environment to which all traces started by the tracer will be submitted.
- // The default value is the environment variable DD_ENV, if it is set.
- func WithEnv(env string) StartOption {
- return func(c *config) {
- c.env = env
- }
- }
- // WithServiceMapping determines service "from" to be renamed to service "to".
- // This option is is case sensitive and can be used multiple times.
- func WithServiceMapping(from, to string) StartOption {
- return func(c *config) {
- if c.serviceMappings == nil {
- c.serviceMappings = make(map[string]string)
- }
- c.serviceMappings[from] = to
- }
- }
- // WithGlobalTag sets a key/value pair which will be set as a tag on all spans
- // created by tracer. This option may be used multiple times.
- func WithGlobalTag(k string, v interface{}) StartOption {
- return func(c *config) {
- if c.globalTags == nil {
- c.globalTags = make(map[string]interface{})
- }
- c.globalTags[k] = v
- }
- }
- // WithSampler sets the given sampler to be used with the tracer. By default
- // an all-permissive sampler is used.
- func WithSampler(s Sampler) StartOption {
- return func(c *config) {
- c.sampler = s
- }
- }
- // WithHTTPRoundTripper is deprecated. Please consider using WithHTTPClient instead.
- // The function allows customizing the underlying HTTP transport for emitting spans.
- func WithHTTPRoundTripper(r http.RoundTripper) StartOption {
- return WithHTTPClient(&http.Client{
- Transport: r,
- Timeout: defaultHTTPTimeout,
- })
- }
- // WithHTTPClient specifies the HTTP client to use when emitting spans to the agent.
- func WithHTTPClient(client *http.Client) StartOption {
- return func(c *config) {
- c.httpClient = client
- }
- }
- // WithUDS configures the HTTP client to dial the Datadog Agent via the specified Unix Domain Socket path.
- func WithUDS(socketPath string) StartOption {
- return WithHTTPClient(udsClient(socketPath))
- }
- // WithAnalytics allows specifying whether Trace Search & Analytics should be enabled
- // for integrations.
- func WithAnalytics(on bool) StartOption {
- return func(cfg *config) {
- if on {
- globalconfig.SetAnalyticsRate(1.0)
- } else {
- globalconfig.SetAnalyticsRate(math.NaN())
- }
- }
- }
- // WithAnalyticsRate sets the global sampling rate for sampling APM events.
- func WithAnalyticsRate(rate float64) StartOption {
- return func(_ *config) {
- if rate >= 0.0 && rate <= 1.0 {
- globalconfig.SetAnalyticsRate(rate)
- } else {
- globalconfig.SetAnalyticsRate(math.NaN())
- }
- }
- }
- // WithRuntimeMetrics enables automatic collection of runtime metrics every 10 seconds.
- func WithRuntimeMetrics() StartOption {
- return func(cfg *config) {
- cfg.runtimeMetrics = true
- }
- }
- // WithDogstatsdAddress specifies the address to connect to for sending metrics to the Datadog
- // Agent. It should be a "host:port" string, or the path to a unix domain socket.If not set, it
- // attempts to determine the address of the statsd service according to the following rules:
- // 1. Look for /var/run/datadog/dsd.socket and use it if present. IF NOT, continue to #2.
- // 2. The host is determined by DD_AGENT_HOST, and defaults to "localhost"
- // 3. The port is retrieved from the agent. If not present, it is determined by DD_DOGSTATSD_PORT, and defaults to 8125
- //
- // This option is in effect when WithRuntimeMetrics is enabled.
- func WithDogstatsdAddress(addr string) StartOption {
- return func(cfg *config) {
- cfg.dogstatsdAddr = addr
- }
- }
- // WithSamplingRules specifies the sampling rates to apply to spans based on the
- // provided rules.
- func WithSamplingRules(rules []SamplingRule) StartOption {
- return func(cfg *config) {
- for _, rule := range rules {
- if rule.ruleType == SamplingRuleSpan {
- cfg.spanRules = append(cfg.spanRules, rule)
- } else {
- cfg.traceRules = append(cfg.traceRules, rule)
- }
- }
- }
- }
- // WithServiceVersion specifies the version of the service that is running. This will
- // be included in spans from this service in the "version" tag, provided that
- // span service name and config service name match. Do NOT use with WithUniversalVersion.
- func WithServiceVersion(version string) StartOption {
- return func(cfg *config) {
- cfg.version = version
- cfg.universalVersion = false
- }
- }
- // WithUniversalVersion specifies the version of the service that is running, and will be applied to all spans,
- // regardless of whether span service name and config service name match.
- // See: WithService, WithServiceVersion. Do NOT use with WithServiceVersion.
- func WithUniversalVersion(version string) StartOption {
- return func(c *config) {
- c.version = version
- c.universalVersion = true
- }
- }
- // WithHostname allows specifying the hostname with which to mark outgoing traces.
- func WithHostname(name string) StartOption {
- return func(c *config) {
- c.hostname = name
- }
- }
- // WithTraceEnabled allows specifying whether tracing will be enabled
- func WithTraceEnabled(enabled bool) StartOption {
- return func(c *config) {
- c.enabled = enabled
- }
- }
- // WithLogStartup allows enabling or disabling the startup log.
- func WithLogStartup(enabled bool) StartOption {
- return func(c *config) {
- c.logStartup = enabled
- }
- }
- // WithProfilerCodeHotspots enables the code hotspots integration between the
- // tracer and profiler. This is done by automatically attaching pprof labels
- // called "span id" and "local root span id" when new spans are created. You
- // should not use these label names in your own code when this is enabled. The
- // enabled value defaults to the value of the
- // DD_PROFILING_CODE_HOTSPOTS_COLLECTION_ENABLED env variable or true.
- func WithProfilerCodeHotspots(enabled bool) StartOption {
- return func(c *config) {
- c.profilerHotspots = enabled
- }
- }
- // WithProfilerEndpoints enables the endpoints integration between the tracer
- // and profiler. This is done by automatically attaching a pprof label called
- // "trace endpoint" holding the resource name of the top-level service span if
- // its type is "http", "rpc" or "" (default). You should not use this label
- // name in your own code when this is enabled. The enabled value defaults to
- // the value of the DD_PROFILING_ENDPOINT_COLLECTION_ENABLED env variable or
- // true.
- func WithProfilerEndpoints(enabled bool) StartOption {
- return func(c *config) {
- c.profilerEndpoints = enabled
- }
- }
- // StartSpanOption is a configuration option for StartSpan. It is aliased in order
- // to help godoc group all the functions returning it together. It is considered
- // more correct to refer to it as the type as the origin, ddtrace.StartSpanOption.
- type StartSpanOption = ddtrace.StartSpanOption
- // Tag sets the given key/value pair as a tag on the started Span.
- func Tag(k string, v interface{}) StartSpanOption {
- return func(cfg *ddtrace.StartSpanConfig) {
- if cfg.Tags == nil {
- cfg.Tags = map[string]interface{}{}
- }
- cfg.Tags[k] = v
- }
- }
- // ServiceName sets the given service name on the started span. For example "http.server".
- func ServiceName(name string) StartSpanOption {
- return Tag(ext.ServiceName, name)
- }
- // ResourceName sets the given resource name on the started span. A resource could
- // be an SQL query, a URL, an RPC method or something else.
- func ResourceName(name string) StartSpanOption {
- return Tag(ext.ResourceName, name)
- }
- // SpanType sets the given span type on the started span. Some examples in the case of
- // the Datadog APM product could be "web", "db" or "cache".
- func SpanType(name string) StartSpanOption {
- return Tag(ext.SpanType, name)
- }
- var measuredTag = Tag(keyMeasured, 1)
- // Measured marks this span to be measured for metrics and stats calculations.
- func Measured() StartSpanOption {
- // cache a global instance of this tag: saves one alloc/call
- return measuredTag
- }
- // WithSpanID sets the SpanID on the started span, instead of using a random number.
- // If there is no parent Span (eg from ChildOf), then the TraceID will also be set to the
- // value given here.
- func WithSpanID(id uint64) StartSpanOption {
- return func(cfg *ddtrace.StartSpanConfig) {
- cfg.SpanID = id
- }
- }
- // ChildOf tells StartSpan to use the given span context as a parent for the
- // created span.
- func ChildOf(ctx ddtrace.SpanContext) StartSpanOption {
- return func(cfg *ddtrace.StartSpanConfig) {
- cfg.Parent = ctx
- }
- }
- // withContext associates the ctx with the span.
- func withContext(ctx context.Context) StartSpanOption {
- return func(cfg *ddtrace.StartSpanConfig) {
- cfg.Context = ctx
- }
- }
- // StartTime sets a custom time as the start time for the created span. By
- // default a span is started using the creation time.
- func StartTime(t time.Time) StartSpanOption {
- return func(cfg *ddtrace.StartSpanConfig) {
- cfg.StartTime = t
- }
- }
- // AnalyticsRate sets a custom analytics rate for a span. It decides the percentage
- // of events that will be picked up by the App Analytics product. It's represents a
- // float64 between 0 and 1 where 0.5 would represent 50% of events.
- func AnalyticsRate(rate float64) StartSpanOption {
- if math.IsNaN(rate) {
- return func(cfg *ddtrace.StartSpanConfig) {}
- }
- return Tag(ext.EventSampleRate, rate)
- }
- // FinishOption is a configuration option for FinishSpan. It is aliased in order
- // to help godoc group all the functions returning it together. It is considered
- // more correct to refer to it as the type as the origin, ddtrace.FinishOption.
- type FinishOption = ddtrace.FinishOption
- // FinishTime sets the given time as the finishing time for the span. By default,
- // the current time is used.
- func FinishTime(t time.Time) FinishOption {
- return func(cfg *ddtrace.FinishConfig) {
- cfg.FinishTime = t
- }
- }
- // WithError marks the span as having had an error. It uses the information from
- // err to set tags such as the error message, error type and stack trace. It has
- // no effect if the error is nil.
- func WithError(err error) FinishOption {
- return func(cfg *ddtrace.FinishConfig) {
- cfg.Error = err
- }
- }
- // NoDebugStack prevents any error presented using the WithError finishing option
- // from generating a stack trace. This is useful in situations where errors are frequent
- // and performance is critical.
- func NoDebugStack() FinishOption {
- return func(cfg *ddtrace.FinishConfig) {
- cfg.NoDebugStack = true
- }
- }
- // StackFrames limits the number of stack frames included into erroneous spans to n, starting from skip.
- func StackFrames(n, skip uint) FinishOption {
- if n == 0 {
- return NoDebugStack()
- }
- return func(cfg *ddtrace.FinishConfig) {
- cfg.StackFrames = n
- cfg.SkipStackFrames = skip
- }
- }
- // UserMonitoringConfig is used to configure what is used to identify a user.
- // This configuration can be set by combining one or several UserMonitoringOption with a call to SetUser().
- type UserMonitoringConfig struct {
- PropagateID bool
- Email string
- Name string
- Role string
- SessionID string
- Scope string
- }
- // UserMonitoringOption represents a function that can be provided as a parameter to SetUser.
- type UserMonitoringOption func(*UserMonitoringConfig)
- // WithUserEmail returns the option setting the email of the authenticated user.
- func WithUserEmail(email string) UserMonitoringOption {
- return func(cfg *UserMonitoringConfig) {
- cfg.Email = email
- }
- }
- // WithUserName returns the option setting the name of the authenticated user.
- func WithUserName(name string) UserMonitoringOption {
- return func(cfg *UserMonitoringConfig) {
- cfg.Name = name
- }
- }
- // WithUserSessionID returns the option setting the session ID of the authenticated user.
- func WithUserSessionID(sessionID string) UserMonitoringOption {
- return func(cfg *UserMonitoringConfig) {
- cfg.SessionID = sessionID
- }
- }
- // WithUserRole returns the option setting the role of the authenticated user.
- func WithUserRole(role string) UserMonitoringOption {
- return func(cfg *UserMonitoringConfig) {
- cfg.Role = role
- }
- }
- // WithUserScope returns the option setting the scope (authorizations) of the authenticated user.
- func WithUserScope(scope string) UserMonitoringOption {
- return func(cfg *UserMonitoringConfig) {
- cfg.Scope = scope
- }
- }
- // WithPropagation returns the option allowing the user id to be propagated through distributed traces.
- // The user id is base64 encoded and added to the datadog propagated tags header.
- // This option should only be used if you are certain that the user id passed to `SetUser()` does not contain any
- // personal identifiable information or any kind of sensitive data, as it will be leaked to other services.
- func WithPropagation() UserMonitoringOption {
- return func(cfg *UserMonitoringConfig) {
- cfg.PropagateID = true
- }
- }
|