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  }