logging

package
v2.2.0 Latest Latest
Warning

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

Go to latest
Published: Dec 2, 2024 License: Apache-2.0 Imports: 10 Imported by: 326

Documentation

Overview

Package logging is a "parent" package for gRPC logging middlewares.

The gRPC logging middleware populates request-scoped data to `logging.Fields` that relate to the current gRPC call (e.g. service and method names). You can extract/inject data in the propagated context using `logging.ExtractFields` and `logging.InjectFields`.

Once the gRPC logging middleware has added the gRPC specific Fields to the ctx they will then be written with the log lines.

All logging middleware will emit a final log statement. It is based on the error returned by the handler function, the gRPC status code, an error (if any) and it emits at a level controlled via `WithLevels`. You can control this behavior using `WithDecider`.

This parent package

This particular package is intended for use by other middleware, logging or otherwise. It contains interfaces that other logging middlewares *could* share. This allows code to be shared between different implementations.

Field names

All field names of loggers follow the OpenTracing semantics definitions, with `grpc.` prefix if needed: https://github.com/opentracing/specification/blob/master/semantic_conventions.md

Implementations:

* providers/kit * providers/logr * providers/logrus * providers/phuslog * providers/slog * providers/zap * providers/zerolog

Index

Constants

This section is empty.

Variables

View Source
var (
	// SystemTag is tag representing an event inside gRPC call.
	SystemTag = []string{"protocol", "grpc"}
	// ComponentFieldKey is a tag representing the client/server that is calling.
	ComponentFieldKey    = "grpc.component"
	KindServerFieldValue = "server"
	KindClientFieldValue = "client"
	ServiceFieldKey      = "grpc.service"
	MethodFieldKey       = "grpc.method"
	MethodTypeFieldKey   = "grpc.method_type"
)
View Source
var DefaultDurationToFields = DurationToTimeMillisFields

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

Functions

func DefaultErrorToCode

func DefaultErrorToCode(err error) codes.Code

func InjectFields

func InjectFields(ctx context.Context, f Fields) context.Context

InjectFields allows adding fields to any existing Fields that will be used by the logging interceptor or can be extracted further in ExtractFields. For explicitness, in case of duplicates, the newest field occurrence wins. This allows nested components to update popular fields like grpc.component (e.g. server invoking gRPC client).

Don't overuse mutation of fields to avoid surprises.

func InjectLogField

func InjectLogField(ctx context.Context, key string, val any) context.Context

InjectLogField is like InjectFields, just for one field.

func StreamClientInterceptor

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

StreamClientInterceptor returns a new streaming client interceptor that optionally logs the execution of external gRPC calls. Logger will read existing and write new logging.Fields available in current context. See `ExtractFields` and `InjectFields` for details.

func StreamServerInterceptor

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

StreamServerInterceptor returns a new stream server interceptors that optionally logs endpoint handling. Logger will read existing and write new logging.Fields available in current context. See `ExtractFields` and `InjectFields` for details..

func UnaryClientInterceptor

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

UnaryClientInterceptor returns a new unary client interceptor that optionally logs the execution of external gRPC calls. Logger will read existing and write new logging.Fields available in current context. See `ExtractFields` and `InjectFields` for details.

func UnaryServerInterceptor

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

UnaryServerInterceptor returns a new unary server interceptors that optionally logs endpoint handling. Logger will read existing and write new logging.Fields available in current context. See `ExtractFields` and `InjectFields` for details.

Types

type CodeToLevel

type CodeToLevel func(code codes.Code) Level

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

type DurationToFields

type DurationToFields func(duration time.Duration) Fields

DurationToFields function defines how to produce duration fields for logging.

type ErrorToCode

type ErrorToCode func(err error) codes.Code

ErrorToCode function determines the error code of an error. This makes using custom errors with grpc middleware easier.

type ErrorToFields added in v2.2.0

type ErrorToFields func(err error) Fields

ErrorToFields function extract fields from error.

type Fields

type Fields []any

Fields loosely represents key value pairs that adds context to log lines. The key has to be type of string, whereas value can be an arbitrary object.

func DurationToDurationField

func DurationToDurationField(duration time.Duration) Fields

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 DurationToTimeMillisFields

func DurationToTimeMillisFields(duration time.Duration) Fields

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

func ExtractFields

func ExtractFields(ctx context.Context) Fields

ExtractFields returns logging fields from the context. Fields can be added from the context using InjectFields. For example logging interceptor adds some (base) fields into context when used. If there are no fields in the context, it returns an empty Fields value. Extracted fields are useful to construct your own logger that has fields from gRPC interceptors.

func (Fields) AppendUnique

func (f Fields) AppendUnique(add Fields) Fields

AppendUnique appends (can reuse array!) fields which does not occur in existing fields slice.

func (*Fields) Delete added in v2.0.1

func (f *Fields) Delete(key string)

func (Fields) Iterator

func (f Fields) Iterator() *iter

Iterator returns iterator that allows iterating over pair of elements representing field. If number of elements is uneven, last element won't be included will be assumed as key with empty string value. If key is not string, At will panic.

func (Fields) WithUnique

func (f Fields) WithUnique(add Fields) Fields

WithUnique returns copy of fields which is the union of all unique keys. Any duplicates in the added or current fields will be deduplicated where first occurrence takes precedence.

type Level

type Level int

A Level is the importance or severity of a log event. The higher the level, the more important or severe the event.

const (
	LevelDebug Level = -4
	LevelInfo  Level = 0
	LevelWarn  Level = 4
	LevelError Level = 8
)

Second, we wanted to make it easy to use levels to specify logger verbosity. Since a larger level means a more severe event, a logger that accepts events with smaller (or more negative) level means a more verbose logger. Logger verbosity is thus the negation of event severity, and the default verbosity of 0 accepts all events at least as severe as INFO.

Third, we wanted some room between levels to accommodate schemes with named levels between ours. For example, Google Cloud Logging defines a Notice level between Info and Warn. Since there are only a few of these intermediate levels, the gap between the numbers need not be large. Our gap of 4 matches OpenTelemetry's mapping. Subtracting 9 from an OpenTelemetry level in the DEBUG, INFO, WARN and ERROR ranges converts it to the corresponding slog Level range. OpenTelemetry also has the names TRACE and FATAL, which slog does not. But those OpenTelemetry levels can still be represented as slog Levels by using the appropriate integers.

Names for common levels.

func DefaultClientCodeToLevel

func DefaultClientCodeToLevel(code codes.Code) Level

DefaultClientCodeToLevel is the helper mapper that maps gRPC return codes to log levels for client side.

func DefaultServerCodeToLevel

func DefaultServerCodeToLevel(code codes.Code) Level

DefaultServerCodeToLevel is the helper mapper that maps gRPC return codes to log levels for server side.

type LoggableEvent

type LoggableEvent uint

LoggableEvent defines the events a log line can be added on.

const (
	// StartCall is a loggable event representing start of the gRPC call.
	StartCall LoggableEvent = iota
	// FinishCall is a loggable event representing finish of the gRPC call.
	FinishCall
	// PayloadReceived is a loggable event representing received request (server) or response (client).
	// Log line for this event also includes (potentially big) proto.Message of that payload in
	// "grpc.request.content" (server) or "grpc.response.content" (client) field.
	// NOTE: This can get quite verbose, especially for streaming calls, use with caution (e.g. debug only purposes).
	PayloadReceived
	// PayloadSent is a loggable event representing sent response (server) or request (client).
	// Log line for this event also includes (potentially big) proto.Message of that payload in
	// "grpc.response.content" (server) or "grpc.request.content" (client) field.
	// NOTE: This can get quite verbose, especially for streaming calls, use with caution (e.g. debug only purposes).
	PayloadSent
)

type Logger

type Logger interface {
	Log(ctx context.Context, level Level, msg string, fields ...any)
}

Logger requires Log method, similar to experimental slog, allowing logging interceptor to be interoperable. Official adapters for popular loggers are in `provider/` directory (separate modules). It's totally ok to copy simple function implementation over. TODO(bwplotka): Once slog is official, we could use slog method directly. Currently level is copied over, so we don't depend on experimental module. interface used for all our interceptors.

type LoggerFunc

type LoggerFunc func(ctx context.Context, level Level, msg string, fields ...any)

LoggerFunc is a function that also implements Logger interface.

func (LoggerFunc) Log

func (f LoggerFunc) Log(ctx context.Context, level Level, msg string, fields ...any)

type Option

type Option func(*options)

func WithCodes

func WithCodes(f ErrorToCode) Option

WithCodes customizes the function for mapping errors to error codes.

func WithDisableLoggingFields added in v2.0.1

func WithDisableLoggingFields(disableGrpcLogFields ...string) Option

WithDisableLoggingFields disables logging of gRPC fields provided. The following are the default logging fields:

  • SystemTag[0]
  • ComponentFieldKey
  • ServiceFieldKey
  • MethodFieldKey
  • MethodTypeFieldKey

Usage example - WithDisableLoggingFields(logging.MethodFieldKey, logging.MethodTypeFieldKey)

func WithDurationField

func WithDurationField(f DurationToFields) Option

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

func WithErrorFields added in v2.2.0

func WithErrorFields(f ErrorToFields) Option

WithErrorFields allows to extract logging fields from an error.

func WithFieldsFromContext

func WithFieldsFromContext(f fieldsFromCtxFn) Option

WithFieldsFromContext allows overriding existing or adding extra fields to all log messages per given context. If called multiple times, it overwrites the existing FieldsFromContext/WithFieldsFromContextAndCallMeta function. If you need to use multiple FieldsFromContext functions then you should combine them in a wrapper fieldsFromCtxFn. Only one of WithFieldsFromContextAndCallMeta or WithFieldsFromContext should be used, using both will result in the last one overwriting the previous.

func WithFieldsFromContextAndCallMeta added in v2.0.1

func WithFieldsFromContextAndCallMeta(f fieldsFromCtxCallMetaFn) Option

WithFieldsFromContextAndCallMeta allows overriding existing or adding extra fields to all log messages per given context and interceptor.CallMeta If called multiple times, it overwrites the existing FieldsFromContext/WithFieldsFromContextAndCallMeta function. If you need to use multiple WithFieldsFromContextAndCallMeta functions then you should combine them in a wrapper fieldsFromCtxCallMetaFn. Only one of WithFieldsFromContextAndCallMeta or WithFieldsFromContext should be used, using both will result in the last one overwriting the previous.

func WithLevels

func WithLevels(f CodeToLevel) Option

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

func WithLogOnEvents

func WithLogOnEvents(events ...LoggableEvent) Option

WithLogOnEvents customizes on what events the gRPC interceptor should log on.

func WithTimestampFormat

func WithTimestampFormat(format string) Option

WithTimestampFormat customizes the timestamps emitted in the log fields.

Jump to

Keyboard shortcuts

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