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