TUN-528: Move cloudflared into a separate repo

This commit is contained in:
Areg Harutyunyan
2018-05-01 18:45:06 -05:00
parent e8c621a648
commit d06fc520c7
4726 changed files with 1763680 additions and 0 deletions

View File

@@ -0,0 +1 @@
.gradle/*

View File

@@ -0,0 +1,27 @@
Copyright (c) 2016, gRPC Ecosystem
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of grpc-opentracing nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,23 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the GRPC project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of GRPC, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of GRPC. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of GRPC or any code incorporated within this
implementation of GRPC constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of GRPC
shall terminate as of the date such litigation is filed.
Status API Training Shop Blog About

View File

@@ -0,0 +1,25 @@
################
GRPC-OpenTracing
################
This package enables distributed tracing in GRPC clients and servers via `The OpenTracing Project`_: a set of consistent, expressive, vendor-neutral APIs for distributed tracing and context propagation.
Once a production system contends with real concurrency or splits into many services, crucial (and formerly easy) tasks become difficult: user-facing latency optimization, root-cause analysis of backend errors, communication about distinct pieces of a now-distributed system, etc. Distributed tracing follows a request on its journey from inception to completion from mobile/browser all the way to the microservices.
As core services and libraries adopt OpenTracing, the application builder is no longer burdened with the task of adding basic tracing instrumentation to their own code. In this way, developers can build their applications with the tools they prefer and benefit from built-in tracing instrumentation. OpenTracing implementations exist for major distributed tracing systems and can be bound or swapped with a one-line configuration change.
*******************
Further Information
*******************
If youre interested in learning more about the OpenTracing standard, join the conversation on our `mailing list`_ or `Gitter`_.
If you want to learn more about the underlying API for your platform, visit the `source code`_.
If you would like to implement OpenTracing in your project and need help, feel free to send us a note at `community@opentracing.io`_.
.. _The OpenTracing Project: http://opentracing.io/
.. _source code: https://github.com/opentracing/
.. _mailing list: http://opentracing.us13.list-manage.com/subscribe?u=180afe03860541dae59e84153&id=19117aa6cd
.. _Gitter: https://gitter.im/opentracing/public
.. _community@opentracing.io: community@opentracing.io

View File

@@ -0,0 +1,57 @@
# OpenTracing support for gRPC in Go
The `otgrpc` package makes it easy to add OpenTracing support to gRPC-based
systems in Go.
## Installation
```
go get github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc
```
## Documentation
See the basic usage examples below and the [package documentation on
godoc.org](https://godoc.org/github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc).
## Client-side usage example
Wherever you call `grpc.Dial`:
```go
// You must have some sort of OpenTracing Tracer instance on hand.
var tracer opentracing.Tracer = ...
...
// Set up a connection to the server peer.
conn, err := grpc.Dial(
address,
... // other options
grpc.WithUnaryInterceptor(
otgrpc.OpenTracingClientInterceptor(tracer)),
grpc.WithStreamInterceptor(
otgrpc.OpenTracingStreamClientInterceptor(tracer)))
// All future RPC activity involving `conn` will be automatically traced.
```
## Server-side usage example
Wherever you call `grpc.NewServer`:
```go
// You must have some sort of OpenTracing Tracer instance on hand.
var tracer opentracing.Tracer = ...
...
// Initialize the gRPC server.
s := grpc.NewServer(
... // other options
grpc.UnaryInterceptor(
otgrpc.OpenTracingServerInterceptor(tracer)),
grpc.StreamInterceptor(
otgrpc.OpenTracingStreamServerInterceptor(tracer)))
// All future RPC activity involving `s` will be automatically traced.
```

View File

@@ -0,0 +1,239 @@
package otgrpc
import (
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/opentracing/opentracing-go/log"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"io"
"runtime"
"sync/atomic"
)
// OpenTracingClientInterceptor returns a grpc.UnaryClientInterceptor suitable
// for use in a grpc.Dial call.
//
// For example:
//
// conn, err := grpc.Dial(
// address,
// ..., // (existing DialOptions)
// grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(tracer)))
//
// All gRPC client spans will inject the OpenTracing SpanContext into the gRPC
// metadata; they will also look in the context.Context for an active
// in-process parent Span and establish a ChildOf reference if such a parent
// Span could be found.
func OpenTracingClientInterceptor(tracer opentracing.Tracer, optFuncs ...Option) grpc.UnaryClientInterceptor {
otgrpcOpts := newOptions()
otgrpcOpts.apply(optFuncs...)
return func(
ctx context.Context,
method string,
req, resp interface{},
cc *grpc.ClientConn,
invoker grpc.UnaryInvoker,
opts ...grpc.CallOption,
) error {
var err error
var parentCtx opentracing.SpanContext
if parent := opentracing.SpanFromContext(ctx); parent != nil {
parentCtx = parent.Context()
}
if otgrpcOpts.inclusionFunc != nil &&
!otgrpcOpts.inclusionFunc(parentCtx, method, req, resp) {
return invoker(ctx, method, req, resp, cc, opts...)
}
clientSpan := tracer.StartSpan(
method,
opentracing.ChildOf(parentCtx),
ext.SpanKindRPCClient,
gRPCComponentTag,
)
defer clientSpan.Finish()
ctx = injectSpanContext(ctx, tracer, clientSpan)
if otgrpcOpts.logPayloads {
clientSpan.LogFields(log.Object("gRPC request", req))
}
err = invoker(ctx, method, req, resp, cc, opts...)
if err == nil {
if otgrpcOpts.logPayloads {
clientSpan.LogFields(log.Object("gRPC response", resp))
}
} else {
SetSpanTags(clientSpan, err, true)
clientSpan.LogFields(log.String("event", "error"), log.String("message", err.Error()))
}
if otgrpcOpts.decorator != nil {
otgrpcOpts.decorator(clientSpan, method, req, resp, err)
}
return err
}
}
// OpenTracingStreamClientInterceptor returns a grpc.StreamClientInterceptor suitable
// for use in a grpc.Dial call. The interceptor instruments streaming RPCs by creating
// a single span to correspond to the lifetime of the RPC's stream.
//
// For example:
//
// conn, err := grpc.Dial(
// address,
// ..., // (existing DialOptions)
// grpc.WithStreamInterceptor(otgrpc.OpenTracingStreamClientInterceptor(tracer)))
//
// All gRPC client spans will inject the OpenTracing SpanContext into the gRPC
// metadata; they will also look in the context.Context for an active
// in-process parent Span and establish a ChildOf reference if such a parent
// Span could be found.
func OpenTracingStreamClientInterceptor(tracer opentracing.Tracer, optFuncs ...Option) grpc.StreamClientInterceptor {
otgrpcOpts := newOptions()
otgrpcOpts.apply(optFuncs...)
return func(
ctx context.Context,
desc *grpc.StreamDesc,
cc *grpc.ClientConn,
method string,
streamer grpc.Streamer,
opts ...grpc.CallOption,
) (grpc.ClientStream, error) {
var err error
var parentCtx opentracing.SpanContext
if parent := opentracing.SpanFromContext(ctx); parent != nil {
parentCtx = parent.Context()
}
if otgrpcOpts.inclusionFunc != nil &&
!otgrpcOpts.inclusionFunc(parentCtx, method, nil, nil) {
return streamer(ctx, desc, cc, method, opts...)
}
clientSpan := tracer.StartSpan(
method,
opentracing.ChildOf(parentCtx),
ext.SpanKindRPCClient,
gRPCComponentTag,
)
ctx = injectSpanContext(ctx, tracer, clientSpan)
cs, err := streamer(ctx, desc, cc, method, opts...)
if err != nil {
clientSpan.LogFields(log.String("event", "error"), log.String("message", err.Error()))
SetSpanTags(clientSpan, err, true)
clientSpan.Finish()
return cs, err
}
return newOpenTracingClientStream(cs, method, desc, clientSpan, otgrpcOpts), nil
}
}
func newOpenTracingClientStream(cs grpc.ClientStream, method string, desc *grpc.StreamDesc, clientSpan opentracing.Span, otgrpcOpts *options) grpc.ClientStream {
finishChan := make(chan struct{})
isFinished := new(int32)
*isFinished = 0
finishFunc := func(err error) {
// The current OpenTracing specification forbids finishing a span more than
// once. Since we have multiple code paths that could concurrently call
// `finishFunc`, we need to add some sort of synchronization to guard against
// multiple finishing.
if !atomic.CompareAndSwapInt32(isFinished, 0, 1) {
return
}
close(finishChan)
defer clientSpan.Finish()
if err != nil {
clientSpan.LogFields(log.String("event", "error"), log.String("message", err.Error()))
SetSpanTags(clientSpan, err, true)
}
if otgrpcOpts.decorator != nil {
otgrpcOpts.decorator(clientSpan, method, nil, nil, err)
}
}
go func() {
select {
case <-finishChan:
// The client span is being finished by another code path; hence, no
// action is necessary.
case <-cs.Context().Done():
finishFunc(cs.Context().Err())
}
}()
otcs := &openTracingClientStream{
ClientStream: cs,
desc: desc,
finishFunc: finishFunc,
}
// The `ClientStream` interface allows one to omit calling `Recv` if it's
// known that the result will be `io.EOF`. See
// http://stackoverflow.com/q/42915337
// In such cases, there's nothing that triggers the span to finish. We,
// therefore, set a finalizer so that the span and the context goroutine will
// at least be cleaned up when the garbage collector is run.
runtime.SetFinalizer(otcs, func(otcs *openTracingClientStream) {
otcs.finishFunc(nil)
})
return otcs
}
type openTracingClientStream struct {
grpc.ClientStream
desc *grpc.StreamDesc
finishFunc func(error)
}
func (cs *openTracingClientStream) Header() (metadata.MD, error) {
md, err := cs.ClientStream.Header()
if err != nil {
cs.finishFunc(err)
}
return md, err
}
func (cs *openTracingClientStream) SendMsg(m interface{}) error {
err := cs.ClientStream.SendMsg(m)
if err != nil {
cs.finishFunc(err)
}
return err
}
func (cs *openTracingClientStream) RecvMsg(m interface{}) error {
err := cs.ClientStream.RecvMsg(m)
if err == io.EOF {
cs.finishFunc(nil)
return err
} else if err != nil {
cs.finishFunc(err)
return err
}
if !cs.desc.ServerStreams {
cs.finishFunc(nil)
}
return err
}
func (cs *openTracingClientStream) CloseSend() error {
err := cs.ClientStream.CloseSend()
if err != nil {
cs.finishFunc(err)
}
return err
}
func injectSpanContext(ctx context.Context, tracer opentracing.Tracer, clientSpan opentracing.Span) context.Context {
md, ok := metadata.FromOutgoingContext(ctx)
if !ok {
md = metadata.New(nil)
} else {
md = md.Copy()
}
mdWriter := metadataReaderWriter{md}
err := tracer.Inject(clientSpan.Context(), opentracing.HTTPHeaders, mdWriter)
// We have no better place to record an error than the Span itself :-/
if err != nil {
clientSpan.LogFields(log.String("event", "Tracer.Inject() failed"), log.Error(err))
}
return metadata.NewOutgoingContext(ctx, md)
}

View File

@@ -0,0 +1,69 @@
package otgrpc
import (
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// A Class is a set of types of outcomes (including errors) that will often
// be handled in the same way.
type Class string
const (
Unknown Class = "0xx"
// Success represents outcomes that achieved the desired results.
Success Class = "2xx"
// ClientError represents errors that were the client's fault.
ClientError Class = "4xx"
// ServerError represents errors that were the server's fault.
ServerError Class = "5xx"
)
// ErrorClass returns the class of the given error
func ErrorClass(err error) Class {
if s, ok := status.FromError(err); ok {
switch s.Code() {
// Success or "success"
case codes.OK, codes.Canceled:
return Success
// Client errors
case codes.InvalidArgument, codes.NotFound, codes.AlreadyExists,
codes.PermissionDenied, codes.Unauthenticated, codes.FailedPrecondition,
codes.OutOfRange:
return ClientError
// Server errors
case codes.DeadlineExceeded, codes.ResourceExhausted, codes.Aborted,
codes.Unimplemented, codes.Internal, codes.Unavailable, codes.DataLoss:
return ServerError
// Not sure
case codes.Unknown:
fallthrough
default:
return Unknown
}
}
return Unknown
}
// SetSpanTags sets one or more tags on the given span according to the
// error.
func SetSpanTags(span opentracing.Span, err error, client bool) {
c := ErrorClass(err)
code := codes.Unknown
if s, ok := status.FromError(err); ok {
code = s.Code()
}
span.SetTag("response_code", code)
span.SetTag("response_class", c)
if err == nil {
return
}
if client || c == ServerError {
ext.Error.Set(span, true)
}
}

View File

@@ -0,0 +1,57 @@
package otgrpc
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/opentracing/opentracing-go/mocktracer"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const (
firstCode = codes.OK
lastCode = codes.DataLoss
)
func TestSpanTags(t *testing.T) {
tracer := mocktracer.New()
for code := firstCode; code <= lastCode; code++ {
// Client error
tracer.Reset()
span := tracer.StartSpan("test-trace-client")
err := status.Error(code, "")
SetSpanTags(span, err, true)
span.Finish()
// Assert added tags
rawSpan := tracer.FinishedSpans()[0]
expectedTags := map[string]interface{}{
"response_code": code,
"response_class": ErrorClass(err),
}
if err != nil {
expectedTags["error"] = true
}
assert.Equal(t, expectedTags, rawSpan.Tags())
// Server error
tracer.Reset()
span = tracer.StartSpan("test-trace-server")
err = status.Error(code, "")
SetSpanTags(span, err, false)
span.Finish()
// Assert added tags
rawSpan = tracer.FinishedSpans()[0]
expectedTags = map[string]interface{}{
"response_code": code,
"response_class": ErrorClass(err),
}
if err != nil && ErrorClass(err) == ServerError {
expectedTags["error"] = true
}
assert.Equal(t, expectedTags, rawSpan.Tags())
}
}

View File

@@ -0,0 +1,76 @@
package otgrpc
import "github.com/opentracing/opentracing-go"
// Option instances may be used in OpenTracing(Server|Client)Interceptor
// initialization.
//
// See this post about the "functional options" pattern:
// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
type Option func(o *options)
// LogPayloads returns an Option that tells the OpenTracing instrumentation to
// try to log application payloads in both directions.
func LogPayloads() Option {
return func(o *options) {
o.logPayloads = true
}
}
// SpanInclusionFunc provides an optional mechanism to decide whether or not
// to trace a given gRPC call. Return true to create a Span and initiate
// tracing, false to not create a Span and not trace.
//
// parentSpanCtx may be nil if no parent could be extraction from either the Go
// context.Context (on the client) or the RPC (on the server).
type SpanInclusionFunc func(
parentSpanCtx opentracing.SpanContext,
method string,
req, resp interface{}) bool
// IncludingSpans binds a IncludeSpanFunc to the options
func IncludingSpans(inclusionFunc SpanInclusionFunc) Option {
return func(o *options) {
o.inclusionFunc = inclusionFunc
}
}
// SpanDecoratorFunc provides an (optional) mechanism for otgrpc users to add
// arbitrary tags/logs/etc to the opentracing.Span associated with client
// and/or server RPCs.
type SpanDecoratorFunc func(
span opentracing.Span,
method string,
req, resp interface{},
grpcError error)
// SpanDecorator binds a function that decorates gRPC Spans.
func SpanDecorator(decorator SpanDecoratorFunc) Option {
return func(o *options) {
o.decorator = decorator
}
}
// The internal-only options struct. Obviously overkill at the moment; but will
// scale well as production use dictates other configuration and tuning
// parameters.
type options struct {
logPayloads bool
decorator SpanDecoratorFunc
// May be nil.
inclusionFunc SpanInclusionFunc
}
// newOptions returns the default options.
func newOptions() *options {
return &options{
logPayloads: false,
inclusionFunc: nil,
}
}
func (o *options) apply(opts ...Option) {
for _, opt := range opts {
opt(o)
}
}

View File

@@ -0,0 +1,5 @@
// Package otgrpc provides OpenTracing support for any gRPC client or server.
//
// See the README for simple usage examples:
// https://github.com/grpc-ecosystem/grpc-opentracing/blob/master/go/otgrpc/README.md
package otgrpc

View File

@@ -0,0 +1,141 @@
package otgrpc
import (
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/opentracing/opentracing-go/log"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
// OpenTracingServerInterceptor returns a grpc.UnaryServerInterceptor suitable
// for use in a grpc.NewServer call.
//
// For example:
//
// s := grpc.NewServer(
// ..., // (existing ServerOptions)
// grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer)))
//
// All gRPC server spans will look for an OpenTracing SpanContext in the gRPC
// metadata; if found, the server span will act as the ChildOf that RPC
// SpanContext.
//
// Root or not, the server Span will be embedded in the context.Context for the
// application-specific gRPC handler(s) to access.
func OpenTracingServerInterceptor(tracer opentracing.Tracer, optFuncs ...Option) grpc.UnaryServerInterceptor {
otgrpcOpts := newOptions()
otgrpcOpts.apply(optFuncs...)
return func(
ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (resp interface{}, err error) {
spanContext, err := extractSpanContext(ctx, tracer)
if err != nil && err != opentracing.ErrSpanContextNotFound {
// TODO: establish some sort of error reporting mechanism here. We
// don't know where to put such an error and must rely on Tracer
// implementations to do something appropriate for the time being.
}
if otgrpcOpts.inclusionFunc != nil &&
!otgrpcOpts.inclusionFunc(spanContext, info.FullMethod, req, nil) {
return handler(ctx, req)
}
serverSpan := tracer.StartSpan(
info.FullMethod,
ext.RPCServerOption(spanContext),
gRPCComponentTag,
)
defer serverSpan.Finish()
ctx = opentracing.ContextWithSpan(ctx, serverSpan)
if otgrpcOpts.logPayloads {
serverSpan.LogFields(log.Object("gRPC request", req))
}
resp, err = handler(ctx, req)
if err == nil {
if otgrpcOpts.logPayloads {
serverSpan.LogFields(log.Object("gRPC response", resp))
}
} else {
SetSpanTags(serverSpan, err, false)
serverSpan.LogFields(log.String("event", "error"), log.String("message", err.Error()))
}
if otgrpcOpts.decorator != nil {
otgrpcOpts.decorator(serverSpan, info.FullMethod, req, resp, err)
}
return resp, err
}
}
// OpenTracingStreamServerInterceptor returns a grpc.StreamServerInterceptor suitable
// for use in a grpc.NewServer call. The interceptor instruments streaming RPCs by
// creating a single span to correspond to the lifetime of the RPC's stream.
//
// For example:
//
// s := grpc.NewServer(
// ..., // (existing ServerOptions)
// grpc.StreamInterceptor(otgrpc.OpenTracingStreamServerInterceptor(tracer)))
//
// All gRPC server spans will look for an OpenTracing SpanContext in the gRPC
// metadata; if found, the server span will act as the ChildOf that RPC
// SpanContext.
//
// Root or not, the server Span will be embedded in the context.Context for the
// application-specific gRPC handler(s) to access.
func OpenTracingStreamServerInterceptor(tracer opentracing.Tracer, optFuncs ...Option) grpc.StreamServerInterceptor {
otgrpcOpts := newOptions()
otgrpcOpts.apply(optFuncs...)
return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
spanContext, err := extractSpanContext(ss.Context(), tracer)
if err != nil && err != opentracing.ErrSpanContextNotFound {
// TODO: establish some sort of error reporting mechanism here. We
// don't know where to put such an error and must rely on Tracer
// implementations to do something appropriate for the time being.
}
if otgrpcOpts.inclusionFunc != nil &&
!otgrpcOpts.inclusionFunc(spanContext, info.FullMethod, nil, nil) {
return handler(srv, ss)
}
serverSpan := tracer.StartSpan(
info.FullMethod,
ext.RPCServerOption(spanContext),
gRPCComponentTag,
)
defer serverSpan.Finish()
ss = &openTracingServerStream{
ServerStream: ss,
ctx: opentracing.ContextWithSpan(ss.Context(), serverSpan),
}
err = handler(srv, ss)
if err != nil {
SetSpanTags(serverSpan, err, false)
serverSpan.LogFields(log.String("event", "error"), log.String("message", err.Error()))
}
if otgrpcOpts.decorator != nil {
otgrpcOpts.decorator(serverSpan, info.FullMethod, nil, nil, err)
}
return err
}
}
type openTracingServerStream struct {
grpc.ServerStream
ctx context.Context
}
func (ss *openTracingServerStream) Context() context.Context {
return ss.ctx
}
func extractSpanContext(ctx context.Context, tracer opentracing.Tracer) (opentracing.SpanContext, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.New(nil)
}
return tracer.Extract(opentracing.HTTPHeaders, metadataReaderWriter{md})
}

View File

@@ -0,0 +1,42 @@
package otgrpc
import (
"strings"
opentracing "github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"google.golang.org/grpc/metadata"
)
var (
// Morally a const:
gRPCComponentTag = opentracing.Tag{string(ext.Component), "gRPC"}
)
// metadataReaderWriter satisfies both the opentracing.TextMapReader and
// opentracing.TextMapWriter interfaces.
type metadataReaderWriter struct {
metadata.MD
}
func (w metadataReaderWriter) Set(key, val string) {
// The GRPC HPACK implementation rejects any uppercase keys here.
//
// As such, since the HTTP_HEADERS format is case-insensitive anyway, we
// blindly lowercase the key (which is guaranteed to work in the
// Inject/Extract sense per the OpenTracing spec).
key = strings.ToLower(key)
w.MD[key] = append(w.MD[key], val)
}
func (w metadataReaderWriter) ForeachKey(handler func(key, val string) error) error {
for k, vals := range w.MD {
for _, v := range vals {
if err := handler(k, v); err != nil {
return err
}
}
}
return nil
}

View File

@@ -0,0 +1,270 @@
package interceptor_test
import (
"io"
"net"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
testpb "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc/test/otgrpc_testing"
"github.com/opentracing/opentracing-go/mocktracer"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
const (
streamLength = 5
)
type testServer struct{}
func (s *testServer) UnaryCall(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
return &testpb.SimpleResponse{in.Payload}, nil
}
func (s *testServer) StreamingOutputCall(in *testpb.SimpleRequest, stream testpb.TestService_StreamingOutputCallServer) error {
for i := 0; i < streamLength; i++ {
if err := stream.Send(&testpb.SimpleResponse{in.Payload}); err != nil {
return err
}
}
return nil
}
func (s *testServer) StreamingInputCall(stream testpb.TestService_StreamingInputCallServer) error {
sum := int32(0)
for {
in, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
return err
}
sum += in.Payload
}
return stream.SendAndClose(&testpb.SimpleResponse{sum})
}
func (s *testServer) StreamingBidirectionalCall(stream testpb.TestService_StreamingBidirectionalCallServer) error {
for {
in, err := stream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
if err = stream.Send(&testpb.SimpleResponse{in.Payload}); err != nil {
return err
}
}
}
type env struct {
unaryClientInt grpc.UnaryClientInterceptor
streamClientInt grpc.StreamClientInterceptor
unaryServerInt grpc.UnaryServerInterceptor
streamServerInt grpc.StreamServerInterceptor
}
type test struct {
t *testing.T
e env
srv *grpc.Server
cc *grpc.ClientConn
c testpb.TestServiceClient
}
func newTest(t *testing.T, e env) *test {
te := &test{
t: t,
e: e,
}
// Set up the server.
sOpts := []grpc.ServerOption{}
if e.unaryServerInt != nil {
sOpts = append(sOpts, grpc.UnaryInterceptor(e.unaryServerInt))
}
if e.streamServerInt != nil {
sOpts = append(sOpts, grpc.StreamInterceptor(e.streamServerInt))
}
lis, err := net.Listen("tcp", "localhost:0")
if err != nil {
te.t.Fatalf("Failed to listen: %v", err)
}
te.srv = grpc.NewServer(sOpts...)
testpb.RegisterTestServiceServer(te.srv, &testServer{})
go te.srv.Serve(lis)
// Set up a connection to the server.
cOpts := []grpc.DialOption{grpc.WithInsecure()}
if e.unaryClientInt != nil {
cOpts = append(cOpts, grpc.WithUnaryInterceptor(e.unaryClientInt))
}
if e.streamClientInt != nil {
cOpts = append(cOpts, grpc.WithStreamInterceptor(e.streamClientInt))
}
_, port, err := net.SplitHostPort(lis.Addr().String())
if err != nil {
te.t.Fatalf("Failed to parse listener address: %v", err)
}
srvAddr := "localhost:" + port
te.cc, err = grpc.Dial(srvAddr, cOpts...)
if err != nil {
te.t.Fatalf("Dial(%q) = %v", srvAddr, err)
}
te.c = testpb.NewTestServiceClient(te.cc)
return te
}
func (te *test) tearDown() {
te.cc.Close()
}
func assertChildParentSpans(t *testing.T, tracer *mocktracer.MockTracer) {
spans := tracer.FinishedSpans()
assert.Equal(t, 2, len(spans))
if len(spans) != 2 {
t.Fatalf("Incorrect span length")
}
parent := spans[1]
child := spans[0]
assert.Equal(t, child.ParentID, parent.Context().(mocktracer.MockSpanContext).SpanID)
}
func TestUnaryOpenTracing(t *testing.T) {
tracer := mocktracer.New()
e := env{
unaryClientInt: otgrpc.OpenTracingClientInterceptor(tracer),
unaryServerInt: otgrpc.OpenTracingServerInterceptor(tracer),
}
te := newTest(t, e)
defer te.tearDown()
payload := int32(0)
resp, err := te.c.UnaryCall(context.Background(), &testpb.SimpleRequest{payload})
if err != nil {
t.Fatalf("Failed UnaryCall: %v", err)
}
assert.Equal(t, payload, resp.Payload)
assertChildParentSpans(t, tracer)
}
func TestStreamingOutputCallOpenTracing(t *testing.T) {
tracer := mocktracer.New()
e := env{
streamClientInt: otgrpc.OpenTracingStreamClientInterceptor(tracer),
streamServerInt: otgrpc.OpenTracingStreamServerInterceptor(tracer),
}
te := newTest(t, e)
defer te.tearDown()
payload := int32(0)
stream, err := te.c.StreamingOutputCall(context.Background(), &testpb.SimpleRequest{payload})
if err != nil {
t.Fatalf("Failed StreamingOutputCall: %v", err)
}
for {
resp, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
t.Fatalf("Failed StreamingOutputCall: %v", err)
}
assert.Equal(t, payload, resp.Payload)
}
assertChildParentSpans(t, tracer)
}
func TestStreamingInputCallOpenTracing(t *testing.T) {
tracer := mocktracer.New()
e := env{
streamClientInt: otgrpc.OpenTracingStreamClientInterceptor(tracer),
streamServerInt: otgrpc.OpenTracingStreamServerInterceptor(tracer),
}
te := newTest(t, e)
defer te.tearDown()
payload := int32(1)
stream, err := te.c.StreamingInputCall(context.Background())
for i := 0; i < streamLength; i++ {
if err = stream.Send(&testpb.SimpleRequest{payload}); err != nil {
t.Fatalf("Failed StreamingInputCall: %v", err)
}
}
resp, err := stream.CloseAndRecv()
if err != nil {
t.Fatalf("Failed StreamingInputCall: %v", err)
}
assert.Equal(t, streamLength*payload, resp.Payload)
assertChildParentSpans(t, tracer)
}
func TestStreamingBidirectionalCallOpenTracing(t *testing.T) {
tracer := mocktracer.New()
e := env{
streamClientInt: otgrpc.OpenTracingStreamClientInterceptor(tracer),
streamServerInt: otgrpc.OpenTracingStreamServerInterceptor(tracer),
}
te := newTest(t, e)
defer te.tearDown()
payload := int32(0)
stream, err := te.c.StreamingBidirectionalCall(context.Background())
if err != nil {
t.Fatalf("Failed StreamingInputCall: %v", err)
}
go func() {
for i := 0; i < streamLength; i++ {
if err := stream.Send(&testpb.SimpleRequest{payload}); err != nil {
t.Fatalf("Failed StreamingInputCall: %v", err)
}
}
stream.CloseSend()
}()
for {
resp, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
t.Fatalf("Failed StreamingOutputCall: %v", err)
}
assert.Equal(t, payload, resp.Payload)
}
assertChildParentSpans(t, tracer)
}
func TestStreamingContextCancellationOpenTracing(t *testing.T) {
tracer := mocktracer.New()
e := env{
streamClientInt: otgrpc.OpenTracingStreamClientInterceptor(tracer),
streamServerInt: otgrpc.OpenTracingStreamServerInterceptor(tracer),
}
te := newTest(t, e)
defer te.tearDown()
payload := int32(0)
ctx, cancel := context.WithCancel(context.Background())
_, err := te.c.StreamingOutputCall(ctx, &testpb.SimpleRequest{payload})
if err != nil {
t.Fatalf("Failed StreamingOutputCall: %v", err)
}
cancel()
time.Sleep(100 * time.Millisecond)
spans := tracer.FinishedSpans()
assert.Equal(t, 2, len(spans))
if len(spans) != 2 {
t.Fatalf("Incorrect span length")
}
parent := spans[0]
child := spans[1]
assert.Equal(t, child.ParentID, parent.Context().(mocktracer.MockSpanContext).SpanID)
assert.True(t, parent.Tag("error").(bool))
}

View File

@@ -0,0 +1,357 @@
// Code generated by protoc-gen-go.
// source: test.proto
// DO NOT EDIT!
/*
Package otgrpc_testing is a generated protocol buffer package.
It is generated from these files:
test.proto
It has these top-level messages:
SimpleRequest
SimpleResponse
*/
package otgrpc_testing
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type SimpleRequest struct {
Payload int32 `protobuf:"varint,1,opt,name=payload" json:"payload,omitempty"`
}
func (m *SimpleRequest) Reset() { *m = SimpleRequest{} }
func (m *SimpleRequest) String() string { return proto.CompactTextString(m) }
func (*SimpleRequest) ProtoMessage() {}
func (*SimpleRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *SimpleRequest) GetPayload() int32 {
if m != nil {
return m.Payload
}
return 0
}
type SimpleResponse struct {
Payload int32 `protobuf:"varint,1,opt,name=payload" json:"payload,omitempty"`
}
func (m *SimpleResponse) Reset() { *m = SimpleResponse{} }
func (m *SimpleResponse) String() string { return proto.CompactTextString(m) }
func (*SimpleResponse) ProtoMessage() {}
func (*SimpleResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *SimpleResponse) GetPayload() int32 {
if m != nil {
return m.Payload
}
return 0
}
func init() {
proto.RegisterType((*SimpleRequest)(nil), "otgrpc.testing.SimpleRequest")
proto.RegisterType((*SimpleResponse)(nil), "otgrpc.testing.SimpleResponse")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for TestService service
type TestServiceClient interface {
UnaryCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (*SimpleResponse, error)
StreamingOutputCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (TestService_StreamingOutputCallClient, error)
StreamingInputCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingInputCallClient, error)
StreamingBidirectionalCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingBidirectionalCallClient, error)
}
type testServiceClient struct {
cc *grpc.ClientConn
}
func NewTestServiceClient(cc *grpc.ClientConn) TestServiceClient {
return &testServiceClient{cc}
}
func (c *testServiceClient) UnaryCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (*SimpleResponse, error) {
out := new(SimpleResponse)
err := grpc.Invoke(ctx, "/otgrpc.testing.TestService/UnaryCall", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *testServiceClient) StreamingOutputCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (TestService_StreamingOutputCallClient, error) {
stream, err := grpc.NewClientStream(ctx, &_TestService_serviceDesc.Streams[0], c.cc, "/otgrpc.testing.TestService/StreamingOutputCall", opts...)
if err != nil {
return nil, err
}
x := &testServiceStreamingOutputCallClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type TestService_StreamingOutputCallClient interface {
Recv() (*SimpleResponse, error)
grpc.ClientStream
}
type testServiceStreamingOutputCallClient struct {
grpc.ClientStream
}
func (x *testServiceStreamingOutputCallClient) Recv() (*SimpleResponse, error) {
m := new(SimpleResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *testServiceClient) StreamingInputCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingInputCallClient, error) {
stream, err := grpc.NewClientStream(ctx, &_TestService_serviceDesc.Streams[1], c.cc, "/otgrpc.testing.TestService/StreamingInputCall", opts...)
if err != nil {
return nil, err
}
x := &testServiceStreamingInputCallClient{stream}
return x, nil
}
type TestService_StreamingInputCallClient interface {
Send(*SimpleRequest) error
CloseAndRecv() (*SimpleResponse, error)
grpc.ClientStream
}
type testServiceStreamingInputCallClient struct {
grpc.ClientStream
}
func (x *testServiceStreamingInputCallClient) Send(m *SimpleRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *testServiceStreamingInputCallClient) CloseAndRecv() (*SimpleResponse, error) {
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
m := new(SimpleResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *testServiceClient) StreamingBidirectionalCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingBidirectionalCallClient, error) {
stream, err := grpc.NewClientStream(ctx, &_TestService_serviceDesc.Streams[2], c.cc, "/otgrpc.testing.TestService/StreamingBidirectionalCall", opts...)
if err != nil {
return nil, err
}
x := &testServiceStreamingBidirectionalCallClient{stream}
return x, nil
}
type TestService_StreamingBidirectionalCallClient interface {
Send(*SimpleRequest) error
Recv() (*SimpleResponse, error)
grpc.ClientStream
}
type testServiceStreamingBidirectionalCallClient struct {
grpc.ClientStream
}
func (x *testServiceStreamingBidirectionalCallClient) Send(m *SimpleRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *testServiceStreamingBidirectionalCallClient) Recv() (*SimpleResponse, error) {
m := new(SimpleResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// Server API for TestService service
type TestServiceServer interface {
UnaryCall(context.Context, *SimpleRequest) (*SimpleResponse, error)
StreamingOutputCall(*SimpleRequest, TestService_StreamingOutputCallServer) error
StreamingInputCall(TestService_StreamingInputCallServer) error
StreamingBidirectionalCall(TestService_StreamingBidirectionalCallServer) error
}
func RegisterTestServiceServer(s *grpc.Server, srv TestServiceServer) {
s.RegisterService(&_TestService_serviceDesc, srv)
}
func _TestService_UnaryCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SimpleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TestServiceServer).UnaryCall(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/otgrpc.testing.TestService/UnaryCall",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TestServiceServer).UnaryCall(ctx, req.(*SimpleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TestService_StreamingOutputCall_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(SimpleRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(TestServiceServer).StreamingOutputCall(m, &testServiceStreamingOutputCallServer{stream})
}
type TestService_StreamingOutputCallServer interface {
Send(*SimpleResponse) error
grpc.ServerStream
}
type testServiceStreamingOutputCallServer struct {
grpc.ServerStream
}
func (x *testServiceStreamingOutputCallServer) Send(m *SimpleResponse) error {
return x.ServerStream.SendMsg(m)
}
func _TestService_StreamingInputCall_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(TestServiceServer).StreamingInputCall(&testServiceStreamingInputCallServer{stream})
}
type TestService_StreamingInputCallServer interface {
SendAndClose(*SimpleResponse) error
Recv() (*SimpleRequest, error)
grpc.ServerStream
}
type testServiceStreamingInputCallServer struct {
grpc.ServerStream
}
func (x *testServiceStreamingInputCallServer) SendAndClose(m *SimpleResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *testServiceStreamingInputCallServer) Recv() (*SimpleRequest, error) {
m := new(SimpleRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func _TestService_StreamingBidirectionalCall_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(TestServiceServer).StreamingBidirectionalCall(&testServiceStreamingBidirectionalCallServer{stream})
}
type TestService_StreamingBidirectionalCallServer interface {
Send(*SimpleResponse) error
Recv() (*SimpleRequest, error)
grpc.ServerStream
}
type testServiceStreamingBidirectionalCallServer struct {
grpc.ServerStream
}
func (x *testServiceStreamingBidirectionalCallServer) Send(m *SimpleResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *testServiceStreamingBidirectionalCallServer) Recv() (*SimpleRequest, error) {
m := new(SimpleRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
var _TestService_serviceDesc = grpc.ServiceDesc{
ServiceName: "otgrpc.testing.TestService",
HandlerType: (*TestServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "UnaryCall",
Handler: _TestService_UnaryCall_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "StreamingOutputCall",
Handler: _TestService_StreamingOutputCall_Handler,
ServerStreams: true,
},
{
StreamName: "StreamingInputCall",
Handler: _TestService_StreamingInputCall_Handler,
ClientStreams: true,
},
{
StreamName: "StreamingBidirectionalCall",
Handler: _TestService_StreamingBidirectionalCall_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "test.proto",
}
func init() { proto.RegisterFile("test.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 210 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0x49, 0x2d, 0x2e,
0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xcb, 0x2f, 0x49, 0x2f, 0x2a, 0x48, 0xd6, 0x03,
0x09, 0x65, 0xe6, 0xa5, 0x2b, 0x69, 0x72, 0xf1, 0x06, 0x67, 0xe6, 0x16, 0xe4, 0xa4, 0x06, 0xa5,
0x16, 0x96, 0xa6, 0x16, 0x97, 0x08, 0x49, 0x70, 0xb1, 0x17, 0x24, 0x56, 0xe6, 0xe4, 0x27, 0xa6,
0x48, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x06, 0xc1, 0xb8, 0x4a, 0x5a, 0x5c, 0x7c, 0x30, 0xa5, 0xc5,
0x05, 0xf9, 0x79, 0xc5, 0xa9, 0xb8, 0xd5, 0x1a, 0xbd, 0x64, 0xe2, 0xe2, 0x0e, 0x49, 0x2d, 0x2e,
0x09, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0x15, 0xf2, 0xe2, 0xe2, 0x0c, 0xcd, 0x4b, 0x2c, 0xaa,
0x74, 0x4e, 0xcc, 0xc9, 0x11, 0x92, 0xd5, 0x43, 0x75, 0x84, 0x1e, 0x8a, 0x0b, 0xa4, 0xe4, 0x70,
0x49, 0x43, 0x6d, 0x0d, 0xe3, 0x12, 0x0e, 0x2e, 0x29, 0x4a, 0x4d, 0xcc, 0xcd, 0xcc, 0x4b, 0xf7,
0x2f, 0x2d, 0x29, 0x28, 0x2d, 0xa1, 0x82, 0xa9, 0x06, 0x8c, 0x42, 0xa1, 0x5c, 0x42, 0x70, 0x73,
0x3d, 0xf3, 0xa8, 0x63, 0xac, 0x06, 0xa3, 0x50, 0x3c, 0x97, 0x14, 0xdc, 0x58, 0xa7, 0xcc, 0x94,
0xcc, 0xa2, 0xd4, 0xe4, 0x92, 0xcc, 0xfc, 0xbc, 0xc4, 0x1c, 0xaa, 0x18, 0x6f, 0xc0, 0x98, 0xc4,
0x06, 0x8e, 0x59, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfd, 0x50, 0x3e, 0xe4, 0xe7, 0x01,
0x00, 0x00,
}

View File

@@ -0,0 +1,21 @@
syntax = "proto3";
package otgrpc.testing;
message SimpleRequest {
int32 payload = 1;
}
message SimpleResponse {
int32 payload = 1;
}
service TestService {
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
rpc StreamingOutputCall(SimpleRequest) returns (stream SimpleResponse);
rpc StreamingInputCall(stream SimpleRequest) returns (SimpleResponse);
rpc StreamingBidirectionalCall(stream SimpleRequest) returns (stream SimpleResponse);
}

View File

@@ -0,0 +1,7 @@
build/*
.gradle/*
gradle.properties
.classpath
.project
.settings/*
bin/

View File

@@ -0,0 +1,319 @@
#####################
GRPC-Java OpenTracing
#####################
============
Installation
============
This package is available on Maven Central and can be added to your project as follows:
**Maven**
.. code-block::
<dependencies>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>grpc-opentracing</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
**Gradle**
.. code-block::
compile 'io.opentracing.contrib:grpc-opentracing:0.2.0'
==========
Quickstart
==========
If you want to add basic tracing to your clients and servers, you can do so in a few short and simple steps, as shown below. (These code snippets use the grpc example's ``GreeterGrpc``, generated by protocol buffers.)
**Servers**
- Instantiate a tracer
- Create a ``ServerTracingInterceptor``
- Intercept a service
- (Optional) Access the `current span`_
.. _current span: `Current Span Context`_
.. code-block:: java
import io.opentracing.Tracer;
public class YourServer {
private int port;
private Server server;
// Any io.opentracing.Tracer implementation will do here. For instance,
// https://github.com/uber/jaeger-client-java/blob/master/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java
// generates Zipkin-compatible data.
private final Tracer tracer;
private void start() throws IOException {
ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor(this.tracer);
server = ServerBuilder.forPort(port)
.addService(tracingInterceptor.intercept(someServiceDef))
.build()
.start();
}
}
**Clients**
- Instantiate a tracer
- Create a ``ClientTracingInterceptor``
- Intercept the client channel
.. code-block:: java
import io.opentracing.Tracer;
public class YourClient {
private final ManagedChannel channel;
private final GreeterGrpc.GreeterBlockingStub blockingStub;
// Any io.opentracing.Tracer implementation will do here. For instance,
// https://github.com/uber/jaeger-client-java/blob/master/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java
// generates Zipkin-compatible data.
private final Tracer tracer;
public YourClient(String host, int port) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor(this.tracer)
blockingStub = GreeterGrpc.newBlockingStub(tracingInterceptor.intercept(channel));
}
}
There's an example of a simple traced client (`TracedClient`) and server (`TracedService`) in `src/test`.
==============
Server Tracing
==============
A ``ServerTracingInterceptor`` uses default settings, which you can override by creating it using a ``ServerTracingInterceptor.Builder``.
- ``withOperationName(OperationNameConstructor constructor)``: Define how the operation name is constructed for all spans created for the intercepted service. Default sets the operation name as the name of the RPC method. More details in the `Operation Name`_ section.
- ``withStreaming()``: Logs to the server span whenever a message is received. *Note:* This package supports streaming but has not been rigorously tested. If you come across any issues, please let us know.
- ``withVerbosity()``: Logs to the server span additional events, such as message received, half close (client finished sending messages), and call complete. Default only logs if a call is cancelled.
- ``withTracedAttributes(ServerRequestAttribute... attrs)``: Sets tags on the server span in case you want to track information about the RPC call. See ServerRequestAttribute.java for a list of traceable request attributes.
**Example**:
.. code-block:: java
ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(new OperationNameConstructor() {
@Override
public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withTracedAttributes(ServerRequestAttribute.HEADERS,
ServerRequestAttribute.METHOD_TYPE)
.build();
==============
Client Tracing
==============
A ``ClientTracingInterceptor`` also has default settings, which you can override by creating it using a ``ClientTracingInterceptor.Builder``.
- ``withOperationName(String operationName)``: Define how the operation name is constructed for all spans created for this intercepted client. Default is the name of the RPC method. More details in the `Operation Name`_ section.
- ``withActiveSpanSource(ActiveSpanSource activeSpanSource)``: Define how to extract the current active span, if any. This is needed if you want your client to continue a trace instead of starting a new one. More details in the `Active Span Source`_ section.
- ``withStreaming()``: Logs to the client span whenever a message is sent or a response is received. *Note:* This package supports streaming but has not been rigorously tested. If you come across any issues, please let us know.
- ``withVerbosity()``: Logs to the client span additional events, such as call started, message sent, half close (client finished sending messages), response received, and call complete. Default only logs if a call is cancelled.
- ``withTracedAttributes(ClientRequestAttribute... attrs)``: Sets tags on the client span in case you want to track information about the RPC call. See ClientRequestAttribute.java for a list of traceable request attributes.
**Example**:
.. code-block:: java
import io.opentracing.Span;
ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(new OperationNameConstructor() {
@Override
public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withActiveSpanSource(new ActiveSpanSource() {
@Override
public Span getActiveSpan() {
// implement how to get the current active span, for example:
return OpenTracingContextKey.activeSpan();
}
})
.withTracingAttributes(ClientRequestAttribute.ALL_CALL_OPTIONS,
ClientRequestAttribute.HEADERS)
.build();
.. _Operation Name: `Operation Names`_
.. _Active Span Source: `Active Span Sources`_
====================
Current Span Context
====================
In your server request handler, you can access the current active span for that request by calling
.. code-block:: java
Span span = OpenTracingContextKey.activeSpan();
This is useful if you want to manually set tags on the span, log important events, or create a new child span for internal units of work. You can also use this key to wrap these internal units of work with a new context that has a user-defined active span.
For example:
.. code-block:: java
Tracer tracer = ...;
// some unit of internal work that you want to trace
Runnable internalWork = someInternalWork
// a wrapper that traces the work of the runnable
class TracedRunnable implements Runnable {
Runnable work;
Tracer tracer;
TracedRunnable(Runnable work, Tracer tracer) {
this.work = work;
this.tracer = tracer;
}
public void run() {
// create a child span for the current active span
Span span = tracer
.buildSpan("internal-work")
.asChildOf(OpenTracingContextKey.activeSpan())
.start();
// create a new context with the child span as the active span
Context contextWithNewSpan = Context.current()
.withValue(OpenTracingContextKey.get(), span);
// wrap the original work and run it
Runnable tracedWork = contextWithNewSpan.wrap(this.work);
tracedWork.run();
// make sure to finish any manually created spans!
span.finish();
}
}
Runnable tracedInternalWork = new TracedRunnable(internalWork, tracer);
tracedInternalWork.run();
===============
Operation Names
===============
The default operation name for any span is the RPC method name (``io.grpc.MethodDescriptor.getFullMethodName()``). However, you may want to add your own prefixes, alter the name, or define a new name. For examples of good operation names, check out the OpenTracing `semantics`_.
To alter the operation name, you need to add an implementation of the interface ``OperationNameConstructor`` to the ``ClientTracingInterceptor.Builder`` or ``ServerTracingInterceptor.Builder``. For example, if you want to add a prefix to the default operation name of your ClientInterceptor, your code would look like this:
.. code-block:: java
ClientTracingInterceptor interceptor = ClientTracingInterceptor.Builder ...
.withOperationName(new OperationNameConstructor() {
@Override
public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
return "your-prefix" + method.getFullMethodName();
}
})
.with....
.build()
.. _semantics: http://opentracing.io/spec/#operation-names
===================
Active Span Sources
===================
If you want your client to continue a trace rather than starting a new one, then you can tell your ``ClientTracingInterceptor`` how to extract the current active span by building it with your own implementation of the interface ``ActiveSpanSource``. This interface has one method, ``getActiveSpan``, in which you will define how to access the current active span.
For example, if you're creating the client in an environment that has the active span stored in a global dictionary-style context under ``OPENTRACING_SPAN_KEY``, then you could configure your Interceptor as follows:
.. code-block:: java
import io.opentracing.Span;
ClientTracingInterceptor interceptor = new ClientTracingInterceptor
.Builder(tracer)
...
.withActiveSpanSource(new ActiveSpanSource() {
@Override
public Span getActiveSpan() {
return Context.get(OPENTRACING_SPAN_KEY);
}
})
...
.build();
We also provide two built-in implementations:
* ``ActiveSpanSource.GRPC_CONTEXT`` uses the current ``io.grpc.Context`` and returns the active span for ``OpenTracingContextKey``. This is the default active span source.
* ``ActiveSpanSource.NONE`` always returns null as the active span, which means the client will always start a new trace
===================================
Integrating with Other Interceptors
===================================
Although we provide ``ServerTracingInterceptor.intercept(service)`` and ``ClientTracingInterceptor.intercept(channel)`` methods, you don't want to use these if you're chaining multiple interceptors. Instead, use the following code (preferably putting the tracing interceptor at the top of the interceptor stack so that it traces the entire request lifecycle, including other interceptors):
**Servers**
.. code-block:: java
server = ServerBuilder.forPort(port)
.addService(ServerInterceptors.intercept(service, someInterceptor,
someOtherInterceptor, serverTracingInterceptor))
.build()
.start();
**Clients**
.. code-block:: java
blockingStub = GreeterGrpc.newBlockingStub(ClientInterceptors.intercept(channel,
someInterceptor, someOtherInterceptor, clientTracingInterceptor));
======================
Releasing new versions
======================
Create a gradle.properties in this directory. It should look approximately like this:
.. code-block::
sonatypeUsername=bensigelman
sonatypePassword=<your OSSRH sonatype password>
signing.keyId=<`gpg --list-keys` output, minus the prefix like "2048R/">
signing.password=<your gpg password>
signing.secretKeyRingFile=/Your/Homedir/.gnupg/secring.gpg
Then run:
.. code-block::
$ gradle uploadArchives closeAndPromoteRepository

View File

@@ -0,0 +1,123 @@
description = "grpc-java: OpenTracing"
group = "io.opentracing.contrib"
version = '0.2.0'
version = '0.3.0'
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'signing'
sourceSets {
main {
java {
srcDirs = ['src/main/java']
}
}
test {
java {
srcDirs = ['src/test/java', 'src/testgen']
}
}
}
task javadocJar(type: Jar) {
classifier = 'javadoc'
from javadoc
}
task sourcesJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.allSource
}
artifacts {
archives jar
archives javadocJar
archives sourcesJar
}
signing {
sign configurations.archives
}
repositories {
mavenCentral()
}
jar {
baseName 'grpc-opentracing'
version = '0.2.0'
version = '0.3.0'
}
dependencies {
compile 'io.grpc:grpc-core:1.6.1'
compile 'io.opentracing:opentracing-api:0.30.0'
testCompile 'io.opentracing:opentracing-mock:0.30.0'
testCompile 'io.grpc:grpc-protobuf:1.6.1'
testCompile 'io.grpc:grpc-netty:1.6.1'
testCompile 'io.grpc:grpc-stub:1.6.1'
testCompile 'junit:junit:4.12'
}
// Allow for automatic promotion and release to Maven Central
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.5.3"
}
}
apply plugin: 'io.codearte.nexus-staging'
nexusStaging {
packageGroup = "io.opentracing"
}
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: sonatypeUsername, password: sonatypePassword)
}
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication(userName: sonatypeUsername, password: sonatypePassword)
}
pom.project {
name 'grpc-opentracing'
packaging 'jar'
// optionally artifactId can be defined here
description 'Provides support for integrating OpenTracing in grpc clients and servers.'
url 'http://www.github.com/grpc-ecosystem/grpc-opentracing'
scm {
url 'scm:git@github.com:grpc-ecosystem:grpc-opentracing.git'
connection 'scm:git@github.com:grpc-ecosystem/grpc-opentracing.git'
developerConnection 'scm:git@github.com:grpc-ecosystem/grpc-opentracing.git'
}
licenses {
license {
name 'BSD-3'
url 'https://opensource.org/licenses/BSD-3-Clause'
}
}
developers {
developer {
name 'Kathy Camenzind'
email 'kcamenzind@lightstep.com'
}
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
package io.opentracing.contrib;
import io.opentracing.Span;
import io.opentracing.contrib.OpenTracingContextKey;
/**
* An interface that defines how to get the current active span
*/
public interface ActiveSpanSource {
/**
* ActiveSpanSource implementation that always returns
* null as the active span
*/
public static ActiveSpanSource NONE = new ActiveSpanSource() {
@Override
public Span getActiveSpan() {
return null;
}
};
/**
* ActiveSpanSource implementation that returns the
* current span stored in the GRPC context under
* {@link OpenTracingContextKey}
*/
public static ActiveSpanSource GRPC_CONTEXT = new ActiveSpanSource() {
@Override
public Span getActiveSpan() {
return OpenTracingContextKey.activeSpan();
}
};
/**
* @return the active span
*/
public Span getActiveSpan();
}

View File

@@ -0,0 +1,292 @@
package io.opentracing.contrib;
import com.google.common.collect.ImmutableMap;
import io.grpc.*;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap;
import javax.annotation.Nullable;
import java.util.Map.Entry;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* An intercepter that applies tracing via OpenTracing to all client requests.
*/
public class ClientTracingInterceptor implements ClientInterceptor {
private final Tracer tracer;
private final OperationNameConstructor operationNameConstructor;
private final boolean streaming;
private final boolean verbose;
private final Set<ClientRequestAttribute> tracedAttributes;
private final ActiveSpanSource activeSpanSource;
/**
* @param tracer to use to trace requests
*/
public ClientTracingInterceptor(Tracer tracer) {
this.tracer = tracer;
this.operationNameConstructor = OperationNameConstructor.DEFAULT;
this.streaming = false;
this.verbose = false;
this.tracedAttributes = new HashSet<ClientRequestAttribute>();
this.activeSpanSource = ActiveSpanSource.GRPC_CONTEXT;
}
private ClientTracingInterceptor(Tracer tracer, OperationNameConstructor operationNameConstructor, boolean streaming,
boolean verbose, Set<ClientRequestAttribute> tracedAttributes, ActiveSpanSource activeSpanSource) {
this.tracer = tracer;
this.operationNameConstructor = operationNameConstructor;
this.streaming = streaming;
this.verbose = verbose;
this.tracedAttributes = tracedAttributes;
this.activeSpanSource = activeSpanSource;
}
/**
* Use this intercepter to trace all requests made by this client channel.
* @param channel to be traced
* @return intercepted channel
*/
public Channel intercept(Channel channel) {
return ClientInterceptors.intercept(channel, this);
}
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next
) {
final String operationName = operationNameConstructor.constructOperationName(method);
Span activeSpan = this.activeSpanSource.getActiveSpan();
final Span span = createSpanFromParent(activeSpan, operationName);
for (ClientRequestAttribute attr : this.tracedAttributes) {
switch (attr) {
case ALL_CALL_OPTIONS:
span.setTag("grpc.call_options", callOptions.toString());
break;
case AUTHORITY:
if (callOptions.getAuthority() == null) {
span.setTag("grpc.authority", "null");
} else {
span.setTag("grpc.authority", callOptions.getAuthority());
}
break;
case COMPRESSOR:
if (callOptions.getCompressor() == null) {
span.setTag("grpc.compressor", "null");
} else {
span.setTag("grpc.compressor", callOptions.getCompressor());
}
break;
case DEADLINE:
if (callOptions.getDeadline() == null) {
span.setTag("grpc.deadline_millis", "null");
} else {
span.setTag("grpc.deadline_millis", callOptions.getDeadline().timeRemaining(TimeUnit.MILLISECONDS));
}
break;
case METHOD_NAME:
span.setTag("grpc.method_name", method.getFullMethodName());
break;
case METHOD_TYPE:
if (method.getType() == null) {
span.setTag("grpc.method_type", "null");
} else {
span.setTag("grpc.method_type", method.getType().toString());
}
break;
case HEADERS:
break;
}
}
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
if (verbose) {
span.log("Started call");
}
if (tracedAttributes.contains(ClientRequestAttribute.HEADERS)) {
span.setTag("grpc.headers", headers.toString());
}
tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new TextMap() {
@Override
public void put(String key, String value) {
Metadata.Key<String> headerKey = Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER);
headers.put(headerKey, value);
}
@Override
public Iterator<Entry<String, String>> iterator() {
throw new UnsupportedOperationException(
"TextMapInjectAdapter should only be used with Tracer.inject()");
}
});
Listener<RespT> tracingResponseListener = new ForwardingClientCallListener
.SimpleForwardingClientCallListener<RespT>(responseListener) {
@Override
public void onHeaders(Metadata headers) {
if (verbose) { span.log(ImmutableMap.of("Response headers received", headers.toString())); }
delegate().onHeaders(headers);
}
@Override
public void onMessage(RespT message) {
if (streaming || verbose) { span.log("Response received"); }
delegate().onMessage(message);
}
@Override
public void onClose(Status status, Metadata trailers) {
if (verbose) {
if (status.getCode().value() == 0) { span.log("Call closed"); }
else { span.log(ImmutableMap.of("Call failed", status.getDescription())); }
}
span.finish();
delegate().onClose(status, trailers);
}
};
delegate().start(tracingResponseListener, headers);
}
@Override
public void cancel(@Nullable String message, @Nullable Throwable cause) {
String errorMessage;
if (message == null) {
errorMessage = "Error";
} else {
errorMessage = message;
}
if (cause == null) {
span.log(errorMessage);
} else {
span.log(ImmutableMap.of(errorMessage, cause.getMessage()));
}
delegate().cancel(message, cause);
}
@Override
public void halfClose() {
if (streaming) { span.log("Finished sending messages"); }
delegate().halfClose();
}
@Override
public void sendMessage(ReqT message) {
if (streaming || verbose) { span.log("Message sent"); }
delegate().sendMessage(message);
}
};
}
private Span createSpanFromParent(Span parentSpan, String operationName) {
if (parentSpan == null) {
return tracer.buildSpan(operationName).startManual();
} else {
return tracer.buildSpan(operationName).asChildOf(parentSpan).startManual();
}
}
/**
* Builds the configuration of a ClientTracingInterceptor.
*/
public static class Builder {
private Tracer tracer;
private OperationNameConstructor operationNameConstructor;
private boolean streaming;
private boolean verbose;
private Set<ClientRequestAttribute> tracedAttributes;
private ActiveSpanSource activeSpanSource;
/**
* @param tracer to use for this intercepter
* Creates a Builder with default configuration
*/
public Builder(Tracer tracer) {
this.tracer = tracer;
this.operationNameConstructor = OperationNameConstructor.DEFAULT;
this.streaming = false;
this.verbose = false;
this.tracedAttributes = new HashSet<ClientRequestAttribute>();
this.activeSpanSource = ActiveSpanSource.GRPC_CONTEXT;
}
/**
* @param operationNameConstructor to name all spans created by this intercepter
* @return this Builder with configured operation name
*/
public Builder withOperationName(OperationNameConstructor operationNameConstructor) {
this.operationNameConstructor = operationNameConstructor;
return this;
}
/**
* Logs streaming events to client spans.
* @return this Builder configured to log streaming events
*/
public Builder withStreaming() {
this.streaming = true;
return this;
}
/**
* @param tracedAttributes to set as tags on client spans
* created by this intercepter
* @return this Builder configured to trace attributes
*/
public Builder withTracedAttributes(ClientRequestAttribute... tracedAttributes) {
this.tracedAttributes = new HashSet<ClientRequestAttribute>(
Arrays.asList(tracedAttributes));
return this;
}
/**
* Logs all request life-cycle events to client spans.
* @return this Builder configured to be verbose
*/
public Builder withVerbosity() {
this.verbose = true;
return this;
}
/**
* @param activeSpanSource that provides a method of getting the
* active span before the client call
* @return this Builder configured to start client span as children
* of the span returned by activeSpanSource.getActiveSpan()
*/
public Builder withActiveSpanSource(ActiveSpanSource activeSpanSource) {
this.activeSpanSource = activeSpanSource;
return this;
}
/**
* @return a ClientTracingInterceptor with this Builder's configuration
*/
public ClientTracingInterceptor build() {
return new ClientTracingInterceptor(this.tracer, this.operationNameConstructor,
this.streaming, this.verbose, this.tracedAttributes, this.activeSpanSource);
}
}
public enum ClientRequestAttribute {
METHOD_TYPE,
METHOD_NAME,
DEADLINE,
COMPRESSOR,
AUTHORITY,
ALL_CALL_OPTIONS,
HEADERS
}
}

View File

@@ -0,0 +1,31 @@
package io.opentracing.contrib;
import io.grpc.Context;
import io.opentracing.Span;
/**
* A {@link io.grpc.Context} key for the current OpenTracing trace state.
*
* Can be used to get the active span, or to set the active span for a scoped unit of work.
* See the <a href="../../../../../../README.rst">grpc-java OpenTracing docs</a> for use cases and examples.
*/
public class OpenTracingContextKey {
public static final String KEY_NAME = "io.opentracing.active-span";
private static final Context.Key<Span> key = Context.key(KEY_NAME);
/**
* @return the active span for the current request
*/
public static Span activeSpan() {
return key.get();
}
/**
* @return the OpenTracing context key
*/
public static Context.Key<Span> getKey() {
return key;
}
}

View File

@@ -0,0 +1,30 @@
package io.opentracing.contrib;
import io.grpc.MethodDescriptor;
/**
* Interface that allows span operation names to be constructed from an RPC's
* method descriptor.
*/
public interface OperationNameConstructor {
/**
* Default span operation name constructor, that will return an RPC's method
* name when constructOperationName is called.
*/
public static OperationNameConstructor DEFAULT = new OperationNameConstructor() {
@Override
public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
return method.getFullMethodName();
}
};
/**
* Constructs a span's operation name from the RPC's method.
* @param method the rpc method to extract a name from
* @param <ReqT> the rpc request type
* @param <RespT> the rpc response type
* @return the operation name
*/
public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method);
}

View File

@@ -0,0 +1,241 @@
package io.opentracing.contrib;
import com.google.common.collect.ImmutableMap;
import io.grpc.BindableService;
import io.grpc.Context;
import io.grpc.Contexts;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.grpc.ServerInterceptors;
import io.grpc.ServerServiceDefinition;
import io.grpc.ForwardingServerCallListener;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMapExtractAdapter;
import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.Tracer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* An intercepter that applies tracing via OpenTracing to all requests
* to the server.
*/
public class ServerTracingInterceptor implements ServerInterceptor {
private final Tracer tracer;
private final OperationNameConstructor operationNameConstructor;
private final boolean streaming;
private final boolean verbose;
private final Set<ServerRequestAttribute> tracedAttributes;
/**
* @param tracer used to trace requests
*/
public ServerTracingInterceptor(Tracer tracer) {
this.tracer = tracer;
this.operationNameConstructor = OperationNameConstructor.DEFAULT;
this.streaming = false;
this.verbose = false;
this.tracedAttributes = new HashSet<ServerRequestAttribute>();
}
private ServerTracingInterceptor(Tracer tracer, OperationNameConstructor operationNameConstructor, boolean streaming,
boolean verbose, Set<ServerRequestAttribute> tracedAttributes) {
this.tracer = tracer;
this.operationNameConstructor = operationNameConstructor;
this.streaming = streaming;
this.verbose = verbose;
this.tracedAttributes = tracedAttributes;
}
/**
* Add tracing to all requests made to this service.
* @param serviceDef of the service to intercept
* @return the serviceDef with a tracing interceptor
*/
public ServerServiceDefinition intercept(ServerServiceDefinition serviceDef) {
return ServerInterceptors.intercept(serviceDef, this);
}
/**
* Add tracing to all requests made to this service.
* @param bindableService to intercept
* @return the serviceDef with a tracing interceptor
*/
public ServerServiceDefinition intercept(BindableService bindableService) {
return ServerInterceptors.intercept(bindableService, this);
}
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
Metadata headers,
ServerCallHandler<ReqT, RespT> next
) {
Map<String, String> headerMap = new HashMap<String, String>();
for (String key : headers.keys()) {
if (!key.endsWith(Metadata.BINARY_HEADER_SUFFIX)) {
String value = headers.get(Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER));
headerMap.put(key, value);
}
}
final String operationName = operationNameConstructor.constructOperationName(call.getMethodDescriptor());
final Span span = getSpanFromHeaders(headerMap, operationName);
for (ServerRequestAttribute attr : this.tracedAttributes) {
switch (attr) {
case METHOD_TYPE:
span.setTag("grpc.method_type", call.getMethodDescriptor().getType().toString());
break;
case METHOD_NAME:
span.setTag("grpc.method_name", call.getMethodDescriptor().getFullMethodName());
break;
case CALL_ATTRIBUTES:
span.setTag("grpc.call_attributes", call.getAttributes().toString());
break;
case HEADERS:
span.setTag("grpc.headers", headers.toString());
break;
}
}
Context ctxWithSpan = Context.current().withValue(OpenTracingContextKey.getKey(), span);
ServerCall.Listener<ReqT> listenerWithContext = Contexts
.interceptCall(ctxWithSpan, call, headers, next);
ServerCall.Listener<ReqT> tracingListenerWithContext =
new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(listenerWithContext) {
@Override
public void onMessage(ReqT message) {
if (streaming || verbose) { span.log(ImmutableMap.of("Message received", message)); }
delegate().onMessage(message);
}
@Override
public void onHalfClose() {
if (streaming) { span.log("Client finished sending messages"); }
delegate().onHalfClose();
}
@Override
public void onCancel() {
span.log("Call cancelled");
span.finish();
delegate().onCancel();
}
@Override
public void onComplete() {
if (verbose) { span.log("Call completed"); }
span.finish();
delegate().onComplete();
}
};
return tracingListenerWithContext;
}
private Span getSpanFromHeaders(Map<String, String> headers, String operationName) {
Span span;
try {
SpanContext parentSpanCtx = tracer.extract(Format.Builtin.HTTP_HEADERS,
new TextMapExtractAdapter(headers));
if (parentSpanCtx == null) {
span = tracer.buildSpan(operationName).startManual();
} else {
span = tracer.buildSpan(operationName).asChildOf(parentSpanCtx).startManual();
}
} catch (IllegalArgumentException iae){
span = tracer.buildSpan(operationName)
.withTag("Error", "Extract failed and an IllegalArgumentException was thrown")
.startManual();
}
return span;
}
/**
* Builds the configuration of a ServerTracingInterceptor.
*/
public static class Builder {
private final Tracer tracer;
private OperationNameConstructor operationNameConstructor;
private boolean streaming;
private boolean verbose;
private Set<ServerRequestAttribute> tracedAttributes;
/**
* @param tracer to use for this intercepter
* Creates a Builder with default configuration
*/
public Builder(Tracer tracer) {
this.tracer = tracer;
this.operationNameConstructor = OperationNameConstructor.DEFAULT;
this.streaming = false;
this.verbose = false;
this.tracedAttributes = new HashSet<ServerRequestAttribute>();
}
/**
* @param operationNameConstructor for all spans created by this intercepter
* @return this Builder with configured operation name
*/
public Builder withOperationName(OperationNameConstructor operationNameConstructor) {
this.operationNameConstructor = operationNameConstructor;
return this;
}
/**
* @param attributes to set as tags on server spans
* created by this intercepter
* @return this Builder configured to trace request attributes
*/
public Builder withTracedAttributes(ServerRequestAttribute... attributes) {
this.tracedAttributes = new HashSet<ServerRequestAttribute>(Arrays.asList(attributes));
return this;
}
/**
* Logs streaming events to server spans.
* @return this Builder configured to log streaming events
*/
public Builder withStreaming() {
this.streaming = true;
return this;
}
/**
* Logs all request life-cycle events to server spans.
* @return this Builder configured to be verbose
*/
public Builder withVerbosity() {
this.verbose = true;
return this;
}
/**
* @return a ServerTracingInterceptor with this Builder's configuration
*/
public ServerTracingInterceptor build() {
return new ServerTracingInterceptor(this.tracer, this.operationNameConstructor,
this.streaming, this.verbose, this.tracedAttributes);
}
}
public enum ServerRequestAttribute {
HEADERS,
METHOD_TYPE,
METHOD_NAME,
CALL_ATTRIBUTES
}
}

View File

@@ -0,0 +1,48 @@
package io.opentracing.contrib;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import io.grpc.Context;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.mock.MockTracer;
public class ActiveSpanSourceTest {
Tracer tracer = new MockTracer();
@Test
public void TestDefaultNone() {
ActiveSpanSource ss = ActiveSpanSource.NONE;
assertEquals("active span should always be null", ss.getActiveSpan(), null);
Span span = tracer.buildSpan("s0").start();
Context ctx = Context.current().withValue(OpenTracingContextKey.getKey(), span);
Context previousCtx = ctx.attach();
assertEquals("active span should always be null", ss.getActiveSpan(), null);
ctx.detach(previousCtx);
span.finish();
}
@Test
public void TestDefaultGrpc() {
ActiveSpanSource ss = ActiveSpanSource.GRPC_CONTEXT;
assertEquals("active span should be null, no span in OpenTracingContextKey", ss.getActiveSpan(), null);
Span span = tracer.buildSpan("s0").start();
Context ctx = Context.current().withValue(OpenTracingContextKey.getKey(), span);
Context previousCtx = ctx.attach();
assertEquals("active span should be OpenTracingContextKey.activeSpan()", ss.getActiveSpan(), span);
ctx.detach(previousCtx);
span.finish();
assertEquals("active span should be null, no span in OpenTracingContextKey", ss.getActiveSpan(), null);
}
}

View File

@@ -0,0 +1,69 @@
package io.opentracing.contrib;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import io.grpc.Context;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.mock.MockTracer;
public class OpenTracingContextKeyTest {
Tracer tracer = new MockTracer();
@Test
public void TestGetKey() {
Context.Key<Span> key = OpenTracingContextKey.getKey();
assertEquals("Key should have correct name", key.toString(), (OpenTracingContextKey.KEY_NAME));
}
@Test
public void TestNoActiveSpan() {
assertEquals("activeSpan() should return null when no span is active",
OpenTracingContextKey.activeSpan(), null);
}
@Test
public void TestGetActiveSpan() {
Span span = tracer.buildSpan("s0").start();
Context ctx = Context.current().withValue(OpenTracingContextKey.getKey(), span);
Context previousCtx = ctx.attach();
assertEquals(OpenTracingContextKey.activeSpan(), span);
ctx.detach(previousCtx);
span.finish();
assertEquals(OpenTracingContextKey.activeSpan(), null);
}
@Test
public void TestMultipleContextLayers() {
Span parentSpan = tracer.buildSpan("s0").start();
Context parentCtx = Context.current().withValue(OpenTracingContextKey.getKey(), parentSpan);
Context previousCtx = parentCtx.attach();
Span childSpan = tracer.buildSpan("s1").start();
Context childCtx = Context.current().withValue(OpenTracingContextKey.getKey(), childSpan);
parentCtx = childCtx.attach();
assertEquals(OpenTracingContextKey.activeSpan(), childSpan);
childCtx.detach(parentCtx);
childSpan.finish();
assertEquals(OpenTracingContextKey.activeSpan(), parentSpan);
parentCtx.detach(previousCtx);
parentSpan.finish();
assertEquals(OpenTracingContextKey.activeSpan(), null);
}
@Test
public void TestWrappedCall() {
}
}

View File

@@ -0,0 +1,9 @@
## Tests
To run tests for grpc-opentracing, run
```
$ gradle test
```
These tests use the protobuf-generated classes from grpc-example, which are located in `src/testgen`.

View File

@@ -0,0 +1,39 @@
package io.opentracing.contrib;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
public class TracedClient {
private final ManagedChannel channel;
private final GreeterGrpc.GreeterBlockingStub blockingStub;
public TracedClient(String host, int port, ClientTracingInterceptor tracingInterceptor) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
if(tracingInterceptor==null) {
blockingStub = GreeterGrpc.newBlockingStub(channel);
} else {
blockingStub = GreeterGrpc.newBlockingStub(tracingInterceptor.intercept(channel));
}
}
void shutdown() throws InterruptedException {
channel.shutdown();
}
boolean greet(String name) {
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
try {
blockingStub.sayHello(request);
} catch (Exception e) {
return false;
} finally {
try { this.shutdown(); }
catch (Exception e) { return false; }
}
return true;
}
}

View File

@@ -0,0 +1,63 @@
package io.opentracing.contrib;
import java.io.IOException;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
public class TracedService {
private int port = 50051;
private Server server;
void start() throws IOException {
server = ServerBuilder.forPort(port)
.addService(new GreeterImpl())
.build()
.start();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
TracedService.this.stop();
}
});
}
void startWithInterceptor(ServerTracingInterceptor tracingInterceptor) throws IOException {
server = ServerBuilder.forPort(port)
.addService(tracingInterceptor.intercept(new GreeterImpl()))
.build()
.start();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
TracedService.this.stop();
}
});
}
void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
void stop() {
if (server != null) {
server.shutdown();
}
}
private class GreeterImpl extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello").build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
}

View File

@@ -0,0 +1,378 @@
package io.opentracing.contrib;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import io.grpc.MethodDescriptor;
import io.opentracing.mock.MockSpan;
import io.opentracing.mock.MockSpan.LogEntry;
import io.opentracing.mock.MockTracer;
public class TracingInterceptorsTest {
@Test
public void TestTracedServerBasic() {
TracedClient client = new TracedClient("localhost", 50051, null);
MockTracer serviceTracer = new MockTracer();
ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor(serviceTracer);
TracedService service = new TracedService();
try {
service.startWithInterceptor(tracingInterceptor);
assertTrue("call should complete", client.greet("world"));
assertEquals("one span should have been created and finished for one client request",
serviceTracer.finishedSpans().size(), 1);
MockSpan span = serviceTracer.finishedSpans().get(0);
assertEquals("span should have default name", span.operationName(), "helloworld.Greeter/SayHello");
assertEquals("span should have no parents", span.parentId(), 0);
assertTrue("span should have no logs", span.logEntries().isEmpty());
assertTrue("span should have no tags", span.tags().isEmpty());
assertFalse("span should have no baggage", span.context().baggageItems().iterator().hasNext());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
serviceTracer.reset();
}
}
@Test
public void TestTracedServerWithVerbosity() {
TracedClient client = new TracedClient("localhost", 50051, null);
MockTracer serviceTracer = new MockTracer();
TracedService service = new TracedService();
ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor
.Builder(serviceTracer)
.withVerbosity()
.build();
try {
service.startWithInterceptor(tracingInterceptor);
assertTrue("call should complete", client.greet("world"));
assertEquals("one span should have been created and finished for one client request",
serviceTracer.finishedSpans().size(), 1);
MockSpan span = serviceTracer.finishedSpans().get(0);
assertEquals("span should have default name", span.operationName(), "helloworld.Greeter/SayHello");
assertEquals("span should have no parents", span.parentId(), 0);
assertEquals("span should log onMessage and onComplete", 2, span.logEntries().size());
assertTrue("span should have no tags", span.tags().isEmpty());
assertFalse("span should have no baggage", span.context().baggageItems().iterator().hasNext());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
serviceTracer.reset();
}
}
@Test
public void TestTracedServerWithStreaming() {
TracedClient client = new TracedClient("localhost", 50051, null);
MockTracer serviceTracer = new MockTracer();
TracedService service = new TracedService();
ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor
.Builder(serviceTracer)
.withStreaming()
.build();
try {
service.startWithInterceptor(tracingInterceptor);
assertTrue("call should complete", client.greet("world"));
assertEquals("one span should have been created and finished for one client request",
serviceTracer.finishedSpans().size(), 1);
MockSpan span = serviceTracer.finishedSpans().get(0);
assertEquals("span should have default name", span.operationName(), "helloworld.Greeter/SayHello");
assertEquals("span should have no parents", span.parentId(), 0);
assertEquals("span should log onMessage and onHalfClose", span.logEntries().size(), 2);
assertTrue("span should have no tags", span.tags().isEmpty());
assertFalse("span should have no baggage", span.context().baggageItems().iterator().hasNext());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
serviceTracer.reset();
}
}
@Test
public void TestTracedServerWithCustomOperationName() {
final String PREFIX = "testing-";
TracedClient client = new TracedClient("localhost", 50051, null);
MockTracer serviceTracer = new MockTracer();
TracedService service = new TracedService();
ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor
.Builder(serviceTracer)
.withOperationName(new OperationNameConstructor() {
@Override
public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
return PREFIX + method.getFullMethodName();
}
})
.build();
try {
service.startWithInterceptor(tracingInterceptor);
assertTrue("call should complete", client.greet("world"));
assertEquals("one span should have been created and finished for one client request",
serviceTracer.finishedSpans().size(), 1);
MockSpan span = serviceTracer.finishedSpans().get(0);
assertEquals("span should have prefix", span.operationName(), PREFIX + "helloworld.Greeter/SayHello");
assertEquals("span should have no parents", span.parentId(), 0);
assertEquals("span should have no logs", span.logEntries().size(), 0);
assertTrue("span should have no tags", span.tags().isEmpty());
assertFalse("span should have no baggage", span.context().baggageItems().iterator().hasNext());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
serviceTracer.reset();
}
}
@Test
public void TestTracedServerWithTracedAttributes() {
TracedClient client = new TracedClient("localhost", 50051, null);
MockTracer serviceTracer = new MockTracer();
TracedService service = new TracedService();
ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor
.Builder(serviceTracer)
.withTracedAttributes(ServerTracingInterceptor.ServerRequestAttribute.values())
.build();
try {
service.startWithInterceptor(tracingInterceptor);
assertTrue("call should complete", client.greet("world"));
assertEquals("one span should have been created and finished for one client request",
serviceTracer.finishedSpans().size(), 1);
MockSpan span = serviceTracer.finishedSpans().get(0);
assertEquals("span should have prefix", span.operationName(), "helloworld.Greeter/SayHello");
assertEquals("span should have no parents", span.parentId(), 0);
assertEquals("span should have no logs", span.logEntries().size(), 0);
assertEquals("span should have a tag for each traced attribute",
ServerTracingInterceptor.ServerRequestAttribute.values().length, span.tags().size());
assertFalse("span should have no baggage", span.context().baggageItems().iterator().hasNext());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
serviceTracer.reset();
}
}
@Test
public void TestTracedClientBasic() {
TracedService service = new TracedService();
MockTracer clientTracer = new MockTracer();
ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor(clientTracer);
TracedClient client = new TracedClient("localhost", 50051, tracingInterceptor);
try {
service.start();
assertTrue("call should complete", client.greet("world"));
assertEquals("one span should have been created and finished for one client request",
clientTracer.finishedSpans().size(), 1);
MockSpan span = clientTracer.finishedSpans().get(0);
assertEquals("span should have prefix", span.operationName(), "helloworld.Greeter/SayHello");
assertEquals("span should have no parents", span.parentId(), 0);
assertEquals("span should have no logs", span.logEntries().size(), 0);
assertEquals("span should have no tags", span.tags().size(), 0);
assertFalse("span should have no baggage", span.context().baggageItems().iterator().hasNext());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
clientTracer.reset();
}
}
@Test
public void TestTracedClientWithVerbosity() {
TracedService service = new TracedService();
MockTracer clientTracer = new MockTracer();
ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor
.Builder(clientTracer)
.withVerbosity()
.build();
TracedClient client = new TracedClient("localhost", 50051, tracingInterceptor);
try {
service.start();
assertTrue("call should complete", client.greet("world"));
assertEquals("one span should have been created and finished for one client request",
clientTracer.finishedSpans().size(), 1);
MockSpan span = clientTracer.finishedSpans().get(0);
assertEquals("span should have prefix", span.operationName(), "helloworld.Greeter/SayHello");
assertEquals("span should have no parents", span.parentId(), 0);
System.out.println(span.logEntries());
assertEquals("span should have logs for start, onHeaders, onMessage, onClose, sendMessage", 5, span.logEntries().size());
assertEquals("span should have no tags", span.tags().size(), 0);
assertFalse("span should have no baggage", span.context().baggageItems().iterator().hasNext());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
clientTracer.reset();
}
}
@Test
public void TestTracedClientWithStreaming() {
TracedService service = new TracedService();
MockTracer clientTracer = new MockTracer();
ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor
.Builder(clientTracer)
.withStreaming()
.build();
TracedClient client = new TracedClient("localhost", 50051, tracingInterceptor);
try {
service.start();
assertTrue("call should complete", client.greet("world"));
assertEquals("one span should have been created and finished for one client request",
clientTracer.finishedSpans().size(), 1);
MockSpan span = clientTracer.finishedSpans().get(0);
assertEquals("span should have prefix", span.operationName(), "helloworld.Greeter/SayHello");
assertEquals("span should have no parents", span.parentId(), 0);
assertEquals("span should have log for onMessage, halfClose, sendMessage", 3, span.logEntries().size());
assertEquals("span should have no tags", span.tags().size(), 0);
assertFalse("span should have no baggage", span.context().baggageItems().iterator().hasNext());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
clientTracer.reset();
}
}
@Test
public void TestTracedClientWithOperationName() {
TracedService service = new TracedService();
final String PREFIX = "testing-";
MockTracer clientTracer = new MockTracer();
ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor
.Builder(clientTracer)
.withOperationName(new OperationNameConstructor() {
@Override
public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
return PREFIX + method.getFullMethodName();
}
})
.build();
TracedClient client = new TracedClient("localhost", 50051, tracingInterceptor);
try {
service.start();
assertTrue("call should complete", client.greet("world"));
assertEquals("one span should have been created and finished for one client request",
clientTracer.finishedSpans().size(), 1);
MockSpan span = clientTracer.finishedSpans().get(0);
assertEquals("span should have prefix", span.operationName(), PREFIX + "helloworld.Greeter/SayHello");
assertEquals("span should have no parents", span.parentId(), 0);
assertEquals("span should have no logs", span.logEntries().size(), 0);
assertEquals("span should have no tags", span.tags().size(), 0);
assertFalse("span should have no baggage", span.context().baggageItems().iterator().hasNext());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
clientTracer.reset();
}
}
@Test
public void TestTracedClientWithTracedAttributes() {
TracedService service = new TracedService();
MockTracer clientTracer = new MockTracer();
ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor
.Builder(clientTracer)
.withTracedAttributes(ClientTracingInterceptor.ClientRequestAttribute.values())
.build();
TracedClient client = new TracedClient("localhost", 50051, tracingInterceptor);
try {
service.start();
assertTrue("call should complete", client.greet("world"));
assertEquals("one span should have been created and finished for one client request",
clientTracer.finishedSpans().size(), 1);
MockSpan span = clientTracer.finishedSpans().get(0);
assertEquals("span should have prefix", span.operationName(), "helloworld.Greeter/SayHello");
assertEquals("span should have no parents", span.parentId(), 0);
assertEquals("span should have no logs", span.logEntries().size(), 0);
assertEquals("span should have tags for all client request attributes",
ClientTracingInterceptor.ClientRequestAttribute.values().length, span.tags().size());
assertFalse("span should have no baggage", span.context().baggageItems().iterator().hasNext());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
clientTracer.reset();
}
}
@Test
public void TestTracedClientAndServer() {
MockTracer clientTracer = new MockTracer();
MockTracer serverTracer = new MockTracer();
ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor(clientTracer);
TracedClient client = new TracedClient("localhost", 50051, tracingInterceptor);
ServerTracingInterceptor serverTracingInterceptor = new ServerTracingInterceptor(serverTracer);
TracedService service = new TracedService();
try {
service.startWithInterceptor(serverTracingInterceptor);
assertTrue("call should complete", client.greet("world"));
assertEquals("a client span should have been created for the request",
1, clientTracer.finishedSpans().size());
assertEquals("a server span should have been created for the request",
1, serverTracer.finishedSpans().size());
MockSpan serverSpan = serverTracer.finishedSpans().get(0);
MockSpan clientSpan = clientTracer.finishedSpans().get(0);
// should ideally also make sure that the parent/child relation is there, but the MockTracer
// doesn't allow for creating new contexts outside of its package to pass in to asChildOf
assertTrue("client span should start before server span", clientSpan.startMicros() <= serverSpan.startMicros());
assertTrue("client span should end after server span", clientSpan.finishMicros() >= serverSpan.finishMicros());
} catch (Exception e) {
assertTrue(e.getMessage(), false);
} finally {
service.stop();
clientTracer.reset();
}
}
}

View File

@@ -0,0 +1,251 @@
package io.opentracing.contrib;
import static io.grpc.MethodDescriptor.generateFullMethodName;
import static io.grpc.stub.ClientCalls.asyncUnaryCall;
import static io.grpc.stub.ClientCalls.blockingUnaryCall;
import static io.grpc.stub.ClientCalls.futureUnaryCall;
import static io.grpc.stub.ServerCalls.asyncUnaryCall;
import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;
/**
* <pre>
* The greeting service definition.
* </pre>
*/
@javax.annotation.Generated(
value = "by gRPC proto compiler (version 0.15.0)",
comments = "Source: helloworld.proto")
public class GreeterGrpc {
private GreeterGrpc() {}
public static final String SERVICE_NAME = "helloworld.Greeter";
// Static method descriptors that strictly reflect the proto.
@io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
public static final io.grpc.MethodDescriptor<io.opentracing.contrib.HelloRequest,
io.opentracing.contrib.HelloReply> METHOD_SAY_HELLO =
io.grpc.MethodDescriptor.create(
io.grpc.MethodDescriptor.MethodType.UNARY,
generateFullMethodName(
"helloworld.Greeter", "SayHello"),
io.grpc.protobuf.ProtoUtils.marshaller(io.opentracing.contrib.HelloRequest.getDefaultInstance()),
io.grpc.protobuf.ProtoUtils.marshaller(io.opentracing.contrib.HelloReply.getDefaultInstance()));
/**
* Creates a new async stub that supports all call types for the service
*/
public static GreeterStub newStub(io.grpc.Channel channel) {
return new GreeterStub(channel);
}
/**
* Creates a new blocking-style stub that supports unary and streaming output calls on the service
*/
public static GreeterBlockingStub newBlockingStub(
io.grpc.Channel channel) {
return new GreeterBlockingStub(channel);
}
/**
* Creates a new ListenableFuture-style stub that supports unary and streaming output calls on the service
*/
public static GreeterFutureStub newFutureStub(
io.grpc.Channel channel) {
return new GreeterFutureStub(channel);
}
/**
* <pre>
* The greeting service definition.
* </pre>
*/
@java.lang.Deprecated public static interface Greeter {
/**
* <pre>
* Sends a greeting
* </pre>
*/
public void sayHello(io.opentracing.contrib.HelloRequest request,
io.grpc.stub.StreamObserver<io.opentracing.contrib.HelloReply> responseObserver);
}
@io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1469")
public static abstract class GreeterImplBase implements Greeter, io.grpc.BindableService {
@java.lang.Override
public void sayHello(io.opentracing.contrib.HelloRequest request,
io.grpc.stub.StreamObserver<io.opentracing.contrib.HelloReply> responseObserver) {
asyncUnimplementedUnaryCall(METHOD_SAY_HELLO, responseObserver);
}
@java.lang.Override public io.grpc.ServerServiceDefinition bindService() {
return GreeterGrpc.bindService(this);
}
}
/**
* <pre>
* The greeting service definition.
* </pre>
*/
@java.lang.Deprecated public static interface GreeterBlockingClient {
/**
* <pre>
* Sends a greeting
* </pre>
*/
public io.opentracing.contrib.HelloReply sayHello(io.opentracing.contrib.HelloRequest request);
}
/**
* <pre>
* The greeting service definition.
* </pre>
*/
@java.lang.Deprecated public static interface GreeterFutureClient {
/**
* <pre>
* Sends a greeting
* </pre>
*/
public com.google.common.util.concurrent.ListenableFuture<io.opentracing.contrib.HelloReply> sayHello(
io.opentracing.contrib.HelloRequest request);
}
public static class GreeterStub extends io.grpc.stub.AbstractStub<GreeterStub>
implements Greeter {
private GreeterStub(io.grpc.Channel channel) {
super(channel);
}
private GreeterStub(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
super(channel, callOptions);
}
@java.lang.Override
protected GreeterStub build(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
return new GreeterStub(channel, callOptions);
}
@java.lang.Override
public void sayHello(io.opentracing.contrib.HelloRequest request,
io.grpc.stub.StreamObserver<io.opentracing.contrib.HelloReply> responseObserver) {
asyncUnaryCall(
getChannel().newCall(METHOD_SAY_HELLO, getCallOptions()), request, responseObserver);
}
}
public static class GreeterBlockingStub extends io.grpc.stub.AbstractStub<GreeterBlockingStub>
implements GreeterBlockingClient {
private GreeterBlockingStub(io.grpc.Channel channel) {
super(channel);
}
private GreeterBlockingStub(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
super(channel, callOptions);
}
@java.lang.Override
protected GreeterBlockingStub build(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
return new GreeterBlockingStub(channel, callOptions);
}
@java.lang.Override
public io.opentracing.contrib.HelloReply sayHello(io.opentracing.contrib.HelloRequest request) {
return blockingUnaryCall(
getChannel(), METHOD_SAY_HELLO, getCallOptions(), request);
}
}
public static class GreeterFutureStub extends io.grpc.stub.AbstractStub<GreeterFutureStub>
implements GreeterFutureClient {
private GreeterFutureStub(io.grpc.Channel channel) {
super(channel);
}
private GreeterFutureStub(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
super(channel, callOptions);
}
@java.lang.Override
protected GreeterFutureStub build(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
return new GreeterFutureStub(channel, callOptions);
}
@java.lang.Override
public com.google.common.util.concurrent.ListenableFuture<io.opentracing.contrib.HelloReply> sayHello(
io.opentracing.contrib.HelloRequest request) {
return futureUnaryCall(
getChannel().newCall(METHOD_SAY_HELLO, getCallOptions()), request);
}
}
@java.lang.Deprecated public static abstract class AbstractGreeter extends GreeterImplBase {}
private static final int METHODID_SAY_HELLO = 0;
private static class MethodHandlers<Req, Resp> implements
io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
private final Greeter serviceImpl;
private final int methodId;
public MethodHandlers(Greeter serviceImpl, int methodId) {
this.serviceImpl = serviceImpl;
this.methodId = methodId;
}
@java.lang.Override
@java.lang.SuppressWarnings("unchecked")
public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
switch (methodId) {
case METHODID_SAY_HELLO:
serviceImpl.sayHello((io.opentracing.contrib.HelloRequest) request,
(io.grpc.stub.StreamObserver<io.opentracing.contrib.HelloReply>) responseObserver);
break;
default:
throw new AssertionError();
}
}
@java.lang.Override
@java.lang.SuppressWarnings("unchecked")
public io.grpc.stub.StreamObserver<Req> invoke(
io.grpc.stub.StreamObserver<Resp> responseObserver) {
switch (methodId) {
default:
throw new AssertionError();
}
}
}
public static io.grpc.ServiceDescriptor getServiceDescriptor() {
return new io.grpc.ServiceDescriptor(SERVICE_NAME,
METHOD_SAY_HELLO);
}
@java.lang.Deprecated public static io.grpc.ServerServiceDefinition bindService(
final Greeter serviceImpl) {
return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
.addMethod(
METHOD_SAY_HELLO,
asyncUnaryCall(
new MethodHandlers<
io.opentracing.contrib.HelloRequest,
io.opentracing.contrib.HelloReply>(
serviceImpl, METHODID_SAY_HELLO)))
.build();
}
}

View File

@@ -0,0 +1,445 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: helloworld.proto
package io.opentracing.contrib;
/**
* <pre>
* The response message containing the greetings
* </pre>
*
* Protobuf type {@code helloworld.HelloReply}
*/
public final class HelloReply extends
com.google.protobuf.GeneratedMessage implements
// @@protoc_insertion_point(message_implements:helloworld.HelloReply)
HelloReplyOrBuilder {
// Use HelloReply.newBuilder() to construct.
private HelloReply(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
super(builder);
}
private HelloReply() {
message_ = "";
}
@java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return com.google.protobuf.UnknownFieldSet.getDefaultInstance();
}
private HelloReply(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
int mutable_bitField0_ = 0;
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
default: {
if (!input.skipField(tag)) {
done = true;
}
break;
}
case 10: {
java.lang.String s = input.readStringRequireUtf8();
message_ = s;
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e).setUnfinishedMessage(this);
} finally {
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return io.opentracing.contrib.HelloWorldProto.internal_static_helloworld_HelloReply_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return io.opentracing.contrib.HelloWorldProto.internal_static_helloworld_HelloReply_fieldAccessorTable
.ensureFieldAccessorsInitialized(
io.opentracing.contrib.HelloReply.class, io.opentracing.contrib.HelloReply.Builder.class);
}
public static final int MESSAGE_FIELD_NUMBER = 1;
private volatile java.lang.Object message_;
/**
* <code>optional string message = 1;</code>
*/
public java.lang.String getMessage() {
java.lang.Object ref = message_;
if (ref instanceof java.lang.String) {
return (java.lang.String) ref;
} else {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
message_ = s;
return s;
}
}
/**
* <code>optional string message = 1;</code>
*/
public com.google.protobuf.ByteString
getMessageBytes() {
java.lang.Object ref = message_;
if (ref instanceof java.lang.String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
message_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (!getMessageBytes().isEmpty()) {
com.google.protobuf.GeneratedMessage.writeString(output, 1, message_);
}
}
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
size = 0;
if (!getMessageBytes().isEmpty()) {
size += com.google.protobuf.GeneratedMessage.computeStringSize(1, message_);
}
memoizedSize = size;
return size;
}
private static final long serialVersionUID = 0L;
public static io.opentracing.contrib.HelloReply parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static io.opentracing.contrib.HelloReply parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static io.opentracing.contrib.HelloReply parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static io.opentracing.contrib.HelloReply parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static io.opentracing.contrib.HelloReply parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input);
}
public static io.opentracing.contrib.HelloReply parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static io.opentracing.contrib.HelloReply parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseDelimitedWithIOException(PARSER, input);
}
public static io.opentracing.contrib.HelloReply parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static io.opentracing.contrib.HelloReply parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input);
}
public static io.opentracing.contrib.HelloReply parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input, extensionRegistry);
}
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(io.opentracing.contrib.HelloReply prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* <pre>
* The response message containing the greetings
* </pre>
*
* Protobuf type {@code helloworld.HelloReply}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:helloworld.HelloReply)
io.opentracing.contrib.HelloReplyOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return io.opentracing.contrib.HelloWorldProto.internal_static_helloworld_HelloReply_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return io.opentracing.contrib.HelloWorldProto.internal_static_helloworld_HelloReply_fieldAccessorTable
.ensureFieldAccessorsInitialized(
io.opentracing.contrib.HelloReply.class, io.opentracing.contrib.HelloReply.Builder.class);
}
// Construct using io.opentracing.contrib.HelloReply.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
}
}
public Builder clear() {
super.clear();
message_ = "";
return this;
}
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return io.opentracing.contrib.HelloWorldProto.internal_static_helloworld_HelloReply_descriptor;
}
public io.opentracing.contrib.HelloReply getDefaultInstanceForType() {
return io.opentracing.contrib.HelloReply.getDefaultInstance();
}
public io.opentracing.contrib.HelloReply build() {
io.opentracing.contrib.HelloReply result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
public io.opentracing.contrib.HelloReply buildPartial() {
io.opentracing.contrib.HelloReply result = new io.opentracing.contrib.HelloReply(this);
result.message_ = message_;
onBuilt();
return result;
}
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof io.opentracing.contrib.HelloReply) {
return mergeFrom((io.opentracing.contrib.HelloReply)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(io.opentracing.contrib.HelloReply other) {
if (other == io.opentracing.contrib.HelloReply.getDefaultInstance()) return this;
if (!other.getMessage().isEmpty()) {
message_ = other.message_;
onChanged();
}
onChanged();
return this;
}
public final boolean isInitialized() {
return true;
}
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
io.opentracing.contrib.HelloReply parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (io.opentracing.contrib.HelloReply) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private java.lang.Object message_ = "";
/**
* <code>optional string message = 1;</code>
*/
public java.lang.String getMessage() {
java.lang.Object ref = message_;
if (!(ref instanceof java.lang.String)) {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
message_ = s;
return s;
} else {
return (java.lang.String) ref;
}
}
/**
* <code>optional string message = 1;</code>
*/
public com.google.protobuf.ByteString
getMessageBytes() {
java.lang.Object ref = message_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
message_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
/**
* <code>optional string message = 1;</code>
*/
public Builder setMessage(
java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
message_ = value;
onChanged();
return this;
}
/**
* <code>optional string message = 1;</code>
*/
public Builder clearMessage() {
message_ = getDefaultInstance().getMessage();
onChanged();
return this;
}
/**
* <code>optional string message = 1;</code>
*/
public Builder setMessageBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
checkByteStringIsUtf8(value);
message_ = value;
onChanged();
return this;
}
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return this;
}
public final Builder mergeUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return this;
}
// @@protoc_insertion_point(builder_scope:helloworld.HelloReply)
}
// @@protoc_insertion_point(class_scope:helloworld.HelloReply)
private static final io.opentracing.contrib.HelloReply DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new io.opentracing.contrib.HelloReply();
}
public static io.opentracing.contrib.HelloReply getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<HelloReply>
PARSER = new com.google.protobuf.AbstractParser<HelloReply>() {
public HelloReply parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new HelloReply(input, extensionRegistry);
}
};
public static com.google.protobuf.Parser<HelloReply> parser() {
return PARSER;
}
@java.lang.Override
public com.google.protobuf.Parser<HelloReply> getParserForType() {
return PARSER;
}
public io.opentracing.contrib.HelloReply getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}

View File

@@ -0,0 +1,19 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: helloworld.proto
package io.opentracing.contrib;
public interface HelloReplyOrBuilder extends
// @@protoc_insertion_point(interface_extends:helloworld.HelloReply)
com.google.protobuf.MessageOrBuilder {
/**
* <code>optional string message = 1;</code>
*/
java.lang.String getMessage();
/**
* <code>optional string message = 1;</code>
*/
com.google.protobuf.ByteString
getMessageBytes();
}

View File

@@ -0,0 +1,445 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: helloworld.proto
package io.opentracing.contrib;
/**
* <pre>
* The request message containing the user's name.
* </pre>
*
* Protobuf type {@code helloworld.HelloRequest}
*/
public final class HelloRequest extends
com.google.protobuf.GeneratedMessage implements
// @@protoc_insertion_point(message_implements:helloworld.HelloRequest)
HelloRequestOrBuilder {
// Use HelloRequest.newBuilder() to construct.
private HelloRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
super(builder);
}
private HelloRequest() {
name_ = "";
}
@java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return com.google.protobuf.UnknownFieldSet.getDefaultInstance();
}
private HelloRequest(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
int mutable_bitField0_ = 0;
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
default: {
if (!input.skipField(tag)) {
done = true;
}
break;
}
case 10: {
java.lang.String s = input.readStringRequireUtf8();
name_ = s;
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e).setUnfinishedMessage(this);
} finally {
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return io.opentracing.contrib.HelloWorldProto.internal_static_helloworld_HelloRequest_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return io.opentracing.contrib.HelloWorldProto.internal_static_helloworld_HelloRequest_fieldAccessorTable
.ensureFieldAccessorsInitialized(
io.opentracing.contrib.HelloRequest.class, io.opentracing.contrib.HelloRequest.Builder.class);
}
public static final int NAME_FIELD_NUMBER = 1;
private volatile java.lang.Object name_;
/**
* <code>optional string name = 1;</code>
*/
public java.lang.String getName() {
java.lang.Object ref = name_;
if (ref instanceof java.lang.String) {
return (java.lang.String) ref;
} else {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
name_ = s;
return s;
}
}
/**
* <code>optional string name = 1;</code>
*/
public com.google.protobuf.ByteString
getNameBytes() {
java.lang.Object ref = name_;
if (ref instanceof java.lang.String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
name_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (!getNameBytes().isEmpty()) {
com.google.protobuf.GeneratedMessage.writeString(output, 1, name_);
}
}
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
size = 0;
if (!getNameBytes().isEmpty()) {
size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_);
}
memoizedSize = size;
return size;
}
private static final long serialVersionUID = 0L;
public static io.opentracing.contrib.HelloRequest parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static io.opentracing.contrib.HelloRequest parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static io.opentracing.contrib.HelloRequest parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static io.opentracing.contrib.HelloRequest parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static io.opentracing.contrib.HelloRequest parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input);
}
public static io.opentracing.contrib.HelloRequest parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static io.opentracing.contrib.HelloRequest parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseDelimitedWithIOException(PARSER, input);
}
public static io.opentracing.contrib.HelloRequest parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static io.opentracing.contrib.HelloRequest parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input);
}
public static io.opentracing.contrib.HelloRequest parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessage
.parseWithIOException(PARSER, input, extensionRegistry);
}
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(io.opentracing.contrib.HelloRequest prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* <pre>
* The request message containing the user's name.
* </pre>
*
* Protobuf type {@code helloworld.HelloRequest}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:helloworld.HelloRequest)
io.opentracing.contrib.HelloRequestOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return io.opentracing.contrib.HelloWorldProto.internal_static_helloworld_HelloRequest_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return io.opentracing.contrib.HelloWorldProto.internal_static_helloworld_HelloRequest_fieldAccessorTable
.ensureFieldAccessorsInitialized(
io.opentracing.contrib.HelloRequest.class, io.opentracing.contrib.HelloRequest.Builder.class);
}
// Construct using io.opentracing.contrib.HelloRequest.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
com.google.protobuf.GeneratedMessage.BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
}
}
public Builder clear() {
super.clear();
name_ = "";
return this;
}
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return io.opentracing.contrib.HelloWorldProto.internal_static_helloworld_HelloRequest_descriptor;
}
public io.opentracing.contrib.HelloRequest getDefaultInstanceForType() {
return io.opentracing.contrib.HelloRequest.getDefaultInstance();
}
public io.opentracing.contrib.HelloRequest build() {
io.opentracing.contrib.HelloRequest result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
public io.opentracing.contrib.HelloRequest buildPartial() {
io.opentracing.contrib.HelloRequest result = new io.opentracing.contrib.HelloRequest(this);
result.name_ = name_;
onBuilt();
return result;
}
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof io.opentracing.contrib.HelloRequest) {
return mergeFrom((io.opentracing.contrib.HelloRequest)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(io.opentracing.contrib.HelloRequest other) {
if (other == io.opentracing.contrib.HelloRequest.getDefaultInstance()) return this;
if (!other.getName().isEmpty()) {
name_ = other.name_;
onChanged();
}
onChanged();
return this;
}
public final boolean isInitialized() {
return true;
}
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
io.opentracing.contrib.HelloRequest parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (io.opentracing.contrib.HelloRequest) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private java.lang.Object name_ = "";
/**
* <code>optional string name = 1;</code>
*/
public java.lang.String getName() {
java.lang.Object ref = name_;
if (!(ref instanceof java.lang.String)) {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
name_ = s;
return s;
} else {
return (java.lang.String) ref;
}
}
/**
* <code>optional string name = 1;</code>
*/
public com.google.protobuf.ByteString
getNameBytes() {
java.lang.Object ref = name_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
name_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
/**
* <code>optional string name = 1;</code>
*/
public Builder setName(
java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
name_ = value;
onChanged();
return this;
}
/**
* <code>optional string name = 1;</code>
*/
public Builder clearName() {
name_ = getDefaultInstance().getName();
onChanged();
return this;
}
/**
* <code>optional string name = 1;</code>
*/
public Builder setNameBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
checkByteStringIsUtf8(value);
name_ = value;
onChanged();
return this;
}
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return this;
}
public final Builder mergeUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return this;
}
// @@protoc_insertion_point(builder_scope:helloworld.HelloRequest)
}
// @@protoc_insertion_point(class_scope:helloworld.HelloRequest)
private static final io.opentracing.contrib.HelloRequest DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new io.opentracing.contrib.HelloRequest();
}
public static io.opentracing.contrib.HelloRequest getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<HelloRequest>
PARSER = new com.google.protobuf.AbstractParser<HelloRequest>() {
public HelloRequest parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new HelloRequest(input, extensionRegistry);
}
};
public static com.google.protobuf.Parser<HelloRequest> parser() {
return PARSER;
}
@java.lang.Override
public com.google.protobuf.Parser<HelloRequest> getParserForType() {
return PARSER;
}
public io.opentracing.contrib.HelloRequest getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}

View File

@@ -0,0 +1,19 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: helloworld.proto
package io.opentracing.contrib;
public interface HelloRequestOrBuilder extends
// @@protoc_insertion_point(interface_extends:helloworld.HelloRequest)
com.google.protobuf.MessageOrBuilder {
/**
* <code>optional string name = 1;</code>
*/
java.lang.String getName();
/**
* <code>optional string name = 1;</code>
*/
com.google.protobuf.ByteString
getNameBytes();
}

View File

@@ -0,0 +1,64 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: helloworld.proto
package io.opentracing.contrib;
public final class HelloWorldProto {
private HelloWorldProto() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
}
static final com.google.protobuf.Descriptors.Descriptor
internal_static_helloworld_HelloRequest_descriptor;
static final
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_helloworld_HelloRequest_fieldAccessorTable;
static final com.google.protobuf.Descriptors.Descriptor
internal_static_helloworld_HelloReply_descriptor;
static final
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_helloworld_HelloReply_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\020helloworld.proto\022\nhelloworld\"\034\n\014HelloR" +
"equest\022\014\n\004name\030\001 \001(\t\"\035\n\nHelloReply\022\017\n\007me" +
"ssage\030\001 \001(\t2I\n\007Greeter\022>\n\010SayHello\022\030.hel" +
"loworld.HelloRequest\032\026.helloworld.HelloR" +
"eply\"\000B6\n\033io.grpc.examples.helloworldB\017H" +
"elloWorldProtoP\001\242\002\003HLWb\006proto3"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
public com.google.protobuf.ExtensionRegistry assignDescriptors(
com.google.protobuf.Descriptors.FileDescriptor root) {
descriptor = root;
return null;
}
};
com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
}, assigner);
internal_static_helloworld_HelloRequest_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_helloworld_HelloRequest_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_helloworld_HelloRequest_descriptor,
new java.lang.String[] { "Name", });
internal_static_helloworld_HelloReply_descriptor =
getDescriptor().getMessageTypes().get(1);
internal_static_helloworld_HelloReply_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_helloworld_HelloReply_descriptor,
new java.lang.String[] { "Message", });
}
// @@protoc_insertion_point(outer_class_scope)
}

View File

@@ -0,0 +1 @@
These are protobuf-generated classes to be used for testing purposes only.

View File

@@ -0,0 +1,94 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# dotenv
.env
# virtualenv
.venv
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject

View File

@@ -0,0 +1,2 @@
[style]
based_on_style = google

View File

@@ -0,0 +1,4 @@
The repo has moved.
-------------------
https://github.com/opentracing-contrib/python-grpc

View File

@@ -0,0 +1,8 @@
An example showing how to connect gRPC's OpenTracing spans to other OpenTracing
spans.
## Usage
```
python integration_server.py &
python integration_client.py
```

View File

@@ -0,0 +1,213 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: command_line.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='command_line.proto',
package='command_line',
syntax='proto3',
serialized_pb=_b('\n\x12\x63ommand_line.proto\x12\x0c\x63ommand_line\"\x1e\n\x0e\x43ommandRequest\x12\x0c\n\x04text\x18\x01 \x01(\t\"\x1f\n\x0f\x43ommandResponse\x12\x0c\n\x04text\x18\x01 \x01(\t2T\n\x0b\x43ommandLine\x12\x45\n\x04\x45\x63ho\x12\x1c.command_line.CommandRequest\x1a\x1d.command_line.CommandResponse\"\x00\x62\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
_COMMANDREQUEST = _descriptor.Descriptor(
name='CommandRequest',
full_name='command_line.CommandRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='text', full_name='command_line.CommandRequest.text', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=36,
serialized_end=66,
)
_COMMANDRESPONSE = _descriptor.Descriptor(
name='CommandResponse',
full_name='command_line.CommandResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='text', full_name='command_line.CommandResponse.text', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=68,
serialized_end=99,
)
DESCRIPTOR.message_types_by_name['CommandRequest'] = _COMMANDREQUEST
DESCRIPTOR.message_types_by_name['CommandResponse'] = _COMMANDRESPONSE
CommandRequest = _reflection.GeneratedProtocolMessageType('CommandRequest', (_message.Message,), dict(
DESCRIPTOR = _COMMANDREQUEST,
__module__ = 'command_line_pb2'
# @@protoc_insertion_point(class_scope:command_line.CommandRequest)
))
_sym_db.RegisterMessage(CommandRequest)
CommandResponse = _reflection.GeneratedProtocolMessageType('CommandResponse', (_message.Message,), dict(
DESCRIPTOR = _COMMANDRESPONSE,
__module__ = 'command_line_pb2'
# @@protoc_insertion_point(class_scope:command_line.CommandResponse)
))
_sym_db.RegisterMessage(CommandResponse)
try:
# THESE ELEMENTS WILL BE DEPRECATED.
# Please use the generated *_pb2_grpc.py files instead.
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
from grpc.beta import implementations as beta_implementations
from grpc.beta import interfaces as beta_interfaces
class CommandLineStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Echo = channel.unary_unary(
'/command_line.CommandLine/Echo',
request_serializer=CommandRequest.SerializeToString,
response_deserializer=CommandResponse.FromString,
)
class CommandLineServicer(object):
def Echo(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_CommandLineServicer_to_server(servicer, server):
rpc_method_handlers = {
'Echo': grpc.unary_unary_rpc_method_handler(
servicer.Echo,
request_deserializer=CommandRequest.FromString,
response_serializer=CommandResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'command_line.CommandLine', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class BetaCommandLineServicer(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def Echo(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaCommandLineStub(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def Echo(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
Echo.future = None
def beta_create_CommandLine_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_deserializers = {
('command_line.CommandLine', 'Echo'): CommandRequest.FromString,
}
response_serializers = {
('command_line.CommandLine', 'Echo'): CommandResponse.SerializeToString,
}
method_implementations = {
('command_line.CommandLine', 'Echo'): face_utilities.unary_unary_inline(servicer.Echo),
}
server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
return beta_implementations.server(method_implementations, options=server_options)
def beta_create_CommandLine_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_serializers = {
('command_line.CommandLine', 'Echo'): CommandRequest.SerializeToString,
}
response_deserializers = {
('command_line.CommandLine', 'Echo'): CommandResponse.FromString,
}
cardinalities = {
'Echo': cardinality.Cardinality.UNARY_UNARY,
}
stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
return beta_implementations.dynamic_stub(channel, 'command_line.CommandLine', cardinalities, options=stub_options)
except ImportError:
pass
# @@protoc_insertion_point(module_scope)

View File

@@ -0,0 +1,42 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
import command_line_pb2 as command__line__pb2
class CommandLineStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Echo = channel.unary_unary(
'/command_line.CommandLine/Echo',
request_serializer=command__line__pb2.CommandRequest.SerializeToString,
response_deserializer=command__line__pb2.CommandResponse.FromString,
)
class CommandLineServicer(object):
def Echo(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_CommandLineServicer_to_server(servicer, server):
rpc_method_handlers = {
'Echo': grpc.unary_unary_rpc_method_handler(
servicer.Echo,
request_deserializer=command__line__pb2.CommandRequest.FromString,
response_serializer=command__line__pb2.CommandResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'command_line.CommandLine', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))

View File

@@ -0,0 +1,67 @@
from __future__ import print_function
import time
import argparse
import grpc
from jaeger_client import Config
from grpc_opentracing import open_tracing_client_interceptor, ActiveSpanSource
from grpc_opentracing.grpcext import intercept_channel
import command_line_pb2
class FixedActiveSpanSource(ActiveSpanSource):
def __init__(self):
self.active_span = None
def get_active_span(self):
return self.active_span
def echo(tracer, active_span_source, stub):
with tracer.start_span('command_line_client_span') as span:
active_span_source.active_span = span
response = stub.Echo(
command_line_pb2.CommandRequest(text='Hello, hello'))
print(response.text)
def run():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='integration-client')
tracer = config.initialize_tracer()
active_span_source = FixedActiveSpanSource()
tracer_interceptor = open_tracing_client_interceptor(
tracer,
active_span_source=active_span_source,
log_payloads=args.log_payloads)
channel = grpc.insecure_channel('localhost:50051')
channel = intercept_channel(channel, tracer_interceptor)
stub = command_line_pb2.CommandLineStub(channel)
echo(tracer, active_span_source, stub)
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
run()

View File

@@ -0,0 +1,69 @@
from __future__ import print_function
import time
import argparse
import grpc
from concurrent import futures
from jaeger_client import Config
from grpc_opentracing import open_tracing_server_interceptor
from grpc_opentracing.grpcext import intercept_server
import command_line_pb2
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
class CommandLine(command_line_pb2.CommandLineServicer):
def __init__(self, tracer):
self._tracer = tracer
def Echo(self, request, context):
with self._tracer.start_span(
'command_line_server_span',
child_of=context.get_active_span().context):
return command_line_pb2.CommandResponse(text=request.text)
def serve():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='integration-server')
tracer = config.initialize_tracer()
tracer_interceptor = open_tracing_server_interceptor(
tracer, log_payloads=args.log_payloads)
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
server = intercept_server(server, tracer_interceptor)
command_line_pb2.add_CommandLineServicer_to_server(
CommandLine(tracer), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
serve()

View File

@@ -0,0 +1,4 @@
from grpc_tools import protoc
protoc.main(('', '-I../protos', '--python_out=.', '--grpc_python_out=.',
'../protos/command_line.proto'))

View File

@@ -0,0 +1,15 @@
syntax = "proto3";
package command_line;
service CommandLine {
rpc Echo(CommandRequest) returns (CommandResponse) {}
}
message CommandRequest {
string text = 1;
}
message CommandResponse {
string text = 1;
}

View File

@@ -0,0 +1,37 @@
syntax = "proto3";
package store;
service Store {
rpc AddItem(AddItemRequest) returns (Empty) {}
rpc AddItems(stream AddItemRequest) returns (Empty) {}
rpc RemoveItem(RemoveItemRequest) returns (RemoveItemResponse) {}
rpc RemoveItems(stream RemoveItemRequest) returns (RemoveItemResponse) {}
rpc ListInventory(Empty) returns (stream QuantityResponse) {}
rpc QueryQuantity(QueryItemRequest) returns (QuantityResponse) {}
rpc QueryQuantities(stream QueryItemRequest)
returns (stream QuantityResponse) {}
}
message Empty {}
message AddItemRequest {
string name = 1;
}
message RemoveItemRequest {
string name = 1;
}
message RemoveItemResponse {
bool was_successful = 1;
}
message QueryItemRequest {
string name = 1;
}
message QuantityResponse {
string name = 1;
int32 count = 2;
}

View File

@@ -0,0 +1,2 @@
grpcio-opentracing>=1.0
jaeger-client>=3.4.0

View File

@@ -0,0 +1,8 @@
An example that demonstrates how the OpenTracing extensions work with
asynchronous and streaming RPC calls.
## Usage
```
python store_server.py &
python store_client.py
```

View File

@@ -0,0 +1,4 @@
from grpc_tools import protoc
protoc.main(('', '-I../protos', '--python_out=.', '--grpc_python_out=.',
'../protos/store.proto'))

View File

@@ -0,0 +1,211 @@
# A OpenTraced client for a Python service that implements the store interface.
from __future__ import print_function
import time
import argparse
from builtins import input, range
import grpc
from jaeger_client import Config
from grpc_opentracing import open_tracing_client_interceptor, \
SpanDecorator
from grpc_opentracing.grpcext import intercept_channel
import store_pb2
class CommandExecuter(object):
def __init__(self, stub):
self._stub = stub
def _execute_rpc(self, method, via, timeout, request_or_iterator):
if via == 'future':
result = getattr(self._stub, method).future(request_or_iterator,
timeout)
return result.result()
elif via == 'with_call':
return getattr(self._stub, method).with_call(request_or_iterator,
timeout)[0]
else:
return getattr(self._stub, method)(request_or_iterator, timeout)
def do_stock_item(self, via, timeout, arguments):
if len(arguments) != 1:
print('must input a single item')
return
request = store_pb2.AddItemRequest(name=arguments[0])
self._execute_rpc('AddItem', via, timeout, request)
def do_stock_items(self, via, timeout, arguments):
if not arguments:
print('must input at least one item')
return
requests = [store_pb2.AddItemRequest(name=name) for name in arguments]
self._execute_rpc('AddItems', via, timeout, iter(requests))
def do_sell_item(self, via, timeout, arguments):
if len(arguments) != 1:
print('must input a single item')
return
request = store_pb2.RemoveItemRequest(name=arguments[0])
response = self._execute_rpc('RemoveItem', via, timeout, request)
if not response.was_successful:
print('unable to sell')
def do_sell_items(self, via, timeout, arguments):
if not arguments:
print('must input at least one item')
return
requests = [
store_pb2.RemoveItemRequest(name=name) for name in arguments
]
response = self._execute_rpc('RemoveItems', via, timeout,
iter(requests))
if not response.was_successful:
print('unable to sell')
def do_inventory(self, via, timeout, arguments):
if arguments:
print('inventory does not take any arguments')
return
if via != 'functor':
print('inventory can only be called via functor')
return
request = store_pb2.Empty()
result = self._execute_rpc('ListInventory', via, timeout, request)
for query in result:
print(query.name, '\t', query.count)
def do_query_item(self, via, timeout, arguments):
if len(arguments) != 1:
print('must input a single item')
return
request = store_pb2.QueryItemRequest(name=arguments[0])
query = self._execute_rpc('QueryQuantity', via, timeout, request)
print(query.name, '\t', query.count)
def do_query_items(self, via, timeout, arguments):
if not arguments:
print('must input at least one item')
return
if via != 'functor':
print('query_items can only be called via functor')
return
requests = [store_pb2.QueryItemRequest(name=name) for name in arguments]
result = self._execute_rpc('QueryQuantities', via, timeout,
iter(requests))
for query in result:
print(query.name, '\t', query.count)
def execute_command(command_executer, command, arguments):
via = 'functor'
timeout = None
for argument_index in range(0, len(arguments), 2):
argument = arguments[argument_index]
if argument == '--via' and argument_index + 1 < len(arguments):
if via not in ('functor', 'with_call', 'future'):
print('invalid --via option')
return
via = arguments[argument_index + 1]
elif argument == '--timeout' and argument_index + 1 < len(arguments):
timeout = float(arguments[argument_index + 1])
else:
arguments = arguments[argument_index:]
break
try:
getattr(command_executer, 'do_' + command)(via, timeout, arguments)
except AttributeError:
print('unknown command: \"%s\"' % command)
INSTRUCTIONS = \
"""Enter commands to interact with the store service:
stock_item Stock a single item.
stock_items Stock one or more items.
sell_item Sell a single item.
sell_items Sell one or more items.
inventory List the store's inventory.
query_item Query the inventory for a single item.
query_items Query the inventory for one or more items.
You can also optionally provide a --via argument to instruct the RPC to be
initiated via either the functor, with_call, or future method; or provide a
--timeout argument to set a deadline for the RPC to be completed.
Example:
> stock_item apple
> stock_items --via future apple milk
> inventory
apple 2
milk 1
"""
def read_and_execute(command_executer):
print(INSTRUCTIONS)
while True:
try:
line = input('> ')
components = line.split()
if not components:
continue
command = components[0]
arguments = components[1:]
execute_command(command_executer, command, arguments)
except EOFError:
break
class StoreSpanDecorator(SpanDecorator):
def __call__(self, span, rpc_info):
span.set_tag('grpc.method', rpc_info.full_method)
span.set_tag('grpc.headers', str(rpc_info.metadata))
span.set_tag('grpc.deadline', str(rpc_info.timeout))
def run():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
parser.add_argument(
'--include_grpc_tags',
action='store_true',
help='set gRPC-specific tags on spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='store-client')
tracer = config.initialize_tracer()
span_decorator = None
if args.include_grpc_tags:
span_decorator = StoreSpanDecorator()
tracer_interceptor = open_tracing_client_interceptor(
tracer, log_payloads=args.log_payloads, span_decorator=span_decorator)
channel = grpc.insecure_channel('localhost:50051')
channel = intercept_channel(channel, tracer_interceptor)
stub = store_pb2.StoreStub(channel)
read_and_execute(CommandExecuter(stub))
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
run()

View File

@@ -0,0 +1,523 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: store.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='store.proto',
package='store',
syntax='proto3',
serialized_pb=_b('\n\x0bstore.proto\x12\x05store\"\x07\n\x05\x45mpty\"\x1e\n\x0e\x41\x64\x64ItemRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"!\n\x11RemoveItemRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\",\n\x12RemoveItemResponse\x12\x16\n\x0ewas_successful\x18\x01 \x01(\x08\" \n\x10QueryItemRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"/\n\x10QuantityResponse\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05\x63ount\x18\x02 \x01(\x05\x32\xc7\x03\n\x05Store\x12\x30\n\x07\x41\x64\x64Item\x12\x15.store.AddItemRequest\x1a\x0c.store.Empty\"\x00\x12\x33\n\x08\x41\x64\x64Items\x12\x15.store.AddItemRequest\x1a\x0c.store.Empty\"\x00(\x01\x12\x43\n\nRemoveItem\x12\x18.store.RemoveItemRequest\x1a\x19.store.RemoveItemResponse\"\x00\x12\x46\n\x0bRemoveItems\x12\x18.store.RemoveItemRequest\x1a\x19.store.RemoveItemResponse\"\x00(\x01\x12:\n\rListInventory\x12\x0c.store.Empty\x1a\x17.store.QuantityResponse\"\x00\x30\x01\x12\x43\n\rQueryQuantity\x12\x17.store.QueryItemRequest\x1a\x17.store.QuantityResponse\"\x00\x12I\n\x0fQueryQuantities\x12\x17.store.QueryItemRequest\x1a\x17.store.QuantityResponse\"\x00(\x01\x30\x01\x62\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
_EMPTY = _descriptor.Descriptor(
name='Empty',
full_name='store.Empty',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=22,
serialized_end=29,
)
_ADDITEMREQUEST = _descriptor.Descriptor(
name='AddItemRequest',
full_name='store.AddItemRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='store.AddItemRequest.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=31,
serialized_end=61,
)
_REMOVEITEMREQUEST = _descriptor.Descriptor(
name='RemoveItemRequest',
full_name='store.RemoveItemRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='store.RemoveItemRequest.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=63,
serialized_end=96,
)
_REMOVEITEMRESPONSE = _descriptor.Descriptor(
name='RemoveItemResponse',
full_name='store.RemoveItemResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='was_successful', full_name='store.RemoveItemResponse.was_successful', index=0,
number=1, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=98,
serialized_end=142,
)
_QUERYITEMREQUEST = _descriptor.Descriptor(
name='QueryItemRequest',
full_name='store.QueryItemRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='store.QueryItemRequest.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=144,
serialized_end=176,
)
_QUANTITYRESPONSE = _descriptor.Descriptor(
name='QuantityResponse',
full_name='store.QuantityResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='store.QuantityResponse.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='count', full_name='store.QuantityResponse.count', index=1,
number=2, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=178,
serialized_end=225,
)
DESCRIPTOR.message_types_by_name['Empty'] = _EMPTY
DESCRIPTOR.message_types_by_name['AddItemRequest'] = _ADDITEMREQUEST
DESCRIPTOR.message_types_by_name['RemoveItemRequest'] = _REMOVEITEMREQUEST
DESCRIPTOR.message_types_by_name['RemoveItemResponse'] = _REMOVEITEMRESPONSE
DESCRIPTOR.message_types_by_name['QueryItemRequest'] = _QUERYITEMREQUEST
DESCRIPTOR.message_types_by_name['QuantityResponse'] = _QUANTITYRESPONSE
Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), dict(
DESCRIPTOR = _EMPTY,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.Empty)
))
_sym_db.RegisterMessage(Empty)
AddItemRequest = _reflection.GeneratedProtocolMessageType('AddItemRequest', (_message.Message,), dict(
DESCRIPTOR = _ADDITEMREQUEST,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.AddItemRequest)
))
_sym_db.RegisterMessage(AddItemRequest)
RemoveItemRequest = _reflection.GeneratedProtocolMessageType('RemoveItemRequest', (_message.Message,), dict(
DESCRIPTOR = _REMOVEITEMREQUEST,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.RemoveItemRequest)
))
_sym_db.RegisterMessage(RemoveItemRequest)
RemoveItemResponse = _reflection.GeneratedProtocolMessageType('RemoveItemResponse', (_message.Message,), dict(
DESCRIPTOR = _REMOVEITEMRESPONSE,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.RemoveItemResponse)
))
_sym_db.RegisterMessage(RemoveItemResponse)
QueryItemRequest = _reflection.GeneratedProtocolMessageType('QueryItemRequest', (_message.Message,), dict(
DESCRIPTOR = _QUERYITEMREQUEST,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.QueryItemRequest)
))
_sym_db.RegisterMessage(QueryItemRequest)
QuantityResponse = _reflection.GeneratedProtocolMessageType('QuantityResponse', (_message.Message,), dict(
DESCRIPTOR = _QUANTITYRESPONSE,
__module__ = 'store_pb2'
# @@protoc_insertion_point(class_scope:store.QuantityResponse)
))
_sym_db.RegisterMessage(QuantityResponse)
try:
# THESE ELEMENTS WILL BE DEPRECATED.
# Please use the generated *_pb2_grpc.py files instead.
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
from grpc.beta import implementations as beta_implementations
from grpc.beta import interfaces as beta_interfaces
class StoreStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.AddItem = channel.unary_unary(
'/store.Store/AddItem',
request_serializer=AddItemRequest.SerializeToString,
response_deserializer=Empty.FromString,
)
self.AddItems = channel.stream_unary(
'/store.Store/AddItems',
request_serializer=AddItemRequest.SerializeToString,
response_deserializer=Empty.FromString,
)
self.RemoveItem = channel.unary_unary(
'/store.Store/RemoveItem',
request_serializer=RemoveItemRequest.SerializeToString,
response_deserializer=RemoveItemResponse.FromString,
)
self.RemoveItems = channel.stream_unary(
'/store.Store/RemoveItems',
request_serializer=RemoveItemRequest.SerializeToString,
response_deserializer=RemoveItemResponse.FromString,
)
self.ListInventory = channel.unary_stream(
'/store.Store/ListInventory',
request_serializer=Empty.SerializeToString,
response_deserializer=QuantityResponse.FromString,
)
self.QueryQuantity = channel.unary_unary(
'/store.Store/QueryQuantity',
request_serializer=QueryItemRequest.SerializeToString,
response_deserializer=QuantityResponse.FromString,
)
self.QueryQuantities = channel.stream_stream(
'/store.Store/QueryQuantities',
request_serializer=QueryItemRequest.SerializeToString,
response_deserializer=QuantityResponse.FromString,
)
class StoreServicer(object):
def AddItem(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def AddItems(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RemoveItem(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RemoveItems(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ListInventory(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def QueryQuantity(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def QueryQuantities(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_StoreServicer_to_server(servicer, server):
rpc_method_handlers = {
'AddItem': grpc.unary_unary_rpc_method_handler(
servicer.AddItem,
request_deserializer=AddItemRequest.FromString,
response_serializer=Empty.SerializeToString,
),
'AddItems': grpc.stream_unary_rpc_method_handler(
servicer.AddItems,
request_deserializer=AddItemRequest.FromString,
response_serializer=Empty.SerializeToString,
),
'RemoveItem': grpc.unary_unary_rpc_method_handler(
servicer.RemoveItem,
request_deserializer=RemoveItemRequest.FromString,
response_serializer=RemoveItemResponse.SerializeToString,
),
'RemoveItems': grpc.stream_unary_rpc_method_handler(
servicer.RemoveItems,
request_deserializer=RemoveItemRequest.FromString,
response_serializer=RemoveItemResponse.SerializeToString,
),
'ListInventory': grpc.unary_stream_rpc_method_handler(
servicer.ListInventory,
request_deserializer=Empty.FromString,
response_serializer=QuantityResponse.SerializeToString,
),
'QueryQuantity': grpc.unary_unary_rpc_method_handler(
servicer.QueryQuantity,
request_deserializer=QueryItemRequest.FromString,
response_serializer=QuantityResponse.SerializeToString,
),
'QueryQuantities': grpc.stream_stream_rpc_method_handler(
servicer.QueryQuantities,
request_deserializer=QueryItemRequest.FromString,
response_serializer=QuantityResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'store.Store', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class BetaStoreServicer(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def AddItem(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def AddItems(self, request_iterator, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def RemoveItem(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def RemoveItems(self, request_iterator, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def ListInventory(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def QueryQuantity(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def QueryQuantities(self, request_iterator, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaStoreStub(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def AddItem(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
AddItem.future = None
def AddItems(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
AddItems.future = None
def RemoveItem(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
RemoveItem.future = None
def RemoveItems(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
RemoveItems.future = None
def ListInventory(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
def QueryQuantity(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
QueryQuantity.future = None
def QueryQuantities(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
def beta_create_Store_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_deserializers = {
('store.Store', 'AddItem'): AddItemRequest.FromString,
('store.Store', 'AddItems'): AddItemRequest.FromString,
('store.Store', 'ListInventory'): Empty.FromString,
('store.Store', 'QueryQuantities'): QueryItemRequest.FromString,
('store.Store', 'QueryQuantity'): QueryItemRequest.FromString,
('store.Store', 'RemoveItem'): RemoveItemRequest.FromString,
('store.Store', 'RemoveItems'): RemoveItemRequest.FromString,
}
response_serializers = {
('store.Store', 'AddItem'): Empty.SerializeToString,
('store.Store', 'AddItems'): Empty.SerializeToString,
('store.Store', 'ListInventory'): QuantityResponse.SerializeToString,
('store.Store', 'QueryQuantities'): QuantityResponse.SerializeToString,
('store.Store', 'QueryQuantity'): QuantityResponse.SerializeToString,
('store.Store', 'RemoveItem'): RemoveItemResponse.SerializeToString,
('store.Store', 'RemoveItems'): RemoveItemResponse.SerializeToString,
}
method_implementations = {
('store.Store', 'AddItem'): face_utilities.unary_unary_inline(servicer.AddItem),
('store.Store', 'AddItems'): face_utilities.stream_unary_inline(servicer.AddItems),
('store.Store', 'ListInventory'): face_utilities.unary_stream_inline(servicer.ListInventory),
('store.Store', 'QueryQuantities'): face_utilities.stream_stream_inline(servicer.QueryQuantities),
('store.Store', 'QueryQuantity'): face_utilities.unary_unary_inline(servicer.QueryQuantity),
('store.Store', 'RemoveItem'): face_utilities.unary_unary_inline(servicer.RemoveItem),
('store.Store', 'RemoveItems'): face_utilities.stream_unary_inline(servicer.RemoveItems),
}
server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
return beta_implementations.server(method_implementations, options=server_options)
def beta_create_Store_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_serializers = {
('store.Store', 'AddItem'): AddItemRequest.SerializeToString,
('store.Store', 'AddItems'): AddItemRequest.SerializeToString,
('store.Store', 'ListInventory'): Empty.SerializeToString,
('store.Store', 'QueryQuantities'): QueryItemRequest.SerializeToString,
('store.Store', 'QueryQuantity'): QueryItemRequest.SerializeToString,
('store.Store', 'RemoveItem'): RemoveItemRequest.SerializeToString,
('store.Store', 'RemoveItems'): RemoveItemRequest.SerializeToString,
}
response_deserializers = {
('store.Store', 'AddItem'): Empty.FromString,
('store.Store', 'AddItems'): Empty.FromString,
('store.Store', 'ListInventory'): QuantityResponse.FromString,
('store.Store', 'QueryQuantities'): QuantityResponse.FromString,
('store.Store', 'QueryQuantity'): QuantityResponse.FromString,
('store.Store', 'RemoveItem'): RemoveItemResponse.FromString,
('store.Store', 'RemoveItems'): RemoveItemResponse.FromString,
}
cardinalities = {
'AddItem': cardinality.Cardinality.UNARY_UNARY,
'AddItems': cardinality.Cardinality.STREAM_UNARY,
'ListInventory': cardinality.Cardinality.UNARY_STREAM,
'QueryQuantities': cardinality.Cardinality.STREAM_STREAM,
'QueryQuantity': cardinality.Cardinality.UNARY_UNARY,
'RemoveItem': cardinality.Cardinality.UNARY_UNARY,
'RemoveItems': cardinality.Cardinality.STREAM_UNARY,
}
stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
return beta_implementations.dynamic_stub(channel, 'store.Store', cardinalities, options=stub_options)
except ImportError:
pass
# @@protoc_insertion_point(module_scope)

View File

@@ -0,0 +1,132 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
import store_pb2 as store__pb2
class StoreStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.AddItem = channel.unary_unary(
'/store.Store/AddItem',
request_serializer=store__pb2.AddItemRequest.SerializeToString,
response_deserializer=store__pb2.Empty.FromString,
)
self.AddItems = channel.stream_unary(
'/store.Store/AddItems',
request_serializer=store__pb2.AddItemRequest.SerializeToString,
response_deserializer=store__pb2.Empty.FromString,
)
self.RemoveItem = channel.unary_unary(
'/store.Store/RemoveItem',
request_serializer=store__pb2.RemoveItemRequest.SerializeToString,
response_deserializer=store__pb2.RemoveItemResponse.FromString,
)
self.RemoveItems = channel.stream_unary(
'/store.Store/RemoveItems',
request_serializer=store__pb2.RemoveItemRequest.SerializeToString,
response_deserializer=store__pb2.RemoveItemResponse.FromString,
)
self.ListInventory = channel.unary_stream(
'/store.Store/ListInventory',
request_serializer=store__pb2.Empty.SerializeToString,
response_deserializer=store__pb2.QuantityResponse.FromString,
)
self.QueryQuantity = channel.unary_unary(
'/store.Store/QueryQuantity',
request_serializer=store__pb2.QueryItemRequest.SerializeToString,
response_deserializer=store__pb2.QuantityResponse.FromString,
)
self.QueryQuantities = channel.stream_stream(
'/store.Store/QueryQuantities',
request_serializer=store__pb2.QueryItemRequest.SerializeToString,
response_deserializer=store__pb2.QuantityResponse.FromString,
)
class StoreServicer(object):
def AddItem(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def AddItems(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RemoveItem(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RemoveItems(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ListInventory(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def QueryQuantity(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def QueryQuantities(self, request_iterator, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_StoreServicer_to_server(servicer, server):
rpc_method_handlers = {
'AddItem': grpc.unary_unary_rpc_method_handler(
servicer.AddItem,
request_deserializer=store__pb2.AddItemRequest.FromString,
response_serializer=store__pb2.Empty.SerializeToString,
),
'AddItems': grpc.stream_unary_rpc_method_handler(
servicer.AddItems,
request_deserializer=store__pb2.AddItemRequest.FromString,
response_serializer=store__pb2.Empty.SerializeToString,
),
'RemoveItem': grpc.unary_unary_rpc_method_handler(
servicer.RemoveItem,
request_deserializer=store__pb2.RemoveItemRequest.FromString,
response_serializer=store__pb2.RemoveItemResponse.SerializeToString,
),
'RemoveItems': grpc.stream_unary_rpc_method_handler(
servicer.RemoveItems,
request_deserializer=store__pb2.RemoveItemRequest.FromString,
response_serializer=store__pb2.RemoveItemResponse.SerializeToString,
),
'ListInventory': grpc.unary_stream_rpc_method_handler(
servicer.ListInventory,
request_deserializer=store__pb2.Empty.FromString,
response_serializer=store__pb2.QuantityResponse.SerializeToString,
),
'QueryQuantity': grpc.unary_unary_rpc_method_handler(
servicer.QueryQuantity,
request_deserializer=store__pb2.QueryItemRequest.FromString,
response_serializer=store__pb2.QuantityResponse.SerializeToString,
),
'QueryQuantities': grpc.stream_stream_rpc_method_handler(
servicer.QueryQuantities,
request_deserializer=store__pb2.QueryItemRequest.FromString,
response_serializer=store__pb2.QuantityResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'store.Store', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))

View File

@@ -0,0 +1,122 @@
# A OpenTraced server for a Python service that implements the store interface.
from __future__ import print_function
import time
import argparse
from collections import defaultdict
from six import iteritems
import grpc
from concurrent import futures
from jaeger_client import Config
from grpc_opentracing import open_tracing_server_interceptor, \
SpanDecorator
from grpc_opentracing.grpcext import intercept_server
import store_pb2
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
class Store(store_pb2.StoreServicer):
def __init__(self):
self._inventory = defaultdict(int)
def AddItem(self, request, context):
self._inventory[request.name] += 1
return store_pb2.Empty()
def AddItems(self, request_iter, context):
for request in request_iter:
self._inventory[request.name] += 1
return store_pb2.Empty()
def RemoveItem(self, request, context):
new_quantity = self._inventory[request.name] - 1
if new_quantity < 0:
return store_pb2.RemoveItemResponse(was_successful=False)
self._inventory[request.name] = new_quantity
return store_pb2.RemoveItemResponse(was_successful=True)
def RemoveItems(self, request_iter, context):
response = store_pb2.RemoveItemResponse(was_successful=True)
for request in request_iter:
response = self.RemoveItem(request, context)
if not response.was_successful:
break
return response
def ListInventory(self, request, context):
for name, count in iteritems(self._inventory):
if not count:
continue
else:
yield store_pb2.QuantityResponse(name=name, count=count)
def QueryQuantity(self, request, context):
count = self._inventory[request.name]
return store_pb2.QuantityResponse(name=request.name, count=count)
def QueryQuantities(self, request_iter, context):
for request in request_iter:
count = self._inventory[request.name]
yield store_pb2.QuantityResponse(name=request.name, count=count)
class StoreSpanDecorator(SpanDecorator):
def __call__(self, span, rpc_info):
span.set_tag('grpc.method', rpc_info.full_method)
span.set_tag('grpc.headers', str(rpc_info.metadata))
span.set_tag('grpc.deadline', str(rpc_info.timeout))
def serve():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
parser.add_argument(
'--include_grpc_tags',
action='store_true',
help='set gRPC-specific tags on spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='store-server')
tracer = config.initialize_tracer()
span_decorator = None
if args.include_grpc_tags:
span_decorator = StoreSpanDecorator()
tracer_interceptor = open_tracing_server_interceptor(
tracer, log_payloads=args.log_payloads, span_decorator=span_decorator)
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
server = intercept_server(server, tracer_interceptor)
store_pb2.add_StoreServicer_to_server(Store(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
serve()

View File

@@ -0,0 +1,7 @@
A simple example showing how to set gRPC up to use OpenTracing.
## Usage
```
python trivial_server.py &
python trivial_client.py
```

View File

@@ -0,0 +1,213 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: command_line.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='command_line.proto',
package='command_line',
syntax='proto3',
serialized_pb=_b('\n\x12\x63ommand_line.proto\x12\x0c\x63ommand_line\"\x1e\n\x0e\x43ommandRequest\x12\x0c\n\x04text\x18\x01 \x01(\t\"\x1f\n\x0f\x43ommandResponse\x12\x0c\n\x04text\x18\x01 \x01(\t2T\n\x0b\x43ommandLine\x12\x45\n\x04\x45\x63ho\x12\x1c.command_line.CommandRequest\x1a\x1d.command_line.CommandResponse\"\x00\x62\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
_COMMANDREQUEST = _descriptor.Descriptor(
name='CommandRequest',
full_name='command_line.CommandRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='text', full_name='command_line.CommandRequest.text', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=36,
serialized_end=66,
)
_COMMANDRESPONSE = _descriptor.Descriptor(
name='CommandResponse',
full_name='command_line.CommandResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='text', full_name='command_line.CommandResponse.text', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=68,
serialized_end=99,
)
DESCRIPTOR.message_types_by_name['CommandRequest'] = _COMMANDREQUEST
DESCRIPTOR.message_types_by_name['CommandResponse'] = _COMMANDRESPONSE
CommandRequest = _reflection.GeneratedProtocolMessageType('CommandRequest', (_message.Message,), dict(
DESCRIPTOR = _COMMANDREQUEST,
__module__ = 'command_line_pb2'
# @@protoc_insertion_point(class_scope:command_line.CommandRequest)
))
_sym_db.RegisterMessage(CommandRequest)
CommandResponse = _reflection.GeneratedProtocolMessageType('CommandResponse', (_message.Message,), dict(
DESCRIPTOR = _COMMANDRESPONSE,
__module__ = 'command_line_pb2'
# @@protoc_insertion_point(class_scope:command_line.CommandResponse)
))
_sym_db.RegisterMessage(CommandResponse)
try:
# THESE ELEMENTS WILL BE DEPRECATED.
# Please use the generated *_pb2_grpc.py files instead.
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
from grpc.beta import implementations as beta_implementations
from grpc.beta import interfaces as beta_interfaces
class CommandLineStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Echo = channel.unary_unary(
'/command_line.CommandLine/Echo',
request_serializer=CommandRequest.SerializeToString,
response_deserializer=CommandResponse.FromString,
)
class CommandLineServicer(object):
def Echo(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_CommandLineServicer_to_server(servicer, server):
rpc_method_handlers = {
'Echo': grpc.unary_unary_rpc_method_handler(
servicer.Echo,
request_deserializer=CommandRequest.FromString,
response_serializer=CommandResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'command_line.CommandLine', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class BetaCommandLineServicer(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def Echo(self, request, context):
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaCommandLineStub(object):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This class was generated
only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
def Echo(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
raise NotImplementedError()
Echo.future = None
def beta_create_CommandLine_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_deserializers = {
('command_line.CommandLine', 'Echo'): CommandRequest.FromString,
}
response_serializers = {
('command_line.CommandLine', 'Echo'): CommandResponse.SerializeToString,
}
method_implementations = {
('command_line.CommandLine', 'Echo'): face_utilities.unary_unary_inline(servicer.Echo),
}
server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
return beta_implementations.server(method_implementations, options=server_options)
def beta_create_CommandLine_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
"""The Beta API is deprecated for 0.15.0 and later.
It is recommended to use the GA API (classes and functions in this
file not marked beta) for all further purposes. This function was
generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
request_serializers = {
('command_line.CommandLine', 'Echo'): CommandRequest.SerializeToString,
}
response_deserializers = {
('command_line.CommandLine', 'Echo'): CommandResponse.FromString,
}
cardinalities = {
'Echo': cardinality.Cardinality.UNARY_UNARY,
}
stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
return beta_implementations.dynamic_stub(channel, 'command_line.CommandLine', cardinalities, options=stub_options)
except ImportError:
pass
# @@protoc_insertion_point(module_scope)

View File

@@ -0,0 +1,42 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
import command_line_pb2 as command__line__pb2
class CommandLineStub(object):
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Echo = channel.unary_unary(
'/command_line.CommandLine/Echo',
request_serializer=command__line__pb2.CommandRequest.SerializeToString,
response_deserializer=command__line__pb2.CommandResponse.FromString,
)
class CommandLineServicer(object):
def Echo(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_CommandLineServicer_to_server(servicer, server):
rpc_method_handlers = {
'Echo': grpc.unary_unary_rpc_method_handler(
servicer.Echo,
request_deserializer=command__line__pb2.CommandRequest.FromString,
response_serializer=command__line__pb2.CommandResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'command_line.CommandLine', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))

View File

@@ -0,0 +1,4 @@
from grpc_tools import protoc
protoc.main(('', '-I../protos', '--python_out=.', '--grpc_python_out=.',
'../protos/command_line.proto'))

View File

@@ -0,0 +1,47 @@
from __future__ import print_function
import time
import argparse
import grpc
from jaeger_client import Config
from grpc_opentracing import open_tracing_client_interceptor
from grpc_opentracing.grpcext import intercept_channel
import command_line_pb2
def run():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='trivial-client')
tracer = config.initialize_tracer()
tracer_interceptor = open_tracing_client_interceptor(
tracer, log_payloads=args.log_payloads)
channel = grpc.insecure_channel('localhost:50051')
channel = intercept_channel(channel, tracer_interceptor)
stub = command_line_pb2.CommandLineStub(channel)
response = stub.Echo(command_line_pb2.CommandRequest(text='Hello, hello'))
print(response.text)
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
run()

View File

@@ -0,0 +1,62 @@
from __future__ import print_function
import time
import argparse
import grpc
from concurrent import futures
from jaeger_client import Config
from grpc_opentracing import open_tracing_server_interceptor
from grpc_opentracing.grpcext import intercept_server
import command_line_pb2
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
class CommandLine(command_line_pb2.CommandLineServicer):
def Echo(self, request, context):
return command_line_pb2.CommandResponse(text=request.text)
def serve():
parser = argparse.ArgumentParser()
parser.add_argument(
'--log_payloads',
action='store_true',
help='log request/response objects to open-tracing spans')
args = parser.parse_args()
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
},
service_name='trivial-server')
tracer = config.initialize_tracer()
tracer_interceptor = open_tracing_server_interceptor(
tracer, log_payloads=args.log_payloads)
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
server = intercept_server(server, tracer_interceptor)
command_line_pb2.add_CommandLineServicer_to_server(CommandLine(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
time.sleep(2)
tracer.close()
time.sleep(2)
if __name__ == '__main__':
serve()

View File

@@ -0,0 +1,96 @@
import abc
import enum
import six
import grpc
class ActiveSpanSource(six.with_metaclass(abc.ABCMeta)):
"""Provides a way to access an the active span."""
@abc.abstractmethod
def get_active_span(self):
"""Identifies the active span.
Returns:
An object that implements the opentracing.Span interface.
"""
raise NotImplementedError()
class RpcInfo(six.with_metaclass(abc.ABCMeta)):
"""Provides information for an RPC call.
Attributes:
full_method: A string of the full RPC method, i.e., /package.service/method.
metadata: The initial :term:`metadata`.
timeout: The length of time in seconds to wait for the computation to
terminate or be cancelled.
request: The RPC request or None for request-streaming RPCs.
response: The RPC response or None for response-streaming or erroring RPCs.
error: The RPC error or None for successful RPCs.
"""
class SpanDecorator(six.with_metaclass(abc.ABCMeta)):
"""Provides a mechanism to add arbitrary tags/logs/etc to the
opentracing.Span associated with client and/or server RPCs."""
@abc.abstractmethod
def __call__(self, span, rpc_info):
"""Customizes an RPC span.
Args:
span: The client-side or server-side opentracing.Span for the RPC.
rpc_info: An RpcInfo describing the RPC.
"""
raise NotImplementedError()
def open_tracing_client_interceptor(tracer,
active_span_source=None,
log_payloads=False,
span_decorator=None):
"""Creates an invocation-side interceptor that can be use with gRPC to add
OpenTracing information.
Args:
tracer: An object implmenting the opentracing.Tracer interface.
active_span_source: An optional ActiveSpanSource to customize how the
active span is determined.
log_payloads: Indicates whether requests should be logged.
span_decorator: An optional SpanDecorator.
Returns:
An invocation-side interceptor object.
"""
from grpc_opentracing import _client
return _client.OpenTracingClientInterceptor(tracer, active_span_source,
log_payloads, span_decorator)
def open_tracing_server_interceptor(tracer,
log_payloads=False,
span_decorator=None):
"""Creates a service-side interceptor that can be use with gRPC to add
OpenTracing information.
Args:
tracer: An object implmenting the opentracing.Tracer interface.
log_payloads: Indicates whether requests should be logged.
span_decorator: An optional SpanDecorator.
Returns:
A service-side interceptor object.
"""
from grpc_opentracing import _server
return _server.OpenTracingServerInterceptor(tracer, log_payloads,
span_decorator)
################################### __all__ #################################
__all__ = ('ActiveSpanSource', 'RpcInfo', 'SpanDecorator',
'open_tracing_client_interceptor',
'open_tracing_server_interceptor',)

View File

@@ -0,0 +1,209 @@
"""Implementation of the invocation-side open-tracing interceptor."""
import sys
import logging
import time
from six import iteritems
import grpc
from grpc_opentracing import grpcext
from grpc_opentracing._utilities import get_method_type, get_deadline_millis,\
log_or_wrap_request_or_iterator, RpcInfo
import opentracing
from opentracing.ext import tags as ot_tags
class _GuardedSpan(object):
def __init__(self, span):
self.span = span
self._engaged = True
def __enter__(self):
self.span.__enter__()
return self
def __exit__(self, *args, **kwargs):
if self._engaged:
return self.span.__exit__(*args, **kwargs)
else:
return False
def release(self):
self._engaged = False
return self.span
def _inject_span_context(tracer, span, metadata):
headers = {}
try:
tracer.inject(span.context, opentracing.Format.HTTP_HEADERS, headers)
except (opentracing.UnsupportedFormatException,
opentracing.InvalidCarrierException,
opentracing.SpanContextCorruptedException) as e:
logging.exception('tracer.inject() failed')
span.log_kv({'event': 'error', 'error.object': e})
return metadata
metadata = () if metadata is None else tuple(metadata)
return metadata + tuple(iteritems(headers))
def _make_future_done_callback(span, rpc_info, log_payloads, span_decorator):
def callback(response_future):
with span:
code = response_future.code()
if code != grpc.StatusCode.OK:
span.set_tag('error', True)
error_log = {'event': 'error', 'error.kind': str(code)}
details = response_future.details()
if details is not None:
error_log['message'] = details
span.log_kv(error_log)
rpc_info.error = code
if span_decorator is not None:
span_decorator(span, rpc_info)
return
response = response_future.result()
rpc_info.response = response
if log_payloads:
span.log_kv({'response': response})
if span_decorator is not None:
span_decorator(span, rpc_info)
return callback
class OpenTracingClientInterceptor(grpcext.UnaryClientInterceptor,
grpcext.StreamClientInterceptor):
def __init__(self, tracer, active_span_source, log_payloads,
span_decorator):
self._tracer = tracer
self._active_span_source = active_span_source
self._log_payloads = log_payloads
self._span_decorator = span_decorator
def _start_span(self, method):
active_span_context = None
if self._active_span_source is not None:
active_span = self._active_span_source.get_active_span()
if active_span is not None:
active_span_context = active_span.context
tags = {
ot_tags.COMPONENT: 'grpc',
ot_tags.SPAN_KIND: ot_tags.SPAN_KIND_RPC_CLIENT
}
return self._tracer.start_span(
operation_name=method, child_of=active_span_context, tags=tags)
def _trace_result(self, guarded_span, rpc_info, result):
# If the RPC is called asynchronously, release the guard and add a callback
# so that the span can be finished once the future is done.
if isinstance(result, grpc.Future):
result.add_done_callback(
_make_future_done_callback(guarded_span.release(
), rpc_info, self._log_payloads, self._span_decorator))
return result
response = result
# Handle the case when the RPC is initiated via the with_call
# method and the result is a tuple with the first element as the
# response.
# http://www.grpc.io/grpc/python/grpc.html#grpc.UnaryUnaryMultiCallable.with_call
if isinstance(result, tuple):
response = result[0]
rpc_info.response = response
if self._log_payloads:
guarded_span.span.log_kv({'response': response})
if self._span_decorator is not None:
self._span_decorator(guarded_span.span, rpc_info)
return result
def _start_guarded_span(self, *args, **kwargs):
return _GuardedSpan(self._start_span(*args, **kwargs))
def intercept_unary(self, request, metadata, client_info, invoker):
with self._start_guarded_span(client_info.full_method) as guarded_span:
metadata = _inject_span_context(self._tracer, guarded_span.span,
metadata)
rpc_info = RpcInfo(
full_method=client_info.full_method,
metadata=metadata,
timeout=client_info.timeout,
request=request)
if self._log_payloads:
guarded_span.span.log_kv({'request': request})
try:
result = invoker(request, metadata)
except:
e = sys.exc_info()[0]
guarded_span.span.set_tag('error', True)
guarded_span.span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(guarded_span.span, rpc_info)
raise
return self._trace_result(guarded_span, rpc_info, result)
# For RPCs that stream responses, the result can be a generator. To record
# the span across the generated responses and detect any errors, we wrap the
# result in a new generator that yields the response values.
def _intercept_server_stream(self, request_or_iterator, metadata,
client_info, invoker):
with self._start_span(client_info.full_method) as span:
metadata = _inject_span_context(self._tracer, span, metadata)
rpc_info = RpcInfo(
full_method=client_info.full_method,
metadata=metadata,
timeout=client_info.timeout)
if client_info.is_client_stream:
rpc_info.request = request_or_iterator
if self._log_payloads:
request_or_iterator = log_or_wrap_request_or_iterator(
span, client_info.is_client_stream, request_or_iterator)
try:
result = invoker(request_or_iterator, metadata)
for response in result:
if self._log_payloads:
span.log_kv({'response': response})
yield response
except:
e = sys.exc_info()[0]
span.set_tag('error', True)
span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
raise
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
def intercept_stream(self, request_or_iterator, metadata, client_info,
invoker):
if client_info.is_server_stream:
return self._intercept_server_stream(request_or_iterator, metadata,
client_info, invoker)
with self._start_guarded_span(client_info.full_method) as guarded_span:
metadata = _inject_span_context(self._tracer, guarded_span.span,
metadata)
rpc_info = RpcInfo(
full_method=client_info.full_method,
metadata=metadata,
timeout=client_info.timeout,
request=request_or_iterator)
if self._log_payloads:
request_or_iterator = log_or_wrap_request_or_iterator(
guarded_span.span, client_info.is_client_stream,
request_or_iterator)
try:
result = invoker(request_or_iterator, metadata)
except:
e = sys.exc_info()[0]
guarded_span.span.set_tag('error', True)
guarded_span.span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(guarded_span.span, rpc_info)
raise
return self._trace_result(guarded_span, rpc_info, result)

View File

@@ -0,0 +1,227 @@
"""Implementation of the service-side open-tracing interceptor."""
import sys
import logging
import re
import grpc
from grpc_opentracing import grpcext, ActiveSpanSource
from grpc_opentracing._utilities import get_method_type, get_deadline_millis,\
log_or_wrap_request_or_iterator, RpcInfo
import opentracing
from opentracing.ext import tags as ot_tags
class _OpenTracingServicerContext(grpc.ServicerContext, ActiveSpanSource):
def __init__(self, servicer_context, active_span):
self._servicer_context = servicer_context
self._active_span = active_span
self.code = grpc.StatusCode.OK
self.details = None
def is_active(self, *args, **kwargs):
return self._servicer_context.is_active(*args, **kwargs)
def time_remaining(self, *args, **kwargs):
return self._servicer_context.time_remaining(*args, **kwargs)
def cancel(self, *args, **kwargs):
return self._servicer_context.cancel(*args, **kwargs)
def add_callback(self, *args, **kwargs):
return self._servicer_context.add_callback(*args, **kwargs)
def invocation_metadata(self, *args, **kwargs):
return self._servicer_context.invocation_metadata(*args, **kwargs)
def peer(self, *args, **kwargs):
return self._servicer_context.peer(*args, **kwargs)
def peer_identities(self, *args, **kwargs):
return self._servicer_context.peer_identities(*args, **kwargs)
def peer_identity_key(self, *args, **kwargs):
return self._servicer_context.peer_identity_key(*args, **kwargs)
def auth_context(self, *args, **kwargs):
return self._servicer_context.auth_context(*args, **kwargs)
def send_initial_metadata(self, *args, **kwargs):
return self._servicer_context.send_initial_metadata(*args, **kwargs)
def set_trailing_metadata(self, *args, **kwargs):
return self._servicer_context.set_trailing_metadata(*args, **kwargs)
def set_code(self, code):
self.code = code
return self._servicer_context.set_code(code)
def set_details(self, details):
self.details = details
return self._servicer_context.set_details(details)
def get_active_span(self):
return self._active_span
def _add_peer_tags(peer_str, tags):
ipv4_re = r"ipv4:(?P<address>.+):(?P<port>\d+)"
match = re.match(ipv4_re, peer_str)
if match:
tags[ot_tags.PEER_HOST_IPV4] = match.group('address')
tags[ot_tags.PEER_PORT] = match.group('port')
return
ipv6_re = r"ipv6:\[(?P<address>.+)\]:(?P<port>\d+)"
match = re.match(ipv6_re, peer_str)
if match:
tags[ot_tags.PEER_HOST_IPV6] = match.group('address')
tags[ot_tags.PEER_PORT] = match.group('port')
return
logging.warning('Unrecognized peer: \"%s\"', peer_str)
# On the service-side, errors can be signaled either by exceptions or by calling
# `set_code` on the `servicer_context`. This function checks for the latter and
# updates the span accordingly.
def _check_error_code(span, servicer_context, rpc_info):
if servicer_context.code != grpc.StatusCode.OK:
span.set_tag('error', True)
error_log = {'event': 'error', 'error.kind': str(servicer_context.code)}
if servicer_context.details is not None:
error_log['message'] = servicer_context.details
span.log_kv(error_log)
rpc_info.error = servicer_context.code
class OpenTracingServerInterceptor(grpcext.UnaryServerInterceptor,
grpcext.StreamServerInterceptor):
def __init__(self, tracer, log_payloads, span_decorator):
self._tracer = tracer
self._log_payloads = log_payloads
self._span_decorator = span_decorator
def _start_span(self, servicer_context, method):
span_context = None
error = None
metadata = servicer_context.invocation_metadata()
try:
if metadata:
span_context = self._tracer.extract(
opentracing.Format.HTTP_HEADERS, dict(metadata))
except (opentracing.UnsupportedFormatException,
opentracing.InvalidCarrierException,
opentracing.SpanContextCorruptedException) as e:
logging.exception('tracer.extract() failed')
error = e
tags = {
ot_tags.COMPONENT: 'grpc',
ot_tags.SPAN_KIND: ot_tags.SPAN_KIND_RPC_SERVER
}
_add_peer_tags(servicer_context.peer(), tags)
span = self._tracer.start_span(
operation_name=method, child_of=span_context, tags=tags)
if error is not None:
span.log_kv({'event': 'error', 'error.object': error})
return span
def intercept_unary(self, request, servicer_context, server_info, handler):
with self._start_span(servicer_context,
server_info.full_method) as span:
rpc_info = RpcInfo(
full_method=server_info.full_method,
metadata=servicer_context.invocation_metadata(),
timeout=servicer_context.time_remaining(),
request=request)
if self._log_payloads:
span.log_kv({'request': request})
servicer_context = _OpenTracingServicerContext(
servicer_context, span)
try:
response = handler(request, servicer_context)
except:
e = sys.exc_info()[0]
span.set_tag('error', True)
span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
raise
if self._log_payloads:
span.log_kv({'response': response})
_check_error_code(span, servicer_context, rpc_info)
rpc_info.response = response
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
return response
# For RPCs that stream responses, the result can be a generator. To record
# the span across the generated responses and detect any errors, we wrap the
# result in a new generator that yields the response values.
def _intercept_server_stream(self, request_or_iterator, servicer_context,
server_info, handler):
with self._start_span(servicer_context,
server_info.full_method) as span:
rpc_info = RpcInfo(
full_method=server_info.full_method,
metadata=servicer_context.invocation_metadata(),
timeout=servicer_context.time_remaining())
if not server_info.is_client_stream:
rpc_info.request = request_or_iterator
if self._log_payloads:
request_or_iterator = log_or_wrap_request_or_iterator(
span, server_info.is_client_stream, request_or_iterator)
servicer_context = _OpenTracingServicerContext(
servicer_context, span)
try:
result = handler(request_or_iterator, servicer_context)
for response in result:
if self._log_payloads:
span.log_kv({'response': response})
yield response
except:
e = sys.exc_info()[0]
span.set_tag('error', True)
span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
raise
_check_error_code(span, servicer_context, rpc_info)
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
def intercept_stream(self, request_or_iterator, servicer_context,
server_info, handler):
if server_info.is_server_stream:
return self._intercept_server_stream(
request_or_iterator, servicer_context, server_info, handler)
with self._start_span(servicer_context,
server_info.full_method) as span:
rpc_info = RpcInfo(
full_method=server_info.full_method,
metadata=servicer_context.invocation_metadata(),
timeout=servicer_context.time_remaining())
if self._log_payloads:
request_or_iterator = log_or_wrap_request_or_iterator(
span, server_info.is_client_stream, request_or_iterator)
servicer_context = _OpenTracingServicerContext(
servicer_context, span)
try:
response = handler(request_or_iterator, servicer_context)
except:
e = sys.exc_info()[0]
span.set_tag('error', True)
span.log_kv({'event': 'error', 'error.object': e})
rpc_info.error = e
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
raise
if self._log_payloads:
span.log_kv({'response': response})
_check_error_code(span, servicer_context, rpc_info)
rpc_info.response = response
if self._span_decorator is not None:
self._span_decorator(span, rpc_info)
return response

View File

@@ -0,0 +1,65 @@
"""Internal utilities for gRPC OpenTracing."""
import collections
import grpc_opentracing
class RpcInfo(grpc_opentracing.RpcInfo):
def __init__(self,
full_method=None,
metadata=None,
timeout=None,
request=None,
response=None,
error=None):
self.full_method = full_method
self.metadata = metadata
self.timeout = timeout
self.request = request
self.response = response
self.error = error
def get_method_type(is_client_stream, is_server_stream):
if is_client_stream and is_server_stream:
return 'BIDI_STREAMING'
elif is_client_stream:
return 'CLIENT_STREAMING'
elif is_server_stream:
return 'SERVER_STREAMING'
else:
return 'UNARY'
def get_deadline_millis(timeout):
if timeout is None:
return 'None'
return str(int(round(timeout * 1000)))
class _RequestLoggingIterator(object):
def __init__(self, request_iterator, span):
self._request_iterator = request_iterator
self._span = span
def __iter__(self):
return self
def next(self):
request = next(self._request_iterator)
self._span.log_kv({'request': request})
return request
def __next__(self):
return self.next()
def log_or_wrap_request_or_iterator(span, is_client_stream,
request_or_iterator):
if is_client_stream:
return _RequestLoggingIterator(request_or_iterator, span)
else:
span.log_kv({'request': request_or_iterator})
return request_or_iterator

View File

@@ -0,0 +1,185 @@
import abc
import six
class UnaryClientInfo(six.with_metaclass(abc.ABCMeta)):
"""Consists of various information about a unary RPC on the invocation-side.
Attributes:
full_method: A string of the full RPC method, i.e., /package.service/method.
timeout: The length of time in seconds to wait for the computation to
terminate or be cancelled, or None if this method should block until
the computation is terminated or is cancelled no matter how long that
takes.
"""
class StreamClientInfo(six.with_metaclass(abc.ABCMeta)):
"""Consists of various information about a stream RPC on the invocation-side.
Attributes:
full_method: A string of the full RPC method, i.e., /package.service/method.
is_client_stream: Indicates whether the RPC is client-streaming.
is_server_stream: Indicates whether the RPC is server-streaming.
timeout: The length of time in seconds to wait for the computation to
terminate or be cancelled, or None if this method should block until
the computation is terminated or is cancelled no matter how long that
takes.
"""
class UnaryClientInterceptor(six.with_metaclass(abc.ABCMeta)):
"""Affords intercepting unary-unary RPCs on the invocation-side."""
@abc.abstractmethod
def intercept_unary(self, request, metadata, client_info, invoker):
"""Intercepts unary-unary RPCs on the invocation-side.
Args:
request: The request value for the RPC.
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
client_info: A UnaryClientInfo containing various information about
the RPC.
invoker: The handler to complete the RPC on the client. It is the
interceptor's responsibility to call it.
Returns:
The result from calling invoker(request, metadata).
"""
raise NotImplementedError()
class StreamClientInterceptor(six.with_metaclass(abc.ABCMeta)):
"""Affords intercepting stream RPCs on the invocation-side."""
@abc.abstractmethod
def intercept_stream(self, request_or_iterator, metadata, client_info,
invoker):
"""Intercepts stream RPCs on the invocation-side.
Args:
request_or_iterator: The request value for the RPC if
`client_info.is_client_stream` is `false`; otherwise, an iterator of
request values.
metadata: Optional :term:`metadata` to be transmitted to the service-side
of the RPC.
client_info: A StreamClientInfo containing various information about
the RPC.
invoker: The handler to complete the RPC on the client. It is the
interceptor's responsibility to call it.
Returns:
The result from calling invoker(metadata).
"""
raise NotImplementedError()
def intercept_channel(channel, *interceptors):
"""Creates an intercepted channel.
Args:
channel: A Channel.
interceptors: Zero or more UnaryClientInterceptors or
StreamClientInterceptors
Returns:
A Channel.
Raises:
TypeError: If an interceptor derives from neither UnaryClientInterceptor
nor StreamClientInterceptor.
"""
from grpc_opentracing.grpcext import _interceptor
return _interceptor.intercept_channel(channel, *interceptors)
class UnaryServerInfo(six.with_metaclass(abc.ABCMeta)):
"""Consists of various information about a unary RPC on the service-side.
Attributes:
full_method: A string of the full RPC method, i.e., /package.service/method.
"""
class StreamServerInfo(six.with_metaclass(abc.ABCMeta)):
"""Consists of various information about a stream RPC on the service-side.
Attributes:
full_method: A string of the full RPC method, i.e., /package.service/method.
is_client_stream: Indicates whether the RPC is client-streaming.
is_server_stream: Indicates whether the RPC is server-streaming.
"""
class UnaryServerInterceptor(six.with_metaclass(abc.ABCMeta)):
"""Affords intercepting unary-unary RPCs on the service-side."""
@abc.abstractmethod
def intercept_unary(self, request, servicer_context, server_info, handler):
"""Intercepts unary-unary RPCs on the service-side.
Args:
request: The request value for the RPC.
servicer_context: A ServicerContext.
server_info: A UnaryServerInfo containing various information about
the RPC.
handler: The handler to complete the RPC on the server. It is the
interceptor's responsibility to call it.
Returns:
The result from calling handler(request, servicer_context).
"""
raise NotImplementedError()
class StreamServerInterceptor(six.with_metaclass(abc.ABCMeta)):
"""Affords intercepting stream RPCs on the service-side."""
@abc.abstractmethod
def intercept_stream(self, request_or_iterator, servicer_context,
server_info, handler):
"""Intercepts stream RPCs on the service-side.
Args:
request_or_iterator: The request value for the RPC if
`server_info.is_client_stream` is `False`; otherwise, an iterator of
request values.
servicer_context: A ServicerContext.
server_info: A StreamServerInfo containing various information about
the RPC.
handler: The handler to complete the RPC on the server. It is the
interceptor's responsibility to call it.
Returns:
The result from calling handler(servicer_context).
"""
raise NotImplementedError()
def intercept_server(server, *interceptors):
"""Creates an intercepted server.
Args:
server: A Server.
interceptors: Zero or more UnaryServerInterceptors or
StreamServerInterceptors
Returns:
A Server.
Raises:
TypeError: If an interceptor derives from neither UnaryServerInterceptor
nor StreamServerInterceptor.
"""
from grpc_opentracing.grpcext import _interceptor
return _interceptor.intercept_server(server, *interceptors)
################################### __all__ #################################
__all__ = ('UnaryClientInterceptor', 'StreamClientInfo',
'StreamClientInterceptor', 'UnaryServerInfo', 'StreamServerInfo',
'UnaryServerInterceptor', 'StreamServerInterceptor',
'intercept_channel', 'intercept_server',)

View File

@@ -0,0 +1,373 @@
"""Implementation of gRPC Python interceptors."""
import collections
import grpc
from grpc_opentracing import grpcext
class _UnaryClientInfo(
collections.namedtuple('_UnaryClientInfo',
('full_method', 'timeout',))):
pass
class _StreamClientInfo(
collections.namedtuple('_StreamClientInfo', (
'full_method', 'is_client_stream', 'is_server_stream', 'timeout'))):
pass
class _InterceptorUnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
def __init__(self, method, base_callable, interceptor):
self._method = method
self._base_callable = base_callable
self._interceptor = interceptor
def __call__(self, request, timeout=None, metadata=None, credentials=None):
def invoker(request, metadata):
return self._base_callable(request, timeout, metadata, credentials)
client_info = _UnaryClientInfo(self._method, timeout)
return self._interceptor.intercept_unary(request, metadata, client_info,
invoker)
def with_call(self, request, timeout=None, metadata=None, credentials=None):
def invoker(request, metadata):
return self._base_callable.with_call(request, timeout, metadata,
credentials)
client_info = _UnaryClientInfo(self._method, timeout)
return self._interceptor.intercept_unary(request, metadata, client_info,
invoker)
def future(self, request, timeout=None, metadata=None, credentials=None):
def invoker(request, metadata):
return self._base_callable.future(request, timeout, metadata,
credentials)
client_info = _UnaryClientInfo(self._method, timeout)
return self._interceptor.intercept_unary(request, metadata, client_info,
invoker)
class _InterceptorUnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
def __init__(self, method, base_callable, interceptor):
self._method = method
self._base_callable = base_callable
self._interceptor = interceptor
def __call__(self, request, timeout=None, metadata=None, credentials=None):
def invoker(request, metadata):
return self._base_callable(request, timeout, metadata, credentials)
client_info = _StreamClientInfo(self._method, False, True, timeout)
return self._interceptor.intercept_stream(request, metadata,
client_info, invoker)
class _InterceptorStreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
def __init__(self, method, base_callable, interceptor):
self._method = method
self._base_callable = base_callable
self._interceptor = interceptor
def __call__(self,
request_iterator,
timeout=None,
metadata=None,
credentials=None):
def invoker(request_iterator, metadata):
return self._base_callable(request_iterator, timeout, metadata,
credentials)
client_info = _StreamClientInfo(self._method, True, False, timeout)
return self._interceptor.intercept_stream(request_iterator, metadata,
client_info, invoker)
def with_call(self,
request_iterator,
timeout=None,
metadata=None,
credentials=None):
def invoker(request_iterator, metadata):
return self._base_callable.with_call(request_iterator, timeout,
metadata, credentials)
client_info = _StreamClientInfo(self._method, True, False, timeout)
return self._interceptor.intercept_stream(request_iterator, metadata,
client_info, invoker)
def future(self,
request_iterator,
timeout=None,
metadata=None,
credentials=None):
def invoker(request_iterator, metadata):
return self._base_callable.future(request_iterator, timeout,
metadata, credentials)
client_info = _StreamClientInfo(self._method, True, False, timeout)
return self._interceptor.intercept_stream(request_iterator, metadata,
client_info, invoker)
class _InterceptorStreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
def __init__(self, method, base_callable, interceptor):
self._method = method
self._base_callable = base_callable
self._interceptor = interceptor
def __call__(self,
request_iterator,
timeout=None,
metadata=None,
credentials=None):
def invoker(request_iterator, metadata):
return self._base_callable(request_iterator, timeout, metadata,
credentials)
client_info = _StreamClientInfo(self._method, True, True, timeout)
return self._interceptor.intercept_stream(request_iterator, metadata,
client_info, invoker)
class _InterceptorChannel(grpc.Channel):
def __init__(self, channel, interceptor):
self._channel = channel
self._interceptor = interceptor
def subscribe(self, *args, **kwargs):
self._channel.subscribe(*args, **kwargs)
def unsubscribe(self, *args, **kwargs):
self._channel.unsubscribe(*args, **kwargs)
def unary_unary(self,
method,
request_serializer=None,
response_deserializer=None):
base_callable = self._channel.unary_unary(method, request_serializer,
response_deserializer)
if isinstance(self._interceptor, grpcext.UnaryClientInterceptor):
return _InterceptorUnaryUnaryMultiCallable(method, base_callable,
self._interceptor)
else:
return base_callable
def unary_stream(self,
method,
request_serializer=None,
response_deserializer=None):
base_callable = self._channel.unary_stream(method, request_serializer,
response_deserializer)
if isinstance(self._interceptor, grpcext.StreamClientInterceptor):
return _InterceptorUnaryStreamMultiCallable(method, base_callable,
self._interceptor)
else:
return base_callable
def stream_unary(self,
method,
request_serializer=None,
response_deserializer=None):
base_callable = self._channel.stream_unary(method, request_serializer,
response_deserializer)
if isinstance(self._interceptor, grpcext.StreamClientInterceptor):
return _InterceptorStreamUnaryMultiCallable(method, base_callable,
self._interceptor)
else:
return base_callable
def stream_stream(self,
method,
request_serializer=None,
response_deserializer=None):
base_callable = self._channel.stream_stream(method, request_serializer,
response_deserializer)
if isinstance(self._interceptor, grpcext.StreamClientInterceptor):
return _InterceptorStreamStreamMultiCallable(method, base_callable,
self._interceptor)
else:
return base_callable
def intercept_channel(channel, *interceptors):
result = channel
for interceptor in interceptors:
if not isinstance(interceptor, grpcext.UnaryClientInterceptor) and \
not isinstance(interceptor, grpcext.StreamClientInterceptor):
raise TypeError('interceptor must be either a '
'grpcext.UnaryClientInterceptor or a '
'grpcext.StreamClientInterceptor')
result = _InterceptorChannel(result, interceptor)
return result
class _UnaryServerInfo(
collections.namedtuple('_UnaryServerInfo', ('full_method',))):
pass
class _StreamServerInfo(
collections.namedtuple('_StreamServerInfo', (
'full_method', 'is_client_stream', 'is_server_stream'))):
pass
class _InterceptorRpcMethodHandler(grpc.RpcMethodHandler):
def __init__(self, rpc_method_handler, method, interceptor):
self._rpc_method_handler = rpc_method_handler
self._method = method
self._interceptor = interceptor
@property
def request_streaming(self):
return self._rpc_method_handler.request_streaming
@property
def response_streaming(self):
return self._rpc_method_handler.response_streaming
@property
def request_deserializer(self):
return self._rpc_method_handler.request_deserializer
@property
def response_serializer(self):
return self._rpc_method_handler.response_serializer
@property
def unary_unary(self):
if not isinstance(self._interceptor, grpcext.UnaryServerInterceptor):
return self._rpc_method_handler.unary_unary
def adaptation(request, servicer_context):
def handler(request, servicer_context):
return self._rpc_method_handler.unary_unary(request,
servicer_context)
return self._interceptor.intercept_unary(
request, servicer_context,
_UnaryServerInfo(self._method), handler)
return adaptation
@property
def unary_stream(self):
if not isinstance(self._interceptor, grpcext.StreamServerInterceptor):
return self._rpc_method_handler.unary_stream
def adaptation(request, servicer_context):
def handler(request, servicer_context):
return self._rpc_method_handler.unary_stream(request,
servicer_context)
return self._interceptor.intercept_stream(
request, servicer_context,
_StreamServerInfo(self._method, False, True), handler)
return adaptation
@property
def stream_unary(self):
if not isinstance(self._interceptor, grpcext.StreamServerInterceptor):
return self._rpc_method_handler.stream_unary
def adaptation(request_iterator, servicer_context):
def handler(request_iterator, servicer_context):
return self._rpc_method_handler.stream_unary(request_iterator,
servicer_context)
return self._interceptor.intercept_stream(
request_iterator, servicer_context,
_StreamServerInfo(self._method, True, False), handler)
return adaptation
@property
def stream_stream(self):
if not isinstance(self._interceptor, grpcext.StreamServerInterceptor):
return self._rpc_method_handler.stream_stream
def adaptation(request_iterator, servicer_context):
def handler(request_iterator, servicer_context):
return self._rpc_method_handler.stream_stream(request_iterator,
servicer_context)
return self._interceptor.intercept_stream(
request_iterator, servicer_context,
_StreamServerInfo(self._method, True, True), handler)
return adaptation
class _InterceptorGenericRpcHandler(grpc.GenericRpcHandler):
def __init__(self, generic_rpc_handler, interceptor):
self.generic_rpc_handler = generic_rpc_handler
self._interceptor = interceptor
def service(self, handler_call_details):
result = self.generic_rpc_handler.service(handler_call_details)
if result:
result = _InterceptorRpcMethodHandler(
result, handler_call_details.method, self._interceptor)
return result
class _InterceptorServer(grpc.Server):
def __init__(self, server, interceptor):
self._server = server
self._interceptor = interceptor
def add_generic_rpc_handlers(self, generic_rpc_handlers):
generic_rpc_handlers = [
_InterceptorGenericRpcHandler(generic_rpc_handler,
self._interceptor)
for generic_rpc_handler in generic_rpc_handlers
]
return self._server.add_generic_rpc_handlers(generic_rpc_handlers)
def add_insecure_port(self, *args, **kwargs):
return self._server.add_insecure_port(*args, **kwargs)
def add_secure_port(self, *args, **kwargs):
return self._server.add_secure_port(*args, **kwargs)
def start(self, *args, **kwargs):
return self._server.start(*args, **kwargs)
def stop(self, *args, **kwargs):
return self._server.stop(*args, **kwargs)
def intercept_server(server, *interceptors):
result = server
for interceptor in interceptors:
if not isinstance(interceptor, grpcext.UnaryServerInterceptor) and \
not isinstance(interceptor, grpcext.StreamServerInterceptor):
raise TypeError('interceptor must be either a '
'grpcext.UnaryServerInterceptor or a '
'grpcext.StreamServerInterceptor')
result = _InterceptorServer(result, interceptor)
return result

View File

@@ -0,0 +1,5 @@
# add dependencies in setup.py
-r requirements.txt
-e .[tests]

View File

@@ -0,0 +1,3 @@
# add dependencies in setup.py
-e .

View File

@@ -0,0 +1,2 @@
[aliases]
test=pytest

View File

@@ -0,0 +1,36 @@
import os
import logging
import sys
import tempfile
from setuptools import setup, find_packages
def readme():
"""Use `pandoc` to convert `README.md` into a `README.rst` file."""
if os.path.isfile('README.md') and any('dist' in x for x in sys.argv[1:]):
if os.system('pandoc -s README.md -o %s/README.rst' %
tempfile.mkdtemp()) != 0:
logging.warning('Unable to generate README.rst')
if os.path.isfile('README.rst'):
with open('README.rst') as fd:
return fd.read()
return ''
setup(
name='grpcio-opentracing',
version='1.0',
description='Python OpenTracing Extensions for gRPC',
long_description=readme(),
author='LightStep',
license='',
install_requires=['opentracing>=1.2.2', 'grpcio>=1.1.3', 'six>=1.10'],
setup_requires=['pytest-runner'],
tests_require=['pytest', 'future'],
keywords=['opentracing'],
classifiers=[
'Operating System :: OS Independent',
'Programming Language :: Python :: 2.7',
],
packages=find_packages(exclude=['docs*', 'tests*', 'examples*']))

View File

@@ -0,0 +1,192 @@
"""Creates a simple service on top of gRPC for testing."""
from builtins import input, range
import grpc
from grpc.framework.foundation import logging_pool
from grpc_opentracing import grpcext
_SERIALIZE_REQUEST = lambda bytestring: bytestring
_DESERIALIZE_REQUEST = lambda bytestring: bytestring
_SERIALIZE_RESPONSE = lambda bytestring: bytestring
_DESERIALIZE_RESPONSE = lambda bytestring: bytestring
_UNARY_UNARY = '/test/UnaryUnary'
_UNARY_STREAM = '/test/UnaryStream'
_STREAM_UNARY = '/test/StreamUnary'
_STREAM_STREAM = '/test/StreamStream'
_STREAM_LENGTH = 5
class _MethodHandler(grpc.RpcMethodHandler):
def __init__(self,
request_streaming=False,
response_streaming=False,
unary_unary=None,
unary_stream=None,
stream_unary=None,
stream_stream=None):
self.request_streaming = request_streaming
self.response_streaming = response_streaming
self.request_deserializer = _DESERIALIZE_REQUEST
self.response_serializer = _SERIALIZE_RESPONSE
self.unary_unary = unary_unary
self.unary_stream = unary_stream
self.stream_unary = stream_unary
self.stream_stream = stream_stream
class Handler(object):
def __init__(self):
self.invocation_metadata = None
self.trailing_metadata = None
def handle_unary_unary(self, request, servicer_context):
if servicer_context is not None:
self.invocation_metadata = servicer_context.invocation_metadata()
if self.trailing_metadata is not None:
servicer_context.set_trailing_metadata(self.trailing_metadata)
return request
def handle_unary_stream(self, request, servicer_context):
if servicer_context is not None:
self.invocation_metadata = servicer_context.invocation_metadata()
if self.trailing_metadata is not None:
servicer_context.set_trailing_metadata(self.trailing_metadata)
for _ in range(_STREAM_LENGTH):
yield request
def handle_stream_unary(self, request_iterator, servicer_context):
if servicer_context is not None:
self.invocation_metadata = servicer_context.invocation_metadata()
if self.trailing_metadata is not None:
servicer_context.set_trailing_metadata(self.trailing_metadata)
return b''.join(list(request_iterator))
def handle_stream_stream(self, request_iterator, servicer_context):
if servicer_context is not None:
self.invocation_metadata = servicer_context.invocation_metadata()
if self.trailing_metadata is not None:
servicer_context.set_trailing_metadata(self.trailing_metadata)
for request in request_iterator:
yield request
def _set_error_code(servicer_context):
servicer_context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
servicer_context.set_details('ErroringHandler')
class ErroringHandler(Handler):
def __init__(self):
super(ErroringHandler, self).__init__()
def handle_unary_unary(self, request, servicer_context):
_set_error_code(servicer_context)
return super(ErroringHandler, self).handle_unary_unary(request,
servicer_context)
def handle_unary_stream(self, request, servicer_context):
_set_error_code(servicer_context)
return super(ErroringHandler, self).handle_unary_stream(
request, servicer_context)
def handle_stream_unary(self, request_iterator, servicer_context):
_set_error_code(servicer_context)
return super(ErroringHandler, self).handle_stream_unary(
request_iterator, servicer_context)
def handle_stream_stream(self, request_iterator, servicer_context):
_set_error_code(servicer_context)
return super(ErroringHandler, self).handle_stream_stream(
request_iterator, servicer_context)
class ExceptionErroringHandler(Handler):
def __init__(self):
super(ExceptionErroringHandler, self).__init__()
def handle_unary_unary(self, request, servicer_context):
raise IndexError()
def handle_unary_stream(self, request, servicer_context):
raise IndexError()
def handle_stream_unary(self, request_iterator, servicer_context):
raise IndexError()
def handle_stream_stream(self, request_iterator, servicer_context):
raise IndexError()
class _GenericHandler(grpc.GenericRpcHandler):
def __init__(self, handler):
self._handler = handler
def service(self, handler_call_details):
method = handler_call_details.method
if method == _UNARY_UNARY:
return _MethodHandler(unary_unary=self._handler.handle_unary_unary)
elif method == _UNARY_STREAM:
return _MethodHandler(
response_streaming=True,
unary_stream=self._handler.handle_unary_stream)
elif method == _STREAM_UNARY:
return _MethodHandler(
request_streaming=True,
stream_unary=self._handler.handle_stream_unary)
elif method == _STREAM_STREAM:
return _MethodHandler(
request_streaming=True,
response_streaming=True,
stream_stream=self._handler.handle_stream_stream)
else:
return None
class Service(object):
def __init__(self,
client_interceptors,
server_interceptors,
handler=Handler()):
self.handler = handler
self._server_pool = logging_pool.pool(2)
self._server = grpcext.intercept_server(
grpc.server(self._server_pool), *server_interceptors)
port = self._server.add_insecure_port('[::]:0')
self._server.add_generic_rpc_handlers((_GenericHandler(self.handler),))
self._server.start()
self.channel = grpcext.intercept_channel(
grpc.insecure_channel('localhost:%d' % port), *client_interceptors)
@property
def unary_unary_multi_callable(self):
return self.channel.unary_unary(_UNARY_UNARY)
@property
def unary_stream_multi_callable(self):
return self.channel.unary_stream(
_UNARY_STREAM,
request_serializer=_SERIALIZE_REQUEST,
response_deserializer=_DESERIALIZE_RESPONSE)
@property
def stream_unary_multi_callable(self):
return self.channel.stream_unary(
_STREAM_UNARY,
request_serializer=_SERIALIZE_REQUEST,
response_deserializer=_DESERIALIZE_RESPONSE)
@property
def stream_stream_multi_callable(self):
return self.channel.stream_stream(
_STREAM_STREAM,
request_serializer=_SERIALIZE_REQUEST,
response_deserializer=_DESERIALIZE_RESPONSE)

View File

@@ -0,0 +1,83 @@
from collections import defaultdict
import enum
import opentracing
@enum.unique
class SpanRelationship(enum.Enum):
NONE = 0
FOLLOWS_FROM = 1
CHILD_OF = 2
class _SpanContext(opentracing.SpanContext):
def __init__(self, identity):
self.identity = identity
class _Span(opentracing.Span):
def __init__(self, tracer, identity, tags=None):
super(_Span, self).__init__(tracer, _SpanContext(identity))
self._identity = identity
if tags is None:
tags = {}
self._tags = tags
def set_tag(self, key, value):
self._tags[key] = value
def get_tag(self, key):
return self._tags.get(key, None)
class Tracer(opentracing.Tracer):
def __init__(self):
super(Tracer, self).__init__()
self._counter = 0
self._spans = {}
self._relationships = defaultdict(lambda: None)
def start_span(self,
operation_name=None,
child_of=None,
references=None,
tags=None,
start_time=None):
identity = self._counter
self._counter += 1
if child_of is not None:
self._relationships[(child_of.identity,
identity)] = opentracing.ReferenceType.CHILD_OF
if references is not None:
assert child_of is None and len(
references) == 1, 'Only a single reference is supported'
reference_type, span_context = references[0]
self._relationships[(span_context.identity,
identity)] = reference_type
span = _Span(self, identity, tags)
self._spans[identity] = span
return span
def inject(self, span_context, format, carrier):
if format != opentracing.Format.HTTP_HEADERS and isinstance(carrier,
dict):
raise opentracing.UnsupportedFormatException(format)
carrier['span-identity'] = str(span_context.identity)
def extract(self, format, carrier):
if format != opentracing.Format.HTTP_HEADERS and isinstance(carrier,
dict):
raise opentracing.UnsupportedFormatException(format)
if 'span-identity' not in carrier:
raise opentracing.SpanContextCorruptedException
return _SpanContext(int(carrier['span-identity']))
def get_relationship(self, identity1, identity2):
return self._relationships[(identity1, identity2)]
def get_span(self, identity):
return self._spans.get(identity, None)

View File

@@ -0,0 +1,168 @@
import unittest
import grpc
from grpc_opentracing import grpcext
from _service import Service
class ClientInterceptor(grpcext.UnaryClientInterceptor,
grpcext.StreamClientInterceptor):
def __init__(self):
self.intercepted = False
def intercept_unary(self, request, metadata, client_info, invoker):
self.intercepted = True
return invoker(request, metadata)
def intercept_stream(self, request_or_iterator, metadata, client_info,
invoker):
self.intercepted = True
return invoker(request_or_iterator, metadata)
class ServerInterceptor(grpcext.UnaryServerInterceptor,
grpcext.StreamServerInterceptor):
def __init__(self):
self.intercepted = False
def intercept_unary(self, request, servicer_context, server_info, handler):
self.intercepted = True
return handler(request, servicer_context)
def intercept_stream(self, request_or_iterator, servicer_context,
server_info, handler):
self.intercepted = True
return handler(request_or_iterator, servicer_context)
class InterceptorTest(unittest.TestCase):
"""Test that RPC calls are intercepted."""
def setUp(self):
self._client_interceptor = ClientInterceptor()
self._server_interceptor = ServerInterceptor()
self._service = Service([self._client_interceptor],
[self._server_interceptor])
def testUnaryUnaryInterception(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable(request)
self.assertEqual(response, expected_response)
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testUnaryUnaryInterceptionWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response, call = multi_callable.with_call(request)
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testUnaryUnaryInterceptionFuture(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable.future(request).result()
self.assertEqual(response, expected_response)
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testUnaryStreamInterception(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_stream(request,
None)
response = multi_callable(request)
self.assertEqual(list(response), list(expected_response))
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testStreamUnaryInterception(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(response, expected_response)
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testStreamUnaryInterceptionWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response, call = multi_callable.with_call(iter(requests))
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testStreamUnaryInterceptionFuture(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response = multi_callable.future(iter(requests)).result()
self.assertEqual(response, expected_response)
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
def testStreamStreamInterception(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_stream(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(list(response), list(expected_response))
self.assertTrue(self._client_interceptor.intercepted)
self.assertTrue(self._server_interceptor.intercepted)
class MultiInterceptorTest(unittest.TestCase):
"""Test that you can chain multiple interceptors together."""
def setUp(self):
self._client_interceptors = [ClientInterceptor(), ClientInterceptor()]
self._server_interceptors = [ServerInterceptor(), ServerInterceptor()]
self._service = Service(self._client_interceptors,
self._server_interceptors)
def _clear(self):
for client_interceptor in self._client_interceptors:
client_interceptor.intercepted = False
for server_interceptor in self._server_interceptors:
server_interceptor.intercepted = False
def testUnaryUnaryMultiInterception(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable(request)
self.assertEqual(response, expected_response)
for client_interceptor in self._client_interceptors:
self.assertTrue(client_interceptor.intercepted)
for server_interceptor in self._server_interceptors:
self.assertTrue(server_interceptor.intercepted)

View File

@@ -0,0 +1,611 @@
import unittest
import grpc
from _service import Service, ErroringHandler, ExceptionErroringHandler
from _tracer import Tracer, SpanRelationship
from grpc_opentracing import open_tracing_client_interceptor, open_tracing_server_interceptor
import opentracing
class OpenTracingTest(unittest.TestCase):
"""Test that tracers create the correct spans when RPC calls are invoked."""
def setUp(self):
self._tracer = Tracer()
self._service = Service([open_tracing_client_interceptor(self._tracer)],
[open_tracing_server_interceptor(self._tracer)])
def testUnaryUnaryOpenTracing(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable(request)
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testUnaryUnaryOpenTracingFuture(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
future = multi_callable.future(request)
response = future.result()
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testUnaryUnaryOpenTracingWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response, call = multi_callable.with_call(request)
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testUnaryStreamOpenTracing(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_stream(request,
None)
response = multi_callable(request)
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testStreamUnaryOpenTracing(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testStreamUnaryOpenTracingWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response, call = multi_callable.with_call(iter(requests))
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testStreamUnaryOpenTracingFuture(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
result = multi_callable.future(iter(requests))
response = result.result()
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
def testStreamStreamOpenTracing(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_stream(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertEqual(span1.get_tag('span.kind'), 'server')
self.assertEqual(
self._tracer.get_relationship(0, 1),
opentracing.ReferenceType.CHILD_OF)
class OpenTracingInteroperabilityClientTest(unittest.TestCase):
"""Test that a traced client can interoperate with a non-trace server."""
def setUp(self):
self._tracer = Tracer()
self._service = Service([open_tracing_client_interceptor(self._tracer)],
[])
def testUnaryUnaryOpenTracing(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable(request)
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testUnaryUnaryOpenTracingWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response, call = multi_callable.with_call(request)
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testUnaryStreamOpenTracing(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_stream(request,
None)
response = multi_callable(request)
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamUnaryOpenTracing(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamUnaryOpenTracingWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response, call = multi_callable.with_call(iter(requests))
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamStreamOpenTracing(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_stream(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'client')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
class OpenTracingMetadataTest(unittest.TestCase):
"""Test that open-tracing doesn't interfere with passing metadata through the
RPC.
"""
def setUp(self):
self._tracer = Tracer()
self._service = Service([open_tracing_client_interceptor(self._tracer)],
[open_tracing_server_interceptor(self._tracer)])
def testInvocationMetadata(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
multi_callable(request, None, (('abc', '123'),))
self.assertIn(('abc', '123'), self._service.handler.invocation_metadata)
def testTrailingMetadata(self):
self._service.handler.trailing_metadata = (('abc', '123'),)
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
future = multi_callable.future(request, None, (('abc', '123'),))
self.assertIn(('abc', '123'), future.trailing_metadata())
class OpenTracingInteroperabilityServerTest(unittest.TestCase):
"""Test that a traced server can interoperate with a non-trace client."""
def setUp(self):
self._tracer = Tracer()
self._service = Service([],
[open_tracing_server_interceptor(self._tracer)])
def testUnaryUnaryOpenTracing(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response = multi_callable(request)
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testUnaryUnaryOpenTracingWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_unary(request,
None)
response, call = multi_callable.with_call(request)
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testUnaryStreamOpenTracing(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
expected_response = self._service.handler.handle_unary_stream(request,
None)
response = multi_callable(request)
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamUnaryOpenTracing(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(response, expected_response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamUnaryOpenTracingWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_unary(
iter(requests), None)
response, call = multi_callable.with_call(iter(requests))
self.assertEqual(response, expected_response)
self.assertIs(grpc.StatusCode.OK, call.code())
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
def testStreamStreamOpenTracing(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
expected_response = self._service.handler.handle_stream_stream(
iter(requests), None)
response = multi_callable(iter(requests))
self.assertEqual(list(response), list(expected_response))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertEqual(span0.get_tag('span.kind'), 'server')
span1 = self._tracer.get_span(1)
self.assertIsNone(span1)
class OpenTracingErroringTest(unittest.TestCase):
"""Test that tracer spans set the error tag when erroring RPC are invoked."""
def setUp(self):
self._tracer = Tracer()
self._service = Service([open_tracing_client_interceptor(self._tracer)],
[open_tracing_server_interceptor(self._tracer)],
ErroringHandler())
def testUnaryUnaryOpenTracing(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
self.assertRaises(grpc.RpcError, multi_callable, request)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testUnaryUnaryOpenTracingWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
self.assertRaises(grpc.RpcError, multi_callable.with_call, request)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testUnaryStreamOpenTracing(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
response = multi_callable(request)
self.assertRaises(grpc.RpcError, list, response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamUnaryOpenTracing(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
self.assertRaises(grpc.RpcError, multi_callable, iter(requests))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamUnaryOpenTracingWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
self.assertRaises(grpc.RpcError, multi_callable.with_call,
iter(requests))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamStreamOpenTracing(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
response = multi_callable(iter(requests))
self.assertRaises(grpc.RpcError, list, response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
class OpenTracingExceptionErroringTest(unittest.TestCase):
"""Test that tracer spans set the error tag when exception erroring RPC are
invoked.
"""
def setUp(self):
self._tracer = Tracer()
self._service = Service([open_tracing_client_interceptor(self._tracer)],
[open_tracing_server_interceptor(self._tracer)],
ExceptionErroringHandler())
def testUnaryUnaryOpenTracing(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
self.assertRaises(grpc.RpcError, multi_callable, request)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testUnaryUnaryOpenTracingWithCall(self):
multi_callable = self._service.unary_unary_multi_callable
request = b'\x01'
self.assertRaises(grpc.RpcError, multi_callable.with_call, request)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testUnaryStreamOpenTracing(self):
multi_callable = self._service.unary_stream_multi_callable
request = b'\x01'
response = multi_callable(request)
self.assertRaises(grpc.RpcError, list, response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamUnaryOpenTracing(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
self.assertRaises(grpc.RpcError, multi_callable, iter(requests))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamUnaryOpenTracingWithCall(self):
multi_callable = self._service.stream_unary_multi_callable
requests = [b'\x01', b'\x02']
self.assertRaises(grpc.RpcError, multi_callable.with_call,
iter(requests))
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))
def testStreamStreamOpenTracing(self):
multi_callable = self._service.stream_stream_multi_callable
requests = [b'\x01', b'\x02']
response = multi_callable(iter(requests))
self.assertRaises(grpc.RpcError, list, response)
span0 = self._tracer.get_span(0)
self.assertIsNotNone(span0)
self.assertTrue(span0.get_tag('error'))
span1 = self._tracer.get_span(1)
self.assertIsNotNone(span1)
self.assertTrue(span1.get_tag('error'))