1
0
Fork 0

Cherry pick v1.7 into master

This commit is contained in:
Ludovic Fernandez 2018-11-19 16:40:03 +01:00 committed by Traefiker Bot
parent a09dfa3ce1
commit b6498cdcbc
73 changed files with 6573 additions and 186 deletions

View file

@ -88,6 +88,9 @@ type FinishConfig struct {
// Error holds an optional error that should be set on the span before
// finishing.
Error error
// NoDebugStack will prevent any set errors from generating an attached stack trace tag.
NoDebugStack bool
}
// StartSpanConfig holds the configuration for starting a new span. It is usually passed

View file

@ -1,19 +1,70 @@
package ext // import "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
// App types determine how to categorize a trace in the Datadog application.
// For more fine-grained behaviour, use the SpanType* constants.
const (
// DEPRECATED: Use SpanTypeWeb
// AppTypeWeb specifies the Web span type and can be used as a tag value
// for a span's SpanType tag.
AppTypeWeb = "web"
// AppTypeDB specifies the DB span type and can be used as a tag value
// for a span's SpanType tag.
// for a span's SpanType tag. If possible, use one of the SpanType*
// constants for a more accurate indication.
AppTypeDB = "db"
// AppTypeCache specifies the Cache span type and can be used as a tag value
// for a span's SpanType tag.
// for a span's SpanType tag. If possible, consider using SpanTypeRedis or
// SpanTypeMemcached.
AppTypeCache = "cache"
// AppTypeRPC specifies the RPC span type and can be used as a tag value
// for a span's SpanType tag.
AppTypeRPC = "rpc"
)
// Span types have similar behaviour to "app types" and help categorize
// traces in the Datadog application. They can also help fine grain agent
// level bahviours such as obfuscation and quantization, when these are
// enabled in the agent's configuration.
const (
// SpanTypeWeb marks a span as an HTTP server request.
SpanTypeWeb = "web"
// SpanTypeHTTP marks a span as an HTTP client request.
SpanTypeHTTP = "http"
// SpanTypeSQL marks a span as an SQL operation. These spans may
// have an "sql.command" tag.
SpanTypeSQL = "sql"
// SpanTypeCassandra marks a span as a Cassandra operation. These
// spans may have an "sql.command" tag.
SpanTypeCassandra = "cassandra"
// SpanTypeRedis marks a span as a Redis operation. These spans may
// also have a "redis.raw_command" tag.
SpanTypeRedis = "redis"
// SpanTypeMemcached marks a span as a memcached operation.
SpanTypeMemcached = "memcached"
// SpanTypeMongoDB marks a span as a MongoDB operation.
SpanTypeMongoDB = "mongodb"
// SpanTypeElasticSearch marks a span as an ElasticSearch operation.
// These spans may also have an "elasticsearch.body" tag.
SpanTypeElasticSearch = "elasticsearch"
// SpanTypeLevelDB marks a span as a leveldb operation
SpanTypeLevelDB = "leveldb"
// SpanTypeDNS marks a span as a DNS operation.
SpanTypeDNS = "dns"
// SpanTypeMessageConsumer marks a span as a queue operation
SpanTypeMessageConsumer = "queue"
// SpanTypeMessageProducer marks a span as a queue operation.
SpanTypeMessageProducer = "queue"
)

View file

@ -0,0 +1,16 @@
package ext
const (
// DBApplication indicates the application using the database.
DBApplication = "db.application"
// DBName indicates the database name.
DBName = "db.name"
// DBType indicates the type of Database.
DBType = "db.type"
// DBInstance indicates the instance name of Database.
DBInstance = "db.instance"
// DBUser indicates the user name of Database, e.g. "readonly_user" or "reporting_user".
DBUser = "db.user"
// DBStatement records a database statement for the given database type.
DBStatement = "db.statement"
)

View file

@ -0,0 +1,14 @@
package ext
const (
// PeerHostIPV4 records IPv4 host address of the peer.
PeerHostIPV4 = "peer.ipv4"
// PeerHostIPV6 records the IPv6 host address of the peer.
PeerHostIPV6 = "peer.ipv6"
// PeerService records the service name of the peer service.
PeerService = "peer.service"
// PeerHostname records the host name of the peer.
PeerHostname = "peer.hostname"
// PeerPort records the port number of the peer.
PeerPort = "peer.port"
)

View file

@ -27,6 +27,10 @@ const (
// HTTPURL sets the HTTP URL for a span.
HTTPURL = "http.url"
// TODO: In the next major version, suffix these constants (SpanType, etc)
// with "*Key" (SpanTypeKey, etc) to more easily differentiate between
// constants representing tag values and constants representing keys.
// SpanType defines the Span type (web, db, cache).
SpanType = "span.type"
@ -47,4 +51,7 @@ const (
// ErrorStack specifies the stack dump.
ErrorStack = "error.stack"
// Environment specifies the environment to use with a trace.
Environment = "env"
)

View file

@ -15,6 +15,10 @@ var (
func SetGlobalTracer(t ddtrace.Tracer) {
mu.Lock()
defer mu.Unlock()
if !Testing {
// avoid infinite loop when calling (*mocktracer.Tracer).Stop
globalTracer.Stop()
}
globalTracer = t
}

View file

@ -154,10 +154,19 @@ func FinishTime(t time.Time) FinishOption {
}
}
// WithError adds the given error to the span before marking it as finished. If it is
// nil it will be disregarded.
// 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.
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
}
}

View file

@ -81,7 +81,7 @@ func (s *span) SetTag(key string, value interface{}) {
return
}
if key == ext.Error {
s.setTagError(value)
s.setTagError(value, true)
return
}
if v, ok := value.(string); ok {
@ -99,7 +99,10 @@ func (s *span) SetTag(key string, value interface{}) {
// setTagError sets the error tag. It accounts for various valid scenarios.
// This method is not safe for concurrent use.
func (s *span) setTagError(value interface{}) {
func (s *span) setTagError(value interface{}, debugStack bool) {
if s.finished {
return
}
switch v := value.(type) {
case bool:
// bool value as per Opentracing spec.
@ -114,7 +117,9 @@ func (s *span) setTagError(value interface{}) {
s.Error = 1
s.Meta[ext.ErrorMsg] = v.Error()
s.Meta[ext.ErrorType] = reflect.TypeOf(v).String()
s.Meta[ext.ErrorStack] = string(debug.Stack())
if debugStack {
s.Meta[ext.ErrorStack] = string(debug.Stack())
}
case nil:
// no error
s.Error = 0
@ -166,7 +171,9 @@ func (s *span) Finish(opts ...ddtrace.FinishOption) {
t = cfg.FinishTime.UnixNano()
}
if cfg.Error != nil {
s.SetTag(ext.Error, cfg.Error)
s.Lock()
s.setTagError(cfg.Error, !cfg.NoDebugStack)
s.Unlock()
}
s.finish(t)
}

View file

@ -63,7 +63,7 @@ func (z *span) DecodeMsg(dc *msgp.Reader) (err error) {
if z.Meta == nil && zb0002 > 0 {
z.Meta = make(map[string]string, zb0002)
} else if len(z.Meta) > 0 {
for key, _ := range z.Meta {
for key := range z.Meta {
delete(z.Meta, key)
}
}
@ -90,7 +90,7 @@ func (z *span) DecodeMsg(dc *msgp.Reader) (err error) {
if z.Metrics == nil && zb0003 > 0 {
z.Metrics = make(map[string]float64, zb0003)
} else if len(z.Metrics) > 0 {
for key, _ := range z.Metrics {
for key := range z.Metrics {
delete(z.Metrics, key)
}
}

View file

@ -17,8 +17,7 @@ var _ TextMapReader = (*HTTPHeadersCarrier)(nil)
// Set implements TextMapWriter.
func (c HTTPHeadersCarrier) Set(key, val string) {
h := http.Header(c)
h.Add(key, val)
http.Header(c).Set(key, val)
}
// ForeachKey implements TextMapReader.
@ -166,12 +165,12 @@ func (p *propagator) extractTextMap(reader TextMapReader) (ddtrace.SpanContext,
key := strings.ToLower(k)
switch key {
case p.cfg.TraceHeader:
ctx.traceID, err = strconv.ParseUint(v, 10, 64)
ctx.traceID, err = parseUint64(v)
if err != nil {
return ErrSpanContextCorrupted
}
case p.cfg.ParentHeader:
ctx.spanID, err = strconv.ParseUint(v, 10, 64)
ctx.spanID, err = parseUint64(v)
if err != nil {
return ErrSpanContextCorrupted
}

View file

@ -64,9 +64,7 @@ func Start(opts ...StartOption) {
if internal.Testing {
return // mock tracer active
}
t := internal.GetGlobalTracer()
internal.SetGlobalTracer(newTracer(opts...))
t.Stop()
}
// Stop stops the started tracer. Subsequent calls are valid but become no-op.
@ -302,16 +300,10 @@ func (t *tracer) flushTraces() {
log.Printf("Sending payload: size: %d traces: %d\n", size, count)
}
err := t.config.transport.send(t.payload)
if err != nil && size > payloadMaxLimit {
// we couldn't send the payload and it is getting too big to be
// accepted by the agent, we have to drop it.
t.payload.reset()
if err != nil {
t.pushError(&dataLossError{context: err, count: count})
}
if err == nil {
// send succeeded
t.payload.reset()
}
t.payload.reset()
}
// flushErrors will process log messages that were queued

View file

@ -10,7 +10,9 @@ import (
"time"
)
var tracerVersion = "v1.0"
// TODO(gbbr): find a more effective way to keep this up to date,
// e.g. via `go generate`
var tracerVersion = "v1.5.0"
const (
defaultHostname = "localhost"
@ -57,16 +59,8 @@ func newHTTPTransport(addr string) *httpTransport {
"Datadog-Meta-Tracer-Version": tracerVersion,
"Content-Type": "application/msgpack",
}
host, port, _ := net.SplitHostPort(addr)
if host == "" {
host = defaultHostname
}
if port == "" {
port = defaultPort
}
addr = fmt.Sprintf("%s:%s", host, port)
return &httpTransport{
traceURL: fmt.Sprintf("http://%s/v0.3/traces", addr),
traceURL: fmt.Sprintf("http://%s/v0.3/traces", resolveAddr(addr)),
client: &http.Client{
// 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.
@ -118,3 +112,20 @@ func (t *httpTransport) send(p *payload) error {
}
return nil
}
// resolveAddr resolves the given agent address and fills in any missing host
// and port using the defaults.
func resolveAddr(addr string) string {
host, port, err := net.SplitHostPort(addr)
if err != nil {
// no port in addr
host = addr
}
if host == "" {
host = defaultHostname
}
if port == "" {
port = defaultPort
}
return fmt.Sprintf("%s:%s", host, port)
}

View file

@ -1,5 +1,10 @@
package tracer
import (
"strconv"
"strings"
)
// toFloat64 attempts to convert value into a float64. If it succeeds it returns
// the value and true, otherwise 0 and false.
func toFloat64(value interface{}) (f float64, ok bool) {
@ -30,3 +35,16 @@ func toFloat64(value interface{}) (f float64, ok bool) {
return 0, false
}
}
// parseUint64 parses a uint64 from either an unsigned 64 bit base-10 string
// or a signed 64 bit base-10 string representing an unsigned integer
func parseUint64(str string) (uint64, error) {
if strings.HasPrefix(str, "-") {
id, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return 0, err
}
return uint64(id), nil
}
return strconv.ParseUint(str, 10, 64)
}