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