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