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 attribute // import "go.opentelemetry.io/otel/attribute"
16
17import (
18	"encoding/json"
19	"fmt"
20	"strconv"
21
22	"go.opentelemetry.io/otel/internal"
23)
24
25//go:generate stringer -type=Type
26
27// Type describes the type of the data Value holds.
28type Type int
29
30// Value represents the value part in key-value pairs.
31type Value struct {
32	vtype    Type
33	numeric  uint64
34	stringly string
35	slice    interface{}
36}
37
38const (
39	// INVALID is used for a Value with no value set.
40	INVALID Type = iota
41	// BOOL is a boolean Type Value.
42	BOOL
43	// INT64 is a 64-bit signed integral Type Value.
44	INT64
45	// FLOAT64 is a 64-bit floating point Type Value.
46	FLOAT64
47	// STRING is a string Type Value.
48	STRING
49	// BOOLSLICE is a slice of booleans Type Value.
50	BOOLSLICE
51	// INT64SLICE is a slice of 64-bit signed integral numbers Type Value.
52	INT64SLICE
53	// FLOAT64SLICE is a slice of 64-bit floating point numbers Type Value.
54	FLOAT64SLICE
55	// STRINGSLICE is a slice of strings Type Value.
56	STRINGSLICE
57)
58
59// BoolValue creates a BOOL Value.
60func BoolValue(v bool) Value {
61	return Value{
62		vtype:   BOOL,
63		numeric: internal.BoolToRaw(v),
64	}
65}
66
67// BoolSliceValue creates a BOOLSLICE Value.
68func BoolSliceValue(v []bool) Value {
69	cp := make([]bool, len(v))
70	copy(cp, v)
71	return Value{
72		vtype: BOOLSLICE,
73		slice: &cp,
74	}
75}
76
77// IntValue creates an INT64 Value.
78func IntValue(v int) Value {
79	return Int64Value(int64(v))
80}
81
82// IntSliceValue creates an INTSLICE Value.
83func IntSliceValue(v []int) Value {
84	cp := make([]int64, 0, len(v))
85	for _, i := range v {
86		cp = append(cp, int64(i))
87	}
88	return Value{
89		vtype: INT64SLICE,
90		slice: &cp,
91	}
92}
93
94// Int64Value creates an INT64 Value.
95func Int64Value(v int64) Value {
96	return Value{
97		vtype:   INT64,
98		numeric: internal.Int64ToRaw(v),
99	}
100}
101
102// Int64SliceValue creates an INT64SLICE Value.
103func Int64SliceValue(v []int64) Value {
104	cp := make([]int64, len(v))
105	copy(cp, v)
106	return Value{
107		vtype: INT64SLICE,
108		slice: &cp,
109	}
110}
111
112// Float64Value creates a FLOAT64 Value.
113func Float64Value(v float64) Value {
114	return Value{
115		vtype:   FLOAT64,
116		numeric: internal.Float64ToRaw(v),
117	}
118}
119
120// Float64SliceValue creates a FLOAT64SLICE Value.
121func Float64SliceValue(v []float64) Value {
122	cp := make([]float64, len(v))
123	copy(cp, v)
124	return Value{
125		vtype: FLOAT64SLICE,
126		slice: &cp,
127	}
128}
129
130// StringValue creates a STRING Value.
131func StringValue(v string) Value {
132	return Value{
133		vtype:    STRING,
134		stringly: v,
135	}
136}
137
138// StringSliceValue creates a STRINGSLICE Value.
139func StringSliceValue(v []string) Value {
140	cp := make([]string, len(v))
141	copy(cp, v)
142	return Value{
143		vtype: STRINGSLICE,
144		slice: &cp,
145	}
146}
147
148// Type returns a type of the Value.
149func (v Value) Type() Type {
150	return v.vtype
151}
152
153// AsBool returns the bool value. Make sure that the Value's type is
154// BOOL.
155func (v Value) AsBool() bool {
156	return internal.RawToBool(v.numeric)
157}
158
159// AsBoolSlice returns the []bool value. Make sure that the Value's type is
160// BOOLSLICE.
161func (v Value) AsBoolSlice() []bool {
162	if s, ok := v.slice.(*[]bool); ok {
163		return *s
164	}
165	return nil
166}
167
168// AsInt64 returns the int64 value. Make sure that the Value's type is
169// INT64.
170func (v Value) AsInt64() int64 {
171	return internal.RawToInt64(v.numeric)
172}
173
174// AsInt64Slice returns the []int64 value. Make sure that the Value's type is
175// INT64SLICE.
176func (v Value) AsInt64Slice() []int64 {
177	if s, ok := v.slice.(*[]int64); ok {
178		return *s
179	}
180	return nil
181}
182
183// AsFloat64 returns the float64 value. Make sure that the Value's
184// type is FLOAT64.
185func (v Value) AsFloat64() float64 {
186	return internal.RawToFloat64(v.numeric)
187}
188
189// AsFloat64Slice returns the []float64 value. Make sure that the Value's type is
190// INT64SLICE.
191func (v Value) AsFloat64Slice() []float64 {
192	if s, ok := v.slice.(*[]float64); ok {
193		return *s
194	}
195	return nil
196}
197
198// AsString returns the string value. Make sure that the Value's type
199// is STRING.
200func (v Value) AsString() string {
201	return v.stringly
202}
203
204// AsStringSlice returns the []string value. Make sure that the Value's type is
205// INT64SLICE.
206func (v Value) AsStringSlice() []string {
207	if s, ok := v.slice.(*[]string); ok {
208		return *s
209	}
210	return nil
211}
212
213type unknownValueType struct{}
214
215// AsInterface returns Value's data as interface{}.
216func (v Value) AsInterface() interface{} {
217	switch v.Type() {
218	case BOOL:
219		return v.AsBool()
220	case BOOLSLICE:
221		return v.AsBoolSlice()
222	case INT64:
223		return v.AsInt64()
224	case INT64SLICE:
225		return v.AsInt64Slice()
226	case FLOAT64:
227		return v.AsFloat64()
228	case FLOAT64SLICE:
229		return v.AsFloat64Slice()
230	case STRING:
231		return v.stringly
232	case STRINGSLICE:
233		return v.AsStringSlice()
234	}
235	return unknownValueType{}
236}
237
238// Emit returns a string representation of Value's data.
239func (v Value) Emit() string {
240	switch v.Type() {
241	case BOOLSLICE:
242		return fmt.Sprint(*(v.slice.(*[]bool)))
243	case BOOL:
244		return strconv.FormatBool(v.AsBool())
245	case INT64SLICE:
246		return fmt.Sprint(*(v.slice.(*[]int64)))
247	case INT64:
248		return strconv.FormatInt(v.AsInt64(), 10)
249	case FLOAT64SLICE:
250		return fmt.Sprint(*(v.slice.(*[]float64)))
251	case FLOAT64:
252		return fmt.Sprint(v.AsFloat64())
253	case STRINGSLICE:
254		return fmt.Sprint(*(v.slice.(*[]string)))
255	case STRING:
256		return v.stringly
257	default:
258		return "unknown"
259	}
260}
261
262// MarshalJSON returns the JSON encoding of the Value.
263func (v Value) MarshalJSON() ([]byte, error) {
264	var jsonVal struct {
265		Type  string
266		Value interface{}
267	}
268	jsonVal.Type = v.Type().String()
269	jsonVal.Value = v.AsInterface()
270	return json.Marshal(jsonVal)
271}
272