github.com/livekit/protocol@v1.16.1-0.20240517185851-47e4c6bba773/logger/proto.go (about) 1 // Copyright 2023 LiveKit, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package logger 16 17 import ( 18 "encoding/base64" 19 "fmt" 20 "strconv" 21 22 "go.uber.org/zap/zapcore" 23 "google.golang.org/protobuf/proto" 24 "google.golang.org/protobuf/reflect/protoreflect" 25 ) 26 27 func Proto(val proto.Message) zapcore.ObjectMarshaler { 28 if val == nil { 29 return nil 30 } 31 return protoMarshaller{val.ProtoReflect()} 32 } 33 34 var _ zapcore.ObjectMarshaler = protoMarshaller{} 35 var _ zapcore.ObjectMarshaler = protoMapMarshaller{} 36 var _ zapcore.ArrayMarshaler = protoListMarshaller{} 37 38 type protoMarshaller struct { 39 m protoreflect.Message 40 } 41 42 func (p protoMarshaller) MarshalLogObject(e zapcore.ObjectEncoder) error { 43 fields := p.m.Descriptor().Fields() 44 for i := 0; i < fields.Len(); i++ { 45 f := fields.Get(i) 46 k := f.JSONName() 47 v := p.m.Get(f) 48 49 if f.IsMap() { 50 if m := v.Map(); m.IsValid() { 51 e.AddObject(k, protoMapMarshaller{f, m}) 52 } 53 } else if f.IsList() { 54 if m := v.List(); m.IsValid() { 55 e.AddArray(k, protoListMarshaller{f, m}) 56 } 57 } else { 58 marshalProtoField(k, f, v, e) 59 } 60 } 61 return nil 62 } 63 64 type protoMapMarshaller struct { 65 f protoreflect.FieldDescriptor 66 m protoreflect.Map 67 } 68 69 func (p protoMapMarshaller) MarshalLogObject(e zapcore.ObjectEncoder) error { 70 p.m.Range(func(ki protoreflect.MapKey, vi protoreflect.Value) bool { 71 var k string 72 switch p.f.MapKey().Kind() { 73 case protoreflect.BoolKind: 74 k = strconv.FormatBool(ki.Bool()) 75 case protoreflect.Int32Kind, protoreflect.Int64Kind, protoreflect.Sint32Kind, protoreflect.Sint64Kind, protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind: 76 k = strconv.FormatInt(ki.Int(), 10) 77 case protoreflect.Uint32Kind, protoreflect.Uint64Kind, protoreflect.Fixed32Kind, protoreflect.Fixed64Kind: 78 k = strconv.FormatUint(ki.Uint(), 10) 79 case protoreflect.StringKind: 80 k = ki.String() 81 } 82 marshalProtoField(k, p.f.MapValue(), vi, e) 83 return true 84 }) 85 return nil 86 } 87 88 type protoListMarshaller struct { 89 f protoreflect.FieldDescriptor 90 m protoreflect.List 91 } 92 93 func (p protoListMarshaller) MarshalLogArray(e zapcore.ArrayEncoder) error { 94 for i := 0; i < p.m.Len(); i++ { 95 v := p.m.Get(i) 96 switch p.f.Kind() { 97 case protoreflect.BoolKind: 98 e.AppendBool(v.Bool()) 99 case protoreflect.EnumKind: 100 e.AppendInt32(int32(v.Enum())) 101 case protoreflect.Int32Kind, protoreflect.Int64Kind, protoreflect.Sint32Kind, protoreflect.Sint64Kind, protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind: 102 e.AppendInt64(v.Int()) 103 case protoreflect.Uint32Kind, protoreflect.Uint64Kind, protoreflect.Fixed32Kind, protoreflect.Fixed64Kind: 104 e.AppendUint64(v.Uint()) 105 case protoreflect.FloatKind, protoreflect.DoubleKind: 106 e.AppendFloat64(v.Float()) 107 case protoreflect.StringKind: 108 e.AppendString(v.String()) 109 case protoreflect.BytesKind: 110 e.AppendString(marshalProtoBytes(v.Bytes())) 111 case protoreflect.MessageKind: 112 e.AppendObject(protoMarshaller{v.Message()}) 113 } 114 } 115 return nil 116 } 117 118 func marshalProtoField(k string, f protoreflect.FieldDescriptor, v protoreflect.Value, e zapcore.ObjectEncoder) { 119 switch f.Kind() { 120 case protoreflect.BoolKind: 121 if b := v.Bool(); b { 122 e.AddBool(k, b) 123 } 124 case protoreflect.EnumKind: 125 if n := v.Enum(); n != 0 { 126 e.AddInt32(k, int32(n)) 127 } 128 case protoreflect.Int32Kind, protoreflect.Int64Kind, protoreflect.Sint32Kind, protoreflect.Sint64Kind, protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind: 129 if n := v.Int(); n != 0 { 130 e.AddInt64(k, n) 131 } 132 case protoreflect.Uint32Kind, protoreflect.Uint64Kind, protoreflect.Fixed32Kind, protoreflect.Fixed64Kind: 133 if n := v.Uint(); n != 0 { 134 e.AddUint64(k, n) 135 } 136 case protoreflect.FloatKind, protoreflect.DoubleKind: 137 if n := v.Float(); n != 0 { 138 e.AddFloat64(k, n) 139 } 140 case protoreflect.StringKind: 141 if s := v.String(); s != "" { 142 e.AddString(k, s) 143 } 144 case protoreflect.BytesKind: 145 if b := v.Bytes(); len(b) != 0 { 146 e.AddString(k, marshalProtoBytes(b)) 147 } 148 case protoreflect.MessageKind: 149 if m := v.Message(); m.IsValid() { 150 e.AddObject(k, protoMarshaller{m}) 151 } 152 } 153 } 154 155 func marshalProtoBytes(b []byte) string { 156 n := len(b) 157 if n > 64 { 158 b = b[:64] 159 } 160 s := base64.RawStdEncoding.EncodeToString(b) 161 switch { 162 case n <= 64: 163 return s 164 case n < 1<<10: 165 return fmt.Sprintf("%s... (%dbytes)", s, n) 166 case n < 1<<20: 167 return fmt.Sprintf("%s... (%.2fkB)", s, float64(n)/float64(1<<10)) 168 case n < 1<<30: 169 return fmt.Sprintf("%s... (%.2fMB)", s, float64(n)/float64(1<<20)) 170 default: 171 return fmt.Sprintf("%s... (%.2fGB)", s, float64(n)/float64(1<<30)) 172 } 173 }