Documentation ¶
Overview ¶
Package trace wraps standard tracing for outreach.
This package wraps honeycomb tracing ¶
Trace Initialization ¶
Applications should call `trace.StartTracing(serviceName)` and `trace.StopTracing()` in their `main` like so:
func main() { trace.StartTracing("example") defer trace.StopTracing() ... main app logic ... }
See https://github.com/getoutreach/gobox/blob/master/cmd/example/main.go.
Servers and incoming requests ¶
The httpx/pkg/handlers package wraps the required trace header parsing logic and so applications that use `handlers.Endpoint` do not have to do anything special here.
Custom http servers should wrap their request handling code like so:
trace.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) *roundtripperState { trace.StartSpan(r.Context(), "my endpoint") defer trace.End(r.Context()) ... do actual request handling ... }), "my endpoint")
Non-HTTP servers should wrap their request handling like so:
ctx = trace.StartSpan(ctx, "my endpoint") defer trace.End(ctx) ... do actual request handling ...
Clients should use a Client with the provided transport like so:
ctx = trace.StartSpan(ctx, "my call") defer trace.End(ctx) client := http.Client{Transport: trace.NewTransport(nil)} ... do actual call using the new client ...
Tracing calls ¶
Any interesting function (such as model fetches or redis fetches) should use the following pattern:
func MyInterestingRedisFunction(ctx context.Context, ...) error { ctx = trace.StartCall(ctx, "redis", RedisInfo{...}) defer trace.EndCall(ctx) .... actual work ... trace.AddInfo(ctx, xyzInfo) return trace.SetCallStatus(ctx, err) }
This automatically updates metrics ("call_request_secconds" is the counter with "redis" as the name label), writes to debug/error logs and also writes traces to our tracing infrastructure
Trace calls can be nested.
Creating spans ¶
Spans should rarely be needed but are available for when the metrics or default logging is not sufficient.
Spans are automatically considered `children` of the current trace or span (based on the `context`). The redis example above would look like so:
ctx = trace.StartSpan(ctx, "redis") defer trace.End(ctx) .... do actual redis call...
Adding tags ¶
Tags can be added to the `current` span (or trace or call) by simply calling `trace.AddInfo`. Note that this accepts the same types that logging accepts. For instance, to record an error with redis:
result, err := redis.Call(....) if err != nil { // if you are using trace.Call, then do trace.SetCallStatus // instead. return trace.Error(ctx, err) }
Index ¶
- Constants
- func AddInfo(ctx context.Context, args ...log.Marshaler)
- func AddSpanInfo(ctx context.Context, args ...log.Marshaler)
- func AsGRPCCall() call.Option
- func AsHTTPCall() call.Option
- func AsOutboundCall() call.Option
- func CloseTracer(ctx context.Context)
- func CommonProps() log.Marshaler
- func End(ctx context.Context)
- func EndCall(ctx context.Context)
- func EndTracing()deprecated
- func Error(ctx context.Context, err error) error
- func ForceTracing(ctx context.Context) context.Context
- func FromHeaders(ctx context.Context, hdrs map[string][]string, name string) context.Context
- func GetCallName(ctx context.Context) string
- func GetTraceStateSampleRate(ts trace.TraceState) (uint, bool)
- func ID(ctx context.Context) string
- func IDs(ctx context.Context) log.Marshaler
- func InitTracer(_ context.Context, serviceName string) error
- func IsInfoLoggingEnabled(ctx context.Context) bool
- func NewForceTraceHeaderSampler(delegate sdktrace.Sampler) sdktrace.Sampler
- func NewHandler(handler http.Handler, operation string, opts ...HandlerOption) http.Handler
- func NewHoneycombDeterministicSampler(sampleRate uint) sdktrace.Sampler
- func NewLogFileExporter(port int) (sdktrace.SpanExporter, error)
- func NewLogFileTracer(ctx context.Context, serviceName string, config *Config) (tracer, error)
- func NewOtelTracer(ctx context.Context, serviceName string, config *Config) (tracer, error)
- func NewSampleRateTaggingSampler(defaultSampleRate uint) sdktrace.Sampler
- func NewTransport(old http.RoundTripper) http.RoundTripper
- func ReevaluateLogging(ctx context.Context, resolver InfoLoggingResolver)
- func RegisterSpanProcessor(s sdktrace.SpanProcessor)
- func ResolvedLogging(logging InfoLoggingResolved) log.Marshaler
- func SetCallError(ctx context.Context, err error) error
- func SetCallStatus(ctx context.Context, err error) error
- func SetCallTypeGRPC(ctx context.Context) context.Contextdeprecated
- func SetCallTypeHTTP(ctx context.Context) context.Contextdeprecated
- func SetCallTypeOutbound(ctx context.Context) context.Contextdeprecated
- func SetCustomCallKind(ctx context.Context, ck metrics.CallKind)
- func SetSpanProcessorHook(hook func([]attribute.KeyValue))
- func SetTraceStateSampleRate(ts trace.TraceState, sampleRate uint) trace.TraceState
- func SpanID(ctx context.Context) string
- func StartCall(ctx context.Context, cType string, args ...log.Marshaler) context.Context
- func StartSpan(ctx context.Context, name string, args ...log.Marshaler) context.Context
- func StartSpanAsync(ctx context.Context, name string, args ...log.Marshaler) context.Contextdeprecated
- func StartSpanWithOptions(ctx context.Context, name string, opts []SpanStartOption, ...) context.Context
- func StartTrace(ctx context.Context, name string) context.Contextdeprecated
- func StartTracing(serviceName string) errordeprecated
- func ToHeaders(ctx context.Context) map[string][]string
- func WithCallOptions(ctx context.Context, opts CallOptions)
- func WithInfoLoggingDisabled() call.Option
- func WithInfoLoggingEnabled() call.Option
- func WithScheduledTime(t time.Time) call.Option
- type Annotator
- type CallOptions
- type Config
- type GlobalTags
- type Handler
- type HandlerOption
- type InfoLoggingResolved
- type InfoLoggingResolver
- type Link
- type LogFile
- type LogFileSpanExporter
- type Otel
- type SpanStartOption
Constants ¶
const ( // Header that enforces the tracing for particular request HeaderForceTracing = "X-Force-Trace" // Header used by OpenTelemetry to propagate traces OtelPropagationHeader = "Traceparent" )
Variables ¶
This section is empty.
Functions ¶
func AddInfo ¶
AddInfo updates the current span with the provided fields. If a call exists, it updates the call info args with the passed in log marshalers
This is not propagated to child spans automatically.
It does nothing if there isn't a current span.
func AddSpanInfo ¶ added in v1.21.0
AddSpanInfo updates the current span with the provided fields.
It does nothing if there isn't a current span.
func AsGRPCCall ¶ added in v1.31.0
AsGRPCCall changes the call type to gRPC. This SHOULD NOT be used for outbound calls to external services. Use AsOutboundCall instead.
func AsHTTPCall ¶ added in v1.31.0
AsHTTPCall changes the call type to HTTP. This SHOULD NOT be used for outbound calls to external services. Use AsOutboundCall instead.
func AsOutboundCall ¶ added in v1.31.0
AsOutboundCall changes the call type to Outbound. This is meant for calls to external services, such as a client making a call to a server.
func CloseTracer ¶
CloseTracer stops all tracing and sends any queued traces.
This should be called when an application is exiting, or when you want to terminate the tracer.
func CommonProps ¶ added in v1.66.0
CommonProps sets up common properties for traces in cli apps
func EndCall ¶
EndCall calculates the duration of the call, writes to metrics, standard logs and closes the trace span.
This call should always be right after the StartCall in a defer pattern. See StartCall for the right pattern of usage.
EndCall, when called within a defer, catches any panics and rethrows them. Any panics are converted to errors and cause error logging to happen (as do any SetCallStatus calls)
func EndTracing
deprecated
func EndTracing()
Deprecated: Use CloseTracer() instead. EndTracing stops the tracing infrastructure.
This should be called at the exit of the application.
func ForceTracing ¶
ForceTracing will enforce tracing for processing started with returned context and all downstream services that will be invoken on the way.
func FromHeaders ¶
FromHeaders fetches trace info from a headers map and starts a new Span on top of the extracted span context (which can be either local or remote). You must end this context with End.
Only use for GRPC. Prefer NewHandler for http calls.
func GetCallName ¶ added in v1.96.0
GetCallName returns name of the current call
func GetTraceStateSampleRate ¶ added in v1.85.1
func GetTraceStateSampleRate(ts trace.TraceState) (uint, bool)
GetTraceStateSampleRate fetches the sample rate from the tracestate.
The second return value is an `ok` bool that is false if the fetch fails.
func ID ¶
ID returns an ID for use with external services to propagate tracing context. The ID returned will be the honeycomb trace ID (if honeycomb is enabled) or an empty string if neither are enabled.
func IDs ¶ added in v1.20.0
IDs returns a log-compatible tracing scope (IDs) data built from the context suitable for logging.
func InitTracer ¶
InitTracer starts all tracing infrastructure.
This needs to be called before sending any traces otherwise they will not be published.
func IsInfoLoggingEnabled ¶ added in v1.98.0
IsInfoLoggingEnabled returns state of info logging
func NewForceTraceHeaderSampler ¶ added in v1.85.1
NewForceTraceHeaderSampler wraps an existing sampler with support for the X-Force-Trace header, with the help of the `isTracingForced` context flag.
func NewHandler ¶ added in v1.42.0
NewHandler creates a new handlers which reads propagated headers from the current trace context.
Supported options are:
- WithPublicEndpointFn conditionally configure the Handler to link the span with an incoming span context instead of child association. Useful for public facing endpoints that don't need to attach to externally defined traces
Usage:
trace.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) *roundtripperState { trace.StartSpan(r.Context(), "my endpoint") defer trace.End(r.Context()) ... do actual request handling ... }), "my endpoint")
func NewHoneycombDeterministicSampler ¶ added in v1.85.1
NewHoneycombDeterministicSampler returns a sampler that mimics the deterministic sampler behavior from Honeycomb's beeline libraries. This was formerly our primary sampler, but now we use it only for new local traces.
Our exact choice of sampling algorithm shouldn't matter in a world where every service respects parent-based sampling. However, we have a lot of old services that still have this HC deterministic sampler hard-coded, and so using this as our sampler reduces the odds of broken traces.
In the longer term, when every service supports parent-based sampling, we can stop caring which sampler we use for this case.
func NewLogFileExporter ¶ added in v1.66.0
func NewLogFileExporter(port int) (sdktrace.SpanExporter, error)
NewLogFileExporter Creates a new exporter that sends all spans to the passed in port on localhost.
func NewLogFileTracer ¶ added in v1.66.0
NewLogFileTracer initializes a tracer that sends traces to a log file.
func NewOtelTracer ¶ added in v1.66.0
NewOtelTracer creates and initializes a new otel tracer.
func NewSampleRateTaggingSampler ¶ added in v1.85.1
NewSampleRateTaggingSampler is a sampler that doesn't actually make sampling decisions. It simply inherits the decision from its parent. We used it not for decision-making, but to ensure all sampled spans include an appropriate "SampleRate" tag that Honeycomb can use for sample rate adjustment.
This is a hack. We hope that one day we can move to an official OpenTelemetry head-based sampling mechanism that handles this more cleanly. [1] At the time of writing, this part of the standard is in flux and not all OpenTelemetry libraries support it.
[1] https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling/
func NewTransport ¶
func NewTransport(old http.RoundTripper) http.RoundTripper
NewTransport creates a new transport which propagates the current trace context.
Usage:
client := &http.Client{Transport: trace.NewTransport(nil)} resp, err := client.Get("/ping")
For most cases, use the httpx/pkg/fetch package as it also logs the request, updates latency metrics and adds traces with full info
Note: the request context must be derived from StartSpan.
func ReevaluateLogging ¶ added in v1.98.0
func ReevaluateLogging(ctx context.Context, resolver InfoLoggingResolver)
func RegisterSpanProcessor ¶ added in v1.42.0
func RegisterSpanProcessor(s sdktrace.SpanProcessor)
func ResolvedLogging ¶ added in v1.98.0
func ResolvedLogging(logging InfoLoggingResolved) log.Marshaler
ResolvedLogging returns signals trace.EndCall whether to enable/disable info logging
func SetCallError ¶
SetCallError is deprecated and will directly call into SetCallStatus for backward compatibility
func SetCallStatus ¶
SetCallStatus can be optionally called to set status of the call. When the error occurs on the current call, the error will be traced. When the error is nil, no-op from this function
func SetCallTypeGRPC
deprecated
added in
v1.11.0
func SetCallTypeHTTP
deprecated
added in
v1.11.0
func SetCallTypeOutbound
deprecated
added in
v1.11.0
func SetCustomCallKind ¶ added in v1.76.0
SetCustomCallKind is meant to alter the Kind property of a traced call. This can be useful as a service specific dimension to slice, e.g. grpc_request_handled metric based on additional context.
func SetSpanProcessorHook ¶ added in v1.42.0
SetSpanProcessorHook sets a hook to run when a span ends
func SetTraceStateSampleRate ¶ added in v1.85.1
func SetTraceStateSampleRate(ts trace.TraceState, sampleRate uint) trace.TraceState
SetTraceStateSampleRate sets the sample rate in the tracestate.
func SpanID ¶ added in v1.53.0
SpanID returns the root tracing SpanID for use when it is needed to correlate the logs belonging to same flow. The SpanID returned will be the honeycomb trace SpanID (if honeycomb is enabled) or an empty string if neither are enabled
func StartCall ¶
StartCall is used to start an internal call. For external calls please use StartExternalCall.
This takes care of standard logging, metrics and tracing for "calls"
Typical usage:
ctx = trace.StartCall(ctx, "sql", SQLEvent{Query: ...}) defer trace.EndCall(ctx) return trace.SetCallStatus(ctx, sqlCall(...));
The callType should be broad category (such as "sql", "redis" etc) as as these are used for metrics and cardinality issues come into play. Do note that commonly used call types are exported as constants in this package and should be used whenever possible. The most common call types are http (trace.CallTypeHTTP) and grpc (trace.CallTypeGRPC).
Use the extra args to add stuff to traces and logs and these can have more information as needed (including actual queries for instance).
The log includes a initial Debug entry and a final Error entry if the call failed (but no IDs entry if the call succeeded). Success or failure is determined by whether there was a SetCallStatus or not. (Panics detected in EndCall are considered errors).
StartCalls can be nested.
func StartSpanAsync
deprecated
added in
v1.25.0
Deprecated: use StartSpan() instead. It will handle async traces automatically. StartSpanAsync starts a new async span.
An async span does not have to complete before the parent span completes.
Use trace.End to end this.
func StartSpanWithOptions ¶ added in v1.52.0
func StartSpanWithOptions(ctx context.Context, name string, opts []SpanStartOption, args ...log.Marshaler) context.Context
StartSpanWithOptions starts a new span, with extra start options (such as links to external spans).
Use trace.End to end this.
func StartTracing
deprecated
func ToHeaders ¶
ToHeaders writes the current trace context into a headers map
Only use for GRPC. Prefer NewTransport for http calls.
func WithCallOptions ¶ added in v1.70.0
func WithCallOptions(ctx context.Context, opts CallOptions)
SetCallOptions sets the provided call options on the current call in the provided context. The provided options replace any existing options. Call options are not preserved across application boundaries.
Example:
ctx = trace.StartCall(ctx, "http", trace.WithCallOptions(ctx, trace.CallOptions{DisableInfoLogging: true}))
func WithInfoLoggingDisabled ¶ added in v1.70.0
WithInfoLoggingDisabled disables info logging on the current call.
Note that the default behavior is configurable. If the info logs were already disabled by default, this will be a no-op.
Example:
ctx = trace.StartCall(ctx, "http", trace.WithInfoLoggingDisabled())
func WithInfoLoggingEnabled ¶ added in v1.80.0
WithInfoLoggingEnabled enables info logging on the current call
Note that the default behavior is configurable. If the info logs were already enabled by default, this will be a no-op.
Example:
ctx = trace.StartCall(ctx, "http", trace.WithInfoLoggingEnabled())
func WithScheduledTime ¶ added in v1.31.0
WithScheduledTime sets the call scheduled time to the provided time. Normally, this is set automatically by StartCall.
Example:
ctx = trace.StartCall(ctx, "http", log.F{"query": query}, trace.WithScheduledTime(time.Now()))
Types ¶
type Annotator ¶ added in v1.42.0
type Annotator struct {
// contains filtered or unexported fields
}
Annotator is a SpanProcessor that adds service-level tags on every span
func (Annotator) OnEnd ¶ added in v1.42.0
func (a Annotator) OnEnd(s sdktrace.ReadOnlySpan)
type CallOptions ¶ added in v1.70.0
CallOptions contains options for all tracing calls. See call.Options for more information.
type Config ¶
type Config struct { Otel `yaml:"OpenTelemetry"` LogFile LogFile `yaml:"LogFile"` GlobalTags `yaml:"GlobalTags,omitempty"` // LogCallByDefault determines info logs for non-error instances of // `trace.StartCall`. The behavior can be overridden by providing // explicit options to specific `trace.StartCall` invocations. A // `trace.StartCall` that ends in an error will always be logged. LogCallsByDefault bool `yaml:"LogCallsByDefault"` }
Config is the tracing config that gets read from trace.yaml
type GlobalTags ¶ added in v1.1.0
type GlobalTags struct {
DevEmail string `yaml:"DevEmail,omitempty"`
}
GlobalTags are tags that get included with every span
func (*GlobalTags) MarshalLog ¶ added in v1.1.0
func (g *GlobalTags) MarshalLog(addField func(key string, v interface{}))
MarshalLog ensures that GlobalTags have a valid value included
type HandlerOption ¶ added in v1.94.0
type HandlerOption func(*Handler)
func WithPublicEndpointFn ¶ added in v1.94.0
func WithPublicEndpointFn(fn func(*http.Request) bool) HandlerOption
type InfoLoggingResolved ¶ added in v1.98.0
type InfoLoggingResolved int32
const ( InfoLoggingDefault InfoLoggingResolved = 0 InfoLoggingEnabled InfoLoggingResolved = 1 InfoLoggingDisabled InfoLoggingResolved = 2 )
type InfoLoggingResolver ¶ added in v1.98.0
type InfoLoggingResolver = func(ctx context.Context, operation string) InfoLoggingResolved
type Link ¶ added in v1.53.0
type Link struct {
// contains filtered or unexported fields
}
Link implements SpanStartOption
func WithLink ¶ added in v1.52.0
WithLink links an external span to the current one. The link can only happen when trace span starts (they cannot be attached mid-span lifetime).
The caller should not modify the argument traceHeaders map after calling WithLink.
The method accepts trace headers as a map: assumption is current 'context' hosts the parent span and the linked contexts come from 'outside' by other means (e.g. clerk system event headers). In case you need to link trace with a span and you have direct access to that Span's context, you can use trace.ToHeaders to extract the same headers map.
type LogFile ¶ added in v1.66.0
type LogFile struct { // Enabled determines whether to turn on tracing to a log file Enabled bool `yaml:"Enabled"` // Port is the port used by the the logfile trace server Port int `yaml:"Port"` }
LogFile is the configuration for log file based tracing
type LogFileSpanExporter ¶ added in v1.66.0
type LogFileSpanExporter struct {
// contains filtered or unexported fields
}
LogFileSpanExporter an exporter that sends all traces across the configured connection.
func (*LogFileSpanExporter) ExportSpans ¶ added in v1.66.0
func (se *LogFileSpanExporter) ExportSpans(ctx context.Context, spans []sdktrace.ReadOnlySpan) error
ExportSpans exports all the provided spans.
type Otel ¶ added in v1.42.0
type Otel struct { // Enabled determines whether to turn on tracing Enabled bool `yaml:"Enabled"` // Endpoint for the tracing backend Endpoint string `yaml:"Endpoint"` // CollectorEndpoint endpoint for the opentelemetry collector for tracing CollectorEndpoint string `yaml:"CollectorEndpoint"` // Dataset the honeycomb grouping of traces Dataset string `yaml:"Dataset"` // SamplePercent the rate at which to sample SamplePercent float64 `yaml:"SamplePercent"` // Debug allows printing debug statements for traces Debug bool `yaml:"Debug"` // Stdout also outputs traces to stdout Stdout bool `yaml:"Stdout"` // APIKey used for authentication with the backend at Endpoint APIKey cfg.Secret `yaml:"APIKey"` }
Otel is the configuration for OpenTelemetry based tracing
type SpanStartOption ¶ added in v1.52.0
type SpanStartOption interface {
// contains filtered or unexported methods
}
SpanStartOption is an interface for various options to be provided during span creation (StartSpan).