Awesome
zenrpc-middleware: Middlewares for vmkteam/zenrpc
zenrpc-middleware
is a set of common middlewares for zenrpc implementing logging,
metrics and error tracking.
Middlewares
WithDevel
Sets bool flag to context for detecting development environment.
WithHeaders
Sets User-Agent, Platform, Version, X-Country headers to context. User-Agent strips to 2048 chars, Platform and Version – to 64, X-Country - to 16.
WithAPILogger
Logs via Printf function (e.g. log.Printf) all requests. For example
ip= platform="" version="" method=nodevel.arith.divide duration=63.659µs params="{ \"a\": 1, \"b\": 24 }" err=<nil> userAgent="Go-http-client/1.1"
WithSentry
Sets additional parameters for current Sentry scope. Extras: params, duration, ip. Tags: platform, version, method.
WithNoCancelContext
Ignores Cancel func from context. This is useful for passing context to go-pg
.
WithMetrics
Logs duration of RPC requests via Prometheus. Default AppName is zenrpc. It exposes two
metrics: appName_rpc_error_requests_count
and appName_rpc_responses_duration_seconds
. Labels: method, code,
platform, version.
WithTiming
Adds timings in JSON-RPC 2.0 Response via extensions
field (not in spec). Middleware is active
when isDevel=true
or AllowDebugFunc returns true
. Sample AllowDebugFunc (checks GET/POST parameters for "true"
value, like ?d=true
):
allowDebugFn := func (param string) middleware.AllowDebugFunc {
return func (req *http.Request) bool {
return req.FormValue(param) == "true"
}
}
DurationLocal
– total method execution time in ms.
If DurationRemote
or DurationDiff
are set then DurationLocal
excludes these values.
WithSQLLogger
Adds SQL
or DurationSQL
fields in JSON-RPC 2.0 Response extensions
field (not in spec).
DurationSQL
field is set then isDevel=true
or AllowDebugFunc(allowDebugFunc) returns true
.
SQL
field is set then isDevel=true
or AllowDebugFunc(allowDebugFunc, allowSqlDebugFunc) returns true
.
WithErrorLogger
Logs all errors (ErrorCode==500 or < 0) via Printf func and sends them to Sentry. It also removes sensitive error data from response. It is good to use pkg/errors for stack trace support in sentry.
ip= platform="Test1" version="v1.0.0 alpha1" method=errordevel.arith.checkzenrpcerror duration=30.786µs params=[ true ] err="test"
XRequestID
Handler for adding X-Request-ID
header to all requests and responses.
s := http.NewServer(middleware.XRequestID(http.HandlerFunc(rpc.ServeHTTP)))
EchoIPContext
Echo middleware for adding client IP info to context for zenrpc middleware
e.Use(middleware.EchoIPContext())
EchoSentryHubContext
Echo middleware for adding sentry hub info to context for zenrpc middleware
e.Use(middleware.EchoSentryHubContext())
Examples
Basic usage
package main
import (
"log"
"net/http"
"os"
"github.com/go-pg/pg/v10"
"github.com/vmkteam/zenrpc-middleware"
"github.com/vmkteam/zenrpc/v2"
)
func main() {
dbс := pg.Connect(&pg.Options{User: "postgres"})
defer dbс.Close()
isDevel := true
elog := log.New(os.Stderr, "E", log.LstdFlags|log.Lshortfile)
dlog := log.New(os.Stdout, "D", log.LstdFlags|log.Lshortfile)
allowDebug := func(param string) middleware.AllowDebugFunc {
return func(req *http.Request) bool {
return req.FormValue(param) == "true"
}
}
rpc := zenrpc.NewServer(zenrpc.Options{
ExposeSMD: true,
AllowCORS: true,
})
rpc.Use(
middleware.WithDevel(isDevel),
middleware.WithHeaders(),
middleware.WithAPILogger(dlog.Printf, middleware.DefaultServerName),
middleware.WithSentry(middleware.DefaultServerName),
middleware.WithNoCancelContext(),
middleware.WithMetrics(middleware.DefaultServerName),
middleware.WithTiming(isDevel, allowDebug("d")),
middleware.WithSQLLogger(dbc, isDevel, allowDebug("d"), allowDebug("s")),
middleware.WithErrorLogger(elog.Printf, middleware.DefaultServerName),
)
}
// rpc.Register and server
Handler snippets
// sentry init
sentry.Init(sentry.ClientOptions{
Dsn: cfg.Sentry.DSN,
Environment: cfg.Sentry.Environment,
Release: version,
}
// sentry middleware for Echo
e.Use(sentryecho.New(sentryecho.Options{
Repanic: true,
WaitForDelivery: true,
}))
// register handler
a.echo.Any("/v1/rpc/", middleware.EchoHandler(rpc))
--- OR ---
e.Use(middleware.EchoIPContext()), middleware.EchoSentryHubContext())
// register handler
e.Any("/int/rpc/", echo.WrapHandler(XRequestID(rpc)))