Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support -H, -B, --jaeger for headers and baggage #121

Merged
merged 17 commits into from
Nov 2, 2016
Merged

Support -H, -B, --jaeger for headers and baggage #121

merged 17 commits into from
Nov 2, 2016

Conversation

kriskowal
Copy link
Contributor

No description provided.

@mention-bot
Copy link

@kriskowal, thanks for your PR! By analyzing the history of the files in this pull request, we identified @prashantv, @abhinav and @blampe to be potential reviewers.

@@ -302,6 +330,7 @@ func runWithOptions(opts Options, out output) {
runBenchmark(out, opts, benchmarkMethod{
serializer: serializer,
req: req,
tracer: tracer,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be removed and assume NoopTracer downstream from here

@@ -30,6 +30,8 @@ import (
"strconv"
"time"

"github.com/opentracing/opentracing-go"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can remove blank since this is a third party import like the below import

ServiceName: "foo",
HostPorts: []string{s.hostPort()},
}
tp, err := getTransport(tOpts, encoding.Thrift)
tp, err := getTransport(tOpts, encoding.Thrift, nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference in behaviour between nil here and NoopTracer in bench_method.go?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you thread nil, TChannel and YARPC will fall back to the global tracer. I’m going to explicitly thread NoopTracer and mandate a non-nil tracer in getTransport, so there’s no question for yab.

@@ -38,7 +39,7 @@ type benchmarkMethod struct {
// up by making some number of requests through it.
func (m benchmarkMethod) WarmTransport(opts TransportOptions, warmupRequests int) (transport.Transport, error) {
opts.benchmarking = true
transport, err := getTransport(opts, m.serializer.Encoding())
transport, err := getTransport(opts, m.serializer.Encoding(), opentracing.NoopTracer{})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realized, baggage only gets with the Jaeger tracer right? Perhaps we can't do this unless we explicitly disallow baggage with benchmarking? Otherwise, the initial request will use baggage but the benchmarking requests will not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good observation. I’ll simplify this so the only rule regarding tracing is that it must be enabled to pass baggage. I’ll work out a way to ensure that only the first request is sampled, and sampling is off for benchmarking. Whether to use Jaeger and whether to sample should be orthogonal.

opts.TOpts.CallerName = "yab-" + os.Getenv("USER")
}

var tracer opentracing.Tracer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we move the logic of get a tracer into a separate method?

Baggage map[string]string
RoutingKey string
RoutingDelegate string
ShardKey string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if routing key/delegate/shard key belong as top level fields on the request, unless we've made those transport-agnostic concerns in YARPC?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are made transport-agnostic in YARPC. There are equivalent HTTP headers for all of these properties and they’re threaded by reqmeta in YARPC. However, I didn’t finish that angle in this PR, so I’ll take them out for now. We can add them either when we refactor yab to use YARPC or explicitly plumb them in future work.

RoutingDelegate string
ShardKey string
Body []byte
Tracer opentracing.Tracer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Request and Response objects only contain values that represent the on-wire presentation currently. I'm not sure if Tracer should be here, should we move it into the Call interface instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In YARPC, the tracer is a dependency for instantiating a transport. I’ll try to do something similar here instead.

@kriskowal kriskowal changed the base branch from dev to tchannel-v1.2.0 October 19, 2016 03:47
@kriskowal kriskowal changed the title WIP - support -H, -B, --jaeger for headers and baggage Support -H, -B, --jaeger for headers and baggage Oct 19, 2016
Copy link

@HelloGrayson HelloGrayson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still a WIP? Can you prepend the title with "WIP - " in that case?

@@ -2,6 +2,9 @@ Changelog
=========

* Upgrade to TChannel 1.2.0 and add Open Tracing support.
* Add support for -H key:value header arguments.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest:

  • Add support for headers with argument -H key:value.
  • Add support for baggage with argument -B key:value when --jaeger is passed.

Copy link

@HelloGrayson HelloGrayson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@@ -384,8 +384,7 @@ func TestAlises(t *testing.T) {
{
args: []cmdArgs{
{"-P", "file"},
{"-H", "file"},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we're stealing the -H flag for headers?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes.

@kriskowal
Copy link
Contributor Author

Added passing tests for baggage. Added a passing test for TChannel headers. Left a broken test for HTTP headers with #125

Now seeking only a stamp from @prashantv

return t.Call(ctx, request)
}

func makeInitialRequest(out output, transport transport.Transport, serializer encoding.Serializer, req *transport.Request) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure where this new code is coming from. There might be rebase magic here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah looks like the diff needs to be rebased off the latest dev branch

@@ -25,6 +25,7 @@ import (
"sync"
"time"

"github.com/opentracing/opentracing-go"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import group ordering. Third party imports should be in a separate group.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, same throughout this change

Copy link
Contributor Author

@kriskowal kriskowal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import group ordering nits

"strings"

"github.com/opentracing/opentracing-go"
"github.com/uber/tchannel-go"
"gopkg.in/yaml.v2"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

third party group should be below first party group

@@ -23,15 +23,19 @@ package transport
import (
"time"

"github.com/opentracing/opentracing-go"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be in same group as bellow

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"os"
"testing"
"time"

"github.com/opentracing/opentracing-go"
opentracing_ext "github.com/opentracing/opentracing-go/ext"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should separate third party group below

@@ -25,6 +25,7 @@ import (
"sync"
"time"

"github.com/opentracing/opentracing-go"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, same throughout this change

@@ -78,11 +83,21 @@ func (methodsT) echo() handler {

func (methodsT) traceEnabled() handler {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a comment that explains the returned result from the method

}{
{
hostPort: s.hostPort(),
},
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks unrelated to headers -- should this have been handled in a previous diff?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a far flung effect of refactoring tracing. Tracing is no longer a transport level concern, since we no longer use trace sampling on the channel level. Consequently it becomes a request scoped concern and the logic to detect whether the caller was overridden had to be factored upward so I could validate benchmark options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…which invalidated this test case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh I see

@@ -37,8 +39,10 @@ type server struct {

type handler func(ctx context.Context, args *raw.Args) (*raw.Res, error)

func newServer(t *testing.T) *server {
ch := testutils.NewServer(t, testutils.NewOpts().SetServiceName("foo").DisableLogVerification())
func newServer(t *testing.T, tracer opentracing.Tracer) *server {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than take a tracer (and get into the pattern of everyone passing nil for default options), we should probably just implement a lightweight options pattern here,

func withTracer(opentracing.Tracer) func(*testutils.ChannelOpts) {
  return func(opts *testutils.ChannelOpts) {
    opts.Tracer = tracer
  }
}

func newServer(t *testing.T, opts... func(*testutils.ChannelOpts)) {
  chOpts := testutils.NewOpts().[...]
  for _, opt := range opts {
    opt(chOpts)
  }
  [...]
}

ret = 0xfe
}
} else {
ret = 0xff
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no span in context case returning 0 seems like a good default

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these cases were helpful in isolating test errors during development. I’ll scale it back down.

return t.Call(ctx, request)
}

func makeInitialRequest(out output, transport transport.Transport, serializer encoding.Serializer, req *transport.Request) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah looks like the diff needs to be rebased off the latest dev branch

@@ -141,7 +141,7 @@ func TestGetHeaders(t *testing.T) {
}

for _, tt := range tests {
got, err := getHeaders(tt.inline, tt.file)
got, err := getHeaders(tt.inline, tt.file, nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add unit tests for the override here

@@ -174,7 +174,6 @@ func TestTChannelCallSuccessRaw(t *testing.T) {
for _, tt := range tests {
var lastSpan uint64
testutils.RegisterFunc(svr, "echo", func(ctx context.Context, args *raw.Args) (*raw.Res, error) {
// assert.False(t, tchannel.CurrentSpan(ctx).TracingEnabled(), "Tracing should be disabled")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intentional change? shouldn't this just be uncommenting?

func (t *tchan) Protocol() Protocol {
return TChannel
}

func (t *tchan) Call(ctx context.Context, r *Request) (*Response, error) {
call, err := t.sc.BeginCall(ctx, r.Method, t.callOptions)
req := *r
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a comment for why we do this

@@ -54,24 +55,18 @@ func benchmarkMethodForTest(t *testing.T, methodString string, p transport.Proto
}

func TestBenchmarkMethodWarmTransport(t *testing.T) {
s := newServer(t)
s := newServer(t, nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional nit: naked nils are uninformative. Consider using a parameter object
where you set Tracer only when you need it. Alternatively, add a /* tracer */
comment next to the nil.

func getTracer(opts Options, out output) (opentracing.Tracer, io.Closer) {
var tracer opentracing.Tracer
var closer io.Closer
tracer = opentracing.NoopTracer{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use var group and initialize tracer at declaration:

var (
  tracer opentracing.Tracer = opentracing.NoopTracer{}
  closer io.Closer
)

@kriskowal kriskowal changed the base branch from tchannel-v1.2.0 to dev November 2, 2016 00:32
Copy link
Contributor

@prashantv prashantv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, just left a few minor comments

}{
{
hostPort: s.hostPort(),
},
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh I see

val := span.BaggageItem("baggagekey")
if val == "" {
return errors.New("missing baggage")
} else if val != "baggagevalue" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no need for else since the above case returns,

val := span.BaggageItem(..)
if val == "" {
  return errors.New("missing baggage")
}
if val != "baggagevalue" {
  return errors.New("unexpected baggage")
}
return nil


func verifyThriftHeaders(ctx thrift.Context) error {
headers := ctx.Headers()
if val, ok := headers["headerkey"]; ok {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: i'd write this the same as the verifyBaggage to reduce nesting

val, ok := ctx.Headers()["headerkey"]
if !ok {
  return errors.New("missing header")
}
if val != "headervalue" {
  return errors.New("unexpected header")
}
return nil

}

func verifyYARPCHeaders(reqMeta yarpc.ReqMeta) error {
headers := reqMeta.Headers()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we instead have a single veriyHeaders(headers map[string]string) error method, and pass in the ctx.Headers() or reqMeta.Headers()? That way we can avoid the duplication here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YARPC does not expose Headers().Items().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I forgot that yarpc headers are not an actual map, this is fine then.

@@ -75,7 +81,7 @@ func NewTChannel(opts TChannelOptions) (Transport, error) {
}

callerName := opts.SourceService
if cn, ok := opts.TransportOpts["cn"]; ok {
if cn, ok := opts.TransportOpts["cn"]; ok && cn != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should we keep this as is -- it might be we want to test what happens if the cn header is empty in a request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants