diff --git a/README.md b/README.md
index ef21047d9..6842f9d41 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
[gRPC Go](https://github.com/grpc/grpc-go) Middleware: interceptors, helpers, utilities.
-**Important** The repo recently moved from `github.com/grpc-ecosystem/go-grpc-middleware`, please update your import paths.
+**Important** The repo recently moved to `github.com/grpc-ecosystem/go-grpc-middleware`, please update your import paths.
## Middleware
@@ -24,7 +24,7 @@ These are generic building blocks that make it easy to build multiple microservi
The purpose of this repository is to act as a go-to point for such reusable functionality. It contains
some of them itself, but also will link to useful external repos.
-`grpc_middleware` itself provides support for chaining interceptors. Se [Documentation](DOC.md), but here's an example:
+`grpc_middleware` itself provides support for chaining interceptors. See [Documentation](DOC.md), but here's an example:
```go
import "github.com/grpc-ecosystem/go-grpc-middleware"
diff --git a/auth/DOC.md b/auth/DOC.md
index 4ba4c463b..5c4de1179 100644
--- a/auth/DOC.md
+++ b/auth/DOC.md
@@ -21,6 +21,42 @@ It also allows for per-service implementation overrides of `AuthFunc`. See `Serv
Please see examples for simple examples of use.
+#### Example:
+
+
+Click to expand code.
+
+```go
+token, err := grpc_auth.AuthFromMD(ctx, "bearer")
+ if err != nil {
+ return nil, err
+ }
+ tokenInfo, err := parseToken(token)
+ if err != nil {
+ return nil, grpc.Errorf(codes.Unauthenticated, "invalid auth token: %v", err)
+ }
+ grpc_ctxtags.Extract(ctx).Set("auth.sub", userClaimFromToken(tokenInfo))
+ newCtx := context.WithValue(ctx, "tokenInfo", tokenInfo)
+ return newCtx, nil
+```
+
+
+
+#### Example:
+
+
+Click to expand code.
+
+```go
+server := grpc.NewServer(
+ grpc.StreamInterceptor(grpc_auth.StreamServerInterceptor(Example_authfunc)),
+ grpc.UnaryInterceptor(grpc_auth.UnaryServerInterceptor(Example_authfunc)),
+ )
+ return server
+```
+
+
+
## Imported Packages
- [github.com/grpc-ecosystem/go-grpc-middleware](./..)
diff --git a/fixup.sh b/fixup.sh
index 8202d6678..850ec557d 100755
--- a/fixup.sh
+++ b/fixup.sh
@@ -17,7 +17,7 @@ function generate_markdown {
package=${realdir##${GOPATH}/src/}
echo "$package"
cd ${dir}
- ${GOBIN}/godoc2ghmd -file DOC.md ${package}
+ ${GOBIN}/godoc2ghmd -ex -file DOC.md ${package}
ln -s DOC.md README.md 2> /dev/null # can fail
cd ${oldpwd}
done;
diff --git a/logging/logrus/DOC.md b/logging/logrus/DOC.md
index a42831258..e12aaec93 100644
--- a/logging/logrus/DOC.md
+++ b/logging/logrus/DOC.md
@@ -15,10 +15,92 @@ It accepts a user-configured `logrus.Entry` that will be used for logging comple
You can use `Extract` to log into a request-scoped `logrus.Entry` instance in your handler code. The fields set on the
logger correspond to the grpc_ctxtags.Tags attached to the context.
+This package also implements request and response *payload* logging, both for server-side and client-side. These will be
+logged as structured `jsonbp` 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.
+
Logrus can also be made as a backend for gRPC library internals. For that use `ReplaceGrpcLogger`.
Please see examples and tests for examples of use.
+#### Example:
+
+
+Click to expand code.
+
+```go
+x := func(ctx context.Context, ping *pb_testproto.PingRequest) (*pb_testproto.PingResponse, error) {
+ // Add fields the ctxtags of the request which will be added to all extracted loggers.
+ grpc_ctxtags.Extract(ctx).Set("custom_tags.string", "something").Set("custom_tags.int", 1337)
+ // Extract a request-scoped zap.Logger and log a message.
+ grpc_logrus.Extract(ctx).Info("some ping")
+ return &pb_testproto.PingResponse{Value: ping.Value}, nil
+ }
+ return x
+```
+
+
+
+#### Example:
+
+
+Click to expand code.
+
+```go
+// Logrus entry is used, allowing pre-definition of certain fields by the user.
+ logrusEntry := logrus.NewEntry(logrusLogger)
+ // Shared options for the logger, with a custom gRPC code to log level function.
+ opts := []grpc_logrus.Option{
+ grpc_logrus.WithLevels(customFunc),
+ }
+ // Make sure that log statements internal to gRPC library are logged using the zapLogger as well.
+ grpc_logrus.ReplaceGrpcLogger(logrusEntry)
+ // Create a server, make sure we put the grpc_ctxtags context before everything else.
+ server := grpc.NewServer(
+ grpc_middleware.WithUnaryServerChain(
+ grpc_ctxtags.UnaryServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
+ grpc_logrus.UnaryServerInterceptor(logrusEntry, opts...),
+ ),
+ grpc_middleware.WithStreamServerChain(
+ grpc_ctxtags.StreamServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
+ grpc_logrus.StreamServerInterceptor(logrusEntry, opts...),
+ ),
+ )
+ return server
+```
+
+
+
+#### Example:
+
+
+Click to expand code.
+
+```go
+// Logrus entry is used, allowing pre-definition of certain fields by the user.
+ logrusEntry := logrus.NewEntry(logrusLogger)
+ // Shared options for the logger, with a custom duration to log field function.
+ opts := []grpc_logrus.Option{
+ grpc_logrus.WithDurationField(func(duration time.Duration) (key string, value interface{}) {
+ return "grpc.time_ns", duration.Nanoseconds()
+ }),
+ }
+ server := grpc.NewServer(
+ grpc_middleware.WithUnaryServerChain(
+ grpc_ctxtags.UnaryServerInterceptor(),
+ grpc_logrus.UnaryServerInterceptor(logrusEntry, opts...),
+ ),
+ grpc_middleware.WithStreamServerChain(
+ grpc_ctxtags.StreamServerInterceptor(),
+ grpc_logrus.StreamServerInterceptor(logrusEntry, opts...),
+ ),
+ )
+ return server
+```
+
+
+
## Imported Packages
- github.com/Sirupsen/logrus
diff --git a/logging/logrus/doc.go b/logging/logrus/doc.go
index 5fddae9bc..0b91720f4 100644
--- a/logging/logrus/doc.go
+++ b/logging/logrus/doc.go
@@ -10,6 +10,11 @@ It accepts a user-configured `logrus.Entry` that will be used for logging comple
You can use `Extract` to log into a request-scoped `logrus.Entry` instance in your handler code. The fields set on the
logger correspond to the grpc_ctxtags.Tags attached to the context.
+This package also implements request and response *payload* logging, both for server-side and client-side. These will be
+logged as structured `jsonbp` 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.
+
Logrus can also be made as a backend for gRPC library internals. For that use `ReplaceGrpcLogger`.
Please see examples and tests for examples of use.
diff --git a/logging/zap/DOC.md b/logging/zap/DOC.md
index bc3a7d285..d97de2c77 100644
--- a/logging/zap/DOC.md
+++ b/logging/zap/DOC.md
@@ -15,10 +15,89 @@ be used for logging completed gRPC calls, and be populated into the `context.Con
You can use `Extract` to log into a request-scoped `zap.Logger` instance in your handler code. The fields set on the
logger correspond to the grpc_ctxtags.Tags attached to the context.
+This package also implements request and response *payload* logging, both for server-side and client-side. These will be
+logged as structured `jsonbp` 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.
+
ZAP can also be made as a backend for gRPC library internals. For that use `ReplaceGrpcLogger`.
Please see examples and tests for examples of use.
+#### Example:
+
+
+Click to expand code.
+
+```go
+x := func(ctx context.Context, ping *pb_testproto.PingRequest) (*pb_testproto.PingResponse, error) {
+ // Add fields the ctxtags of the request which will be added to all extracted loggers.
+ grpc_ctxtags.Extract(ctx).Set("custom_tags.string", "something").Set("custom_tags.int", 1337)
+ // Extract a request-scoped zap.Logger and log a message.
+ grpc_zap.Extract(ctx).Info("some ping")
+ return &pb_testproto.PingResponse{Value: ping.Value}, nil
+ }
+ return x
+```
+
+
+
+#### Example:
+
+
+Click to expand code.
+
+```go
+// Shared options for the logger, with a custom gRPC code to log level function.
+ opts := []grpc_zap.Option{
+ grpc_zap.WithLevels(customFunc),
+ }
+ // Make sure that log statements internal to gRPC library are logged using the zapLogger as well.
+ grpc_zap.ReplaceGrpcLogger(zapLogger)
+ // Create a server, make sure we put the grpc_ctxtags context before everything else.
+ server := grpc.NewServer(
+ grpc_middleware.WithUnaryServerChain(
+ grpc_ctxtags.UnaryServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
+ grpc_zap.UnaryServerInterceptor(zapLogger, opts...),
+ ),
+ grpc_middleware.WithStreamServerChain(
+ grpc_ctxtags.StreamServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
+ grpc_zap.StreamServerInterceptor(zapLogger, opts...),
+ ),
+ )
+ return server
+```
+
+
+
+#### Example:
+
+
+Click to expand code.
+
+```go
+opts := []grpc_zap.Option{
+ grpc_zap.WithDurationField(func(duration time.Duration) zapcore.Field {
+ return zap.Int64("grpc.time_ns", duration.Nanoseconds())
+ }),
+ }
+
+ server := grpc.NewServer(
+ grpc_middleware.WithUnaryServerChain(
+ grpc_ctxtags.UnaryServerInterceptor(),
+ grpc_zap.UnaryServerInterceptor(zapLogger, opts...),
+ ),
+ grpc_middleware.WithStreamServerChain(
+ grpc_ctxtags.StreamServerInterceptor(),
+ grpc_zap.StreamServerInterceptor(zapLogger, opts...),
+ ),
+ )
+
+ return server
+```
+
+
+
## Imported Packages
- [github.com/golang/protobuf/jsonpb](https://godoc.org/github.com/golang/protobuf/jsonpb)
diff --git a/logging/zap/doc.go b/logging/zap/doc.go
index aa333d97d..c6d2169e3 100644
--- a/logging/zap/doc.go
+++ b/logging/zap/doc.go
@@ -10,6 +10,11 @@ be used for logging completed gRPC calls, and be populated into the `context.Con
You can use `Extract` to log into a request-scoped `zap.Logger` instance in your handler code. The fields set on the
logger correspond to the grpc_ctxtags.Tags attached to the context.
+This package also implements request and response *payload* logging, both for server-side and client-side. These will be
+logged as structured `jsonbp` 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.
+
ZAP can also be made as a backend for gRPC library internals. For that use `ReplaceGrpcLogger`.
Please see examples and tests for examples of use.
diff --git a/recovery/DOC.md b/recovery/DOC.md
index e34a48d59..6f391f58f 100644
--- a/recovery/DOC.md
+++ b/recovery/DOC.md
@@ -7,7 +7,7 @@
* [Examples](#pkg-examples)
## Overview
-`grpc_recovery` conversion of panics into gRPC errors
+`grpc_recovery` are intereceptors that recover from gRPC handler panics.
### Server Side Recovery Middleware
By default a panic will be converted into a gRPC error with `code.Internal`.
@@ -16,6 +16,31 @@ Handling can be customised by providing an alternate recovery function.
Please see examples for simple examples of use.
+#### Example:
+
+
+Click to expand code.
+
+```go
+// Shared options for the logger, with a custom gRPC code to log level function.
+ opts := []grpc_recovery.Option{
+ grpc_recovery.WithRecoveryHandler(customFunc),
+ }
+ // Create a server. Recovery handlers should typically be last in the chain so that other middleware
+ // (e.g. logging) can operate on the recovered state instead of being directly affected by any panic
+ server := grpc.NewServer(
+ grpc_middleware.WithUnaryServerChain(
+ grpc_recovery.UnaryServerInterceptor(opts...),
+ ),
+ grpc_middleware.WithStreamServerChain(
+ grpc_recovery.StreamServerInterceptor(opts...),
+ ),
+ )
+ return server
+```
+
+
+
## Imported Packages
- [golang.org/x/net/context](https://godoc.org/golang.org/x/net/context)
diff --git a/recovery/doc.go b/recovery/doc.go
index d0ec6e6da..da40190c5 100644
--- a/recovery/doc.go
+++ b/recovery/doc.go
@@ -2,7 +2,7 @@
// See LICENSE for licensing terms.
/*
-`grpc_recovery` conversion of panics into gRPC errors
+`grpc_recovery` are intereceptors that recover from gRPC handler panics.
Server Side Recovery Middleware
diff --git a/retry/DOC.md b/retry/DOC.md
index cb99689f7..8a76d11f2 100644
--- a/retry/DOC.md
+++ b/retry/DOC.md
@@ -23,6 +23,84 @@ linear backoff with 10% jitter.
Please see examples for more advanced use.
+#### Example:
+
+
+Click to expand code.
+
+```go
+client := pb_testproto.NewTestServiceClient(cc)
+ pong, err := client.Ping(
+ newCtx(5*time.Second),
+ &pb_testproto.PingRequest{},
+ grpc_retry.WithMax(3),
+ grpc_retry.WithPerRetryTimeout(1*time.Second))
+ if err != nil {
+ return err
+ }
+ fmt.Printf("got pong: %v", pong)
+ return nil
+```
+
+
+
+#### Example:
+
+
+Click to expand code.
+
+```go
+opts := []grpc_retry.CallOption{
+ grpc_retry.WithBackoff(grpc_retry.BackoffLinear(100 * time.Millisecond)),
+ grpc_retry.WithCodes(codes.NotFound, codes.Aborted),
+ }
+ return grpc.Dial("myservice.example.com",
+ grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(opts...)),
+ grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor(opts...)),
+ )
+```
+
+
+
+#### Example:
+
+
+Click to expand code.
+
+```go
+return grpc.Dial("myservice.example.com",
+ grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor()),
+ grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor()),
+ )
+```
+
+
+
+#### Example:
+
+
+Click to expand code.
+
+```go
+client := pb_testproto.NewTestServiceClient(cc)
+ stream, err := client.PingList(newCtx(1*time.Second), &pb_testproto.PingRequest{}, grpc_retry.WithMax(3))
+ if err != nil {
+ return err
+ }
+ for {
+ pong, err := stream.Recv() // retries happen here
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return err
+ }
+ fmt.Printf("got pong: %v", pong)
+ }
+ return nil
+```
+
+
+
## Imported Packages
- [github.com/grpc-ecosystem/go-grpc-middleware/util/backoffutils](./../util/backoffutils)
diff --git a/tags/DOC.md b/tags/DOC.md
index b9823c642..62ec88118 100644
--- a/tags/DOC.md
+++ b/tags/DOC.md
@@ -7,6 +7,38 @@
* [Examples](#pkg-examples)
## Overview
+`grpc_ctxtags` adds a Tag object to the context that can be used by other middleware to add context about a request.
+
+### Request Context Tags
+Tags describe information about the request, and can be set and used by other middleware, or handlers. Tags are used
+for logging and tracing of requests. Tags are populated both upwards, *and* downwards in the interceptor-handler stack.
+
+You can automatically extract tags (in `grpc.request.`) from request payloads (in unary and server-streaming)
+by passing in the `WithFieldExtractor` option.
+
+If a user doesn't use the interceptors that initialize the `Tags` object, all operations following from an `Extract(ctx)`
+will be no-ops. This is to ensure that code doesn't panic if the interceptors weren't used.
+
+Tags fields are typed, and shallow and should follow the OpenTracing semantics convention:
+https://github.com/opentracing/specification/blob/master/semantic_conventions.md
+
+#### Example:
+
+
+Click to expand code.
+
+```go
+opts := []grpc_ctxtags.Option{
+ grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.TagBasedRequestFieldExtractor("log_fields")),
+ }
+ server := grpc.NewServer(
+ grpc.StreamInterceptor(grpc_ctxtags.StreamServerInterceptor(opts...)),
+ grpc.UnaryInterceptor(grpc_ctxtags.UnaryServerInterceptor(opts...)),
+ )
+ return server
+```
+
+
## Imported Packages
diff --git a/tags/doc.go b/tags/doc.go
index 03b8cd881..8bfdb0ddc 100644
--- a/tags/doc.go
+++ b/tags/doc.go
@@ -2,7 +2,7 @@
// See LICENSE for licensing terms.
/*
-`grpc_ctxtags` adds a Tag object to the context that can be used by other middleware to add context about a request
+`grpc_ctxtags` adds a Tag object to the context that can be used by other middleware to add context about a request.
Request Context Tags
@@ -17,7 +17,5 @@ will be no-ops. This is to ensure that code doesn't panic if the interceptors we
Tags fields are typed, and shallow and should follow the OpenTracing semantics convention:
https://github.com/opentracing/specification/blob/master/semantic_conventions.md
-
*/
-
package grpc_ctxtags
diff --git a/tracing/opentracing/DOC.md b/tracing/opentracing/DOC.md
index 09ec447cd..823b05d81 100644
--- a/tracing/opentracing/DOC.md
+++ b/tracing/opentracing/DOC.md
@@ -6,6 +6,20 @@
* [Index](#pkg-index)
## Overview
+`grpc_opentracing` adds OpenTracing
+
+### OpenTracing Interceptors
+These are both client-side and server-side interceptors for OpenTracing. They are a provider-agnostic, with backends
+such as Zipkin, or Google Stackdriver Trace.
+
+For a service that sends out requests and receives requests, you *need* to use both, otherwise downstream requests will
+not have the appropriate requests propagated.
+
+All server-side spans are tagged with grpc_ctxtags information.
+
+For more information see:
+http://opentracing.io/documentation/
+https://github.com/opentracing/specification/blob/master/semantic_conventions.md
## Imported Packages
diff --git a/tracing/opentracing/doc.go b/tracing/opentracing/doc.go
index 9471059c7..7a58efc22 100644
--- a/tracing/opentracing/doc.go
+++ b/tracing/opentracing/doc.go
@@ -19,5 +19,4 @@ http://opentracing.io/documentation/
https://github.com/opentracing/specification/blob/master/semantic_conventions.md
*/
-
package grpc_opentracing