datadog

package module
v0.0.0-...-2043312 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 7, 2018 License: Apache-2.0 Imports: 24 Imported by: 0

README

datadog

GoDoc Build Status

datadog opentracing implementation. For more information on opentracing and the terminology, take a look at the OpenTracing Project.

Requirements:

  • Go 1.7
  • docker-dd-agent

Installation

go get github.com/savaki/datadog
Singleton initialization

The simplest starting point is to register datadog as the default tracer.

package main

import (
	"github.com/opentracing/opentracing-go"
	"github.com/savaki/datadog"
)

func main() {
	tracer, _ := datadog.New("service")
	defer tracer.Close()

	opentracing.SetGlobalTracer(tracer)

	// ...
}

Alternately, you can manage the reference to Tracer explicitly.

By default, the datadog tracer will connect to the datadog agent at localhost:8126

Specify the host and port of the datadog agent
func main() {
	tracer, _ := datadog.New("service", 
		datadog.WithHost("10.0.0.1"), 
		datadog.WithPort("8200"), 
	) 
	defer tracer.Close()
}
From within an ECS container, specify a docker-dd-agent running on the host
func main() {
	tracer, _ := datadog.New("service", datadog.WithECS())
	defer tracer.Close()
}
Specifying Datadog Resource

Unlike the opentracing default, datadog has a notion of resource. Resource can be defined in two ways:

span := opentracing.StartSpan("operation_name", datadog.Resource("/"))
span := opentracing.StartSpan("operation_name")
span.SetTag(ext.Resource, "/foo")
Specifying Datadog service type

Datadog has a number of default service, types: web, cache, db, and rpc. By default, the datadog tracer defaults the type to web. To override this you can do either of the following:

span := opentracing.StartSpan("operation_name", datadog.Type(datadog.TypeRPC))
span := opentracing.StartSpan("operation_name")
span.SetTag(ext.Type, "custom")
Handling Errors

Errors can be propagated to datadog in a couple ways:

Via Tag:

span := opentracing.StartSpan("operation_name")
span.SetTag(ext.Error, error)

Via LogFields:

span := opentracing.StartSpan("operation_name")
span.LogFields(log.Error(err))

Via LogKV:

span := opentracing.StartSpan("operation_name")
span.LogKV("err", err)
Starting an empty trace by creating a "root span"

It's always possible to create a "root" Span with no parent or other causal reference.

    func xyz() {
        ...
        sp := opentracing.StartSpan("operation_name")
        defer sp.Finish()
        ...
    }
Creating a (child) Span given an existing (parent) Span
    func xyz(parentSpan opentracing.Span, ...) {
        ...
        sp := opentracing.StartSpan(
            "operation_name",
            opentracing.ChildOf(parentSpan.Context()))
        defer sp.Finish()
        ...
    }
Serializing over http

As a convenience, the datadog tracer provides a couple of convenience methods above the standard opentracing Inject/Extract.

Instrument an http client with the datadog tracer.

client := &http.Client{
	Transport: datadog.WrapRoundTripper(http.DefaultRoundTripper, tracer),
}

Instrument an http server with the datadog tracer.

var h http.Handler = ....
h = datadog.WrapHandler(h, tracer)

Logging

By default, datadog logs to os.Stdout via the datadog.Stdout logger.

Using a custom logger

You can use a custom logger by specifying WithLogger when you construct the datadog tracer.

For example:


func main() {
	tracer, _ := datadog.New("service", datadog.WithLogger(datadog.Stderr))
	defer tracer.Close()
}

Todo

  • allow direct posts of traces to datadog e.g. agent-free tracer
  • integration datadog log api
  • allow direct posts of logs to datadog

Documentation

Index

Constants

View Source
const (
	// EnvAgentHost specifies optional environment property to specify datadog agent host
	EnvAgentHost = "DATADOG_AGENT_HOST"

	// EnvAgentPort specifies optional environment property to specify datadog agent port
	EnvAgentPort = "DATADOG_AGENT_PORT"
)
View Source
const (
	// FlushInterval contains the default length of time between flushes
	FlushInterval = time.Second * 3

	// DefaultBufSize contains the number of Spans to cache
	DefaultThreshold = 8192
)
View Source
const (
	// TypeWeb indicates span handled by web server
	TypeWeb = "web"

	// TypeRPC indicates span handled by rpc server
	TypeRPC = "rpc"

	// TypeDB indicates span handles a DB connection
	TypeDB = "db"

	// TypeCache indicates span handles a Cache
	TypeCache = "cache"
)

Variables

View Source
var (
	// Stdout provides a default logger implementation that logs to os.Stdout
	Stdout = newLogger(os.Stdout, func() time.Time { return time.Now() })

	// Stderr provides a default logger implementation that logs to os.Stderr
	Stderr = newLogger(os.Stderr, func() time.Time { return time.Now() })
)

Functions

func WrapHandler

func WrapHandler(h http.Handler, tracer *Tracer) http.Handler

func WrapRoundTripper

func WrapRoundTripper(rt http.RoundTripper, tracer *Tracer) http.RoundTripper

Types

type LogContext

type LogContext interface {
	// Service provides the name of the service
	Service() string

	// EachBaggageItem allows baggage content to be returned
	ForeachBaggageItem(fn func(key, value string) bool)

	// ForeachTag allows tag values to be enumerated
	ForeachTag(fn func(key string, value interface{}) bool)
}

LogContext provides an abstraction for metadata to be passed to the Log

type Logger

type Logger interface {
	Log(logContext LogContext, fields ...log.Field)
}

Logger allows the logger to be specified

func MultiLogger

func MultiLogger(loggers ...Logger) Logger

MultiLogger allows logging messages to be sent to multiple loggers

type LoggerFunc

type LoggerFunc func(logContext LogContext, fields ...log.Field)

LoggerFunc provides a functional adapter to Logger

func (LoggerFunc) Log

func (fn LoggerFunc) Log(logContext LogContext, fields ...log.Field)

Log implements Logger

type Option

type Option interface {
	Apply(*options)
}

Option defines a functional configuration

func WithBaggageItem

func WithBaggageItem(key, value string) Option

WithBaggageItem allows root baggage to be specified that will propagate to all spans

func WithBufSize

func WithBufSize(n int) Option

WithBufSize configures the numbers of Spans to cache

func WithECSHost

func WithECSHost() Option

func WithHost

func WithHost(host string) Option

WithHost configures the target host

func WithLogSpans

func WithLogSpans() Option

func WithLogger

func WithLogger(logger Logger) Option

WithLogger allows the logger to be configured

func WithLoggerFunc

func WithLoggerFunc(logger LoggerFunc) Option

WithLogger allows the logger to be configured

func WithNop

func WithNop() Option

WithNop is provided primarily for testing. No traces will be published to datadog.

func WithPort

func WithPort(port string) Option

WithPort configures a target host

func WithTimeFunc

func WithTimeFunc(fn func() int64) Option

WithTimeFunc allows for custom calculations of time.Now().UnixNano()

func WithTransporter

func WithTransporter(transporter Transporter) Option

type Span

type Span struct {
	// contains filtered or unexported fields
}

Span references a dapper Span

func (*Span) BaggageItem

func (s *Span) BaggageItem(restrictedKey string) string

Gets the value for a baggage item given its key. Returns the empty string if the value isn't found in this *Span.

func (*Span) Context

func (s *Span) Context() opentracing.SpanContext

Context() yields the SpanContext for this *Span. Note that the return value of Context() is still valid after a call to Span.Finish(), as is a call to Span.Context() after a call to Span.Finish().

func (*Span) Finish

func (s *Span) Finish()

Sets the end timestamp and finalizes *Span state.

With the exception of calls to Context() (which are always allowed), Finish() must be the last call made to any span instance, and to do otherwise leads to undefined behavior.

func (*Span) FinishWithOptions

func (s *Span) FinishWithOptions(opts opentracing.FinishOptions)

FinishWithOptions is like Finish() but with explicit control over timestamps and log data.

func (*Span) ForeachBaggageItem

func (s *Span) ForeachBaggageItem(fn func(k, v string) bool)

ForeachBaggageItem implements SpanContext and LogContext

func (*Span) ForeachTag

func (s *Span) ForeachTag(fn func(k string, v interface{}) bool)

ForeachTag implements LogContext

func (*Span) Log deprecated

func (s *Span) Log(data opentracing.LogData)

Deprecated: use LogFields or LogKV

func (*Span) LogEvent deprecated

func (s *Span) LogEvent(event string)

Deprecated: use LogFields or LogKV

func (*Span) LogEventWithPayload deprecated

func (s *Span) LogEventWithPayload(event string, payload interface{})

Deprecated: use LogFields or LogKV

func (*Span) LogFields

func (s *Span) LogFields(fields ...log.Field)

LogFields is an efficient and type-checked way to record key:value logging data about a Span, though the programming interface is a little more verbose than LogKV(). Here's an example:

span.LogFields(
    log.String("event", "soft error"),
    log.String("type", "cache timeout"),
    log.Int("waited.millis", 1500))

Also see Span.FinishWithOptions() and FinishOptions.BulkLogData.

func (*Span) LogKV

func (s *Span) LogKV(alternatingKeyValues ...interface{})

LogKV is a concise, readable way to record key:value logging data about a Span, though unfortunately this also makes it less efficient and less type-safe than LogFields(). Here's an example:

span.LogKV(
    "event", "soft error",
    "type", "cache timeout",
    "waited.millis", 1500)

For LogKV (as opposed to LogFields()), the parameters must appear as key-value pairs, like

span.LogKV(key1, val1, key2, val2, key3, val3, ...)

The keys must all be strings. The values may be strings, numeric types, bools, Go error instances, or arbitrary structs.

(Note to implementors: consider the log.InterleavedKVToFields() helper)

func (*Span) Service

func (s *Span) Service() string

Service implements LogContext

func (*Span) SetBaggageItem

func (s *Span) SetBaggageItem(restrictedKey, value string) opentracing.Span

SetBaggageItem sets a key:value pair on this *Span and its *SpanContext that also propagates to descendants of this *Span.

SetBaggageItem() enables powerful functionality given a full-stack opentracing integration (e.g., arbitrary application data from a mobile app can make it, transparently, all the way into the depths of a storage system), and with it some powerful costs: use this feature with care.

IMPORTANT NOTE #1: SetBaggageItem() will only propagate baggage items to *future* causal descendants of the associated Span.

IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and value is copied into every local *and remote* child of the associated Span, and that can add up to a lot of network and cpu overhead.

Returns a reference to this *Span for chaining.

func (*Span) SetOperationName

func (s *Span) SetOperationName(operationName string) opentracing.Span

Sets or changes the operation name.

func (*Span) SetTag

func (s *Span) SetTag(key string, value interface{}) opentracing.Span

Adds a tag to the span.

If there is a pre-existing tag set for `key`, it is overwritten.

Tag values can be numeric types, strings, or bools. The behavior of other tag value types is undefined at the OpenTracing level. If a tracing system does not know how to handle a particular value type, it may ignore the tag, but shall not panic.

func (*Span) Tracer

func (s *Span) Tracer() opentracing.Tracer

Provides access to the Tracer that created this *Span.

type StartSpanOption

type StartSpanOption interface {
	Apply(opts *opentracing.StartSpanOptions)
}

func Resource

func Resource(r string) StartSpanOption

Resource specifies the resource being accessed

func Service

func Service(s string) StartSpanOption

Service overrides the name of the service

func Type

func Type(t string) StartSpanOption

Type specifies the type of service: web, rpc, cache, db, etc

type Trace

type Trace struct {
	TraceID      uint64            `json:"trace_id"`
	SpanID       uint64            `json:"span_id"`
	Name         string            `json:"name"`
	Resource     string            `json:"resource"`
	Service      string            `json:"service"`
	Type         string            `json:"type"`
	Start        int64             `json:"start"`
	Duration     int64             `json:"duration"`
	ParentSpanID uint64            `json:"parent_id"`
	Error        int32             `json:"error"`
	Meta         map[string]string `json:"meta,omitempty"`
}

type Tracer

type Tracer struct {
	// contains filtered or unexported fields
}

Tracer is a simple, thin interface for Span creation and SpanContext propagation.

func New

func New(service string, opts ...Option) (*Tracer, error)

New constructs a new datadog tracer for the specified service. See https://docs.datadoghq.com/tracing/api/

func (*Tracer) Close

func (t *Tracer) Close() error

func (*Tracer) Extract

func (t *Tracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error)

Extract() returns a SpanContext instance given `format` and `carrier`.

OpenTracing defines a common set of `format` values (see BuiltinFormat), and each has an expected carrier type.

Other packages may declare their own `format` values, much like the keys used by `context.Context` (see https://godoc.org/golang.org/x/net/context#WithValue).

Example usage (with StartSpan):

carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)

// ... assuming the ultimate goal here is to resume the trace with a
// server-side Span:
var serverSpan opentracing.Span
if err == nil {
    span = tracer.StartSpan(
        rpcMethodName, ext.RPCServerOption(clientContext))
} else {
    span = tracer.StartSpan(rpcMethodName)
}

NOTE: All opentracing.Tracer implementations MUST support all BuiltinFormats.

Return values:

  • A successful Extract returns a SpanContext instance and a nil error
  • If there was simply no SpanContext to extract in `carrier`, Extract() returns (nil, opentracing.ErrSpanContextNotFound)
  • If `format` is unsupported or unrecognized, Extract() returns (nil, opentracing.ErrUnsupportedFormat)
  • If there are more fundamental problems with the `carrier` object, Extract() may return opentracing.ErrInvalidCarrier, opentracing.ErrSpanContextCorrupted, or implementation-specific errors.

See Tracer.Inject().

func (*Tracer) Flush

func (t *Tracer) Flush()

func (*Tracer) Inject

func (t *Tracer) Inject(sm opentracing.SpanContext, format interface{}, carrier interface{}) error

Inject() takes the `sm` SpanContext instance and injects it for propagation within `carrier`. The actual type of `carrier` depends on the value of `format`.

OpenTracing defines a common set of `format` values (see BuiltinFormat), and each has an expected carrier type.

Other packages may declare their own `format` values, much like the keys used by `context.Context` (see https://godoc.org/golang.org/x/net/context#WithValue).

Example usage (sans error handling):

carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
err := tracer.Inject(
    span.Context(),
    opentracing.HTTPHeaders,
    carrier)

NOTE: All opentracing.Tracer implementations MUST support all BuiltinFormats.

Implementations may return opentracing.ErrUnsupportedFormat if `format` is not supported by (or not known by) the implementation.

Implementations may return opentracing.ErrInvalidCarrier or any other implementation-specific error if the format is supported but injection fails anyway.

See Tracer.Extract().

func (*Tracer) LogFields

func (t *Tracer) LogFields(fields ...log.Field)

LogFields allows logging outside the scope of a span

func (*Tracer) StartSpan

func (t *Tracer) StartSpan(operationName string, opts ...opentracing.StartSpanOption) opentracing.Span

Create, start, and return a new Span with the given `operationName` and incorporate the given StartSpanOption `opts`. (Note that `opts` borrows from the "functional options" pattern, per http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis)

A Span with no SpanReference options (e.g., opentracing.ChildOf() or opentracing.FollowsFrom()) becomes the root of its own trace.

Examples:

var tracer opentracing.Tracer = ...

// The root-span case:
sp := tracer.StartSpan("GetFeed")

// The vanilla child span case:
sp := tracer.StartSpan(
    "GetFeed",
    opentracing.ChildOf(parentSpan.Context()))

// All the bells and whistles:
sp := tracer.StartSpan(
    "GetFeed",
    opentracing.ChildOf(parentSpan.Context()),
    opentracing.Tag{"user_agent", loggedReq.UserAgent},
    opentracing.StartTime(loggedReq.Timestamp),
)

type Transporter

type Transporter interface {
	Publish(groups [][]*Trace) error
}

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL