698 lines
16 KiB
Go
698 lines
16 KiB
Go
|
package exerr
|
||
|
|
||
|
import (
|
||
|
"encoding/hex"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"github.com/rs/zerolog"
|
||
|
"github.com/rs/zerolog/log"
|
||
|
"go.mongodb.org/mongo-driver/bson"
|
||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
type MetaMap map[string]MetaValue
|
||
|
|
||
|
type metaDataType string
|
||
|
|
||
|
const (
|
||
|
MDTString metaDataType = "String"
|
||
|
MDTStringPtr metaDataType = "StringPtr"
|
||
|
MDTInt metaDataType = "Int"
|
||
|
MDTInt8 metaDataType = "Int8"
|
||
|
MDTInt16 metaDataType = "Int16"
|
||
|
MDTInt32 metaDataType = "Int32"
|
||
|
MDTInt64 metaDataType = "Int64"
|
||
|
MDTFloat32 metaDataType = "Float32"
|
||
|
MDTFloat64 metaDataType = "Float64"
|
||
|
MDTBool metaDataType = "Bool"
|
||
|
MDTBytes metaDataType = "Bytes"
|
||
|
MDTObjectID metaDataType = "ObjectID"
|
||
|
MDTTime metaDataType = "Time"
|
||
|
MDTDuration metaDataType = "Duration"
|
||
|
MDTStringArray metaDataType = "StringArr"
|
||
|
MDTIntArray metaDataType = "IntArr"
|
||
|
MDTInt32Array metaDataType = "Int32Arr"
|
||
|
MDTID metaDataType = "ID"
|
||
|
MDTAny metaDataType = "Interface"
|
||
|
MDTNil metaDataType = "Nil"
|
||
|
)
|
||
|
|
||
|
type MetaValue struct {
|
||
|
DataType metaDataType `json:"dataType"`
|
||
|
Value interface{} `json:"value"`
|
||
|
}
|
||
|
|
||
|
type metaValueSerialization struct {
|
||
|
DataType metaDataType `bson:"dataType"`
|
||
|
Value string `bson:"value"`
|
||
|
Raw interface{} `bson:"raw"`
|
||
|
}
|
||
|
|
||
|
func (v MetaValue) SerializeValue() (string, error) {
|
||
|
switch v.DataType {
|
||
|
case MDTString:
|
||
|
return v.Value.(string), nil
|
||
|
case MDTID:
|
||
|
return v.Value.(IDWrap).Serialize(), nil
|
||
|
case MDTAny:
|
||
|
return v.Value.(AnyWrap).Serialize(), nil
|
||
|
case MDTStringPtr:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "#", nil
|
||
|
}
|
||
|
r := v.Value.(*string)
|
||
|
if r != nil {
|
||
|
return "*" + *r, nil
|
||
|
} else {
|
||
|
return "#", nil
|
||
|
}
|
||
|
case MDTInt:
|
||
|
return strconv.Itoa(v.Value.(int)), nil
|
||
|
case MDTInt8:
|
||
|
return strconv.FormatInt(int64(v.Value.(int8)), 10), nil
|
||
|
case MDTInt16:
|
||
|
return strconv.FormatInt(int64(v.Value.(int16)), 10), nil
|
||
|
case MDTInt32:
|
||
|
return strconv.FormatInt(int64(v.Value.(int32)), 10), nil
|
||
|
case MDTInt64:
|
||
|
return strconv.FormatInt(v.Value.(int64), 10), nil
|
||
|
case MDTFloat32:
|
||
|
return strconv.FormatFloat(float64(v.Value.(float32)), 'X', -1, 32), nil
|
||
|
case MDTFloat64:
|
||
|
return strconv.FormatFloat(v.Value.(float64), 'X', -1, 64), nil
|
||
|
case MDTBool:
|
||
|
if v.Value.(bool) {
|
||
|
return "true", nil
|
||
|
} else {
|
||
|
return "false", nil
|
||
|
}
|
||
|
case MDTBytes:
|
||
|
return hex.EncodeToString(v.Value.([]byte)), nil
|
||
|
case MDTObjectID:
|
||
|
return v.Value.(primitive.ObjectID).Hex(), nil
|
||
|
case MDTTime:
|
||
|
return strconv.FormatInt(v.Value.(time.Time).Unix(), 10) + "|" + strconv.FormatInt(int64(v.Value.(time.Time).Nanosecond()), 10), nil
|
||
|
case MDTDuration:
|
||
|
return v.Value.(time.Duration).String(), nil
|
||
|
case MDTStringArray:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "#", nil
|
||
|
}
|
||
|
r, err := json.Marshal(v.Value.([]string))
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
return string(r), nil
|
||
|
case MDTIntArray:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "#", nil
|
||
|
}
|
||
|
r, err := json.Marshal(v.Value.([]int))
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
return string(r), nil
|
||
|
case MDTInt32Array:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "#", nil
|
||
|
}
|
||
|
r, err := json.Marshal(v.Value.([]int32))
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
return string(r), nil
|
||
|
case MDTNil:
|
||
|
return "", nil
|
||
|
}
|
||
|
return "", errors.New("Unknown type: " + string(v.DataType))
|
||
|
}
|
||
|
|
||
|
func (v MetaValue) ShortString(lim int) string {
|
||
|
switch v.DataType {
|
||
|
case MDTString:
|
||
|
r := strings.ReplaceAll(v.Value.(string), "\r", "")
|
||
|
r = strings.ReplaceAll(r, "\n", "\\n")
|
||
|
r = strings.ReplaceAll(r, "\t", "\\t")
|
||
|
return langext.StrLimit(r, lim, "...")
|
||
|
case MDTID:
|
||
|
return v.Value.(IDWrap).String()
|
||
|
case MDTAny:
|
||
|
return v.Value.(AnyWrap).String()
|
||
|
case MDTStringPtr:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "<<null>>"
|
||
|
}
|
||
|
r := langext.CoalesceString(v.Value.(*string), "<<null>>")
|
||
|
r = strings.ReplaceAll(r, "\r", "")
|
||
|
r = strings.ReplaceAll(r, "\n", "\\n")
|
||
|
r = strings.ReplaceAll(r, "\t", "\\t")
|
||
|
return langext.StrLimit(r, lim, "...")
|
||
|
case MDTInt:
|
||
|
return strconv.Itoa(v.Value.(int))
|
||
|
case MDTInt8:
|
||
|
return strconv.FormatInt(int64(v.Value.(int8)), 10)
|
||
|
case MDTInt16:
|
||
|
return strconv.FormatInt(int64(v.Value.(int16)), 10)
|
||
|
case MDTInt32:
|
||
|
return strconv.FormatInt(int64(v.Value.(int32)), 10)
|
||
|
case MDTInt64:
|
||
|
return strconv.FormatInt(v.Value.(int64), 10)
|
||
|
case MDTFloat32:
|
||
|
return strconv.FormatFloat(float64(v.Value.(float32)), 'g', 4, 32)
|
||
|
case MDTFloat64:
|
||
|
return strconv.FormatFloat(v.Value.(float64), 'g', 4, 64)
|
||
|
case MDTBool:
|
||
|
return fmt.Sprintf("%v", v.Value.(bool))
|
||
|
case MDTBytes:
|
||
|
return langext.StrLimit(hex.EncodeToString(v.Value.([]byte)), lim, "...")
|
||
|
case MDTObjectID:
|
||
|
return v.Value.(primitive.ObjectID).Hex()
|
||
|
case MDTTime:
|
||
|
return v.Value.(time.Time).Format(time.RFC3339)
|
||
|
case MDTDuration:
|
||
|
return v.Value.(time.Duration).String()
|
||
|
case MDTStringArray:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "<<null>>"
|
||
|
}
|
||
|
r, err := json.Marshal(v.Value.([]string))
|
||
|
if err != nil {
|
||
|
return "(err)"
|
||
|
}
|
||
|
return langext.StrLimit(string(r), lim, "...")
|
||
|
case MDTIntArray:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "<<null>>"
|
||
|
}
|
||
|
r, err := json.Marshal(v.Value.([]int))
|
||
|
if err != nil {
|
||
|
return "(err)"
|
||
|
}
|
||
|
return langext.StrLimit(string(r), lim, "...")
|
||
|
case MDTInt32Array:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "<<null>>"
|
||
|
}
|
||
|
r, err := json.Marshal(v.Value.([]int32))
|
||
|
if err != nil {
|
||
|
return "(err)"
|
||
|
}
|
||
|
return langext.StrLimit(string(r), lim, "...")
|
||
|
case MDTNil:
|
||
|
return "<<null>>"
|
||
|
}
|
||
|
return "(err)"
|
||
|
}
|
||
|
|
||
|
func (v MetaValue) Apply(key string, evt *zerolog.Event) *zerolog.Event {
|
||
|
switch v.DataType {
|
||
|
case MDTString:
|
||
|
return evt.Str(key, v.Value.(string))
|
||
|
case MDTID:
|
||
|
return evt.Str(key, v.Value.(IDWrap).Value)
|
||
|
case MDTAny:
|
||
|
if v.Value.(AnyWrap).IsError {
|
||
|
return evt.Str(key, "(err)")
|
||
|
} else {
|
||
|
return evt.Str(key, v.Value.(AnyWrap).Json)
|
||
|
}
|
||
|
case MDTStringPtr:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return evt.Str(key, "<<null>>")
|
||
|
}
|
||
|
return evt.Str(key, langext.CoalesceString(v.Value.(*string), "<<null>>"))
|
||
|
case MDTInt:
|
||
|
return evt.Int(key, v.Value.(int))
|
||
|
case MDTInt8:
|
||
|
return evt.Int8(key, v.Value.(int8))
|
||
|
case MDTInt16:
|
||
|
return evt.Int16(key, v.Value.(int16))
|
||
|
case MDTInt32:
|
||
|
return evt.Int32(key, v.Value.(int32))
|
||
|
case MDTInt64:
|
||
|
return evt.Int64(key, v.Value.(int64))
|
||
|
case MDTFloat32:
|
||
|
return evt.Float32(key, v.Value.(float32))
|
||
|
case MDTFloat64:
|
||
|
return evt.Float64(key, v.Value.(float64))
|
||
|
case MDTBool:
|
||
|
return evt.Bool(key, v.Value.(bool))
|
||
|
case MDTBytes:
|
||
|
return evt.Bytes(key, v.Value.([]byte))
|
||
|
case MDTObjectID:
|
||
|
return evt.Str(key, v.Value.(primitive.ObjectID).Hex())
|
||
|
case MDTTime:
|
||
|
return evt.Time(key, v.Value.(time.Time))
|
||
|
case MDTDuration:
|
||
|
return evt.Dur(key, v.Value.(time.Duration))
|
||
|
case MDTStringArray:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return evt.Strs(key, nil)
|
||
|
}
|
||
|
return evt.Strs(key, v.Value.([]string))
|
||
|
case MDTIntArray:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return evt.Ints(key, nil)
|
||
|
}
|
||
|
return evt.Ints(key, v.Value.([]int))
|
||
|
case MDTInt32Array:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return evt.Ints32(key, nil)
|
||
|
}
|
||
|
return evt.Ints32(key, v.Value.([]int32))
|
||
|
case MDTNil:
|
||
|
return evt.Str(key, "<<null>>")
|
||
|
}
|
||
|
return evt.Str(key, "(err)")
|
||
|
}
|
||
|
|
||
|
func (v MetaValue) MarshalJSON() ([]byte, error) {
|
||
|
str, err := v.SerializeValue()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return json.Marshal(string(v.DataType) + ":" + str)
|
||
|
}
|
||
|
|
||
|
func (v *MetaValue) UnmarshalJSON(data []byte) error {
|
||
|
var str = ""
|
||
|
err := json.Unmarshal(data, &str)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
split := strings.SplitN(str, ":", 2)
|
||
|
if len(split) != 2 {
|
||
|
return errors.New("failed to decode MetaValue: '" + str + "'")
|
||
|
}
|
||
|
|
||
|
return v.Deserialize(split[1], metaDataType(split[0]))
|
||
|
}
|
||
|
|
||
|
func (v MetaValue) MarshalBSON() ([]byte, error) {
|
||
|
serval, err := v.SerializeValue()
|
||
|
if err != nil {
|
||
|
return nil, Wrap(err, "failed to bson-marshal MetaValue (serialize)").Build()
|
||
|
}
|
||
|
|
||
|
// this is an kinda ugly hack - but serialization to mongodb and back can loose the correct type information....
|
||
|
bin, err := bson.Marshal(metaValueSerialization{
|
||
|
DataType: v.DataType,
|
||
|
Value: serval,
|
||
|
Raw: v.Value,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, Wrap(err, "failed to bson-marshal MetaValue (marshal)").Build()
|
||
|
}
|
||
|
|
||
|
return bin, nil
|
||
|
}
|
||
|
|
||
|
func (v *MetaValue) UnmarshalBSON(bytes []byte) error {
|
||
|
var serval metaValueSerialization
|
||
|
err := bson.Unmarshal(bytes, &serval)
|
||
|
if err != nil {
|
||
|
return Wrap(err, "failed to bson-unmarshal MetaValue (unmarshal)").Build()
|
||
|
}
|
||
|
|
||
|
err = v.Deserialize(serval.Value, serval.DataType)
|
||
|
if err != nil {
|
||
|
return Wrap(err, "failed to deserialize MetaValue from bson").Str("raw", serval.Value).Build()
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (v *MetaValue) Deserialize(value string, datatype metaDataType) error {
|
||
|
switch datatype {
|
||
|
case MDTString:
|
||
|
v.Value = value
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTID:
|
||
|
v.Value = deserializeIDWrap(value)
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTAny:
|
||
|
v.Value = deserializeAnyWrap(value)
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTStringPtr:
|
||
|
if len(value) <= 0 || (value[0] != '*' && value[0] != '#') {
|
||
|
return errors.New("Invalid StringPtr: " + value)
|
||
|
} else if value == "#" {
|
||
|
v.Value = nil
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
} else {
|
||
|
r, err := valueFromProto(value[1:], MDTString)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = langext.Ptr(r.Value.(string))
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
}
|
||
|
case MDTInt:
|
||
|
pv, err := strconv.ParseInt(value, 10, 0)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = int(pv)
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTInt8:
|
||
|
pv, err := strconv.ParseInt(value, 10, 8)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = int8(pv)
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTInt16:
|
||
|
pv, err := strconv.ParseInt(value, 10, 16)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = int16(pv)
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTInt32:
|
||
|
pv, err := strconv.ParseInt(value, 10, 32)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = int32(pv)
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTInt64:
|
||
|
pv, err := strconv.ParseInt(value, 10, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = pv
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTFloat32:
|
||
|
pv, err := strconv.ParseFloat(value, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = float32(pv)
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTFloat64:
|
||
|
pv, err := strconv.ParseFloat(value, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = pv
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTBool:
|
||
|
if value == "true" {
|
||
|
v.Value = true
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
}
|
||
|
if value == "false" {
|
||
|
v.Value = false
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
}
|
||
|
return errors.New("invalid bool value: " + value)
|
||
|
case MDTBytes:
|
||
|
r, err := hex.DecodeString(value)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = r
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTObjectID:
|
||
|
r, err := primitive.ObjectIDFromHex(value)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = r
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTTime:
|
||
|
ps := strings.Split(value, "|")
|
||
|
if len(ps) != 2 {
|
||
|
return errors.New("invalid time.time: " + value)
|
||
|
}
|
||
|
p1, err := strconv.ParseInt(ps[0], 10, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
p2, err := strconv.ParseInt(ps[1], 10, 32)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = time.Unix(p1, p2)
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTDuration:
|
||
|
r, err := time.ParseDuration(value)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = r
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTStringArray:
|
||
|
if value == "#" {
|
||
|
v.Value = nil
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
}
|
||
|
pj := make([]string, 0)
|
||
|
err := json.Unmarshal([]byte(value), &pj)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = pj
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTIntArray:
|
||
|
if value == "#" {
|
||
|
v.Value = nil
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
}
|
||
|
pj := make([]int, 0)
|
||
|
err := json.Unmarshal([]byte(value), &pj)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = pj
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTInt32Array:
|
||
|
if value == "#" {
|
||
|
v.Value = nil
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
}
|
||
|
pj := make([]int32, 0)
|
||
|
err := json.Unmarshal([]byte(value), &pj)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
v.Value = pj
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
case MDTNil:
|
||
|
v.Value = nil
|
||
|
v.DataType = datatype
|
||
|
return nil
|
||
|
}
|
||
|
return errors.New("Unknown type: " + string(datatype))
|
||
|
}
|
||
|
|
||
|
func (v MetaValue) ValueString() string {
|
||
|
switch v.DataType {
|
||
|
case MDTString:
|
||
|
return v.Value.(string)
|
||
|
case MDTID:
|
||
|
return v.Value.(IDWrap).String()
|
||
|
case MDTAny:
|
||
|
return v.Value.(AnyWrap).String()
|
||
|
case MDTStringPtr:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "<<null>>"
|
||
|
}
|
||
|
return langext.CoalesceString(v.Value.(*string), "<<null>>")
|
||
|
case MDTInt:
|
||
|
return strconv.Itoa(v.Value.(int))
|
||
|
case MDTInt8:
|
||
|
return strconv.FormatInt(int64(v.Value.(int8)), 10)
|
||
|
case MDTInt16:
|
||
|
return strconv.FormatInt(int64(v.Value.(int16)), 10)
|
||
|
case MDTInt32:
|
||
|
return strconv.FormatInt(int64(v.Value.(int32)), 10)
|
||
|
case MDTInt64:
|
||
|
return strconv.FormatInt(v.Value.(int64), 10)
|
||
|
case MDTFloat32:
|
||
|
return strconv.FormatFloat(float64(v.Value.(float32)), 'g', 4, 32)
|
||
|
case MDTFloat64:
|
||
|
return strconv.FormatFloat(v.Value.(float64), 'g', 4, 64)
|
||
|
case MDTBool:
|
||
|
return fmt.Sprintf("%v", v.Value.(bool))
|
||
|
case MDTBytes:
|
||
|
return hex.EncodeToString(v.Value.([]byte))
|
||
|
case MDTObjectID:
|
||
|
return v.Value.(primitive.ObjectID).Hex()
|
||
|
case MDTTime:
|
||
|
return v.Value.(time.Time).Format(time.RFC3339Nano)
|
||
|
case MDTDuration:
|
||
|
return v.Value.(time.Duration).String()
|
||
|
case MDTStringArray:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "<<null>>"
|
||
|
}
|
||
|
r, err := json.MarshalIndent(v.Value.([]string), "", " ")
|
||
|
if err != nil {
|
||
|
return "(err)"
|
||
|
}
|
||
|
return string(r)
|
||
|
case MDTIntArray:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "<<null>>"
|
||
|
}
|
||
|
r, err := json.MarshalIndent(v.Value.([]int), "", " ")
|
||
|
if err != nil {
|
||
|
return "(err)"
|
||
|
}
|
||
|
return string(r)
|
||
|
case MDTInt32Array:
|
||
|
if langext.IsNil(v.Value) {
|
||
|
return "<<null>>"
|
||
|
}
|
||
|
r, err := json.MarshalIndent(v.Value.([]int32), "", " ")
|
||
|
if err != nil {
|
||
|
return "(err)"
|
||
|
}
|
||
|
return string(r)
|
||
|
case MDTNil:
|
||
|
return "<<null>>"
|
||
|
}
|
||
|
return "(err)"
|
||
|
}
|
||
|
|
||
|
func valueFromProto(value string, datatype metaDataType) (MetaValue, error) {
|
||
|
obj := MetaValue{}
|
||
|
err := obj.Deserialize(value, datatype)
|
||
|
if err != nil {
|
||
|
return MetaValue{}, err
|
||
|
}
|
||
|
return obj, nil
|
||
|
}
|
||
|
|
||
|
func metaFromProto(proto []*spbmodels.CustomError_MetaValue) MetaMap {
|
||
|
r := make(MetaMap)
|
||
|
|
||
|
for _, v := range proto {
|
||
|
mval, err := valueFromProto(v.Value, metaDataType(v.Type))
|
||
|
if err != nil {
|
||
|
log.Warn().Err(err).Msg("metaFromProto failed for " + v.Key)
|
||
|
continue
|
||
|
}
|
||
|
r[v.Key] = mval
|
||
|
}
|
||
|
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
func (mm MetaMap) ToProto() []*spbmodels.CustomError_MetaValue {
|
||
|
if mm == nil {
|
||
|
return make([]*spbmodels.CustomError_MetaValue, 0)
|
||
|
}
|
||
|
r := make([]*spbmodels.CustomError_MetaValue, 0, len(mm))
|
||
|
for k, v := range mm {
|
||
|
strval, err := v.SerializeValue()
|
||
|
if err != nil {
|
||
|
log.Warn().Err(err).Msg("MetaMap.ToProto failed for " + k)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
r = append(r, &spbmodels.CustomError_MetaValue{
|
||
|
Key: k,
|
||
|
Type: string(v.DataType),
|
||
|
Value: strval,
|
||
|
})
|
||
|
}
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
func (mm MetaMap) FormatOneLine(singleMaxLen int) string {
|
||
|
r := ""
|
||
|
|
||
|
i := 0
|
||
|
for key, val := range mm {
|
||
|
if i > 0 {
|
||
|
r += ", "
|
||
|
}
|
||
|
|
||
|
r += "\"" + key + "\""
|
||
|
r += ": "
|
||
|
r += "\"" + val.ShortString(singleMaxLen) + "\""
|
||
|
|
||
|
i++
|
||
|
}
|
||
|
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
func (mm MetaMap) FormatMultiLine(indentFront string, indentKeys string, maxLenValue int) string {
|
||
|
r := ""
|
||
|
|
||
|
r += indentFront + "{" + "\n"
|
||
|
for key, val := range mm {
|
||
|
if key == "gin.body" {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
r += indentFront
|
||
|
r += indentKeys
|
||
|
r += "\"" + key + "\""
|
||
|
r += ": "
|
||
|
r += "\"" + val.ShortString(maxLenValue) + "\""
|
||
|
r += ",\n"
|
||
|
}
|
||
|
r += indentFront + "}"
|
||
|
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
func (mm MetaMap) Any() bool {
|
||
|
return len(mm) > 0
|
||
|
}
|
||
|
|
||
|
func (mm MetaMap) Apply(evt *zerolog.Event) *zerolog.Event {
|
||
|
for key, val := range mm {
|
||
|
evt = val.Apply(key, evt)
|
||
|
}
|
||
|
return evt
|
||
|
}
|
||
|
|
||
|
func (mm MetaMap) add(key string, mdtype metaDataType, val interface{}) {
|
||
|
if _, ok := mm[key]; !ok {
|
||
|
mm[key] = MetaValue{DataType: mdtype, Value: val}
|
||
|
return
|
||
|
}
|
||
|
for i := 2; ; i++ {
|
||
|
realkey := key + "-" + strconv.Itoa(i)
|
||
|
if _, ok := mm[realkey]; !ok {
|
||
|
mm[realkey] = MetaValue{DataType: mdtype, Value: val}
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}
|