logadapter

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: May 17, 2021 License: MIT Imports: 32 Imported by: 1

README

logrus-stackdriver-formatter

Go Report Card GoDoc License MIT

Logrus-stackdriver-formatter provides:

In addition to supporting level-based logging to Stackdriver, for Error, Fatal and Panic levels it will append error context for Error Reporting.

Installation

go get -u github.com/TV4/logrus-stackdriver-formatter
Logrus Usage
package main

import (

stackdriver "github.com/StevenACoffman/logrus-stackdriver-formatter"
"github.com/sirupsen/logrus"
)

var log = logrus.New()

func init() {
    log.Formatter = stackdriver.NewFormatter(
        stackdriver.WithService("your-service"), 
        stackdriver.WithVersion("v0.1.0"),
    )
    log.Level = logrus.DebugLevel

    log.Info("ready to log!")
}

Here's a sample entry (prettified) from the example:

{
  "serviceContext": {
    "service": "test-service",
    "version": "v0.1.0"
  },
  "message": "unable to parse integer: strconv.ParseInt: parsing \"text\": invalid syntax",
  "severity": "ERROR",
  "context": {
    "reportLocation": {
      "file": "github.com/StevenACoffman/logrus-stackdriver-formatter/example_test.go",
      "line": 21,
      "function": "ExampleLogError"
    }
  }
}
HTTP request context

If you'd like to add additional context like the httpRequest, here's a convenience function for creating a HTTP logger:

func httpLogger(logger *logrus.Logger, r *http.Request) *logrus.Entry {
    return logger.WithFields(logrus.Fields{
        "httpRequest": map[string]interface{}{
            "method":    r.Method,
            "url":       r.URL.String(),
            "userAgent": r.Header.Get("User-Agent"),
            "referrer":  r.Header.Get("Referer"),
        },
    })
}

Then, in your HTTP handler, create a new context logger and all your log entries will have the HTTP request context appended to them:

func handler(w http.ResponseWriter, r *http.Request) {
    httplog := httpLogger(log, r)
    // ...
    httplog.Infof("Logging with HTTP request context")
}
Go-kit Log Adapter

Go-kit log is wrapped to encode conventions, enforce type-safety, provide leveled logging, and so on. It can be used for both typical application log events, and log-structured data streams.

Typical application logging
import (
	"os"
	logadapter "github.com/StevenACoffman/logrus-stackdriver-formatter"
	kitlog "github.com/go-kit/kit/log"
)

func main() {
	w := kitlog.NewSyncWriter(os.Stderr)
	logger := logadapter.InitLogrusGoKitLogger(w)
	logger.Log("question", "what is the meaning of life?", "answer", 42)

	// Output:
	// question="what is the meaning of life?" answer=42
}
Contextual Loggers
import (
	"os"
	logadapter "github.com/StevenACoffman/logrus-stackdriver-formatter"
	kitlog "github.com/go-kit/kit/log"
)

func main() {
	logger := logadapter.InitLogrusGoKitLogger(kitlog.NewSyncWriter(os.Stderr))
	logger = kitlog.With(logger, "instance_id", 123)

	logger.Log("msg", "starting")
	NewWorker(kitlog.With(logger, "component", "worker")).Run()
	NewSlacker(kitlog.With(logger, "component", "slacker")).Run()
}

// Output:
// instance_id=123 msg=starting
// instance_id=123 component=worker msg=running
// instance_id=123 component=slacker msg=running

Enhancements

go-kit's package log is centered on the one-method Logger interface.

type Logger interface {
	Log(keyvals ...interface{}) error
}

This interface, and its supporting code like is the product of much iteration and evaluation. For more details on the evolution of the Logger interface, see The Hunt for a Logger Interface, a talk by Chris Hines. Also, please see #63, #76, #131, #157, #164, and #252 to review historical conversations about package log and the Logger interface.

Value-add packages and suggestions, like improvements to the leveled logger, are of course welcome. Good proposals should

Alternatives

  • Both go-kit log and logr both provide to developers clean, minimal surface area for sending log messages. However, neither has direct, first-class stackdriver support.
  • Uber's Zap is very performant, but it's SugaredLogger API is unfamiliar to me.

So one choice could be logr -> zapr -> zap -> zap-stackdriver or zapdriver but zapr still uses dep, didn't have go module support.

I could also have gone with go-kit log -> zap -> zap-stackdriver or zapdriver.

Instead, I pulled a bunch of people's forks together into this piece of mad science because it seemed like it would work. ¯\_(ツ)_/¯

Documentation

Overview

Package logadapter provides an adapter to the go-kit log.Logger interface.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultErrorHandler added in v1.0.0

func DefaultErrorHandler(ctx context.Context, err error, method string) (handled bool)

DefaultErrorHandler does nothing.

func DefaultFilterHTTP added in v1.0.0

func DefaultFilterHTTP(r *http.Request) bool

DefaultFilterHTTP filters health checks and monitoring canaries from some well known user agents or URL paths.

func DefaultFilterRPC added in v1.0.0

func DefaultFilterRPC(_ context.Context, fullMethod string, _ error) bool

DefaultFilterRPC filters gRPC standard health check and gRPC reflection requests.

func InitLogging added in v1.0.0

func InitLogging(w io.Writer, opts ...Option) *logrus.Logger

InitLogging initializes a logrus logger to send things to stackdriver.

func LoggingMiddleware added in v1.0.0

func LoggingMiddleware(log *logrus.Logger, opts ...MiddlewareOption) func(http.Handler) http.Handler

LoggingMiddleware proivdes a request-scoped log entry into context for HTTP requests, writes request logs in a structured format to stackdriver.

func RecoveryMiddleware added in v1.0.0

func RecoveryMiddleware(next http.Handler) http.Handler

RecoveryMiddleware recovers from panics in the HTTP handler chain, logging an error for Error Reporting.

func StreamLoggingInterceptor added in v1.0.0

func StreamLoggingInterceptor(logger *logrus.Logger, opts ...MiddlewareOption) grpc.StreamServerInterceptor

StreamLoggingInterceptor provides a request-scoped log entry into context for Streaming gRPC requests, and logs request details at the end of the stream. Logging interceptors should be chained at the very top of the request scope.

func StreamRecoveryInterceptor added in v1.0.0

func StreamRecoveryInterceptor(srv interface{}, ss grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) (err error)

StreamRecoveryInterceptor is an interceptor that recovers panics from Streaming services and turns them into nicer gRPC errors.

func UnaryLoggingInterceptor added in v1.0.0

func UnaryLoggingInterceptor(logger *logrus.Logger, opts ...MiddlewareOption) grpc.UnaryServerInterceptor

UnaryLoggingInterceptor provides a request-scoped log entry into context for Unary gRPC requests, and logs request details on the response. Logging interceptors should be chained at the very top of the request scope.

func UnaryRecoveryInterceptor added in v1.0.0

func UnaryRecoveryInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error)

UnaryRecoveryInterceptor is an interceptor that recovers panics and turns them into nicer GRPC errors.

func WithLogger added in v1.1.0

func WithLogger(ctx context.Context, logger *logrus.Logger) context.Context

WithLogger initializes the log entry in context

Types

type Context added in v1.0.0

type Context struct {
	Data             map[string]interface{} `json:"data,omitempty"`
	User             string                 `json:"user,omitempty"`
	ReportLocation   *ReportLocation        `json:"reportLocation,omitempty"`
	HTTPRequest      *HTTPRequest           `json:"httpRequest,omitempty"`
	PubSubRequest    map[string]interface{} `json:"pubSubRequest,omitempty"`
	GRPCRequest      *GRPCRequest           `json:"grpcRequest,omitempty"`
	GRPCStatus       json.RawMessage        `json:"grpcStatus,omitempty"`
	SourceReferences []SourceReference      `json:"sourceReferences,omitempty"`
}

Context is sent with every message to stackdriver.

type Entry added in v1.0.0

type Entry struct {
	Type           string          `json:"@type,omitempty"`
	LogName        string          `json:"logName,omitempty"`
	Timestamp      string          `json:"timestamp,omitempty"`
	ServiceContext *ServiceContext `json:"serviceContext,omitempty"`
	Message        string          `json:"message,omitempty"`
	Severity       severity        `json:"severity,omitempty"`
	Context        *Context        `json:"context,omitempty"`
	SourceLocation *SourceLocation `json:"logging.googleapis.com/sourceLocation,omitempty"`
	StackTrace     string          `json:"stack_trace,omitempty"`
	Trace          string          `json:"logging.googleapis.com/trace,omitempty"`
	SpanID         string          `json:"logging.googleapis.com/spanId,omitempty"`
	TraceSampled   bool            `json:"logging.googleapis.com/trace_sampled,omitempty"`
	HTTPRequest    *HTTPRequest    `json:"httpRequest,omitempty"`
}

Entry stores a log entry.

type ErrorHandler added in v1.0.0

type ErrorHandler func(ctx context.Context, err error, method string) (handled bool)

ErrorHandler should return true if the error provided has already been logged

type FilterHTTP added in v1.0.0

type FilterHTTP func(r *http.Request) bool

Logging filters

type FilterRPC added in v1.0.0

type FilterRPC func(ctx context.Context, fullMethod string, err error) bool

Logging filters

type Formatter

type Formatter struct {
	Service         string
	Version         string
	SourceReference []SourceReference
	ProjectID       string
	StackSkip       []string
	StackStyle      StackTraceStyle
	SkipTimestamp   bool
	RegexSkip       string
	PrettyPrint     bool
	GlobalTraceID   string
}

Formatter implements Stackdriver formatting for logrus.

func NewFormatter

func NewFormatter(options ...Option) *Formatter

NewFormatter returns a new Formatter.

func (*Formatter) Format

func (f *Formatter) Format(e *logrus.Entry) (b []byte, err error)

Format formats a logrus entry according to the Stackdriver specifications.

func (*Formatter) ToEntry added in v1.0.0

func (f *Formatter) ToEntry(e *logrus.Entry) (Entry, error)

ToEntry formats a logrus entry to a stackdriver entry.

type GRPCRequest added in v1.0.0

type GRPCRequest struct {
	Method    string `json:"method,omitempty"`
	UserAgent string `json:"userAgent,omitempty"`
	PeerAddr  string `json:"peer,omitempty"`
	Deadline  string `json:"deadline,omitempty"`
	Duration  string `json:"duration,omitempty"`
}

GRPCRequest represents details of a gRPC request and response appended to a log.

type HTTPRequest added in v1.0.0

type HTTPRequest struct {
	RequestMethod                  string `json:"requestMethod,omitempty"`
	RequestURL                     string `json:"requestUrl,omitempty"`
	RequestSize                    string `json:"requestSize,omitempty"`
	Status                         string `json:"status,omitempty"`
	ResponseSize                   string `json:"responseSize,omitempty"`
	UserAgent                      string `json:"userAgent,omitempty"`
	RemoteIP                       string `json:"remoteIp,omitempty"`
	ServerIP                       string `json:"serverIp,omitempty"`
	Referer                        string `json:"referer,omitempty"`
	Latency                        string `json:"latency,omitempty"`
	CacheLookup                    bool   `json:"cacheLookup,omitempty"`
	CacheHit                       bool   `json:"cacheHit,omitempty"`
	CacheValidatedWithOriginServer bool   `json:"cacheValidatedWithOriginServer,omitempty"`
	CacheFillBytes                 string `json:"cacheFillBytes,omitempty"`
	Protocol                       string `json:"protocol,omitempty"`
}

HTTPRequest defines details of a request and response to append to a log. https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#httprequest

type LogrusGoKitLogger added in v1.0.0

type LogrusGoKitLogger struct {
	// contains filtered or unexported fields
}

LogrusGoKitLogger is a gokit-compatible wrapper for logrus.LogrusGoKitLogger

func InitLogrusGoKitLogger added in v1.0.0

func InitLogrusGoKitLogger(w io.Writer, opts ...Option) *LogrusGoKitLogger

InitLogrusGoKitLogger initializes a go kit logger to send things to stackdriver.

func NewLogrusGoKitLogger added in v1.0.0

func NewLogrusGoKitLogger(logger logrusLogger) *LogrusGoKitLogger

NewLogrusGoKitLogger creates a gokit-compatible logger

func (LogrusGoKitLogger) Log added in v1.0.0

func (l LogrusGoKitLogger) Log(keyvals ...interface{}) error

Log implements the fundamental Logger interface

type MiddlewareOption added in v1.0.0

type MiddlewareOption func(*middlewareOptions)

func WithErrorHandler added in v1.0.0

func WithErrorHandler(h ErrorHandler) MiddlewareOption

func WithHTTPFilter added in v1.0.0

func WithHTTPFilter(f FilterHTTP) MiddlewareOption

WithHTTPFilter provides a filter to the logging middleware that determines whether or not to log individual messages

func WithRPCFilter added in v1.0.0

func WithRPCFilter(f FilterRPC) MiddlewareOption

WithRPCFilter provides a filter to the logging middleware that determines whether or not to log individual messages

type Option

type Option func(*Formatter)

Option lets you configure the Formatter.

func WithGlobalTraceID added in v1.0.0

func WithGlobalTraceID(id uuid.UUID) Option

WithGlobalTraceID sets a consistent trace id on the global logger context If not provided, a random id will be generated at runtime

func WithPrettyPrint added in v1.0.0

func WithPrettyPrint() Option

WithPrettyPrint pretty-prints logs.

func WithProjectID added in v1.0.0

func WithProjectID(i string) Option

WithProjectID makes sure all entries have your Project information.

func WithRegexSkip added in v1.0.0

func WithRegexSkip(v string) Option

WithRegexSkip lets you configure which functions or packages should be skipped for locating the error.

func WithService

func WithService(n string) Option

WithService lets you configure the service name used for error reporting.

func WithSkipTimestamp added in v1.0.0

func WithSkipTimestamp() Option

WithSkipTimestamp lets you avoid setting the timestamp

func WithSourceReference added in v1.0.0

func WithSourceReference(repository, revision string) Option

WithSourceReference adds reference to the source code.

func WithStackSkip

func WithStackSkip(v string) Option

WithStackSkip lets you configure which packages should be skipped for locating the error.

func WithStackTraceStyle added in v1.0.0

func WithStackTraceStyle(s StackTraceStyle) Option

WithStackTraceStyle configures where to write the stacktrace: appended to the message, as its own field, or both

func WithVersion

func WithVersion(v string) Option

WithVersion lets you configure the service version used for error reporting.

type ReportLocation added in v1.0.0

type ReportLocation struct {
	FilePath     string `json:"filePath,omitempty"`
	LineNumber   int    `json:"lineNumber,omitempty"`
	FunctionName string `json:"functionName,omitempty"`
}

ReportLocation is the information about where an error occurred. https://cloud.google.com/error-reporting/reference/rest/v1beta1/ErrorContext#SourceLocation

type ServiceContext added in v1.0.0

type ServiceContext struct {
	Service string `json:"service,omitempty"`
	Version string `json:"version,omitempty"`
}

ServiceContext provides the data about the service we are sending to Google.

type SourceLocation added in v1.0.0

type SourceLocation struct {
	FilePath     string `json:"file,omitempty"`
	LineNumber   int    `json:"line,omitempty"`
	FunctionName string `json:"function,omitempty"`
}

SourceLocation is the information about where a log entry was produced. https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogEntrySourceLocation

type SourceReference added in v1.0.0

type SourceReference struct {
	Repository string `json:"repository,omitempty"`
	RevisionID string `json:"revisionId,omitempty"`
}

SourceReference is a reference to a particular snapshot of the source tree used to build and deploy an application

type SpanHook added in v1.1.0

type SpanHook struct{}

func (*SpanHook) Fire added in v1.1.0

func (s *SpanHook) Fire(e *logrus.Entry) error

func (*SpanHook) Levels added in v1.1.0

func (s *SpanHook) Levels() []logrus.Level

type StackTraceStyle added in v1.0.0

type StackTraceStyle int
const (
	TraceInMessage StackTraceStyle = iota
	TraceInPayload
	TraceInBoth
)

Directories

Path Synopsis
Package ctxlogrus wraps the go-grpc-middleware ctxlogrus, extracts a trace context to correlate logs emitted to the correct trace and span
Package ctxlogrus wraps the go-grpc-middleware ctxlogrus, extracts a trace context to correlate logs emitted to the correct trace and span

Jump to

Keyboard shortcuts

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