Forcing zap to log every structure field

75 views Asked by At

I'm building logger like this

config := zap.NewDevelopmentConfig()

logger, err := config.Build()
if err != nil {
    log.Fatal(err)
}

Imagine I have structure Request

type Request {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Name    string `protobuf:"bytes,1,opt,name=name`
    Surname string `protobuf:"bytes,1,opt,name=surname`
}

After I'm trying to log grpc request, important that request do not contains Surname field

logger.Infof("got request: %v", log)

Output message is

got request: name:"Bob"

I want to all the structure with zero value fields, like this

got request: name:"Bob" surname:""

Is in zap any config about data types otput

2

There are 2 answers

2
coxley On

It looks like logger.Sugar() was omitted from the example — zap.Logger doesn't have an Infof method.

SugaredLogger.Infof formats the objects according to fmt.Sprintf. You'll need to implement your own Stringer to customize the representation. Given that the example struct is a generated protobuf, you could embed the type:

type wrapper struct {
  *pb.Request
}

func (wrapper) String() string {
  // custom logic here
}

logger.Infof("got request: %v", wrapper{request})

If you care about performance, you should use zap.Logger instead.

It's not quite clear from your question whether you always want to include empty string values or not. If you want them, then use logger.Info(msg, zap.Any("request", request)). If you don't, then implement zapcore.ObjectMarshaler instead of fmt.Stringer.

type wrapper struct {
  *pb.Request
}

func (w wrapper) MarshalLogObject(enc zapcore.ObjectEncoder) error {
    enc.AddString("name", w.Name)
    if w.Surname != "" {
        enc.AddString("surname", w.Surname)
    }
    return nil
}

logger.Info("got request", zap.Object("request", wrapper{request}))
logger.Info("got request (without customization)", zap.Any("request", request))
3
Evadore On

While logging either %+v or %#v can be used to log all the fields of the object. check this example : https://go.dev/play/p/nnemDuMh4ZM for a demo.