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	"context"
19	"fmt"
20
21	"go.opentelemetry.io/otel/attribute"
22)
23
24/*
25Sometimes information about a runtime environment can change dynamically or be
26delayed from startup. Instead of continuously recreating and distributing a
27TracerProvider with an immutable Resource or delaying the startup of your
28application on a slow-loading piece of information, annotate the created spans
29dynamically using a SpanProcessor.
30*/
31
32var (
33	// owner represents the owner of the application. In this example it is
34	// stored as a simple string, but in real-world use this may be the
35	// response to an asynchronous request.
36	owner    = "unknown"
37	ownerKey = attribute.Key("owner")
38)
39
40// Annotator is a SpanProcessor that adds attributes to all started spans.
41type Annotator struct {
42	// AttrsFunc is called when a span is started. The attributes it returns
43	// are set on the Span being started.
44	AttrsFunc func() []attribute.KeyValue
45}
46
47func (a Annotator) OnStart(_ context.Context, s ReadWriteSpan) { s.SetAttributes(a.AttrsFunc()...) }
48func (a Annotator) Shutdown(context.Context) error             { return nil }
49func (a Annotator) ForceFlush(context.Context) error           { return nil }
50func (a Annotator) OnEnd(s ReadOnlySpan) {
51	attr := s.Attributes()[0]
52	fmt.Printf("%s: %s\n", attr.Key, attr.Value.AsString())
53}
54
55func ExampleSpanProcessor_annotated() {
56	a := Annotator{
57		AttrsFunc: func() []attribute.KeyValue {
58			return []attribute.KeyValue{ownerKey.String(owner)}
59		},
60	}
61	tracer := NewTracerProvider(WithSpanProcessor(a)).Tracer("annotated")
62
63	// Simulate the situation where we want to annotate spans with an owner,
64	// but at startup we do not now this information. Instead of waiting for
65	// the owner to be known before starting and blocking here, start doing
66	// work and update when the information becomes available.
67	ctx := context.Background()
68	_, s0 := tracer.Start(ctx, "span0")
69
70	// Simulate an asynchronous call to determine the owner succeeding. We now
71	// know that the owner of this application has been determined to be
72	// Alice. Make sure all subsequent spans are annotated appropriately.
73	owner = "alice"
74
75	_, s1 := tracer.Start(ctx, "span1")
76	s0.End()
77	s1.End()
78
79	// Output:
80	// owner: unknown
81	// owner: alice
82}
83