grpc_zerolog

package module
v0.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 25, 2021 License: MIT Imports: 13 Imported by: 3

README

gRPC interceptors backed by zerolog logger.

Inspired by github.com/grpc-ecosystem/go-grpc-middleware/logging and motivated by this issue.

Instead of loggers of grpc-middleware it not depend on grpc-ecosystem and not need the grpc_widleware at all. It uses the grpc.Chain* functions instead.

Documentation at pkg.go.dev

Documentation

Overview

'grpc_zerolog' is a gRPC logging interceptors backed by zerolog loggers.

It inspired by https://github.com/grpc-ecosystem/go-grpc-middleware/tree/master/logging packages but without dependency from https://github.com/grpc-ecosystem/go-grpc-middleware

It accepts a user-configured zerolog.Logger interface that will be used for logging compleeted gRPC calls, and be populated into the 'context.Context' passed into gRPC handler code.

Example (ClientInitializationSimple)
package main

import (
	"os"

	"github.com/pereslava/grpc_zerolog"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"google.golang.org/grpc"
)

func main() {
	addr := "localhost:9000"
	log.Print("Connecting to ", addr)
	// Make sure that log statements internal to gRPC library are logged using the zerolog Logger as well
	grpc_zerolog.ReplaceGrpcLogger(zerolog.New(os.Stderr).Level(zerolog.ErrorLevel))

	// Create and customize the zerolog logger instance
	clientLogger := log.Level(zerolog.TraceLevel)
	conn, err := grpc.Dial(
		addr,
		grpc.WithInsecure(),
		grpc.WithChainUnaryInterceptor(
			grpc_zerolog.NewPayloadUnaryClientInterceptor(clientLogger),
			grpc_zerolog.NewUnaryClientInterceptor(clientLogger),
		),
		grpc.WithChainStreamInterceptor(
			grpc_zerolog.NewPayloadStreamClientInterceptor(clientLogger),
			grpc_zerolog.NewStreamClientInterceptor(clientLogger),
		),
	)
	if err != nil {
		log.Fatal().Err(err).Str("addr", addr).Send()
	}
	defer conn.Close()

}
Output:

Example (ServerInitializationSimple)
package main

import (
	"os"

	"github.com/pereslava/grpc_zerolog"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"google.golang.org/grpc"
)

func main() {
	// Make sure that log statements internal to gRPC library are logged using the zerolog Logger as well
	grpc_zerolog.ReplaceGrpcLogger(zerolog.New(os.Stderr).Level(zerolog.ErrorLevel))

	// Create and customize the zerolog logger instance
	serverLogger := log.Level(zerolog.TraceLevel)
	_ = grpc.NewServer(
		grpc.ChainUnaryInterceptor(
			grpc_zerolog.NewPayloadUnaryServerInterceptor(serverLogger),
			grpc_zerolog.NewUnaryServerInterceptor(serverLogger),
		),
		grpc.ChainStreamInterceptor(
			grpc_zerolog.NewPayloadStreamServerInterceptor(serverLogger),
			grpc_zerolog.NewStreamServerInterceptor(serverLogger),
		),
	)
}
Output:

Example (ServerInitializationWithOptions)
package main

import (
	"github.com/pereslava/grpc_zerolog"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"google.golang.org/grpc"
)

var (
	customDecider             grpc_zerolog.Decider        = grpc_zerolog.DefaultDeciderFunc
	customPayloadDecider      grpc_zerolog.PayloadDecider = grpc_zerolog.DefaultPayloadDecider
	customCodeToLevelFunction grpc_zerolog.CodeToLevel    = grpc_zerolog.DefaultCodeToLevelFunc
)

func main() {
	_ = grpc.NewServer(
		grpc.ChainUnaryInterceptor(
			grpc_zerolog.NewPayloadUnaryServerInterceptor(
				log.Logger,
				grpc_zerolog.WithPayloadDecider(customPayloadDecider),
				grpc_zerolog.WithPayloadLevel(zerolog.Disabled),
			),
			grpc_zerolog.NewUnaryServerInterceptor(
				log.Logger,
				grpc_zerolog.WithDecider(customDecider),
				grpc_zerolog.WithLevels(customCodeToLevelFunction),
			),
		),
		grpc.ChainStreamInterceptor(
			grpc_zerolog.NewPayloadStreamServerInterceptor(
				log.Logger,
				grpc_zerolog.WithPayloadDecider(customPayloadDecider),
				grpc_zerolog.WithPayloadLevel(zerolog.InfoLevel),
			),
			grpc_zerolog.NewStreamServerInterceptor(
				log.Logger,
				grpc_zerolog.WithDecider(customDecider),
				grpc_zerolog.WithLevels(customCodeToLevelFunction),
			),
		),
	)
}
Output:

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// DefaultCodeToLevelFunc is the default implementation code to level logic.
	// returns Info on codes.OK and Error in all other cases
	DefaultCodeToLevelFunc CodeToLevel = func(code codes.Code) zerolog.Level {
		if code == codes.OK {
			return zerolog.InfoLevel
		}
		return zerolog.ErrorLevel
	}

	// DefaultDeciderFunc is the default implementation of decider
	// returns true always
	DefaultDeciderFunc Decider = func(fullMethodName string, err error) bool {
		return true
	}
)
View Source
var (
	// DefaultPayloadDecider is the default implementation of payload decider
	// returns always true
	DefaultPayloadDecider PayloadDecider = func(fullMethodName string) bool {
		return true
	}

	// DefaultPayloadLogLevel is the default log level of payload interceptors
	DefaultPayloadLogLevel zerolog.Level = zerolog.TraceLevel

	// DefaultLogErrorsDecider is the default decider for logging errors, it returns true if error exist with WarnLevel
	DefaultLogErrorsDecider LogErrorsDecider = func(fullMethodName string, err error) (bool, zerolog.Level) {
		if err == nil {
			return false, zerolog.NoLevel
		}
		return true, zerolog.WarnLevel
	}
)

Functions

func NewPayloadStreamClientInterceptor

func NewPayloadStreamClientInterceptor(logger zerolog.Logger, opts ...PayloadOption) grpc.StreamClientInterceptor

NewPayloadUnaryClientInterceptor returns a streaming client interceptor that logs the payloads of requests and responses

func NewPayloadStreamServerInterceptor

func NewPayloadStreamServerInterceptor(logger zerolog.Logger, opts ...PayloadOption) grpc.StreamServerInterceptor

NewPayloadStreamServerInterceptor returns a streaming server interceptor that logs the payloads of requests and responses

func NewPayloadUnaryClientInterceptor

func NewPayloadUnaryClientInterceptor(logger zerolog.Logger, opts ...PayloadOption) grpc.UnaryClientInterceptor

NewPayloadUnaryClientInterceptor returns an unary client interceptor that logs the payloads of requests and responses

func NewPayloadUnaryServerInterceptor

func NewPayloadUnaryServerInterceptor(logger zerolog.Logger, opts ...PayloadOption) grpc.UnaryServerInterceptor

NewPayloadUnaryServerInterceptor return an unary server interceptor that logs the payloads of requests and responses

func NewStreamClientInterceptor

func NewStreamClientInterceptor(logger zerolog.Logger, opts ...Option) grpc.StreamClientInterceptor

NewStreamClientInterceptor returns a streaming client interceptor that logs the gRPC calls

func NewStreamServerInterceptor

func NewStreamServerInterceptor(logger zerolog.Logger, opts ...Option) grpc.StreamServerInterceptor

NewStreamServerInterceptor returns a streaming server interceptor that adds zerolog to context and logs the gRPC calls

func NewUnaryClientInterceptor

func NewUnaryClientInterceptor(logger zerolog.Logger, opts ...Option) grpc.UnaryClientInterceptor

NewUnaryClientInterceptor returns an unary client interceptor that logs the gRPC calls

func NewUnaryServerInterceptor

func NewUnaryServerInterceptor(logger zerolog.Logger, opts ...Option) grpc.UnaryServerInterceptor

NewUnaryServerInterceptor returns an unary server interceptor that adds zerolog to context and logs the gRPC calls

func ReplaceGrpcLogger

func ReplaceGrpcLogger(logger zerolog.Logger)

Types

type CodeToLevel

type CodeToLevel func(code codes.Code) zerolog.Level

CodeToLevel function defines the mapping between gRPC return codes and interceptor log level

type Decider

type Decider func(fullMethodName string, err error) bool

Decider function defines rules for suppressing any interceptor logs

type LogErrorsDecider added in v0.0.3

type LogErrorsDecider func(fullMethodName string, err error) (bool, zerolog.Level)

LogErrorsDecider defines rules for suppressing log payload in error case, also returns the log level for zerolog

type Option

type Option func(*options)

Option used to configure the interceptors

func WithDecider

func WithDecider(f Decider) Option

WithDecider customizes the function for deciding if the gRPC interceptor logs should log depends on fullMethodName and error from handler

Example
package main

import (
	"net"
	"path"

	"github.com/pereslava/grpc_zerolog"
	"github.com/rs/zerolog/log"
	"google.golang.org/grpc"
)

func main() {
	addr := ":9000"
	conn, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal().Err(err).Str("addr", addr).Msg("cannont listen")
	}
	defer conn.Close()

	s := grpc.NewServer(
		grpc.ChainUnaryInterceptor(
			grpc_zerolog.NewUnaryServerInterceptor(
				log.Logger,
				grpc_zerolog.WithDecider(func(fullMethodName string, err error) bool {
					// will not log Hello method if no error
					method := path.Base(fullMethodName)
					if err == nil && method == "Hello" {
						return false
					}
					return true

				}),
			),
		),
	)

	// pb.Register .... your service (s, my_service.New(opts...))

	log.Info().Str("addr", addr).Msg("serving")
	if err := s.Serve(conn); err != nil {
		log.Fatal().Err(err).Msg("failed to serve")
	}
}
Output:

func WithLevels

func WithLevels(f CodeToLevel) Option

WithLevels customizes the function for mapping gRPC return codes and interceptor log level statements

Example
package main

import (
	"github.com/pereslava/grpc_zerolog"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

func main() {
	addr := ":9090"
	log.Info().Str("addr", addr).Msg("connecting")

	conn, err := grpc.Dial(
		addr,
		grpc.WithInsecure(),
		grpc.WithChainUnaryInterceptor(
			grpc_zerolog.NewUnaryClientInterceptor(
				log.Logger,
				// set custom log to level logic
				grpc_zerolog.WithLevels(func(code codes.Code) zerolog.Level {
					switch code {
					case codes.OK:
						return zerolog.DebugLevel
					case codes.Canceled:
						return zerolog.DebugLevel
					case codes.Unknown:
						return zerolog.InfoLevel
					case codes.InvalidArgument:
						return zerolog.DebugLevel
					case codes.DeadlineExceeded:
						return zerolog.InfoLevel
					case codes.NotFound:
						return zerolog.DebugLevel
					case codes.AlreadyExists:
						return zerolog.DebugLevel
					case codes.PermissionDenied:
						return zerolog.InfoLevel
					case codes.Unauthenticated:
						return zerolog.InfoLevel
					case codes.ResourceExhausted:
						return zerolog.DebugLevel
					case codes.FailedPrecondition:
						return zerolog.DebugLevel
					case codes.Aborted:
						return zerolog.DebugLevel
					case codes.OutOfRange:
						return zerolog.DebugLevel
					case codes.Unimplemented:
						return zerolog.WarnLevel
					case codes.Internal:
						return zerolog.WarnLevel
					case codes.Unavailable:
						return zerolog.WarnLevel
					case codes.DataLoss:
						return zerolog.WarnLevel
					default:
						return zerolog.InfoLevel
					}
				}),
			),
		),
	)

	if err != nil {
		log.Fatal().Err(err).Str("addr", addr).Send()
	}
	defer conn.Close()
}
Output:

type PayloadDecider

type PayloadDecider func(fullMethodName string) bool

PayloadDecider defines rules for suppressing payload interceptor logs

type PayloadOption

type PayloadOption func(*payloadOptions)

PayloadOption used to configure the payload interceptors

func WithLogErrorsDecider added in v0.0.3

func WithLogErrorsDecider(f LogErrorsDecider) PayloadOption

WithLogErrorsDecider customizes the function for deciding if the gRPC interceptor logs should log in error case this decider will be executed if logging payload disabled by log level or by PayloadDecider

func WithPayloadDecider

func WithPayloadDecider(f PayloadDecider) PayloadOption

WithPayloadDecider customizes the function for deciding if the gRPC interceptor logs should log, depends on fullMethodName

func WithPayloadLevel

func WithPayloadLevel(l zerolog.Level) PayloadOption

WithPayloadLevel overrides the log level of payload interceptors

Directories

Path Synopsis
ctxzerolog provides the Context idiom for embedding zerolog into the execution context
ctxzerolog provides the Context idiom for embedding zerolog into the execution context

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL