github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/internal/kv/field.go (about)

     1  package kv
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/version"
    11  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
    12  	"github.com/ydb-platform/ydb-go-sdk/v3/trace"
    13  )
    14  
    15  const nilPtr = "<nil>"
    16  
    17  // KeyValue represents typed log field (a key-value pair). Adapters should determine
    18  // KeyValue's type based on Type and use the corresponding getter method to retrieve
    19  // the value:
    20  //
    21  //	switch f.Type() {
    22  //	case logs.IntType:
    23  //	    var i int = f.Int()
    24  //	    // handle int value
    25  //	case logs.StringType:
    26  //	    var s string = f.String()
    27  //	    // handle string value
    28  //	//...
    29  //	}
    30  //
    31  // Getter methods must not be called on fields with wrong Type (e.g. calling String()
    32  // on fields with Type != StringType).
    33  // KeyValue must not be initialized directly as a struct literal.
    34  type KeyValue struct {
    35  	ftype FieldType
    36  	key   string
    37  
    38  	vint int64
    39  	vstr string
    40  	vany interface{}
    41  }
    42  
    43  func (f KeyValue) Type() FieldType {
    44  	return f.ftype
    45  }
    46  
    47  func (f KeyValue) Key() string {
    48  	return f.key
    49  }
    50  
    51  // StringValue is a value getter for fields with StringType type
    52  func (f KeyValue) StringValue() string {
    53  	f.checkType(StringType)
    54  
    55  	return f.vstr
    56  }
    57  
    58  // IntValue is a value getter for fields with IntType type
    59  func (f KeyValue) IntValue() int {
    60  	f.checkType(IntType)
    61  
    62  	return int(f.vint)
    63  }
    64  
    65  // Int64Value is a value getter for fields with Int64Type type
    66  func (f KeyValue) Int64Value() int64 {
    67  	f.checkType(Int64Type)
    68  
    69  	return f.vint
    70  }
    71  
    72  // BoolValue is a value getter for fields with BoolType type
    73  func (f KeyValue) BoolValue() bool {
    74  	f.checkType(BoolType)
    75  
    76  	return f.vint != 0
    77  }
    78  
    79  // DurationValue is a value getter for fields with DurationType type
    80  func (f KeyValue) DurationValue() time.Duration {
    81  	f.checkType(DurationType)
    82  
    83  	return time.Nanosecond * time.Duration(f.vint)
    84  }
    85  
    86  // StringsValue is a value getter for fields with StringsType type
    87  func (f KeyValue) StringsValue() []string {
    88  	f.checkType(StringsType)
    89  	if f.vany == nil {
    90  		return nil
    91  	}
    92  	val, ok := f.vany.([]string)
    93  	if !ok {
    94  		panic(fmt.Sprintf("unsupported type conversion from %T to []string", val))
    95  	}
    96  
    97  	return val
    98  }
    99  
   100  // ErrorValue is a value getter for fields with ErrorType type
   101  func (f KeyValue) ErrorValue() error {
   102  	f.checkType(ErrorType)
   103  	if f.vany == nil {
   104  		return nil
   105  	}
   106  	val, ok := f.vany.(error)
   107  	if !ok {
   108  		panic(fmt.Sprintf("unsupported type conversion from %T to error", val))
   109  	}
   110  
   111  	return val
   112  }
   113  
   114  // AnyValue is a value getter for fields with AnyType type
   115  func (f KeyValue) AnyValue() interface{} {
   116  	switch f.ftype {
   117  	case AnyType:
   118  		return f.vany
   119  	case IntType:
   120  		return f.IntValue()
   121  	case Int64Type:
   122  		return f.Int64Value()
   123  	case StringType:
   124  		return f.StringValue()
   125  	case BoolType:
   126  		return f.BoolValue()
   127  	case DurationType:
   128  		return f.DurationValue()
   129  	case StringsType:
   130  		return f.StringsValue()
   131  	case ErrorType:
   132  		return f.ErrorValue()
   133  	case StringerType:
   134  		return f.Stringer()
   135  	default:
   136  		panic(fmt.Sprintf("unknown FieldType %d", f.ftype))
   137  	}
   138  }
   139  
   140  // Stringer is a value getter for fields with StringerType type
   141  func (f KeyValue) Stringer() fmt.Stringer {
   142  	f.checkType(StringerType)
   143  	if f.vany == nil {
   144  		return nil
   145  	}
   146  	val, ok := f.vany.(fmt.Stringer)
   147  	if !ok {
   148  		panic(fmt.Sprintf("unsupported type conversion from %T to fmt.Stringer", val))
   149  	}
   150  
   151  	return val
   152  }
   153  
   154  // Panics on type mismatch
   155  func (f KeyValue) checkType(want FieldType) {
   156  	if f.ftype != want {
   157  		panic(fmt.Sprintf("bad type. have: %s, want: %s", f.ftype, want))
   158  	}
   159  }
   160  
   161  // Returns default string representation of KeyValue value.
   162  // It should be used by adapters that don't support f.Type directly.
   163  func (f KeyValue) String() string {
   164  	switch f.ftype {
   165  	case IntType, Int64Type:
   166  		return strconv.FormatInt(f.vint, 10)
   167  	case StringType:
   168  		return f.vstr
   169  	case BoolType:
   170  		return strconv.FormatBool(f.BoolValue())
   171  	case DurationType:
   172  		return f.DurationValue().String()
   173  	case StringsType:
   174  		return fmt.Sprintf("%v", f.StringsValue())
   175  	case ErrorType:
   176  		if f.vany == nil {
   177  			return nilPtr
   178  		}
   179  
   180  		val, ok := f.vany.(error)
   181  		if !ok {
   182  			panic(fmt.Sprintf("unsupported type conversion from %T to fmt.Stringer", val))
   183  		}
   184  
   185  		if val == nil {
   186  			return "<nil>"
   187  		}
   188  
   189  		return f.ErrorValue().Error()
   190  	case AnyType:
   191  		if f.vany == nil {
   192  			return nilPtr
   193  		}
   194  		if v := reflect.ValueOf(f.vany); v.Type().Kind() == reflect.Ptr {
   195  			if v.IsNil() {
   196  				return nilPtr
   197  			}
   198  
   199  			return v.Type().String() + "(" + fmt.Sprint(v.Elem()) + ")"
   200  		}
   201  
   202  		return fmt.Sprint(f.vany)
   203  	case StringerType:
   204  		return f.Stringer().String()
   205  	default:
   206  		panic(fmt.Sprintf("unknown FieldType %d", f.ftype))
   207  	}
   208  }
   209  
   210  // String constructs KeyValue with StringType
   211  func String(k, v string) KeyValue {
   212  	return KeyValue{
   213  		ftype: StringType,
   214  		key:   k,
   215  		vstr:  v,
   216  	}
   217  }
   218  
   219  // Int constructs KeyValue with IntType
   220  func Int(k string, v int) KeyValue {
   221  	return KeyValue{
   222  		ftype: IntType,
   223  		key:   k,
   224  		vint:  int64(v),
   225  	}
   226  }
   227  
   228  func Int64(k string, v int64) KeyValue {
   229  	return KeyValue{
   230  		ftype: Int64Type,
   231  		key:   k,
   232  		vint:  v,
   233  	}
   234  }
   235  
   236  // Bool constructs KeyValue with BoolType
   237  func Bool(key string, value bool) KeyValue {
   238  	var vint int64
   239  	if value {
   240  		vint = 1
   241  	} else {
   242  		vint = 0
   243  	}
   244  
   245  	return KeyValue{
   246  		ftype: BoolType,
   247  		key:   key,
   248  		vint:  vint,
   249  	}
   250  }
   251  
   252  // Duration constructs KeyValue with DurationType
   253  func Duration(key string, value time.Duration) KeyValue {
   254  	return KeyValue{
   255  		ftype: DurationType,
   256  		key:   key,
   257  		vint:  value.Nanoseconds(),
   258  	}
   259  }
   260  
   261  // Strings constructs KeyValue with StringsType
   262  func Strings(key string, value []string) KeyValue {
   263  	return KeyValue{
   264  		ftype: StringsType,
   265  		key:   key,
   266  		vany:  value,
   267  	}
   268  }
   269  
   270  // NamedError constructs KeyValue with ErrorType
   271  func NamedError(key string, value error) KeyValue {
   272  	return KeyValue{
   273  		ftype: ErrorType,
   274  		key:   key,
   275  		vany:  value,
   276  	}
   277  }
   278  
   279  // Error is the same as NamedError("error", value)
   280  func Error(value error) KeyValue {
   281  	return NamedError("error", value)
   282  }
   283  
   284  // Any constructs untyped KeyValue.
   285  func Any(key string, value interface{}) KeyValue {
   286  	return KeyValue{
   287  		ftype: AnyType,
   288  		key:   key,
   289  		vany:  value,
   290  	}
   291  }
   292  
   293  // Stringer constructs KeyValue with StringerType. If value is nil,
   294  // resulting KeyValue will be of AnyType instead of StringerType.
   295  func Stringer(key string, value fmt.Stringer) KeyValue {
   296  	if value == nil {
   297  		return Any(key, nil)
   298  	}
   299  
   300  	return KeyValue{
   301  		ftype: StringerType,
   302  		key:   key,
   303  		vany:  value,
   304  	}
   305  }
   306  
   307  // FieldType indicates type info about the KeyValue. This enum might be extended in future releases.
   308  // Adapters that don't support some FieldType value should use KeyValue.Fallback() for marshaling.
   309  type FieldType int
   310  
   311  const (
   312  	// InvalidType indicates that KeyValue was not initialized correctly. Adapters
   313  	// should either ignore such field or issue an error. No value getters should
   314  	// be called on field with such type.
   315  	InvalidType FieldType = iota
   316  
   317  	IntType
   318  	Int64Type
   319  	StringType
   320  	BoolType
   321  	DurationType
   322  
   323  	// StringsType corresponds to []string
   324  	StringsType
   325  
   326  	ErrorType
   327  	// AnyType indicates that the KeyValue is untyped. Adapters should use
   328  	// reflection-based approached to marshal this field.
   329  	AnyType
   330  
   331  	// StringerType corresponds to fmt.Stringer
   332  	StringerType
   333  
   334  	endType
   335  )
   336  
   337  func (ft FieldType) String() (typeName string) {
   338  	switch ft {
   339  	case InvalidType:
   340  		typeName = "invalid"
   341  	case IntType:
   342  		typeName = "int"
   343  	case Int64Type:
   344  		typeName = "int64"
   345  	case StringType:
   346  		typeName = "string"
   347  	case BoolType:
   348  		typeName = "bool"
   349  	case DurationType:
   350  		typeName = "time.Duration"
   351  	case StringsType:
   352  		typeName = "[]string"
   353  	case ErrorType:
   354  		typeName = "error"
   355  	case AnyType:
   356  		typeName = "any"
   357  	case StringerType:
   358  		typeName = "stringer"
   359  	case endType:
   360  		typeName = "endtype"
   361  	default:
   362  		panic("not implemented")
   363  	}
   364  
   365  	return typeName
   366  }
   367  
   368  // Latency creates KeyValue "latency": time.Since(start)
   369  func Latency(start time.Time) KeyValue {
   370  	return Duration("latency", time.Since(start))
   371  }
   372  
   373  // Version creates KeyValue "version": version.Version
   374  func Version() KeyValue {
   375  	return String("version", version.Version)
   376  }
   377  
   378  type Endpoints []trace.EndpointInfo
   379  
   380  func (ee Endpoints) String() string {
   381  	b := xstring.Buffer()
   382  	defer b.Free()
   383  	b.WriteByte('[')
   384  	for i, e := range ee {
   385  		if i != 0 {
   386  			b.WriteByte(',')
   387  		}
   388  		b.WriteString(e.String())
   389  	}
   390  	b.WriteByte(']')
   391  
   392  	return b.String()
   393  }
   394  
   395  type Metadata map[string][]string
   396  
   397  func (m Metadata) String() string {
   398  	b, err := json.Marshal(m)
   399  	if err != nil {
   400  		return fmt.Sprintf("error:%s", err)
   401  	}
   402  
   403  	return xstring.FromBytes(b)
   404  }