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 }