// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package trace import ( "context" "time" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/label" ) type Provider interface { // Tracer creates an implementation of the Tracer interface. // The instrumentationName must be the name of the library providing // instrumentation. This name may be the same as the instrumented code // only if that code provides built-in instrumentation. If the // instrumentationName is empty, then a implementation defined default // name will be used instead. Tracer(instrumentationName string, opts ...TracerOption) Tracer } // TracerConfig is a group of options for a Tracer. // // Most users will use the tracer options instead. type TracerConfig struct { // InstrumentationVersion is the version of the instrumentation library. InstrumentationVersion string } // NewTracerConfig applies all the options to a returned TracerConfig. // The default value for all the fields of the returned TracerConfig are the // default zero value of the type. Also, this does not perform any validation // on the returned TracerConfig (e.g. no uniqueness checking or bounding of // data), instead it is left to the implementations of the SDK to perform this // action. func NewTracerConfig(opts ...TracerOption) *TracerConfig { config := new(TracerConfig) for _, option := range opts { option.Apply(config) } return config } // TracerOption applies an options to a TracerConfig. type TracerOption interface { Apply(*TracerConfig) } type instVersionTracerOption string func (o instVersionTracerOption) Apply(c *TracerConfig) { c.InstrumentationVersion = string(o) } // WithInstrumentationVersion sets the instrumentation version for a Tracer. func WithInstrumentationVersion(version string) TracerOption { return instVersionTracerOption(version) } type Tracer interface { // Start a span. Start(ctx context.Context, spanName string, opts ...SpanOption) (context.Context, Span) } // ErrorConfig provides options to set properties of an error // event at the time it is recorded. // // Most users will use the error options instead. type ErrorConfig struct { Timestamp time.Time StatusCode codes.Code } // ErrorOption applies changes to ErrorConfig that sets options when an error event is recorded. type ErrorOption func(*ErrorConfig) // WithErrorTime sets the time at which the error event should be recorded. func WithErrorTime(t time.Time) ErrorOption { return func(c *ErrorConfig) { c.Timestamp = t } } // WithErrorStatus indicates the span status that should be set when recording an error event. func WithErrorStatus(s codes.Code) ErrorOption { return func(c *ErrorConfig) { c.StatusCode = s } } type Span interface { // Tracer returns tracer used to create this span. Tracer cannot be nil. Tracer() Tracer // End completes the span. No updates are allowed to span after it // ends. The only exception is setting status of the span. End(options ...SpanOption) // AddEvent adds an event to the span. AddEvent(ctx context.Context, name string, attrs ...label.KeyValue) // AddEventWithTimestamp adds an event with a custom timestamp // to the span. AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...label.KeyValue) // IsRecording returns true if the span is active and recording events is enabled. IsRecording() bool // RecordError records an error as a span event. RecordError(ctx context.Context, err error, opts ...ErrorOption) // SpanContext returns span context of the span. Returned SpanContext is usable // even after the span ends. SpanContext() SpanContext // SetStatus sets the status of the span in the form of a code // and a message. SetStatus overrides the value of previous // calls to SetStatus on the Span. // // The default span status is OK, so it is not necessary to // explicitly set an OK status on successful Spans unless it // is to add an OK message or to override a previous status on the Span. SetStatus(code codes.Code, msg string) // SetName sets the name of the span. SetName(name string) // Set span attributes SetAttributes(kv ...label.KeyValue) // Set singular span attribute, with type inference. SetAttribute(k string, v interface{}) } // SpanConfig is a group of options for a Span. // // Most users will use span options instead. type SpanConfig struct { // Attributes describe the associated qualities of a Span. Attributes []label.KeyValue // Timestamp is a time in a Span life-cycle. Timestamp time.Time // Links are the associations a Span has with other Spans. Links []Link // Record is the recording state of a Span. Record bool // NewRoot identifies a Span as the root Span for a new trace. This is // commonly used when an existing trace crosses trust boundaries and the // remote parent span context should be ignored for security. NewRoot bool // SpanKind is the role a Span has in a trace. SpanKind SpanKind } // NewSpanConfig applies all the options to a returned SpanConfig. // The default value for all the fields of the returned SpanConfig are the // default zero value of the type. Also, this does not perform any validation // on the returned SpanConfig (e.g. no uniqueness checking or bounding of // data). Instead, it is left to the implementations of the SDK to perform this // action. func NewSpanConfig(opts ...SpanOption) *SpanConfig { c := new(SpanConfig) for _, option := range opts { option.Apply(c) } return c } // SpanOption applies an option to a SpanConfig. type SpanOption interface { Apply(*SpanConfig) } type attributeSpanOption []label.KeyValue func (o attributeSpanOption) Apply(c *SpanConfig) { c.Attributes = append(c.Attributes, []label.KeyValue(o)...) } // WithAttributes adds the attributes to a span. These attributes are meant to // provide additional information about the work the Span represents. The // attributes are added to the existing Span attributes, i.e. this does not // overwrite. func WithAttributes(attributes ...label.KeyValue) SpanOption { return attributeSpanOption(attributes) } type timestampSpanOption time.Time func (o timestampSpanOption) Apply(c *SpanConfig) { c.Timestamp = time.Time(o) } // WithTimestamp sets the time of a Span life-cycle moment (e.g. started or // stopped). func WithTimestamp(t time.Time) SpanOption { return timestampSpanOption(t) } type linksSpanOption []Link func (o linksSpanOption) Apply(c *SpanConfig) { c.Links = append(c.Links, []Link(o)...) } // WithLinks adds links to a Span. The links are added to the existing Span // links, i.e. this does not overwrite. func WithLinks(links ...Link) SpanOption { return linksSpanOption(links) } type recordSpanOption bool func (o recordSpanOption) Apply(c *SpanConfig) { c.Record = bool(o) } // WithRecord specifies that the span should be recorded. It is important to // note that implementations may override this option, i.e. if the span is a // child of an un-sampled trace. func WithRecord() SpanOption { return recordSpanOption(true) } type newRootSpanOption bool func (o newRootSpanOption) Apply(c *SpanConfig) { c.NewRoot = bool(o) } // WithNewRoot specifies that the Span should be treated as a root Span. Any // existing parent span context will be ignored when defining the Span's trace // identifiers. func WithNewRoot() SpanOption { return newRootSpanOption(true) } type spanKindSpanOption SpanKind func (o spanKindSpanOption) Apply(c *SpanConfig) { c.SpanKind = SpanKind(o) } // WithSpanKind sets the SpanKind of a Span. func WithSpanKind(kind SpanKind) SpanOption { return spanKindSpanOption(kind) } // Link is used to establish relationship between two spans within the same Trace or // across different Traces. Few examples of Link usage. // 1. Batch Processing: A batch of elements may contain elements associated with one // or more traces/spans. Since there can only be one parent SpanContext, Link is // used to keep reference to SpanContext of all elements in the batch. // 2. Public Endpoint: A SpanContext in incoming client request on a public endpoint // is untrusted from service provider perspective. In such case it is advisable to // start a new trace with appropriate sampling decision. // However, it is desirable to associate incoming SpanContext to new trace initiated // on service provider side so two traces (from Client and from Service Provider) can // be correlated. type Link struct { SpanContext Attributes []label.KeyValue } // SpanKind represents the role of a Span inside a Trace. Often, this defines how a Span // will be processed and visualized by various backends. type SpanKind int const ( // As a convenience, these match the proto definition, see // opentelemetry/proto/trace/v1/trace.proto // // The unspecified value is not a valid `SpanKind`. Use // `ValidateSpanKind()` to coerce a span kind to a valid // value. SpanKindUnspecified SpanKind = 0 SpanKindInternal SpanKind = 1 SpanKindServer SpanKind = 2 SpanKindClient SpanKind = 3 SpanKindProducer SpanKind = 4 SpanKindConsumer SpanKind = 5 ) // ValidateSpanKind returns a valid span kind value. This will coerce // invalid values into the default value, SpanKindInternal. func ValidateSpanKind(spanKind SpanKind) SpanKind { switch spanKind { case SpanKindInternal, SpanKindServer, SpanKindClient, SpanKindProducer, SpanKindConsumer: // valid return spanKind default: return SpanKindInternal } } // String returns the specified name of the SpanKind in lower-case. func (sk SpanKind) String() string { switch sk { case SpanKindInternal: return "internal" case SpanKindServer: return "server" case SpanKindClient: return "client" case SpanKindProducer: return "producer" case SpanKindConsumer: return "consumer" default: return "unspecified" } }