1// Licensed to Elasticsearch B.V. under one or more contributor
2// license agreements. See the NOTICE file distributed with
3// this work for additional information regarding copyright
4// ownership. Elasticsearch B.V. licenses this file to you under
5// the Apache License, Version 2.0 (the "License"); you may
6// not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9//     http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18package apm
19
20import (
21	"encoding/hex"
22	"errors"
23)
24
25var (
26	errZeroTraceID = errors.New("zero trace-id is invalid")
27	errZeroSpanID  = errors.New("zero span-id is invalid")
28)
29
30const (
31	traceOptionsRecordedFlag = 0x01
32)
33
34// TraceContext holds trace context for an incoming or outgoing request.
35type TraceContext struct {
36	// Trace identifies the trace forest.
37	Trace TraceID
38
39	// Span identifies a span: the parent span if this context
40	// corresponds to an incoming request, or the current span
41	// if this is an outgoing request.
42	Span SpanID
43
44	// Options holds the trace options propagated by the parent.
45	Options TraceOptions
46}
47
48// TraceID identifies a trace forest.
49type TraceID [16]byte
50
51// Validate validates the trace ID.
52// This will return non-nil for a zero trace ID.
53func (id TraceID) Validate() error {
54	if id.isZero() {
55		return errZeroTraceID
56	}
57	return nil
58}
59
60func (id TraceID) isZero() bool {
61	return id == (TraceID{})
62}
63
64// String returns id encoded as hex.
65func (id TraceID) String() string {
66	text, _ := id.MarshalText()
67	return string(text)
68}
69
70// MarshalText returns id encoded as hex, satisfying encoding.TextMarshaler.
71func (id TraceID) MarshalText() ([]byte, error) {
72	text := make([]byte, hex.EncodedLen(len(id)))
73	hex.Encode(text, id[:])
74	return text, nil
75}
76
77// SpanID identifies a span within a trace.
78type SpanID [8]byte
79
80// Validate validates the span ID.
81// This will return non-nil for a zero span ID.
82func (id SpanID) Validate() error {
83	if id.isZero() {
84		return errZeroSpanID
85	}
86	return nil
87}
88
89func (id SpanID) isZero() bool {
90	return id == SpanID{}
91}
92
93// String returns id encoded as hex.
94func (id SpanID) String() string {
95	text, _ := id.MarshalText()
96	return string(text)
97}
98
99// MarshalText returns id encoded as hex, satisfying encoding.TextMarshaler.
100func (id SpanID) MarshalText() ([]byte, error) {
101	text := make([]byte, hex.EncodedLen(len(id)))
102	hex.Encode(text, id[:])
103	return text, nil
104}
105
106// TraceOptions describes the options for a trace.
107type TraceOptions uint8
108
109// Recorded reports whether or not the transaction/span may have been (or may be) recorded.
110func (o TraceOptions) Recorded() bool {
111	return (o & traceOptionsRecordedFlag) == traceOptionsRecordedFlag
112}
113
114// WithRecorded changes the "recorded" flag, and returns the new options
115// without modifying the original value.
116func (o TraceOptions) WithRecorded(recorded bool) TraceOptions {
117	if recorded {
118		return o | traceOptionsRecordedFlag
119	}
120	return o & (0xFF ^ traceOptionsRecordedFlag)
121}
122