1// Copyright 2019, 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
20	"go.opentelemetry.io/otel/api/core"
21	apitrace "go.opentelemetry.io/otel/api/trace"
22)
23
24type tracer struct {
25	provider *Provider
26	name     string
27}
28
29var _ apitrace.Tracer = &tracer{}
30
31func (tr *tracer) Start(ctx context.Context, name string, o ...apitrace.StartOption) (context.Context, apitrace.Span) {
32	var opts apitrace.StartConfig
33	var parent core.SpanContext
34	var remoteParent bool
35
36	//TODO [rghetia] : Add new option for parent. If parent is configured then use that parent.
37	for _, op := range o {
38		op(&opts)
39	}
40
41	if relation := opts.Relation; relation.SpanContext != core.EmptySpanContext() {
42		switch relation.RelationshipType {
43		case apitrace.ChildOfRelationship, apitrace.FollowsFromRelationship:
44			parent = relation.SpanContext
45			remoteParent = true
46		default:
47			// Future relationship types may have different behavior,
48			// e.g., adding a `Link` instead of setting the `parent`
49		}
50	} else if p, ok := apitrace.SpanFromContext(ctx).(*span); ok {
51		p.addChild()
52		parent = p.spanContext
53	}
54
55	spanName := tr.spanNameWithPrefix(name)
56	span := startSpanInternal(tr, spanName, parent, remoteParent, opts)
57	for _, l := range opts.Links {
58		span.addLink(l)
59	}
60	span.SetAttributes(opts.Attributes...)
61
62	span.tracer = tr
63
64	if span.IsRecording() {
65		sps, _ := tr.provider.spanProcessors.Load().(spanProcessorMap)
66		for sp := range sps {
67			sp.OnStart(span.data)
68		}
69	}
70
71	ctx, end := startExecutionTracerTask(ctx, spanName)
72	span.executionTracerTaskEnd = end
73	return apitrace.ContextWithSpan(ctx, span), span
74}
75
76func (tr *tracer) WithSpan(ctx context.Context, name string, body func(ctx context.Context) error) error {
77	ctx, span := tr.Start(ctx, name)
78	defer span.End()
79
80	if err := body(ctx); err != nil {
81		// TODO: set event with boolean attribute for error.
82		return err
83	}
84	return nil
85}
86
87func (tr *tracer) spanNameWithPrefix(name string) string {
88	if tr.name != "" {
89		return tr.name + "/" + name
90	}
91	return name
92}
93