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
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 is the version of the library providing
26	// instrumentation.
27	InstrumentationVersion string
28}
29
30// NewTracerConfig applies all the options to a returned TracerConfig.
31func NewTracerConfig(options ...TracerOption) *TracerConfig {
32	config := new(TracerConfig)
33	for _, option := range options {
34		option.ApplyTracer(config)
35	}
36	return config
37}
38
39// TracerOption applies an option to a TracerConfig.
40type TracerOption interface {
41	ApplyTracer(*TracerConfig)
42
43	// A private method to prevent users implementing the
44	// interface and so future additions to it will not
45	// violate compatibility.
46	private()
47}
48
49// SpanConfig is a group of options for a Span.
50type SpanConfig struct {
51	// Attributes describe the associated qualities of a Span.
52	Attributes []attribute.KeyValue
53	// Timestamp is a time in a Span life-cycle.
54	Timestamp time.Time
55	// Links are the associations a Span has with other Spans.
56	Links []Link
57	// NewRoot identifies a Span as the root Span for a new trace. This is
58	// commonly used when an existing trace crosses trust boundaries and the
59	// remote parent span context should be ignored for security.
60	NewRoot bool
61	// SpanKind is the role a Span has in a trace.
62	SpanKind SpanKind
63}
64
65// NewSpanConfig applies all the options to a returned SpanConfig.
66// No validation is performed on the returned SpanConfig (e.g. no uniqueness
67// checking or bounding of data), it is left to the SDK to perform this
68// action.
69func NewSpanConfig(options ...SpanOption) *SpanConfig {
70	c := new(SpanConfig)
71	for _, option := range options {
72		option.ApplySpan(c)
73	}
74	return c
75}
76
77// SpanOption applies an option to a SpanConfig.
78type SpanOption interface {
79	ApplySpan(*SpanConfig)
80
81	// A private method to prevent users implementing the
82	// interface and so future additions to it will not
83	// violate compatibility.
84	private()
85}
86
87// NewEventConfig applies all the EventOptions to a returned SpanConfig. If no
88// timestamp option is passed, the returned SpanConfig will have a Timestamp
89// set to the call time, otherwise no validation is performed on the returned
90// SpanConfig.
91func NewEventConfig(options ...EventOption) *SpanConfig {
92	c := new(SpanConfig)
93	for _, option := range options {
94		option.ApplyEvent(c)
95	}
96	if c.Timestamp.IsZero() {
97		c.Timestamp = time.Now()
98	}
99	return c
100}
101
102// EventOption applies span event options to a SpanConfig.
103type EventOption interface {
104	ApplyEvent(*SpanConfig)
105
106	// A private method to prevent users implementing the
107	// interface and so future additions to it will not
108	// violate compatibility.
109	private()
110}
111
112// LifeCycleOption applies span life-cycle options to a SpanConfig. These
113// options set values releated to events in a spans life-cycle like starting,
114// ending, experiencing an error and other user defined notable events.
115type LifeCycleOption interface {
116	SpanOption
117	EventOption
118}
119
120type attributeSpanOption []attribute.KeyValue
121
122func (o attributeSpanOption) ApplySpan(c *SpanConfig)  { o.apply(c) }
123func (o attributeSpanOption) ApplyEvent(c *SpanConfig) { o.apply(c) }
124func (attributeSpanOption) private()                   {}
125func (o attributeSpanOption) apply(c *SpanConfig) {
126	c.Attributes = append(c.Attributes, []attribute.KeyValue(o)...)
127}
128
129// WithAttributes adds the attributes related to a span life-cycle event.
130// These attributes are used to describe the work a Span represents when this
131// option is provided to a Span's start or end events. Otherwise, these
132// attributes provide additional information about the event being recorded
133// (e.g. error, state change, processing progress, system event).
134//
135// If multiple of these options are passed the attributes of each successive
136// option will extend the attributes instead of overwriting. There is no
137// guarantee of uniqueness in the resulting attributes.
138func WithAttributes(attributes ...attribute.KeyValue) LifeCycleOption {
139	return attributeSpanOption(attributes)
140}
141
142type timestampSpanOption time.Time
143
144func (o timestampSpanOption) ApplySpan(c *SpanConfig)  { o.apply(c) }
145func (o timestampSpanOption) ApplyEvent(c *SpanConfig) { o.apply(c) }
146func (timestampSpanOption) private()                   {}
147func (o timestampSpanOption) apply(c *SpanConfig)      { c.Timestamp = time.Time(o) }
148
149// WithTimestamp sets the time of a Span life-cycle moment (e.g. started,
150// stopped, errored).
151func WithTimestamp(t time.Time) LifeCycleOption {
152	return timestampSpanOption(t)
153}
154
155type linksSpanOption []Link
156
157func (o linksSpanOption) ApplySpan(c *SpanConfig) { c.Links = append(c.Links, []Link(o)...) }
158func (linksSpanOption) private()                  {}
159
160// WithLinks adds links to a Span. The links are added to the existing Span
161// links, i.e. this does not overwrite.
162func WithLinks(links ...Link) SpanOption {
163	return linksSpanOption(links)
164}
165
166type newRootSpanOption bool
167
168func (o newRootSpanOption) ApplySpan(c *SpanConfig) { c.NewRoot = bool(o) }
169func (newRootSpanOption) private()                  {}
170
171// WithNewRoot specifies that the Span should be treated as a root Span. Any
172// existing parent span context will be ignored when defining the Span's trace
173// identifiers.
174func WithNewRoot() SpanOption {
175	return newRootSpanOption(true)
176}
177
178type spanKindSpanOption SpanKind
179
180func (o spanKindSpanOption) ApplySpan(c *SpanConfig) { c.SpanKind = SpanKind(o) }
181func (o spanKindSpanOption) private()                {}
182
183// WithSpanKind sets the SpanKind of a Span.
184func WithSpanKind(kind SpanKind) SpanOption {
185	return spanKindSpanOption(kind)
186}
187
188// InstrumentationOption is an interface for applying instrumentation specific
189// options.
190type InstrumentationOption interface {
191	TracerOption
192}
193
194// WithInstrumentationVersion sets the instrumentation version.
195func WithInstrumentationVersion(version string) InstrumentationOption {
196	return instrumentationVersionOption(version)
197}
198
199type instrumentationVersionOption string
200
201func (i instrumentationVersionOption) ApplyTracer(config *TracerConfig) {
202	config.InstrumentationVersion = string(i)
203}
204
205func (instrumentationVersionOption) private() {}
206