...

Package kit

import "github.com/grpc-ecosystem/go-grpc-middleware/logging/kit"
Overview
Index
Examples
Subdirectories

Overview ▾

`grpc_kit` is a gRPC logging middleware backed by go-kit loggers

It accepts a user-configured `log.Logger` that will be used for logging completed gRPC calls, and be populated into the `context.Context` passed into gRPC handler code.

On calling `StreamServerInterceptor` or `UnaryServerInterceptor` this logging middleware will add gRPC call information to the ctx so that it will be present on subsequent use of the `ctxkit` logger.

If a deadline is present on the gRPC request the grpc.request.deadline tag is populated when the request begins. grpc.request.deadline is a string representing the time (RFC3339) when the current call will expire.

This package also implements request and response *payload* logging, both for server-side and client-side. These will be logged as structured `jsonpb` fields for every message received/sent (both unary and streaming). For that please use `Payload*Interceptor` functions for that. Please note that the user-provided function that determines whetether to log the full request/response payload needs to be written with care, this can significantly slow down gRPC.

*Server Interceptor* Below is a JSON formatted example of a log that would be logged by the server interceptor:

{
  "level": "info",									// string  log level
  "msg": "finished unary call",						// string  log message

  "grpc.code": "OK",								// string  grpc status code
  "grpc.method": "Ping",							// string  method name
  "grpc.service": "mwitkow.testproto.TestService",  // string  full name of the called service
  "grpc.start_time": "2006-01-02T15:04:05Z07:00",   // string  RFC3339 representation of the start time
  "grpc.request.deadline": "2006-01-02T15:04:05Z07:00",   // string  RFC3339 deadline of the current request if supplied
  "grpc.request.value": "something",				// string  value on the request
  "grpc.time_ms": 1.345,							// float32 run time of the call in ms

  "peer.address": {
    "IP": "127.0.0.1",								// string  IP address of calling party
    "Port": 60216,									// int     port call is coming in on
    "Zone": ""										// string  peer zone for caller
  },
  "span.kind": "server",							// string  client | server
  "system": "grpc"									// string

  "custom_field": "custom_value",					// string  user defined field
  "custom_tags.int": 1337,							// int     user defined tag on the ctx
  "custom_tags.string": "something",				// string  user defined tag on the ctx
}

*Payload Interceptor* Below is a JSON formatted example of a log that would be logged by the payload interceptor:

{
  "level": "info",													// string kit log levels
  "msg": "client request payload logged as grpc.request.content",   // string log message

  "grpc.request.content": {											// object content of RPC request
    "msg" : {														// object kit specific inner object
	  "value": "something",											// string defined by caller
      "sleepTimeMs": 9999											// int    defined by caller
    }
  },
  "grpc.method": "Ping",											// string method being called
  "grpc.service": "mwitkow.testproto.TestService",					// string service being called

  "span.kind": "client",											// string client | server
  "system": "grpc"													// string
}

Please see examples and tests for examples of use.

Example (Initialization)

Initialization shows a relatively complex initialization sequence.

Code:

// Logger is used, allowing pre-definition of certain fields by the user.
logger := log.NewNopLogger()
// Shared options for the logger, with a custom gRPC code to log level function.
opts := []kit.Option{
    kit.WithLevels(customFunc),
}
// Create a server, make sure we put the grpc_ctxtags context before everything else.
_ = grpc.NewServer(
    grpc_middleware.WithUnaryServerChain(
        grpc_ctxtags.UnaryServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
        kit.UnaryServerInterceptor(logger, opts...),
    ),
    grpc_middleware.WithStreamServerChain(
        grpc_ctxtags.StreamServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
        kit.StreamServerInterceptor(logger, opts...),
    ),
)

Example (InitializationWithDurationFieldOverride)

Code:

// Logger is used, allowing pre-definition of certain fields by the user.
logger := log.NewNopLogger()
// Shared options for the logger, with a custom duration to log field function.
opts := []kit.Option{
    kit.WithDurationField(func(duration time.Duration) []interface{} {
        return kit.DurationToTimeMillisField(duration)
    }),
}
_ = grpc.NewServer(
    grpc_middleware.WithUnaryServerChain(
        grpc_ctxtags.UnaryServerInterceptor(),
        kit.UnaryServerInterceptor(logger, opts...),
    ),
    grpc_middleware.WithStreamServerChain(
        grpc_ctxtags.StreamServerInterceptor(),
        kit.StreamServerInterceptor(logger, opts...),
    ),
)

Index ▾

Variables
func DefaultClientCodeToLevel(code codes.Code, logger log.Logger) log.Logger
func DefaultCodeToLevel(code codes.Code, logger log.Logger) log.Logger
func DurationToDurationField(duration time.Duration) []interface{}
func DurationToTimeMillisField(duration time.Duration) []interface{}
func PayloadStreamClientInterceptor(logger log.Logger, decider grpc_logging.ClientPayloadLoggingDecider) grpc.StreamClientInterceptor
func PayloadStreamServerInterceptor(logger log.Logger, decider grpc_logging.ServerPayloadLoggingDecider) grpc.StreamServerInterceptor
func PayloadUnaryClientInterceptor(logger log.Logger, decider grpc_logging.ClientPayloadLoggingDecider) grpc.UnaryClientInterceptor
func PayloadUnaryServerInterceptor(logger log.Logger, decider grpc_logging.ServerPayloadLoggingDecider) grpc.UnaryServerInterceptor
func StreamClientInterceptor(logger log.Logger, opts ...Option) grpc.StreamClientInterceptor
func StreamServerInterceptor(logger log.Logger, opts ...Option) grpc.StreamServerInterceptor
func UnaryClientInterceptor(logger log.Logger, opts ...Option) grpc.UnaryClientInterceptor
func UnaryServerInterceptor(logger log.Logger, opts ...Option) grpc.UnaryServerInterceptor
type CodeToLevel
type DurationToField
type Option
    func WithCodes(f grpc_logging.ErrorToCode) Option
    func WithDecider(f grpc_logging.Decider) Option
    func WithDurationField(f DurationToField) Option
    func WithLevels(f CodeToLevel) Option
    func WithTimestampFormat(format string) Option

Package files

client_interceptors.go doc.go options.go payload_interceptors.go server_interceptors.go

Variables

var (
    // SystemField is used in every log statement made through grpc_zap. Can be overwritten before any initialization code.
    SystemField = "grpc"
    // ServerField is used in every server-side log statement made through grpc_zap.Can be overwritten before initialization.
    ServerField = "server"
)

DefaultDurationToField is the default implementation of converting request duration to a kit field.

var DefaultDurationToField = DurationToTimeMillisField
var (
    // JsonPbMarshaller is the marshaller used for serializing protobuf messages.
    // If needed, this variable can be reassigned with a different marshaller with the same Marshal() signature.
    JsonPbMarshaller grpc_logging.JsonPbMarshaler = &jsonpb.Marshaler{}
)

func DefaultClientCodeToLevel

func DefaultClientCodeToLevel(code codes.Code, logger log.Logger) log.Logger

DefaultClientCodeToLevel is the default implementation of gRPC return codes to log levels for client side.

func DefaultCodeToLevel

func DefaultCodeToLevel(code codes.Code, logger log.Logger) log.Logger

DefaultCodeToLevel is the default implementation of gRPC return codes and interceptor log level for server side.

func DurationToDurationField

func DurationToDurationField(duration time.Duration) []interface{}

DurationToDurationField uses a Duration field to log the request duration and leaves it up to Log's encoder settings to determine how that is output.

func DurationToTimeMillisField

func DurationToTimeMillisField(duration time.Duration) []interface{}

DurationToTimeMillisField converts the duration to milliseconds and uses the key `grpc.time_ms`.

func PayloadStreamClientInterceptor

func PayloadStreamClientInterceptor(logger log.Logger, decider grpc_logging.ClientPayloadLoggingDecider) grpc.StreamClientInterceptor

PayloadStreamClientInterceptor returns a new streaming client interceptor that logs the paylods of requests and responses.

func PayloadStreamServerInterceptor

func PayloadStreamServerInterceptor(logger log.Logger, decider grpc_logging.ServerPayloadLoggingDecider) grpc.StreamServerInterceptor

PayloadStreamServerInterceptor returns a new server server interceptors that logs the payloads of requests.

This *only* works when placed *after* the `kit.StreamServerInterceptor`. However, the logging can be done to a separate instance of the logger.

func PayloadUnaryClientInterceptor

func PayloadUnaryClientInterceptor(logger log.Logger, decider grpc_logging.ClientPayloadLoggingDecider) grpc.UnaryClientInterceptor

PayloadUnaryClientInterceptor returns a new unary client interceptor that logs the paylods of requests and responses.

func PayloadUnaryServerInterceptor

func PayloadUnaryServerInterceptor(logger log.Logger, decider grpc_logging.ServerPayloadLoggingDecider) grpc.UnaryServerInterceptor

PayloadUnaryServerInterceptor returns a new unary server interceptors that logs the payloads of requests.

This *only* works when placed *after* the `kit.UnaryServerInterceptor`. However, the logging can be done to a separate instance of the logger.

func StreamClientInterceptor

func StreamClientInterceptor(logger log.Logger, opts ...Option) grpc.StreamClientInterceptor

StreamClientInterceptor returns a new streaming client interceptor that optionally logs the execution of external gRPC calls.

func StreamServerInterceptor

func StreamServerInterceptor(logger log.Logger, opts ...Option) grpc.StreamServerInterceptor

StreamServerInterceptor returns a new stream server interceptors that adds kit.Logger to the context.

func UnaryClientInterceptor

func UnaryClientInterceptor(logger log.Logger, opts ...Option) grpc.UnaryClientInterceptor

UnaryClientInterceptor returns a new unary client interceptor that optionally logs the execution of external gRPC calls.

func UnaryServerInterceptor

func UnaryServerInterceptor(logger log.Logger, opts ...Option) grpc.UnaryServerInterceptor

UnaryServerInterceptor returns a new unary server interceptors that adds kit.Logger to the context.

type CodeToLevel

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

type CodeToLevel func(code codes.Code, logger log.Logger) log.Logger

type DurationToField

DurationToField function defines how to produce duration fields for logging

type DurationToField func(duration time.Duration) []interface{}

type Option

type Option func(*options)

func WithCodes

func WithCodes(f grpc_logging.ErrorToCode) Option

WithCodes customizes the function for mapping errors to error codes.

func WithDecider

func WithDecider(f grpc_logging.Decider) Option

WithDecider customizes the function for deciding if the gRPC interceptor logs should log.

Example

Code:

opts := []kit.Option{
    kit.WithDecider(func(methodFullName string, err error) bool {
        // will not log gRPC calls if it was a call to healthcheck and no error was raised
        if err == nil && methodFullName == "blah.foo.healthcheck" {
            return false
        }

        // by default you will log all calls
        return true
    }),
}

_ = []grpc.ServerOption{
    grpc_middleware.WithStreamServerChain(
        grpc_ctxtags.StreamServerInterceptor(),
        kit.StreamServerInterceptor(log.NewNopLogger(), opts...)),
    grpc_middleware.WithUnaryServerChain(
        grpc_ctxtags.UnaryServerInterceptor(),
        kit.UnaryServerInterceptor(log.NewNopLogger(), opts...)),
}

func WithDurationField

func WithDurationField(f DurationToField) Option

WithDurationField customizes the function for mapping request durations to log fields.

func WithLevels

func WithLevels(f CodeToLevel) Option

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

func WithTimestampFormat

func WithTimestampFormat(format string) Option

WithTimestampFormat customizes the timestamps emitted in the log fields.

Subdirectories

Name Synopsis
..
ctxkit `ctxkit` is a ctxlogger that is backed by go-kit