zapmw

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: May 30, 2019 License: MIT Imports: 8 Imported by: 3

README

zapmw

CircleCI codecov

zapmw is net/http.Handler middleware using zap.

Installation

go get -u github.com/purini-to/zapmw

Quick Start

It can be used as middleware on compatible routers due to the net/http.Handler interface.

router http.NewServeMux:

package main

import (
	"github.com/purini-to/zapmw"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"net/http"
)

var cnt = 1

func main() {
	logger, _ := zap.NewDevelopment()

	m := http.NewServeMux()
	m.Handle("/",
		zapmw.WithZap(logger)(zapmw.Request(zapcore.InfoLevel, "request")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			logger := zapmw.GetZap(r)
			logger.Debug("access!", zap.Int("cnt", cnt))
			w.Write([]byte("Hello world"))
			cnt++
		}))),
	)

	s := http.Server{Addr: ":3000", Handler: m}
	s.ListenAndServe()
}
// out:
// 2019-05-23T14:00:15.410+0900	DEBUG	cmd/main.go:19	access!	{"cnt": 1}
// 2019-05-23T14:00:15.410+0900	INFO	zapmw/request.go:32	request	{"method": "GET", "url": "/", "proto": "HTTP/1.1", "status": 200, "ip": "[::1]:54434", "byte": 11, "took": "440.597µs"}
// 2019-05-23T14:00:15.917+0900	DEBUG	cmd/main.go:19	access!	{"cnt": 2}
// 2019-05-23T14:00:15.917+0900	INFO	zapmw/request.go:32	request	{"method": "GET", "url": "/", "proto": "HTTP/1.1", "status": 200, "ip": "[::1]:54434", "byte": 11, "took": "86.27µs"}

router chi:

package main

import (
	"github.com/go-chi/chi"
	"github.com/go-chi/chi/middleware"
	"github.com/purini-to/zapmw"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"net/http"
)

var cnt = 1

func withRequestID(logger *zap.Logger, r *http.Request) *zap.Logger {
	reqID := middleware.GetReqID(r.Context())
	if len(reqID) == 0 {
		return logger
	}

	return logger.With(zap.String("reqId", reqID))
}

func main() {
	logger, _ := zap.NewDevelopment()

	r := chi.NewRouter()

	r.Use(
		middleware.RequestID,
		zapmw.WithZap(logger, withRequestID), // logger with request id.
		zapmw.Request(zapcore.InfoLevel, "request"),
		zapmw.Recoverer(zapcore.ErrorLevel, "recover", zapmw.RecovererDefault),
	)

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		logger := zapmw.GetZap(r)
		logger.Debug("access!", zap.Int("cnt", cnt))
		w.Write([]byte("Hello world"))
		cnt++
	})

	http.ListenAndServe(":3000", r)
}
// out:
// 2019-05-23T14:11:38.650+0900	DEBUG	chi/main.go:37	access!	{"reqId": "xxxxxx-000001", "cnt": 1}
// 2019-05-23T14:11:38.650+0900	INFO	zapmw/request.go:32	request	{"reqId": "xxxxxx-000001", "method": "GET", "url": "/", "proto": "HTTP/1.1", "status": 200, "ip": "[::1]:54517", "byte": 11, "took": "174.504µs"}
// 2019-05-23T14:11:39.442+0900	DEBUG	chi/main.go:37	access!	{"reqId": "xxxxxx-000002", "cnt": 2}
// 2019-05-23T14:11:39.442+0900	INFO	zapmw/request.go:32	request	{"reqId": "xxxxxx-000002", "method": "GET", "url": "/", "proto": "HTTP/1.1", "status": 200, "ip": "[::1]:54517", "byte": 11, "took": "55.185µs"}

router gorilla/mux:

package main

import (
	"github.com/gorilla/mux"
	"github.com/purini-to/zapmw"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"net/http"
)

var cnt = 1

func main() {
	logger, _ := zap.NewDevelopment()

	r := mux.NewRouter()

	r.Use(
		zapmw.WithZap(logger),
		zapmw.Request(zapcore.InfoLevel, "request"),
		zapmw.Recoverer(zapcore.ErrorLevel, "recover", zapmw.RecovererDefault),
	)

	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		logger := zapmw.GetZap(r)
		logger.Debug("access!", zap.Int("cnt", cnt))
		w.Write([]byte("Hello world"))
		cnt++
	})

	http.ListenAndServe(":3000", r)
}
// out:
// 2019-05-23T14:18:35.966+0900	DEBUG	gorilla/main.go:26	access!	{"cnt": 1}
// 2019-05-23T14:18:35.966+0900	INFO	zapmw/request.go:32	request	{"method": "GET", "url": "/", "proto": "HTTP/1.1", "status": 200, "ip": "[::1]:54563", "byte": 11, "took": "426.231µs"}
// 2019-05-23T14:18:36.588+0900	DEBUG	gorilla/main.go:26	access!	{"cnt": 2}
// 2019-05-23T14:18:36.588+0900	INFO	zapmw/request.go:32	request	{"method": "GET", "url": "/", "proto": "HTTP/1.1", "status": 200, "ip": "[::1]:54563", "byte": 11, "took": "84.474µs"}

Documentation

Index

Constants

View Source
const ZapKey ctxKeyZap = iota

ZapKey is the key that holds the unique zap logger in a request context.

Variables

This section is empty.

Functions

func GetZap

func GetZap(r *http.Request) *zap.Logger

GetZap returns the zap logger in a request context.

func GetZapCtx added in v1.1.0

func GetZapCtx(ctx context.Context) *zap.Logger

GetZapCtx returns the zap logger in a context.

func Recoverer

func Recoverer(lvl zapcore.Level, msg string, opts ...OptionRecoverer) func(next http.Handler) http.Handler

Recoverer is a middleware that recovers from panics.

func RecovererDefault

func RecovererDefault(w http.ResponseWriter, _ *http.Request)

RecovererDefault writes server error response.

func Request

func Request(lvl zapcore.Level, msg string, opts ...OptionRequest) func(next http.Handler) http.Handler

Request a middleware that logs the start and end of each request.

func WithZap

func WithZap(logger *zap.Logger, opts ...OptionWithZap) func(next http.Handler) http.Handler

WithZap is a middleware that sets the zap logger in a context chain.

Types

type OptionRecoverer

type OptionRecoverer func(w http.ResponseWriter, r *http.Request)

OptionRecoverer is an option to change error response process.

type OptionRequest

type OptionRequest func(r *http.Request) []zap.Field

OptionRequest is an option to add fields for request log.

type OptionWithZap

type OptionWithZap func(logger *zap.Logger, r *http.Request) *zap.Logger

OptionWithZap is an option to add processing to zap logger held in request context.

type WrapResponseWriter

type WrapResponseWriter interface {
	http.ResponseWriter
	// Status returns the HTTP status of the request, or 0 if one has not
	// yet been sent.
	Status() int
	// BytesWritten returns the total number of bytes sent to the client.
	BytesWritten() int
	// Tee causes the response body to be written to the given io.Writer in
	// addition to proxying the writes through. Only one io.Writer can be
	// tee'd to at once: setting a second one will overwrite the first.
	// Writes will be sent to the proxy before being written to this
	// io.Writer. It is illegal for the tee'd writer to be modified
	// concurrently with writes.
	Tee(io.Writer)
	// Unwrap returns the original proxied target.
	Unwrap() http.ResponseWriter
}

WrapResponseWriter is a proxy around an http.ResponseWriter that allows you to hook into various parts of the response process.

func NewWrapResponseWriter

func NewWrapResponseWriter(w http.ResponseWriter, protoMajor int) WrapResponseWriter

NewWrapResponseWriter wraps an http.ResponseWriter, returning a proxy that allows you to hook into various parts of the response process.

Directories

Path Synopsis
examples
chi

Jump to

Keyboard shortcuts

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