1// Copyright The OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package trace // import "go.opentelemetry.io/otel/trace"
16
17import (
18	"time"
19
20	"go.opentelemetry.io/otel/attribute"
21)
22
23// TracerConfig is a group of options for a Tracer.
24type TracerConfig struct {
25	instrumentationVersion string
26	// Schema URL of the telemetry emitted by the Tracer.
27	schemaURL string
28}
29
30// InstrumentationVersion returns the version of the library providing instrumentation.
31func (t *TracerConfig) InstrumentationVersion() string {
32	return t.instrumentationVersion
33}
34
35// SchemaURL returns the Schema URL of the telemetry emitted by the Tracer.
36func (t *TracerConfig) SchemaURL() string {
37	return t.schemaURL
38}
39
40// NewTracerConfig applies all the options to a returned TracerConfig.
41func NewTracerConfig(options ...TracerOption) TracerConfig {
42	var config TracerConfig
43	for _, option := range options {
44		option.apply(&config)
45	}
46	return config
47}
48
49// TracerOption applies an option to a TracerConfig.
50type TracerOption interface {
51	apply(*TracerConfig)
52}
53
54type tracerOptionFunc func(*TracerConfig)
55
56func (fn tracerOptionFunc) apply(cfg *TracerConfig) {
57	fn(cfg)
58}
59
60// SpanConfig is a group of options for a Span.
61type SpanConfig struct {
62	attributes []attribute.KeyValue
63	timestamp  time.Time
64	links      []Link
65	newRoot    bool
66	spanKind   SpanKind
67	stackTrace bool
68}
69
70// Attributes describe the associated qualities of a Span.
71func (cfg *SpanConfig) Attributes() []attribute.KeyValue {
72	return cfg.attributes
73}
74
75// Timestamp is a time in a Span life-cycle.
76func (cfg *SpanConfig) Timestamp() time.Time {
77	return cfg.timestamp
78}
79
80// StackTrace checks whether stack trace capturing is enabled.
81func (cfg *SpanConfig) StackTrace() bool {
82	return cfg.stackTrace
83}
84
85// Links are the associations a Span has with other Spans.
86func (cfg *SpanConfig) Links() []Link {
87	return cfg.links
88}
89
90// NewRoot identifies a Span as the root Span for a new trace. This is
91// commonly used when an existing trace crosses trust boundaries and the
92// remote parent span context should be ignored for security.
93func (cfg *SpanConfig) NewRoot() bool {
94	return cfg.newRoot
95}
96
97// SpanKind is the role a Span has in a trace.
98func (cfg *SpanConfig) SpanKind() SpanKind {
99	return cfg.spanKind
100}
101
102// NewSpanStartConfig applies all the options to a returned SpanConfig.
103// No validation is performed on the returned SpanConfig (e.g. no uniqueness
104// checking or bounding of data), it is left to the SDK to perform this
105// action.
106func NewSpanStartConfig(options ...SpanStartOption) SpanConfig {
107	var c SpanConfig
108	for _, option := range options {
109		option.applySpanStart(&c)
110	}
111	return c
112}
113
114// NewSpanEndConfig applies all the options to a returned SpanConfig.
115// No validation is performed on the returned SpanConfig (e.g. no uniqueness
116// checking or bounding of data), it is left to the SDK to perform this
117// action.
118func NewSpanEndConfig(options ...SpanEndOption) SpanConfig {
119	var c SpanConfig
120	for _, option := range options {
121		option.applySpanEnd(&c)
122	}
123	return c
124}
125
126// SpanStartOption applies an option to a SpanConfig. These options are applicable
127// only when the span is created
128type SpanStartOption interface {
129	applySpanStart(*SpanConfig)
130}
131
132type spanOptionFunc func(*SpanConfig)
133
134func (fn spanOptionFunc) applySpanStart(cfg *SpanConfig) {
135	fn(cfg)
136}
137
138// SpanEndOption applies an option to a SpanConfig. These options are
139// applicable only when the span is ended.
140type SpanEndOption interface {
141	applySpanEnd(*SpanConfig)
142}
143
144// EventConfig is a group of options for an Event.
145type EventConfig struct {
146	attributes []attribute.KeyValue
147	timestamp  time.Time
148	stackTrace bool
149}
150
151// Attributes describe the associated qualities of an Event.
152func (cfg *EventConfig) Attributes() []attribute.KeyValue {
153	return cfg.attributes
154}
155
156// Timestamp is a time in an Event life-cycle.
157func (cfg *EventConfig) Timestamp() time.Time {
158	return cfg.timestamp
159}
160
161// StackTrace checks whether stack trace capturing is enabled.
162func (cfg *EventConfig) StackTrace() bool {
163	return cfg.stackTrace
164}
165
166// NewEventConfig applies all the EventOptions to a returned EventConfig. If no
167// timestamp option is passed, the returned EventConfig will have a Timestamp
168// set to the call time, otherwise no validation is performed on the returned
169// EventConfig.
170func NewEventConfig(options ...EventOption) EventConfig {
171	var c EventConfig
172	for _, option := range options {
173		option.applyEvent(&c)
174	}
175	if c.timestamp.IsZero() {
176		c.timestamp = time.Now()
177	}
178	return c
179}
180
181// EventOption applies span event options to an EventConfig.
182type EventOption interface {
183	applyEvent(*EventConfig)
184}
185
186// SpanOption are options that can be used at both the beginning and end of a span.
187type SpanOption interface {
188	SpanStartOption
189	SpanEndOption
190}
191
192// SpanStartEventOption are options that can be used at the start of a span, or with an event.
193type SpanStartEventOption interface {
194	SpanStartOption
195	EventOption
196}
197
198// SpanEndEventOption are options that can be used at the end of a span, or with an event.
199type SpanEndEventOption interface {
200	SpanEndOption
201	EventOption
202}
203
204type attributeOption []attribute.KeyValue
205
206func (o attributeOption) applySpan(c *SpanConfig) {
207	c.attributes = append(c.attributes, []attribute.KeyValue(o)...)
208}
209func (o attributeOption) applySpanStart(c *SpanConfig) { o.applySpan(c) }
210func (o attributeOption) applyEvent(c *EventConfig) {
211	c.attributes = append(c.attributes, []attribute.KeyValue(o)...)
212}
213
214var _ SpanStartEventOption = attributeOption{}
215
216// WithAttributes adds the attributes related to a span life-cycle event.
217// These attributes are used to describe the work a Span represents when this
218// option is provided to a Span's start or end events. Otherwise, these
219// attributes provide additional information about the event being recorded
220// (e.g. error, state change, processing progress, system event).
221//
222// If multiple of these options are passed the attributes of each successive
223// option will extend the attributes instead of overwriting. There is no
224// guarantee of uniqueness in the resulting attributes.
225func WithAttributes(attributes ...attribute.KeyValue) SpanStartEventOption {
226	return attributeOption(attributes)
227}
228
229// SpanEventOption are options that can be used with an event or a span.
230type SpanEventOption interface {
231	SpanOption
232	EventOption
233}
234
235type timestampOption time.Time
236
237func (o timestampOption) applySpan(c *SpanConfig)      { c.timestamp = time.Time(o) }
238func (o timestampOption) applySpanStart(c *SpanConfig) { o.applySpan(c) }
239func (o timestampOption) applySpanEnd(c *SpanConfig)   { o.applySpan(c) }
240func (o timestampOption) applyEvent(c *EventConfig)    { c.timestamp = time.Time(o) }
241
242var _ SpanEventOption = timestampOption{}
243
244// WithTimestamp sets the time of a Span or Event life-cycle moment (e.g.
245// started, stopped, errored).
246func WithTimestamp(t time.Time) SpanEventOption {
247	return timestampOption(t)
248}
249
250type stackTraceOption bool
251
252func (o stackTraceOption) applyEvent(c *EventConfig)  { c.stackTrace = bool(o) }
253func (o stackTraceOption) applySpan(c *SpanConfig)    { c.stackTrace = bool(o) }
254func (o stackTraceOption) applySpanEnd(c *SpanConfig) { o.applySpan(c) }
255
256// WithStackTrace sets the flag to capture the error with stack trace (e.g. true, false).
257func WithStackTrace(b bool) SpanEndEventOption {
258	return stackTraceOption(b)
259}
260
261// WithLinks adds links to a Span. The links are added to the existing Span
262// links, i.e. this does not overwrite. Links with invalid span context are ignored.
263func WithLinks(links ...Link) SpanStartOption {
264	return spanOptionFunc(func(cfg *SpanConfig) {
265		cfg.links = append(cfg.links, links...)
266	})
267}
268
269// WithNewRoot specifies that the Span should be treated as a root Span. Any
270// existing parent span context will be ignored when defining the Span's trace
271// identifiers.
272func WithNewRoot() SpanStartOption {
273	return spanOptionFunc(func(cfg *SpanConfig) {
274		cfg.newRoot = true
275	})
276}
277
278// WithSpanKind sets the SpanKind of a Span.
279func WithSpanKind(kind SpanKind) SpanStartOption {
280	return spanOptionFunc(func(cfg *SpanConfig) {
281		cfg.spanKind = kind
282	})
283}
284
285// WithInstrumentationVersion sets the instrumentation version.
286func WithInstrumentationVersion(version string) TracerOption {
287	return tracerOptionFunc(func(cfg *TracerConfig) {
288		cfg.instrumentationVersion = version
289	})
290}
291
292// WithSchemaURL sets the schema URL for the Tracer.
293func WithSchemaURL(schemaURL string) TracerOption {
294	return tracerOptionFunc(func(cfg *TracerConfig) {
295		cfg.schemaURL = schemaURL
296	})
297}
298