remove unused code from vendor
This commit is contained in:
@@ -1 +0,0 @@
|
||||
/crossdock
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
FROM scratch
|
||||
|
||||
ADD crossdock /
|
||||
|
||||
ENV AGENT_HOST_PORT=jaeger-agent:5775
|
||||
ENV SAMPLING_SERVER_URL=http://test_driver:5778/sampling
|
||||
|
||||
EXPOSE 8080-8082
|
||||
|
||||
CMD ["/crossdock"]
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
# Crossdock-based Integration Test Suite
|
||||
|
||||
This package implements integration test suite for testing
|
||||
interoperability between different Jaeger client libraries.
|
||||
|
||||
## Actors
|
||||
|
||||
There are five actors participating in any given test case,
|
||||
the crossdock driver itself, a Client, and three Servers, S1-S3.
|
||||
|
||||
### Driver
|
||||
|
||||
The crossdock driver reads axis and test definitions from the YAML file,
|
||||
generates permutations based on values listed for each axis, and
|
||||
makes an HTTP request to the Client, passing it the selected value
|
||||
for each axis.
|
||||
|
||||
### Client
|
||||
|
||||
Client runs as part of the `jaeger-client/go` image and orchestrates
|
||||
the actual test case with the servers S1-S3. The incoming request
|
||||
from the driver is expected to have parameters defined in
|
||||
[client/constants.go](client/constants.go), which specify
|
||||
|
||||
1. The type of test to execute (only `trace` is currently supported)
|
||||
1. Whether the trace should be sampled or not
|
||||
1. For each of the servers S1-S3:
|
||||
* the name of the server (same as docker image name, same as host name)
|
||||
* the transport to send request to that server (http or TChannel)
|
||||
* the type of client to use (e.g. in Python, `urllib2` vs. `requests`)
|
||||
|
||||
The Client translates the parameters into a "call tree" instruction set,
|
||||
and calls S1, which in turn calls S2 with the sub-set of instructions,
|
||||
and so on. Upon receiving the response from S1, the Client validates the
|
||||
response against the conditions of the test, and returns a summary result
|
||||
to the crossdock driver, indicating a success of a failure of the test.
|
||||
For the `trace` test type, the success conditions are that at all levels
|
||||
the observed tracing spans have the same trace ID, the same sampling flag
|
||||
equal to the input `sampled` parameter, and the same value of a baggage
|
||||
item. The baggage item value is randomly selected by the client at the
|
||||
start of each test.
|
||||
|
||||
### Servers
|
||||
|
||||
Servers represent examples of business services with Jaeger tracing enabled.
|
||||
Servers must be implemented for each supported language, and potentially
|
||||
multiple times for a given language depending on the framework used to build
|
||||
the service, such as Flask vs. Tornado in Python. Each implementation of the
|
||||
server may act as any of the S1-S3 servers in the test. Each server must
|
||||
implement the `TracedService` interface from
|
||||
[thrift/tracetest.thrift](thrift/tracetest.thrift):
|
||||
|
||||
service TracedService {
|
||||
TraceResponse startTrace(1: StartTraceRequest request)
|
||||
TraceResponse joinTrace(1: JoinTraceRequest request)
|
||||
}
|
||||
|
||||
* In `startTrace` the server is supposed to ignore any trace it may have
|
||||
received via inbound request and start a brand new trace, with the
|
||||
sampling flag set appropriately, using `sampling.priority` tag,
|
||||
see [Go server implementation](server/trace.go) for example.
|
||||
* In `joinTrace` the server is supposed to respect the trace in the
|
||||
inbound request and propagate it to the outbound downstream request.
|
||||
|
||||
The response from the server contains the information about the current
|
||||
tracing span it has observed (or started), including trace ID, sampling
|
||||
flag, and the value of a baggage item. For S1 and S2 the response also
|
||||
includes the response of the downstream server.
|
||||
|
||||
## Running the tests
|
||||
|
||||
The intended setup is that every commit to master branch of each of the client
|
||||
libraries results in a build of a new docker image (or images, e.g. in Python).
|
||||
When a new pull request is tested against one of the libraries, it will build
|
||||
a new image from the modified version of the library, and use the existing
|
||||
images for the other languages. The `docker-compose.yaml` file refers to those
|
||||
images by name.
|
||||
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/crossdock/crossdock-go"
|
||||
|
||||
"github.com/uber/jaeger-client-go/crossdock/common"
|
||||
)
|
||||
|
||||
// Client is a controller for the tests
|
||||
type Client struct {
|
||||
ClientHostPort string
|
||||
ServerPortHTTP string
|
||||
ServerPortTChannel string
|
||||
listener net.Listener
|
||||
hostMapper func(service string) string
|
||||
}
|
||||
|
||||
// Start begins a blocking Crossdock client
|
||||
func (c *Client) Start() error {
|
||||
if err := c.Listen(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Serve()
|
||||
}
|
||||
|
||||
// AsyncStart begins a Crossdock client in the background,
|
||||
// but does not return until it started serving.
|
||||
func (c *Client) AsyncStart() error {
|
||||
if err := c.Listen(); err != nil {
|
||||
return err
|
||||
}
|
||||
var started sync.WaitGroup
|
||||
started.Add(1)
|
||||
go func() {
|
||||
started.Done()
|
||||
c.Serve()
|
||||
}()
|
||||
started.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Listen initializes the server
|
||||
func (c *Client) Listen() error {
|
||||
c.setDefaultPort(&c.ClientHostPort, ":"+common.DefaultClientPortHTTP)
|
||||
c.setDefaultPort(&c.ServerPortHTTP, common.DefaultServerPortHTTP)
|
||||
c.setDefaultPort(&c.ServerPortTChannel, common.DefaultServerPortTChannel)
|
||||
|
||||
behaviors := crossdock.Behaviors{
|
||||
behaviorTrace: c.trace,
|
||||
}
|
||||
|
||||
http.Handle("/", crossdock.Handler(behaviors, true))
|
||||
|
||||
listener, err := net.Listen("tcp", c.ClientHostPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.listener = listener
|
||||
c.ClientHostPort = listener.Addr().String()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Serve starts service crossdock traffic. This is a blocking call.
|
||||
func (c *Client) Serve() error {
|
||||
return http.Serve(c.listener, nil)
|
||||
}
|
||||
|
||||
// Close stops the client
|
||||
func (c *Client) Close() error {
|
||||
return c.listener.Close()
|
||||
}
|
||||
|
||||
// URL returns a URL that the client can be accessed on
|
||||
func (c *Client) URL() string {
|
||||
return fmt.Sprintf("http://%s/", c.ClientHostPort)
|
||||
}
|
||||
|
||||
func (c *Client) setDefaultPort(port *string, defaultPort string) {
|
||||
if *port == "" {
|
||||
*port = defaultPort
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) mapServiceToHost(service string) string {
|
||||
mapper := c.hostMapper
|
||||
if mapper == nil {
|
||||
return service
|
||||
}
|
||||
return mapper(service)
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package client
|
||||
|
||||
// Different parameter keys and values used by the system
|
||||
const (
|
||||
// S1 instructions
|
||||
sampledParam = "sampled"
|
||||
server1NameParam = "s1name"
|
||||
// S1->S2 instructions
|
||||
server2NameParam = "s2name"
|
||||
server2TransportParam = "s2transport"
|
||||
// S2->S3 instructions
|
||||
server3NameParam = "s3name"
|
||||
server3TransportParam = "s3transport"
|
||||
|
||||
transportHTTP = "http"
|
||||
transportTChannel = "tchannel"
|
||||
transportDummy = "dummy"
|
||||
|
||||
behaviorTrace = "trace"
|
||||
|
||||
// RoleS1 is the name of the role for server S1
|
||||
RoleS1 = "S1"
|
||||
|
||||
// RoleS2 is the name of the role for server S2
|
||||
RoleS2 = "S2"
|
||||
|
||||
// RoleS3 is the name of the role for server S3
|
||||
RoleS3 = "S3"
|
||||
)
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/crossdock/crossdock-go"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/uber/jaeger-client-go/crossdock/common"
|
||||
"github.com/uber/jaeger-client-go/crossdock/log"
|
||||
"github.com/uber/jaeger-client-go/crossdock/thrift/tracetest"
|
||||
"github.com/uber/jaeger-client-go/utils"
|
||||
)
|
||||
|
||||
func (c *Client) trace(t crossdock.T) {
|
||||
sampled := str2bool(t.Param(sampledParam))
|
||||
baggage := randomBaggage()
|
||||
|
||||
level1 := tracetest.NewStartTraceRequest()
|
||||
level1.ServerRole = RoleS1
|
||||
level1.Sampled = sampled
|
||||
level1.Baggage = baggage
|
||||
server1 := t.Param(server1NameParam)
|
||||
|
||||
level2 := tracetest.NewDownstream()
|
||||
level2.ServiceName = t.Param(server2NameParam)
|
||||
level2.ServerRole = RoleS2
|
||||
level2.Host = c.mapServiceToHost(level2.ServiceName)
|
||||
level2.Port = c.transport2port(t.Param(server2TransportParam))
|
||||
level2.Transport = transport2transport(t.Param(server2TransportParam))
|
||||
level1.Downstream = level2
|
||||
|
||||
level3 := tracetest.NewDownstream()
|
||||
level3.ServiceName = t.Param(server3NameParam)
|
||||
level3.ServerRole = RoleS3
|
||||
level3.Host = c.mapServiceToHost(level3.ServiceName)
|
||||
level3.Port = c.transport2port(t.Param(server3TransportParam))
|
||||
level3.Transport = transport2transport(t.Param(server3TransportParam))
|
||||
level2.Downstream = level3
|
||||
|
||||
server1host := c.mapServiceToHost(server1)
|
||||
url := fmt.Sprintf("http://%s:%s/start_trace", server1host, c.ServerPortHTTP)
|
||||
resp, err := common.PostJSON(context.Background(), url, level1)
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for r := resp; r != nil; r = r.Downstream {
|
||||
if r.NotImplementedError != "" {
|
||||
t.Skipf(r.NotImplementedError)
|
||||
log.Printf("SKIP: %s", r.NotImplementedError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
traceID := resp.Span.TraceId
|
||||
if traceID == "" {
|
||||
t.Errorf("Trace ID is empty in S1(%s)", server1)
|
||||
return
|
||||
}
|
||||
|
||||
success := validateTrace(t, level1.Downstream, resp, server1, 1, traceID, sampled, baggage)
|
||||
if success {
|
||||
t.Successf("trace checks out")
|
||||
log.Printf("PASS")
|
||||
}
|
||||
}
|
||||
|
||||
func validateTrace(
|
||||
t crossdock.T,
|
||||
target *tracetest.Downstream,
|
||||
resp *tracetest.TraceResponse,
|
||||
service string,
|
||||
level int,
|
||||
traceID string,
|
||||
sampled bool,
|
||||
baggage string) bool {
|
||||
|
||||
success := true
|
||||
if traceID != resp.Span.TraceId {
|
||||
t.Errorf("Trace ID mismatch in S%d(%s): expected %s, received %s",
|
||||
level, service, traceID, resp.Span.TraceId)
|
||||
success = false
|
||||
}
|
||||
if baggage != resp.Span.Baggage {
|
||||
t.Errorf("Baggage mismatch in S%d(%s): expected %s, received %s",
|
||||
level, service, baggage, resp.Span.Baggage)
|
||||
success = false
|
||||
}
|
||||
if sampled != resp.Span.Sampled {
|
||||
t.Errorf("Sampled mismatch in S%d(%s): expected %t, received %t",
|
||||
level, service, sampled, resp.Span.Sampled)
|
||||
success = false
|
||||
}
|
||||
if target != nil {
|
||||
if resp.Downstream == nil {
|
||||
t.Errorf("Missing downstream in S%d(%s)", level, service)
|
||||
success = false
|
||||
} else {
|
||||
success = validateTrace(t, target.Downstream, resp.Downstream,
|
||||
target.Host, level+1, traceID, sampled, baggage) && success
|
||||
}
|
||||
} else if resp.Downstream != nil {
|
||||
t.Errorf("Unexpected downstream in S%d(%s)", level, service)
|
||||
success = false
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
func randomBaggage() string {
|
||||
r := utils.NewRand(time.Now().UnixNano())
|
||||
n := uint64(r.Int63())
|
||||
return fmt.Sprintf("%x", n)
|
||||
}
|
||||
|
||||
func str2bool(v string) bool {
|
||||
switch v {
|
||||
case "true":
|
||||
return true
|
||||
case "false":
|
||||
return false
|
||||
default:
|
||||
panic(v + " is not a Boolean")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) transport2port(v string) string {
|
||||
switch v {
|
||||
case transportHTTP:
|
||||
return c.ServerPortHTTP
|
||||
case transportTChannel:
|
||||
return c.ServerPortTChannel
|
||||
case transportDummy:
|
||||
return "9999"
|
||||
default:
|
||||
panic("Unknown protocol " + v)
|
||||
}
|
||||
}
|
||||
|
||||
func transport2transport(v string) tracetest.Transport {
|
||||
switch v {
|
||||
case transportHTTP:
|
||||
return tracetest.Transport_HTTP
|
||||
case transportTChannel:
|
||||
return tracetest.Transport_TCHANNEL
|
||||
case transportDummy:
|
||||
return tracetest.Transport_DUMMY
|
||||
default:
|
||||
panic("Unknown protocol " + v)
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package common
|
||||
|
||||
const (
|
||||
// DefaultClientPortHTTP is the port where the client (controller) runs
|
||||
DefaultClientPortHTTP = "8080"
|
||||
|
||||
// DefaultServerPortHTTP is the port where HTTP server runs
|
||||
DefaultServerPortHTTP = "8081"
|
||||
|
||||
// DefaultServerPortTChannel is the port where TChannel server runs
|
||||
DefaultServerPortTChannel = "8082"
|
||||
|
||||
// DefaultServiceName is the service name used by TChannel server
|
||||
DefaultServiceName = "go"
|
||||
|
||||
// DefaultTracerServiceName is the service name used by the tracer
|
||||
DefaultTracerServiceName = "crossdock-go"
|
||||
)
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/uber/jaeger-client-go/crossdock/thrift/tracetest"
|
||||
"github.com/uber/jaeger-client-go/utils"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// PostJSON sends a POST request to `url` with body containing JSON-serialized `req`.
|
||||
// It injects tracing span into the headers (if found in the context).
|
||||
// It returns parsed TraceResponse, or error.
|
||||
func PostJSON(ctx context.Context, url string, req interface{}) (*tracetest.TraceResponse, error) {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpReq.Header.Set("Content-Type", "application/json")
|
||||
|
||||
span, err := injectSpan(ctx, httpReq)
|
||||
if span != nil {
|
||||
defer span.Finish()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(httpReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result tracetest.TraceResponse
|
||||
err = utils.ReadJSON(resp, &result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func injectSpan(ctx context.Context, req *http.Request) (opentracing.Span, error) {
|
||||
span := opentracing.SpanFromContext(ctx)
|
||||
if span == nil {
|
||||
return nil, nil
|
||||
}
|
||||
span = span.Tracer().StartSpan("post", opentracing.ChildOf(span.Context()))
|
||||
ext.SpanKindRPCClient.Set(span)
|
||||
c := opentracing.HTTPHeadersCarrier(req.Header)
|
||||
err := span.Tracer().Inject(span.Context(), opentracing.HTTPHeaders, c)
|
||||
return span, err
|
||||
}
|
||||
-145
@@ -1,145 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package endtoend
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
|
||||
"github.com/uber/jaeger-client-go"
|
||||
"github.com/uber/jaeger-client-go/config"
|
||||
"github.com/uber/jaeger-client-go/crossdock/common"
|
||||
"github.com/uber/jaeger-client-go/crossdock/log"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultSamplerType = jaeger.SamplerTypeRemote
|
||||
|
||||
endToEndConfig = config.Configuration{
|
||||
Disabled: false,
|
||||
Sampler: &config.SamplerConfig{
|
||||
Type: defaultSamplerType,
|
||||
Param: 1.0,
|
||||
SamplingRefreshInterval: 5 * time.Second,
|
||||
},
|
||||
Reporter: &config.ReporterConfig{
|
||||
BufferFlushInterval: time.Second,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
/*Handler handles creating traces from a http request.
|
||||
*
|
||||
* json: {
|
||||
* "type": "remote",
|
||||
* "operation": "operationName",
|
||||
* "count": 2,
|
||||
* "tags": {
|
||||
* "key": "value"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* Given the above json payload, the handler will use a tracer with the RemotelyControlledSampler
|
||||
* to create 2 traces for "operationName" operation with the tags: {"key":"value"}. These traces
|
||||
* are reported to the agent with the hostname "test_driver".
|
||||
*/
|
||||
type Handler struct {
|
||||
sync.RWMutex
|
||||
|
||||
tracers map[string]opentracing.Tracer
|
||||
agentHostPort string
|
||||
samplingServerURL string
|
||||
}
|
||||
|
||||
type traceRequest struct {
|
||||
Type string `json:"type"`
|
||||
Operation string `json:"operation"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
// NewHandler returns a Handler.
|
||||
func NewHandler(agentHostPort string, samplingServerURL string) *Handler {
|
||||
return &Handler{
|
||||
agentHostPort: agentHostPort,
|
||||
samplingServerURL: samplingServerURL,
|
||||
tracers: make(map[string]opentracing.Tracer),
|
||||
}
|
||||
}
|
||||
|
||||
// init initializes the handler with a tracer
|
||||
func (h *Handler) init(cfg config.Configuration) error {
|
||||
if cfg.Sampler != nil && cfg.Sampler.SamplingServerURL == "" {
|
||||
cfg.Sampler.SamplingServerURL = h.samplingServerURL
|
||||
}
|
||||
if cfg.Reporter != nil && cfg.Reporter.LocalAgentHostPort == "" {
|
||||
cfg.Reporter.LocalAgentHostPort = h.agentHostPort
|
||||
}
|
||||
tracer, _, err := cfg.New(common.DefaultTracerServiceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.tracers[cfg.Sampler.Type] = tracer
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) getTracer(samplerType string) opentracing.Tracer {
|
||||
if samplerType == "" {
|
||||
samplerType = defaultSamplerType
|
||||
}
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
tracer, ok := h.tracers[samplerType]
|
||||
if !ok {
|
||||
endToEndConfig.Sampler.Type = samplerType
|
||||
if err := h.init(endToEndConfig); err != nil {
|
||||
log.Printf("Failed to create tracer: %s", err.Error())
|
||||
return nil
|
||||
}
|
||||
tracer, _ = h.tracers[samplerType]
|
||||
}
|
||||
return tracer
|
||||
}
|
||||
|
||||
// GenerateTraces creates traces given the parameters in the request.
|
||||
func (h *Handler) GenerateTraces(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var req traceRequest
|
||||
if err := decoder.Decode(&req); err != nil {
|
||||
http.Error(w, fmt.Sprintf("JSON payload is invalid: %s", err.Error()), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
tracer := h.getTracer(req.Type)
|
||||
if tracer == nil {
|
||||
http.Error(w, "Tracer is not initialized", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
generateTraces(tracer, &req)
|
||||
}
|
||||
|
||||
func generateTraces(tracer opentracing.Tracer, r *traceRequest) {
|
||||
for i := 0; i < r.Count; i++ {
|
||||
span := tracer.StartSpan(r.Operation)
|
||||
for k, v := range r.Tags {
|
||||
span.SetTag(k, v)
|
||||
}
|
||||
span.Finish()
|
||||
}
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
real_log "log"
|
||||
)
|
||||
|
||||
// Enabled controls logging from crossdock tests. It is enabled in main.go, but off in unit tests.
|
||||
var Enabled bool
|
||||
|
||||
// Printf delegates to log.Printf if Enabled == true
|
||||
func Printf(msg string, args ...interface{}) {
|
||||
if Enabled {
|
||||
real_log.Printf(msg, args)
|
||||
}
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
|
||||
"github.com/uber/jaeger-client-go"
|
||||
"github.com/uber/jaeger-client-go/crossdock/client"
|
||||
"github.com/uber/jaeger-client-go/crossdock/common"
|
||||
"github.com/uber/jaeger-client-go/crossdock/log"
|
||||
"github.com/uber/jaeger-client-go/crossdock/server"
|
||||
jlog "github.com/uber/jaeger-client-go/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Enabled = true
|
||||
|
||||
agentHostPort, ok := os.LookupEnv("AGENT_HOST_PORT")
|
||||
if !ok {
|
||||
jlog.StdLogger.Error("env AGENT_HOST_PORT is not specified!")
|
||||
}
|
||||
sServerURL, ok := os.LookupEnv("SAMPLING_SERVER_URL")
|
||||
if !ok {
|
||||
jlog.StdLogger.Error("env SAMPLING_SERVER_URL is not specified!")
|
||||
}
|
||||
|
||||
tracer, tCloser := initTracer()
|
||||
defer tCloser.Close()
|
||||
|
||||
s := &server.Server{Tracer: tracer, SamplingServerURL: sServerURL, AgentHostPort: agentHostPort}
|
||||
if err := s.Start(); err != nil {
|
||||
panic(err.Error())
|
||||
} else {
|
||||
defer s.Close()
|
||||
}
|
||||
client := &client.Client{}
|
||||
if err := client.Start(); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func initTracer() (opentracing.Tracer, io.Closer) {
|
||||
t, c := jaeger.NewTracer(
|
||||
common.DefaultTracerServiceName,
|
||||
jaeger.NewConstSampler(false),
|
||||
jaeger.NewLoggingReporter(jlog.StdLogger))
|
||||
return t, c
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
XDOCK_YAML=crossdock/docker-compose.yml
|
||||
|
||||
JAEGER_COMPOSE_URL=https://raw.githubusercontent.com/jaegertracing/jaeger/master/docker-compose/jaeger-docker-compose.yml
|
||||
XDOCK_JAEGER_YAML=crossdock/jaeger-docker-compose.yml
|
||||
|
||||
.PHONY: crossdock-linux-bin
|
||||
crossdock-linux-bin:
|
||||
CGO_ENABLED=0 GOOS=linux time go build -a -installsuffix cgo -o crossdock/crossdock ./crossdock
|
||||
|
||||
.PHONY: crossdock
|
||||
crossdock: crossdock-linux-bin crossdock-download-jaeger
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) kill go
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) rm -f go
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) build go
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) run crossdock 2>&1 | tee run-crossdock.log
|
||||
grep 'Tests passed!' run-crossdock.log
|
||||
|
||||
.PHONY: crossdock-fresh
|
||||
crossdock-fresh: crossdock-linux-bin crossdock-download-jaeger
|
||||
docker-compose -f $(XDOCK_JAEGER_YAML) -f $(XDOCK_YAML) kill
|
||||
docker-compose -f $(XDOCK_JAEGER_YAML) -f $(XDOCK_YAML) rm --force
|
||||
docker-compose -f $(XDOCK_JAEGER_YAML) -f $(XDOCK_YAML) pull
|
||||
docker-compose -f $(XDOCK_JAEGER_YAML) -f $(XDOCK_YAML) build
|
||||
docker-compose -f $(XDOCK_JAEGER_YAML) -f $(XDOCK_YAML) run crossdock
|
||||
|
||||
.PHONE: crossdock-logs
|
||||
crossdock-logs: crossdock-download-jaeger
|
||||
docker-compose -f $(XDOCK_JAEGER_YAML) -f $(XDOCK_YAML) logs
|
||||
|
||||
.PHONY: crossdock-download-jaeger
|
||||
crossdock-download-jaeger:
|
||||
curl -o $(XDOCK_JAEGER_YAML) $(JAEGER_COMPOSE_URL)
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package server
|
||||
|
||||
import "errors"
|
||||
|
||||
// BaggageKey is the key used to pass baggage item
|
||||
const BaggageKey = "crossdock-baggage-key"
|
||||
|
||||
var (
|
||||
errNoSpanObserved = errors.New("no span found in Context")
|
||||
errUnrecognizedProtocol = errors.New("unrecognized protocol for downstream call")
|
||||
errCannotStartInTChannel = errors.New("cannot start new trace in tchannel server")
|
||||
)
|
||||
-166
@@ -1,166 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"github.com/uber/tchannel-go"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/uber/jaeger-client-go/crossdock/common"
|
||||
"github.com/uber/jaeger-client-go/crossdock/endtoend"
|
||||
"github.com/uber/jaeger-client-go/crossdock/log"
|
||||
"github.com/uber/jaeger-client-go/crossdock/thrift/tracetest"
|
||||
)
|
||||
|
||||
// Server implements S1-S3 servers
|
||||
type Server struct {
|
||||
HostPortHTTP string
|
||||
HostPortTChannel string
|
||||
AgentHostPort string
|
||||
SamplingServerURL string
|
||||
Tracer opentracing.Tracer
|
||||
listener net.Listener
|
||||
channel *tchannel.Channel
|
||||
eHandler *endtoend.Handler
|
||||
}
|
||||
|
||||
// Start starts the test server called by the Client and other upstream servers.
|
||||
func (s *Server) Start() error {
|
||||
if s.HostPortHTTP == "" {
|
||||
s.HostPortHTTP = ":" + common.DefaultServerPortHTTP
|
||||
}
|
||||
if s.HostPortTChannel == "" {
|
||||
s.HostPortTChannel = ":" + common.DefaultServerPortTChannel
|
||||
}
|
||||
|
||||
if err := s.startTChannelServer(s.Tracer); err != nil {
|
||||
return err
|
||||
}
|
||||
s.eHandler = endtoend.NewHandler(s.AgentHostPort, s.SamplingServerURL)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { return }) // health check
|
||||
mux.HandleFunc("/start_trace", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.handleJSON(w, r, func() interface{} {
|
||||
return tracetest.NewStartTraceRequest()
|
||||
}, func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return s.doStartTrace(req.(*tracetest.StartTraceRequest))
|
||||
})
|
||||
})
|
||||
mux.HandleFunc("/join_trace", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.handleJSON(w, r, func() interface{} {
|
||||
return tracetest.NewJoinTraceRequest()
|
||||
}, func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return s.doJoinTrace(ctx, req.(*tracetest.JoinTraceRequest))
|
||||
})
|
||||
})
|
||||
mux.HandleFunc("/create_traces", s.eHandler.GenerateTraces)
|
||||
|
||||
listener, err := net.Listen("tcp", s.HostPortHTTP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.listener = listener
|
||||
s.HostPortHTTP = listener.Addr().String()
|
||||
|
||||
var started sync.WaitGroup
|
||||
started.Add(1)
|
||||
go func() {
|
||||
started.Done()
|
||||
http.Serve(listener, mux)
|
||||
}()
|
||||
started.Wait()
|
||||
log.Printf("Started http server at %s\n", s.HostPortHTTP)
|
||||
return nil
|
||||
}
|
||||
|
||||
// URL returns URL of the HTTP server
|
||||
func (s *Server) URL() string {
|
||||
return fmt.Sprintf("http://%s/", s.HostPortHTTP)
|
||||
}
|
||||
|
||||
// Close stops the server
|
||||
func (s *Server) Close() error {
|
||||
return s.listener.Close()
|
||||
}
|
||||
|
||||
// GetPortHTTP returns the network port the server listens to.
|
||||
func (s *Server) GetPortHTTP() string {
|
||||
hostPort := s.HostPortHTTP
|
||||
hostPortSplit := strings.Split(hostPort, ":")
|
||||
port := hostPortSplit[len(hostPortSplit)-1]
|
||||
return port
|
||||
}
|
||||
|
||||
// GetPortTChannel returns the actual port the server listens to
|
||||
func (s *Server) GetPortTChannel() string {
|
||||
hostPortSplit := strings.Split(s.HostPortTChannel, ":")
|
||||
port := hostPortSplit[len(hostPortSplit)-1]
|
||||
return port
|
||||
}
|
||||
|
||||
func (s *Server) handleJSON(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
newReq func() interface{},
|
||||
handle func(ctx context.Context, req interface{}) (interface{}, error),
|
||||
) {
|
||||
spanCtx, err := s.Tracer.Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header))
|
||||
if err != nil && err != opentracing.ErrSpanContextNotFound {
|
||||
http.Error(w, fmt.Sprintf("Cannot read request body: %+v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
span := s.Tracer.StartSpan("post", ext.RPCServerOption(spanCtx))
|
||||
ctx := opentracing.ContextWithSpan(context.Background(), span)
|
||||
defer span.Finish()
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Cannot read request body: %+v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Printf("Server request: %s", string(body))
|
||||
req := newReq()
|
||||
if err := json.Unmarshal(body, req); err != nil {
|
||||
http.Error(w, fmt.Sprintf("Cannot parse request JSON: %+v. body=[%s]", err, string(body)), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
resp, err := handle(ctx, req)
|
||||
if err != nil {
|
||||
log.Printf("Handle error: %s", err.Error())
|
||||
http.Error(w, fmt.Sprintf("Execution error: %+v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
json, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Cannot marshall response to JSON: %+v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Printf("Server response: %s", string(json))
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
if _, err := w.Write(json); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/uber/tchannel-go"
|
||||
"github.com/uber/tchannel-go/thrift"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/uber/jaeger-client-go/crossdock/log"
|
||||
"github.com/uber/jaeger-client-go/crossdock/thrift/tracetest"
|
||||
)
|
||||
|
||||
func (s *Server) startTChannelServer(tracer opentracing.Tracer) error {
|
||||
channelOpts := &tchannel.ChannelOptions{
|
||||
Tracer: tracer,
|
||||
}
|
||||
ch, err := tchannel.NewChannel("go", channelOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
server := thrift.NewServer(ch)
|
||||
|
||||
s.channel = ch
|
||||
|
||||
handler := tracetest.NewTChanTracedServiceServer(s)
|
||||
server.Register(handler)
|
||||
|
||||
if err := ch.ListenAndServe(s.HostPortTChannel); err != nil {
|
||||
return err
|
||||
}
|
||||
s.HostPortTChannel = ch.PeerInfo().HostPort
|
||||
log.Printf("Started tchannel server at %s\n", s.HostPortTChannel)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartTrace implements StartTrace() of TChanTracedService
|
||||
func (s *Server) StartTrace(ctx thrift.Context, request *tracetest.StartTraceRequest) (*tracetest.TraceResponse, error) {
|
||||
return nil, errCannotStartInTChannel
|
||||
}
|
||||
|
||||
// JoinTrace implements JoinTrace() of TChanTracedService
|
||||
func (s *Server) JoinTrace(ctx thrift.Context, request *tracetest.JoinTraceRequest) (*tracetest.TraceResponse, error) {
|
||||
log.Printf("tchannel server handling JoinTrace")
|
||||
return s.prepareResponse(ctx, request.ServerRole, request.Downstream)
|
||||
}
|
||||
|
||||
func (s *Server) callDownstreamTChannel(ctx context.Context, target *tracetest.Downstream) (*tracetest.TraceResponse, error) {
|
||||
req := &tracetest.JoinTraceRequest{
|
||||
ServerRole: target.ServerRole,
|
||||
Downstream: target.Downstream,
|
||||
}
|
||||
|
||||
hostPort := fmt.Sprintf("%s:%s", target.Host, target.Port)
|
||||
log.Printf("calling downstream '%s' over tchannel:%s", target.ServiceName, hostPort)
|
||||
|
||||
channelOpts := &tchannel.ChannelOptions{
|
||||
Tracer: s.Tracer,
|
||||
}
|
||||
ch, err := tchannel.NewChannel("tchannel-client", channelOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts := &thrift.ClientOptions{HostPort: hostPort}
|
||||
thriftClient := thrift.NewClient(ch, target.ServiceName, opts)
|
||||
|
||||
client := tracetest.NewTChanTracedServiceClient(thriftClient)
|
||||
ctx, cx := context.WithTimeout(ctx, time.Second)
|
||||
defer cx()
|
||||
return client.JoinTrace(thrift.Wrap(ctx), req)
|
||||
}
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/uber/jaeger-client-go"
|
||||
"github.com/uber/jaeger-client-go/crossdock/common"
|
||||
"github.com/uber/jaeger-client-go/crossdock/log"
|
||||
"github.com/uber/jaeger-client-go/crossdock/thrift/tracetest"
|
||||
)
|
||||
|
||||
func (s *Server) doStartTrace(req *tracetest.StartTraceRequest) (*tracetest.TraceResponse, error) {
|
||||
span := s.Tracer.StartSpan(req.ServerRole)
|
||||
if req.Sampled {
|
||||
ext.SamplingPriority.Set(span, 1)
|
||||
}
|
||||
span.SetBaggageItem(BaggageKey, req.Baggage)
|
||||
defer span.Finish()
|
||||
|
||||
ctx := opentracing.ContextWithSpan(context.Background(), span)
|
||||
|
||||
return s.prepareResponse(ctx, req.ServerRole, req.Downstream)
|
||||
}
|
||||
|
||||
func (s *Server) doJoinTrace(ctx context.Context, req *tracetest.JoinTraceRequest) (*tracetest.TraceResponse, error) {
|
||||
return s.prepareResponse(ctx, req.ServerRole, req.Downstream)
|
||||
}
|
||||
|
||||
func (s *Server) prepareResponse(ctx context.Context, role string, reqDwn *tracetest.Downstream) (*tracetest.TraceResponse, error) {
|
||||
observedSpan, err := observeSpan(ctx, s.Tracer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := tracetest.NewTraceResponse()
|
||||
resp.Span = observedSpan
|
||||
|
||||
if reqDwn != nil {
|
||||
downstreamResp, err := s.callDownstream(ctx, role, reqDwn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Downstream = downstreamResp
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Server) callDownstream(ctx context.Context, role string, downstream *tracetest.Downstream) (*tracetest.TraceResponse, error) {
|
||||
switch downstream.Transport {
|
||||
case tracetest.Transport_HTTP:
|
||||
return s.callDownstreamHTTP(ctx, downstream)
|
||||
case tracetest.Transport_TCHANNEL:
|
||||
return s.callDownstreamTChannel(ctx, downstream)
|
||||
case tracetest.Transport_DUMMY:
|
||||
return &tracetest.TraceResponse{NotImplementedError: "DUMMY transport not implemented"}, nil
|
||||
default:
|
||||
return nil, errUnrecognizedProtocol
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) callDownstreamHTTP(ctx context.Context, target *tracetest.Downstream) (*tracetest.TraceResponse, error) {
|
||||
req := &tracetest.JoinTraceRequest{
|
||||
ServerRole: target.ServerRole,
|
||||
Downstream: target.Downstream,
|
||||
}
|
||||
url := fmt.Sprintf("http://%s:%s/join_trace", target.Host, target.Port)
|
||||
log.Printf("Calling downstream service '%s' at %s", target.ServiceName, url)
|
||||
return common.PostJSON(ctx, url, req)
|
||||
}
|
||||
|
||||
func observeSpan(ctx context.Context, tracer opentracing.Tracer) (*tracetest.ObservedSpan, error) {
|
||||
span := opentracing.SpanFromContext(ctx)
|
||||
if span == nil {
|
||||
return nil, errNoSpanObserved
|
||||
}
|
||||
sc := span.Context().(jaeger.SpanContext)
|
||||
observedSpan := tracetest.NewObservedSpan()
|
||||
observedSpan.TraceId = sc.TraceID().String()
|
||||
observedSpan.Sampled = sc.IsSampled()
|
||||
observedSpan.Baggage = span.BaggageItem(BaggageKey)
|
||||
return observedSpan, nil
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
// Autogenerated by Thrift Compiler (0.9.3)
|
||||
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
|
||||
package tracetest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/apache/thrift/lib/go/thrift"
|
||||
)
|
||||
|
||||
// (needed to ensure safety because of naive import list construction.)
|
||||
var _ = thrift.ZERO
|
||||
var _ = fmt.Printf
|
||||
var _ = bytes.Equal
|
||||
|
||||
func init() {
|
||||
}
|
||||
Generated
Vendored
-137
@@ -1,137 +0,0 @@
|
||||
// @generated Code generated by thrift-gen. Do not modify.
|
||||
|
||||
// Package tracetest is generated code used to make or handle TChannel calls using Thrift.
|
||||
package tracetest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
athrift "github.com/apache/thrift/lib/go/thrift"
|
||||
"github.com/uber/tchannel-go/thrift"
|
||||
)
|
||||
|
||||
// Interfaces for the service and client for the services defined in the IDL.
|
||||
|
||||
// TChanTracedService is the interface that defines the server handler and client interface.
|
||||
type TChanTracedService interface {
|
||||
JoinTrace(ctx thrift.Context, request *JoinTraceRequest) (*TraceResponse, error)
|
||||
StartTrace(ctx thrift.Context, request *StartTraceRequest) (*TraceResponse, error)
|
||||
}
|
||||
|
||||
// Implementation of a client and service handler.
|
||||
|
||||
type tchanTracedServiceClient struct {
|
||||
thriftService string
|
||||
client thrift.TChanClient
|
||||
}
|
||||
|
||||
func NewTChanTracedServiceInheritedClient(thriftService string, client thrift.TChanClient) *tchanTracedServiceClient {
|
||||
return &tchanTracedServiceClient{
|
||||
thriftService,
|
||||
client,
|
||||
}
|
||||
}
|
||||
|
||||
// NewTChanTracedServiceClient creates a client that can be used to make remote calls.
|
||||
func NewTChanTracedServiceClient(client thrift.TChanClient) TChanTracedService {
|
||||
return NewTChanTracedServiceInheritedClient("TracedService", client)
|
||||
}
|
||||
|
||||
func (c *tchanTracedServiceClient) JoinTrace(ctx thrift.Context, request *JoinTraceRequest) (*TraceResponse, error) {
|
||||
var resp TracedServiceJoinTraceResult
|
||||
args := TracedServiceJoinTraceArgs{
|
||||
Request: request,
|
||||
}
|
||||
success, err := c.client.Call(ctx, c.thriftService, "joinTrace", &args, &resp)
|
||||
if err == nil && !success {
|
||||
}
|
||||
|
||||
return resp.GetSuccess(), err
|
||||
}
|
||||
|
||||
func (c *tchanTracedServiceClient) StartTrace(ctx thrift.Context, request *StartTraceRequest) (*TraceResponse, error) {
|
||||
var resp TracedServiceStartTraceResult
|
||||
args := TracedServiceStartTraceArgs{
|
||||
Request: request,
|
||||
}
|
||||
success, err := c.client.Call(ctx, c.thriftService, "startTrace", &args, &resp)
|
||||
if err == nil && !success {
|
||||
}
|
||||
|
||||
return resp.GetSuccess(), err
|
||||
}
|
||||
|
||||
type tchanTracedServiceServer struct {
|
||||
handler TChanTracedService
|
||||
}
|
||||
|
||||
// NewTChanTracedServiceServer wraps a handler for TChanTracedService so it can be
|
||||
// registered with a thrift.Server.
|
||||
func NewTChanTracedServiceServer(handler TChanTracedService) thrift.TChanServer {
|
||||
return &tchanTracedServiceServer{
|
||||
handler,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *tchanTracedServiceServer) Service() string {
|
||||
return "TracedService"
|
||||
}
|
||||
|
||||
func (s *tchanTracedServiceServer) Methods() []string {
|
||||
return []string{
|
||||
"joinTrace",
|
||||
"startTrace",
|
||||
}
|
||||
}
|
||||
|
||||
func (s *tchanTracedServiceServer) Handle(ctx thrift.Context, methodName string, protocol athrift.TProtocol) (bool, athrift.TStruct, error) {
|
||||
switch methodName {
|
||||
case "joinTrace":
|
||||
return s.handleJoinTrace(ctx, protocol)
|
||||
case "startTrace":
|
||||
return s.handleStartTrace(ctx, protocol)
|
||||
|
||||
default:
|
||||
return false, nil, fmt.Errorf("method %v not found in service %v", methodName, s.Service())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *tchanTracedServiceServer) handleJoinTrace(ctx thrift.Context, protocol athrift.TProtocol) (bool, athrift.TStruct, error) {
|
||||
var req TracedServiceJoinTraceArgs
|
||||
var res TracedServiceJoinTraceResult
|
||||
|
||||
if err := req.Read(protocol); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
r, err :=
|
||||
s.handler.JoinTrace(ctx, req.Request)
|
||||
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
} else {
|
||||
res.Success = r
|
||||
}
|
||||
|
||||
return err == nil, &res, nil
|
||||
}
|
||||
|
||||
func (s *tchanTracedServiceServer) handleStartTrace(ctx thrift.Context, protocol athrift.TProtocol) (bool, athrift.TStruct, error) {
|
||||
var req TracedServiceStartTraceArgs
|
||||
var res TracedServiceStartTraceResult
|
||||
|
||||
if err := req.Read(protocol); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
r, err :=
|
||||
s.handler.StartTrace(ctx, req.Request)
|
||||
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
} else {
|
||||
res.Success = r
|
||||
}
|
||||
|
||||
return err == nil, &res, nil
|
||||
}
|
||||
Generated
Vendored
-747
@@ -1,747 +0,0 @@
|
||||
// Autogenerated by Thrift Compiler (0.9.3)
|
||||
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
|
||||
package tracetest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/apache/thrift/lib/go/thrift"
|
||||
)
|
||||
|
||||
// (needed to ensure safety because of naive import list construction.)
|
||||
var _ = thrift.ZERO
|
||||
var _ = fmt.Printf
|
||||
var _ = bytes.Equal
|
||||
|
||||
type TracedService interface {
|
||||
// Parameters:
|
||||
// - Request
|
||||
StartTrace(request *StartTraceRequest) (r *TraceResponse, err error)
|
||||
// Parameters:
|
||||
// - Request
|
||||
JoinTrace(request *JoinTraceRequest) (r *TraceResponse, err error)
|
||||
}
|
||||
|
||||
type TracedServiceClient struct {
|
||||
Transport thrift.TTransport
|
||||
ProtocolFactory thrift.TProtocolFactory
|
||||
InputProtocol thrift.TProtocol
|
||||
OutputProtocol thrift.TProtocol
|
||||
SeqId int32
|
||||
}
|
||||
|
||||
func NewTracedServiceClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *TracedServiceClient {
|
||||
return &TracedServiceClient{Transport: t,
|
||||
ProtocolFactory: f,
|
||||
InputProtocol: f.GetProtocol(t),
|
||||
OutputProtocol: f.GetProtocol(t),
|
||||
SeqId: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func NewTracedServiceClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *TracedServiceClient {
|
||||
return &TracedServiceClient{Transport: t,
|
||||
ProtocolFactory: nil,
|
||||
InputProtocol: iprot,
|
||||
OutputProtocol: oprot,
|
||||
SeqId: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Parameters:
|
||||
// - Request
|
||||
func (p *TracedServiceClient) StartTrace(request *StartTraceRequest) (r *TraceResponse, err error) {
|
||||
if err = p.sendStartTrace(request); err != nil {
|
||||
return
|
||||
}
|
||||
return p.recvStartTrace()
|
||||
}
|
||||
|
||||
func (p *TracedServiceClient) sendStartTrace(request *StartTraceRequest) (err error) {
|
||||
oprot := p.OutputProtocol
|
||||
if oprot == nil {
|
||||
oprot = p.ProtocolFactory.GetProtocol(p.Transport)
|
||||
p.OutputProtocol = oprot
|
||||
}
|
||||
p.SeqId++
|
||||
if err = oprot.WriteMessageBegin("startTrace", thrift.CALL, p.SeqId); err != nil {
|
||||
return
|
||||
}
|
||||
args := TracedServiceStartTraceArgs{
|
||||
Request: request,
|
||||
}
|
||||
if err = args.Write(oprot); err != nil {
|
||||
return
|
||||
}
|
||||
if err = oprot.WriteMessageEnd(); err != nil {
|
||||
return
|
||||
}
|
||||
return oprot.Flush()
|
||||
}
|
||||
|
||||
func (p *TracedServiceClient) recvStartTrace() (value *TraceResponse, err error) {
|
||||
iprot := p.InputProtocol
|
||||
if iprot == nil {
|
||||
iprot = p.ProtocolFactory.GetProtocol(p.Transport)
|
||||
p.InputProtocol = iprot
|
||||
}
|
||||
method, mTypeId, seqId, err := iprot.ReadMessageBegin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if method != "startTrace" {
|
||||
err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "startTrace failed: wrong method name")
|
||||
return
|
||||
}
|
||||
if p.SeqId != seqId {
|
||||
err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "startTrace failed: out of sequence response")
|
||||
return
|
||||
}
|
||||
if mTypeId == thrift.EXCEPTION {
|
||||
error0 := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "Unknown Exception")
|
||||
var error1 error
|
||||
error1, err = error0.Read(iprot)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = iprot.ReadMessageEnd(); err != nil {
|
||||
return
|
||||
}
|
||||
err = error1
|
||||
return
|
||||
}
|
||||
if mTypeId != thrift.REPLY {
|
||||
err = thrift.NewTApplicationException(thrift.INVALID_MESSAGE_TYPE_EXCEPTION, "startTrace failed: invalid message type")
|
||||
return
|
||||
}
|
||||
result := TracedServiceStartTraceResult{}
|
||||
if err = result.Read(iprot); err != nil {
|
||||
return
|
||||
}
|
||||
if err = iprot.ReadMessageEnd(); err != nil {
|
||||
return
|
||||
}
|
||||
value = result.GetSuccess()
|
||||
return
|
||||
}
|
||||
|
||||
// Parameters:
|
||||
// - Request
|
||||
func (p *TracedServiceClient) JoinTrace(request *JoinTraceRequest) (r *TraceResponse, err error) {
|
||||
if err = p.sendJoinTrace(request); err != nil {
|
||||
return
|
||||
}
|
||||
return p.recvJoinTrace()
|
||||
}
|
||||
|
||||
func (p *TracedServiceClient) sendJoinTrace(request *JoinTraceRequest) (err error) {
|
||||
oprot := p.OutputProtocol
|
||||
if oprot == nil {
|
||||
oprot = p.ProtocolFactory.GetProtocol(p.Transport)
|
||||
p.OutputProtocol = oprot
|
||||
}
|
||||
p.SeqId++
|
||||
if err = oprot.WriteMessageBegin("joinTrace", thrift.CALL, p.SeqId); err != nil {
|
||||
return
|
||||
}
|
||||
args := TracedServiceJoinTraceArgs{
|
||||
Request: request,
|
||||
}
|
||||
if err = args.Write(oprot); err != nil {
|
||||
return
|
||||
}
|
||||
if err = oprot.WriteMessageEnd(); err != nil {
|
||||
return
|
||||
}
|
||||
return oprot.Flush()
|
||||
}
|
||||
|
||||
func (p *TracedServiceClient) recvJoinTrace() (value *TraceResponse, err error) {
|
||||
iprot := p.InputProtocol
|
||||
if iprot == nil {
|
||||
iprot = p.ProtocolFactory.GetProtocol(p.Transport)
|
||||
p.InputProtocol = iprot
|
||||
}
|
||||
method, mTypeId, seqId, err := iprot.ReadMessageBegin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if method != "joinTrace" {
|
||||
err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "joinTrace failed: wrong method name")
|
||||
return
|
||||
}
|
||||
if p.SeqId != seqId {
|
||||
err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "joinTrace failed: out of sequence response")
|
||||
return
|
||||
}
|
||||
if mTypeId == thrift.EXCEPTION {
|
||||
error2 := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "Unknown Exception")
|
||||
var error3 error
|
||||
error3, err = error2.Read(iprot)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = iprot.ReadMessageEnd(); err != nil {
|
||||
return
|
||||
}
|
||||
err = error3
|
||||
return
|
||||
}
|
||||
if mTypeId != thrift.REPLY {
|
||||
err = thrift.NewTApplicationException(thrift.INVALID_MESSAGE_TYPE_EXCEPTION, "joinTrace failed: invalid message type")
|
||||
return
|
||||
}
|
||||
result := TracedServiceJoinTraceResult{}
|
||||
if err = result.Read(iprot); err != nil {
|
||||
return
|
||||
}
|
||||
if err = iprot.ReadMessageEnd(); err != nil {
|
||||
return
|
||||
}
|
||||
value = result.GetSuccess()
|
||||
return
|
||||
}
|
||||
|
||||
type TracedServiceProcessor struct {
|
||||
processorMap map[string]thrift.TProcessorFunction
|
||||
handler TracedService
|
||||
}
|
||||
|
||||
func (p *TracedServiceProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {
|
||||
p.processorMap[key] = processor
|
||||
}
|
||||
|
||||
func (p *TracedServiceProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) {
|
||||
processor, ok = p.processorMap[key]
|
||||
return processor, ok
|
||||
}
|
||||
|
||||
func (p *TracedServiceProcessor) ProcessorMap() map[string]thrift.TProcessorFunction {
|
||||
return p.processorMap
|
||||
}
|
||||
|
||||
func NewTracedServiceProcessor(handler TracedService) *TracedServiceProcessor {
|
||||
|
||||
self4 := &TracedServiceProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)}
|
||||
self4.processorMap["startTrace"] = &tracedServiceProcessorStartTrace{handler: handler}
|
||||
self4.processorMap["joinTrace"] = &tracedServiceProcessorJoinTrace{handler: handler}
|
||||
return self4
|
||||
}
|
||||
|
||||
func (p *TracedServiceProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
|
||||
name, _, seqId, err := iprot.ReadMessageBegin()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if processor, ok := p.GetProcessorFunction(name); ok {
|
||||
return processor.Process(seqId, iprot, oprot)
|
||||
}
|
||||
iprot.Skip(thrift.STRUCT)
|
||||
iprot.ReadMessageEnd()
|
||||
x5 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name)
|
||||
oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId)
|
||||
x5.Write(oprot)
|
||||
oprot.WriteMessageEnd()
|
||||
oprot.Flush()
|
||||
return false, x5
|
||||
|
||||
}
|
||||
|
||||
type tracedServiceProcessorStartTrace struct {
|
||||
handler TracedService
|
||||
}
|
||||
|
||||
func (p *tracedServiceProcessorStartTrace) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
|
||||
args := TracedServiceStartTraceArgs{}
|
||||
if err = args.Read(iprot); err != nil {
|
||||
iprot.ReadMessageEnd()
|
||||
x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())
|
||||
oprot.WriteMessageBegin("startTrace", thrift.EXCEPTION, seqId)
|
||||
x.Write(oprot)
|
||||
oprot.WriteMessageEnd()
|
||||
oprot.Flush()
|
||||
return false, err
|
||||
}
|
||||
|
||||
iprot.ReadMessageEnd()
|
||||
result := TracedServiceStartTraceResult{}
|
||||
var retval *TraceResponse
|
||||
var err2 error
|
||||
if retval, err2 = p.handler.StartTrace(args.Request); err2 != nil {
|
||||
x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing startTrace: "+err2.Error())
|
||||
oprot.WriteMessageBegin("startTrace", thrift.EXCEPTION, seqId)
|
||||
x.Write(oprot)
|
||||
oprot.WriteMessageEnd()
|
||||
oprot.Flush()
|
||||
return true, err2
|
||||
} else {
|
||||
result.Success = retval
|
||||
}
|
||||
if err2 = oprot.WriteMessageBegin("startTrace", thrift.REPLY, seqId); err2 != nil {
|
||||
err = err2
|
||||
}
|
||||
if err2 = result.Write(oprot); err == nil && err2 != nil {
|
||||
err = err2
|
||||
}
|
||||
if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil {
|
||||
err = err2
|
||||
}
|
||||
if err2 = oprot.Flush(); err == nil && err2 != nil {
|
||||
err = err2
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
type tracedServiceProcessorJoinTrace struct {
|
||||
handler TracedService
|
||||
}
|
||||
|
||||
func (p *tracedServiceProcessorJoinTrace) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
|
||||
args := TracedServiceJoinTraceArgs{}
|
||||
if err = args.Read(iprot); err != nil {
|
||||
iprot.ReadMessageEnd()
|
||||
x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())
|
||||
oprot.WriteMessageBegin("joinTrace", thrift.EXCEPTION, seqId)
|
||||
x.Write(oprot)
|
||||
oprot.WriteMessageEnd()
|
||||
oprot.Flush()
|
||||
return false, err
|
||||
}
|
||||
|
||||
iprot.ReadMessageEnd()
|
||||
result := TracedServiceJoinTraceResult{}
|
||||
var retval *TraceResponse
|
||||
var err2 error
|
||||
if retval, err2 = p.handler.JoinTrace(args.Request); err2 != nil {
|
||||
x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing joinTrace: "+err2.Error())
|
||||
oprot.WriteMessageBegin("joinTrace", thrift.EXCEPTION, seqId)
|
||||
x.Write(oprot)
|
||||
oprot.WriteMessageEnd()
|
||||
oprot.Flush()
|
||||
return true, err2
|
||||
} else {
|
||||
result.Success = retval
|
||||
}
|
||||
if err2 = oprot.WriteMessageBegin("joinTrace", thrift.REPLY, seqId); err2 != nil {
|
||||
err = err2
|
||||
}
|
||||
if err2 = result.Write(oprot); err == nil && err2 != nil {
|
||||
err = err2
|
||||
}
|
||||
if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil {
|
||||
err = err2
|
||||
}
|
||||
if err2 = oprot.Flush(); err == nil && err2 != nil {
|
||||
err = err2
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
// HELPER FUNCTIONS AND STRUCTURES
|
||||
|
||||
// Attributes:
|
||||
// - Request
|
||||
type TracedServiceStartTraceArgs struct {
|
||||
Request *StartTraceRequest `thrift:"request,1" json:"request"`
|
||||
}
|
||||
|
||||
func NewTracedServiceStartTraceArgs() *TracedServiceStartTraceArgs {
|
||||
return &TracedServiceStartTraceArgs{}
|
||||
}
|
||||
|
||||
var TracedServiceStartTraceArgs_Request_DEFAULT *StartTraceRequest
|
||||
|
||||
func (p *TracedServiceStartTraceArgs) GetRequest() *StartTraceRequest {
|
||||
if !p.IsSetRequest() {
|
||||
return TracedServiceStartTraceArgs_Request_DEFAULT
|
||||
}
|
||||
return p.Request
|
||||
}
|
||||
func (p *TracedServiceStartTraceArgs) IsSetRequest() bool {
|
||||
return p.Request != nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceStartTraceArgs) Read(iprot thrift.TProtocol) error {
|
||||
if _, err := iprot.ReadStructBegin(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
|
||||
}
|
||||
|
||||
for {
|
||||
_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
|
||||
if err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
|
||||
}
|
||||
if fieldTypeId == thrift.STOP {
|
||||
break
|
||||
}
|
||||
switch fieldId {
|
||||
case 1:
|
||||
if err := p.readField1(iprot); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := iprot.Skip(fieldTypeId); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := iprot.ReadFieldEnd(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := iprot.ReadStructEnd(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceStartTraceArgs) readField1(iprot thrift.TProtocol) error {
|
||||
p.Request = &StartTraceRequest{}
|
||||
if err := p.Request.Read(iprot); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Request), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceStartTraceArgs) Write(oprot thrift.TProtocol) error {
|
||||
if err := oprot.WriteStructBegin("startTrace_args"); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
|
||||
}
|
||||
if err := p.writeField1(oprot); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := oprot.WriteFieldStop(); err != nil {
|
||||
return thrift.PrependError("write field stop error: ", err)
|
||||
}
|
||||
if err := oprot.WriteStructEnd(); err != nil {
|
||||
return thrift.PrependError("write struct stop error: ", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceStartTraceArgs) writeField1(oprot thrift.TProtocol) (err error) {
|
||||
if err := oprot.WriteFieldBegin("request", thrift.STRUCT, 1); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:request: ", p), err)
|
||||
}
|
||||
if err := p.Request.Write(oprot); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Request), err)
|
||||
}
|
||||
if err := oprot.WriteFieldEnd(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field end error 1:request: ", p), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *TracedServiceStartTraceArgs) String() string {
|
||||
if p == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return fmt.Sprintf("TracedServiceStartTraceArgs(%+v)", *p)
|
||||
}
|
||||
|
||||
// Attributes:
|
||||
// - Success
|
||||
type TracedServiceStartTraceResult struct {
|
||||
Success *TraceResponse `thrift:"success,0" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func NewTracedServiceStartTraceResult() *TracedServiceStartTraceResult {
|
||||
return &TracedServiceStartTraceResult{}
|
||||
}
|
||||
|
||||
var TracedServiceStartTraceResult_Success_DEFAULT *TraceResponse
|
||||
|
||||
func (p *TracedServiceStartTraceResult) GetSuccess() *TraceResponse {
|
||||
if !p.IsSetSuccess() {
|
||||
return TracedServiceStartTraceResult_Success_DEFAULT
|
||||
}
|
||||
return p.Success
|
||||
}
|
||||
func (p *TracedServiceStartTraceResult) IsSetSuccess() bool {
|
||||
return p.Success != nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceStartTraceResult) Read(iprot thrift.TProtocol) error {
|
||||
if _, err := iprot.ReadStructBegin(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
|
||||
}
|
||||
|
||||
for {
|
||||
_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
|
||||
if err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
|
||||
}
|
||||
if fieldTypeId == thrift.STOP {
|
||||
break
|
||||
}
|
||||
switch fieldId {
|
||||
case 0:
|
||||
if err := p.readField0(iprot); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := iprot.Skip(fieldTypeId); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := iprot.ReadFieldEnd(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := iprot.ReadStructEnd(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceStartTraceResult) readField0(iprot thrift.TProtocol) error {
|
||||
p.Success = &TraceResponse{}
|
||||
if err := p.Success.Read(iprot); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Success), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceStartTraceResult) Write(oprot thrift.TProtocol) error {
|
||||
if err := oprot.WriteStructBegin("startTrace_result"); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
|
||||
}
|
||||
if err := p.writeField0(oprot); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := oprot.WriteFieldStop(); err != nil {
|
||||
return thrift.PrependError("write field stop error: ", err)
|
||||
}
|
||||
if err := oprot.WriteStructEnd(); err != nil {
|
||||
return thrift.PrependError("write struct stop error: ", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceStartTraceResult) writeField0(oprot thrift.TProtocol) (err error) {
|
||||
if p.IsSetSuccess() {
|
||||
if err := oprot.WriteFieldBegin("success", thrift.STRUCT, 0); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err)
|
||||
}
|
||||
if err := p.Success.Write(oprot); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Success), err)
|
||||
}
|
||||
if err := oprot.WriteFieldEnd(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *TracedServiceStartTraceResult) String() string {
|
||||
if p == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return fmt.Sprintf("TracedServiceStartTraceResult(%+v)", *p)
|
||||
}
|
||||
|
||||
// Attributes:
|
||||
// - Request
|
||||
type TracedServiceJoinTraceArgs struct {
|
||||
Request *JoinTraceRequest `thrift:"request,1" json:"request"`
|
||||
}
|
||||
|
||||
func NewTracedServiceJoinTraceArgs() *TracedServiceJoinTraceArgs {
|
||||
return &TracedServiceJoinTraceArgs{}
|
||||
}
|
||||
|
||||
var TracedServiceJoinTraceArgs_Request_DEFAULT *JoinTraceRequest
|
||||
|
||||
func (p *TracedServiceJoinTraceArgs) GetRequest() *JoinTraceRequest {
|
||||
if !p.IsSetRequest() {
|
||||
return TracedServiceJoinTraceArgs_Request_DEFAULT
|
||||
}
|
||||
return p.Request
|
||||
}
|
||||
func (p *TracedServiceJoinTraceArgs) IsSetRequest() bool {
|
||||
return p.Request != nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceJoinTraceArgs) Read(iprot thrift.TProtocol) error {
|
||||
if _, err := iprot.ReadStructBegin(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
|
||||
}
|
||||
|
||||
for {
|
||||
_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
|
||||
if err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
|
||||
}
|
||||
if fieldTypeId == thrift.STOP {
|
||||
break
|
||||
}
|
||||
switch fieldId {
|
||||
case 1:
|
||||
if err := p.readField1(iprot); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := iprot.Skip(fieldTypeId); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := iprot.ReadFieldEnd(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := iprot.ReadStructEnd(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceJoinTraceArgs) readField1(iprot thrift.TProtocol) error {
|
||||
p.Request = &JoinTraceRequest{}
|
||||
if err := p.Request.Read(iprot); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Request), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceJoinTraceArgs) Write(oprot thrift.TProtocol) error {
|
||||
if err := oprot.WriteStructBegin("joinTrace_args"); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
|
||||
}
|
||||
if err := p.writeField1(oprot); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := oprot.WriteFieldStop(); err != nil {
|
||||
return thrift.PrependError("write field stop error: ", err)
|
||||
}
|
||||
if err := oprot.WriteStructEnd(); err != nil {
|
||||
return thrift.PrependError("write struct stop error: ", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceJoinTraceArgs) writeField1(oprot thrift.TProtocol) (err error) {
|
||||
if err := oprot.WriteFieldBegin("request", thrift.STRUCT, 1); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:request: ", p), err)
|
||||
}
|
||||
if err := p.Request.Write(oprot); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Request), err)
|
||||
}
|
||||
if err := oprot.WriteFieldEnd(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field end error 1:request: ", p), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *TracedServiceJoinTraceArgs) String() string {
|
||||
if p == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return fmt.Sprintf("TracedServiceJoinTraceArgs(%+v)", *p)
|
||||
}
|
||||
|
||||
// Attributes:
|
||||
// - Success
|
||||
type TracedServiceJoinTraceResult struct {
|
||||
Success *TraceResponse `thrift:"success,0" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func NewTracedServiceJoinTraceResult() *TracedServiceJoinTraceResult {
|
||||
return &TracedServiceJoinTraceResult{}
|
||||
}
|
||||
|
||||
var TracedServiceJoinTraceResult_Success_DEFAULT *TraceResponse
|
||||
|
||||
func (p *TracedServiceJoinTraceResult) GetSuccess() *TraceResponse {
|
||||
if !p.IsSetSuccess() {
|
||||
return TracedServiceJoinTraceResult_Success_DEFAULT
|
||||
}
|
||||
return p.Success
|
||||
}
|
||||
func (p *TracedServiceJoinTraceResult) IsSetSuccess() bool {
|
||||
return p.Success != nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceJoinTraceResult) Read(iprot thrift.TProtocol) error {
|
||||
if _, err := iprot.ReadStructBegin(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
|
||||
}
|
||||
|
||||
for {
|
||||
_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
|
||||
if err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
|
||||
}
|
||||
if fieldTypeId == thrift.STOP {
|
||||
break
|
||||
}
|
||||
switch fieldId {
|
||||
case 0:
|
||||
if err := p.readField0(iprot); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := iprot.Skip(fieldTypeId); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := iprot.ReadFieldEnd(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := iprot.ReadStructEnd(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceJoinTraceResult) readField0(iprot thrift.TProtocol) error {
|
||||
p.Success = &TraceResponse{}
|
||||
if err := p.Success.Read(iprot); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Success), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceJoinTraceResult) Write(oprot thrift.TProtocol) error {
|
||||
if err := oprot.WriteStructBegin("joinTrace_result"); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
|
||||
}
|
||||
if err := p.writeField0(oprot); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := oprot.WriteFieldStop(); err != nil {
|
||||
return thrift.PrependError("write field stop error: ", err)
|
||||
}
|
||||
if err := oprot.WriteStructEnd(); err != nil {
|
||||
return thrift.PrependError("write struct stop error: ", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TracedServiceJoinTraceResult) writeField0(oprot thrift.TProtocol) (err error) {
|
||||
if p.IsSetSuccess() {
|
||||
if err := oprot.WriteFieldBegin("success", thrift.STRUCT, 0); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err)
|
||||
}
|
||||
if err := p.Success.Write(oprot); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Success), err)
|
||||
}
|
||||
if err := oprot.WriteFieldEnd(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *TracedServiceJoinTraceResult) String() string {
|
||||
if p == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return fmt.Sprintf("TracedServiceJoinTraceResult(%+v)", *p)
|
||||
}
|
||||
-1103
File diff suppressed because it is too large
Load Diff
-60
@@ -1,60 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
jaeger "github.com/uber/jaeger-client-go"
|
||||
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// Trace creates a field that extracts tracing information from a context and
|
||||
// includes it under the "trace" key.
|
||||
//
|
||||
// Because the opentracing APIs don't expose this information, the returned
|
||||
// zap.Field is a no-op for contexts that don't contain a span or contain a
|
||||
// non-Jaeger span.
|
||||
func Trace(ctx context.Context) zapcore.Field {
|
||||
if ctx == nil {
|
||||
return zap.Skip()
|
||||
}
|
||||
return zap.Object("trace", trace{ctx})
|
||||
}
|
||||
|
||||
type trace struct {
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (t trace) MarshalLogObject(enc zapcore.ObjectEncoder) error {
|
||||
span := opentracing.SpanFromContext(t.ctx)
|
||||
if span == nil {
|
||||
return nil
|
||||
}
|
||||
j, ok := span.Context().(jaeger.SpanContext)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if !j.IsValid() {
|
||||
return fmt.Errorf("invalid span: %v", j.SpanID())
|
||||
}
|
||||
enc.AddString("span", j.SpanID().String())
|
||||
enc.AddString("trace", j.TraceID().String())
|
||||
return nil
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package zap
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Logger is an adapter from zap Logger to jaeger-lib Logger.
|
||||
type Logger struct {
|
||||
logger *zap.SugaredLogger
|
||||
}
|
||||
|
||||
// NewLogger creates a new Logger.
|
||||
func NewLogger(logger *zap.Logger) *Logger {
|
||||
return &Logger{logger: logger.Sugar()}
|
||||
}
|
||||
|
||||
// Error logs a message at error priority
|
||||
func (l *Logger) Error(msg string) {
|
||||
l.logger.Error(msg)
|
||||
}
|
||||
|
||||
// Infof logs a message at info priority
|
||||
func (l *Logger) Infof(msg string, args ...interface{}) {
|
||||
l.logger.Infof(msg, args...)
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
COVER=.cover
|
||||
ROOT_PKG=github.com/uber/jaeger-client-go/
|
||||
|
||||
if [[ -d "$COVER" ]]; then
|
||||
rm -rf "$COVER"
|
||||
fi
|
||||
mkdir -p "$COVER"
|
||||
|
||||
# If a package directory has a .nocover file, don't count it when calculating
|
||||
# coverage.
|
||||
filter=""
|
||||
for pkg in "$@"; do
|
||||
if [[ -f "$GOPATH/src/$pkg/.nocover" ]]; then
|
||||
if [[ -n "$filter" ]]; then
|
||||
filter="$filter, "
|
||||
fi
|
||||
filter="\"$pkg\": true"
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
i=0
|
||||
for pkg in "$@"; do
|
||||
i=$((i + 1))
|
||||
|
||||
extracoverpkg=""
|
||||
if [[ -f "$GOPATH/src/$pkg/.extra-coverpkg" ]]; then
|
||||
extracoverpkg=$( \
|
||||
sed -e "s|^|$pkg/|g" < "$GOPATH/src/$pkg/.extra-coverpkg" \
|
||||
| tr '\n' ',')
|
||||
fi
|
||||
|
||||
coverpkg=$(go list -json "$pkg" | jq -r '
|
||||
.Deps
|
||||
| . + ["'"$pkg"'"]
|
||||
| map
|
||||
( select(startswith("'"$ROOT_PKG"'"))
|
||||
| select(contains("/vendor/") | not)
|
||||
| select(in({'"$filter"'}) | not)
|
||||
)
|
||||
| join(",")
|
||||
')
|
||||
if [[ -n "$extracoverpkg" ]]; then
|
||||
coverpkg="$extracoverpkg$coverpkg"
|
||||
fi
|
||||
|
||||
args=""
|
||||
if [[ -n "$coverpkg" ]]; then
|
||||
args="-coverprofile $COVER/cover.${i}.out" # -coverpkg $coverpkg"
|
||||
fi
|
||||
|
||||
echo go test -v -race "$pkg"
|
||||
go test $args -v -race "$pkg"
|
||||
done
|
||||
|
||||
gocovmerge "$COVER"/*.out > cover.out
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
python scripts/updateLicense.py $(git ls-files "*\.go" | grep -v thrift-gen | grep -v tracetest)
|
||||
-189
@@ -1,189 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/apache/thrift/lib/go/thrift"
|
||||
|
||||
"github.com/uber/jaeger-client-go/thrift-gen/agent"
|
||||
"github.com/uber/jaeger-client-go/thrift-gen/jaeger"
|
||||
"github.com/uber/jaeger-client-go/thrift-gen/sampling"
|
||||
"github.com/uber/jaeger-client-go/thrift-gen/zipkincore"
|
||||
"github.com/uber/jaeger-client-go/utils"
|
||||
)
|
||||
|
||||
// StartMockAgent runs a mock representation of jaeger-agent.
|
||||
// This function returns a started server.
|
||||
func StartMockAgent() (*MockAgent, error) {
|
||||
transport, err := NewTUDPServerTransport("127.0.0.1:0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
samplingManager := newSamplingManager()
|
||||
samplingHandler := &samplingHandler{manager: samplingManager}
|
||||
samplingServer := httptest.NewServer(samplingHandler)
|
||||
|
||||
agent := &MockAgent{
|
||||
transport: transport,
|
||||
samplingMgr: samplingManager,
|
||||
samplingSrv: samplingServer,
|
||||
}
|
||||
|
||||
var started sync.WaitGroup
|
||||
started.Add(1)
|
||||
go agent.serve(&started)
|
||||
started.Wait()
|
||||
|
||||
return agent, nil
|
||||
}
|
||||
|
||||
// Close stops the serving of traffic
|
||||
func (s *MockAgent) Close() {
|
||||
atomic.StoreUint32(&s.serving, 0)
|
||||
s.transport.Close()
|
||||
s.samplingSrv.Close()
|
||||
}
|
||||
|
||||
// MockAgent is a mock representation of Jaeger Agent.
|
||||
// It receives spans over UDP, and has an HTTP endpoint for sampling strategies.
|
||||
type MockAgent struct {
|
||||
transport *TUDPTransport
|
||||
jaegerBatches []*jaeger.Batch
|
||||
mutex sync.Mutex
|
||||
serving uint32
|
||||
samplingMgr *samplingManager
|
||||
samplingSrv *httptest.Server
|
||||
}
|
||||
|
||||
// SpanServerAddr returns the UDP host:port where MockAgent listens for spans
|
||||
func (s *MockAgent) SpanServerAddr() string {
|
||||
return s.transport.Addr().String()
|
||||
}
|
||||
|
||||
// SpanServerClient returns a UDP client that can be used to send spans to the MockAgent
|
||||
func (s *MockAgent) SpanServerClient() (agent.Agent, error) {
|
||||
return utils.NewAgentClientUDP(s.SpanServerAddr(), 0)
|
||||
}
|
||||
|
||||
// SamplingServerAddr returns the host:port of HTTP server exposing sampling strategy endpoint
|
||||
func (s *MockAgent) SamplingServerAddr() string {
|
||||
return s.samplingSrv.Listener.Addr().String()
|
||||
}
|
||||
|
||||
func (s *MockAgent) serve(started *sync.WaitGroup) {
|
||||
handler := agent.NewAgentProcessor(s)
|
||||
protocolFact := thrift.NewTCompactProtocolFactory()
|
||||
buf := make([]byte, utils.UDPPacketMaxLength, utils.UDPPacketMaxLength)
|
||||
trans := thrift.NewTMemoryBufferLen(utils.UDPPacketMaxLength)
|
||||
|
||||
atomic.StoreUint32(&s.serving, 1)
|
||||
started.Done()
|
||||
for s.IsServing() {
|
||||
n, err := s.transport.Read(buf)
|
||||
if err == nil {
|
||||
trans.Write(buf[:n])
|
||||
protocol := protocolFact.GetProtocol(trans)
|
||||
handler.Process(protocol, protocol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EmitZipkinBatch is deprecated, use EmitBatch
|
||||
func (s *MockAgent) EmitZipkinBatch(spans []*zipkincore.Span) (err error) {
|
||||
// TODO remove this for 3.0.0
|
||||
return errors.New("Not implemented")
|
||||
}
|
||||
|
||||
// GetZipkinSpans is deprecated use GetJaegerBatches
|
||||
func (s *MockAgent) GetZipkinSpans() []*zipkincore.Span {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetZipkinSpans is deprecated use ResetJaegerBatches
|
||||
func (s *MockAgent) ResetZipkinSpans() {}
|
||||
|
||||
// EmitBatch implements EmitBatch() of TChanSamplingManagerServer
|
||||
func (s *MockAgent) EmitBatch(batch *jaeger.Batch) (err error) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
s.jaegerBatches = append(s.jaegerBatches, batch)
|
||||
return err
|
||||
}
|
||||
|
||||
// IsServing indicates whether the server is currently serving traffic
|
||||
func (s *MockAgent) IsServing() bool {
|
||||
return atomic.LoadUint32(&s.serving) == 1
|
||||
}
|
||||
|
||||
// AddSamplingStrategy registers a sampling strategy for a service
|
||||
func (s *MockAgent) AddSamplingStrategy(service string, strategy *sampling.SamplingStrategyResponse) {
|
||||
s.samplingMgr.AddSamplingStrategy(service, strategy)
|
||||
}
|
||||
|
||||
// GetJaegerBatches returns accumulated Jaeger batches
|
||||
func (s *MockAgent) GetJaegerBatches() []*jaeger.Batch {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
n := len(s.jaegerBatches)
|
||||
batches := make([]*jaeger.Batch, n, n)
|
||||
copy(batches, s.jaegerBatches)
|
||||
return batches
|
||||
}
|
||||
|
||||
// ResetJaegerBatches discards accumulated Jaeger batches
|
||||
func (s *MockAgent) ResetJaegerBatches() {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
s.jaegerBatches = nil
|
||||
}
|
||||
|
||||
type samplingHandler struct {
|
||||
manager *samplingManager
|
||||
}
|
||||
|
||||
func (h *samplingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
services := r.URL.Query()["service"]
|
||||
if len(services) == 0 {
|
||||
http.Error(w, "'service' parameter is empty", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if len(services) > 1 {
|
||||
http.Error(w, "'service' parameter must occur only once", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
resp, err := h.manager.GetSamplingStrategy(services[0])
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error retrieving strategy: %+v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
json, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
http.Error(w, "Cannot marshall Thrift to JSON", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
if _, err := w.Write(json); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/uber/jaeger-client-go/thrift-gen/sampling"
|
||||
)
|
||||
|
||||
func newSamplingManager() *samplingManager {
|
||||
return &samplingManager{
|
||||
sampling: make(map[string]*sampling.SamplingStrategyResponse),
|
||||
}
|
||||
}
|
||||
|
||||
type samplingManager struct {
|
||||
sampling map[string]*sampling.SamplingStrategyResponse
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// GetSamplingStrategy implements handler method of sampling.SamplingManager
|
||||
func (s *samplingManager) GetSamplingStrategy(serviceName string) (*sampling.SamplingStrategyResponse, error) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
if strategy, ok := s.sampling[serviceName]; ok {
|
||||
return strategy, nil
|
||||
}
|
||||
return &sampling.SamplingStrategyResponse{
|
||||
StrategyType: sampling.SamplingStrategyType_PROBABILISTIC,
|
||||
ProbabilisticSampling: &sampling.ProbabilisticSamplingStrategy{
|
||||
SamplingRate: 0.01,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
// AddSamplingStrategy registers a sampling strategy for a service
|
||||
func (s *samplingManager) AddSamplingStrategy(service string, strategy *sampling.SamplingStrategyResponse) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
s.sampling[service] = strategy
|
||||
}
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/apache/thrift/lib/go/thrift"
|
||||
)
|
||||
|
||||
const (
|
||||
// used in RemainingBytes()
|
||||
maxRemainingBytes = ^uint64(0)
|
||||
)
|
||||
|
||||
// TUDPTransport does UDP as a thrift.TTransport (read-only, write functions not implemented).
|
||||
type TUDPTransport struct {
|
||||
conn *net.UDPConn
|
||||
addr net.Addr
|
||||
writeBuf bytes.Buffer
|
||||
closed uint32
|
||||
}
|
||||
|
||||
// NewTUDPServerTransport creates a net.UDPConn-backed TTransport for Thrift servers
|
||||
// It will listen for incoming udp packets on the specified host/port
|
||||
// Example:
|
||||
// trans, err := utils.NewTUDPClientTransport("localhost:9001")
|
||||
func NewTUDPServerTransport(hostPort string) (*TUDPTransport, error) {
|
||||
addr, err := net.ResolveUDPAddr("udp", hostPort)
|
||||
if err != nil {
|
||||
return nil, thrift.NewTTransportException(thrift.NOT_OPEN, err.Error())
|
||||
}
|
||||
conn, err := net.ListenUDP(addr.Network(), addr)
|
||||
if err != nil {
|
||||
return nil, thrift.NewTTransportException(thrift.NOT_OPEN, err.Error())
|
||||
}
|
||||
return &TUDPTransport{addr: conn.LocalAddr(), conn: conn}, nil
|
||||
}
|
||||
|
||||
// Open does nothing as connection is opened on creation
|
||||
// Required to maintain thrift.TTransport interface
|
||||
func (p *TUDPTransport) Open() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Conn retrieves the underlying net.UDPConn
|
||||
func (p *TUDPTransport) Conn() *net.UDPConn {
|
||||
return p.conn
|
||||
}
|
||||
|
||||
// IsOpen returns true if the connection is open
|
||||
func (p *TUDPTransport) IsOpen() bool {
|
||||
return p.conn != nil && atomic.LoadUint32(&p.closed) == 0
|
||||
}
|
||||
|
||||
// Close closes the connection
|
||||
func (p *TUDPTransport) Close() error {
|
||||
if p.conn != nil && atomic.CompareAndSwapUint32(&p.closed, 0, 1) {
|
||||
return p.conn.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Addr returns the address that the transport is listening on or writing to
|
||||
func (p *TUDPTransport) Addr() net.Addr {
|
||||
return p.addr
|
||||
}
|
||||
|
||||
// Read reads one UDP packet and puts it in the specified buf
|
||||
func (p *TUDPTransport) Read(buf []byte) (int, error) {
|
||||
if !p.IsOpen() {
|
||||
return 0, thrift.NewTTransportException(thrift.NOT_OPEN, "Connection not open")
|
||||
}
|
||||
n, err := p.conn.Read(buf)
|
||||
return n, thrift.NewTTransportExceptionFromError(err)
|
||||
}
|
||||
|
||||
// RemainingBytes returns the max number of bytes (same as Thrift's StreamTransport) as we
|
||||
// do not know how many bytes we have left.
|
||||
func (p *TUDPTransport) RemainingBytes() uint64 {
|
||||
return maxRemainingBytes
|
||||
}
|
||||
|
||||
// Write writes specified buf to the write buffer
|
||||
func (p *TUDPTransport) Write(buf []byte) (int, error) {
|
||||
return 0, thrift.NewTTransportException(thrift.UNKNOWN_TRANSPORT_EXCEPTION, "Write not implemented")
|
||||
}
|
||||
|
||||
// Flush flushes the write buffer as one udp packet
|
||||
func (p *TUDPTransport) Flush() error {
|
||||
return thrift.NewTTransportException(thrift.UNKNOWN_TRANSPORT_EXCEPTION, "Flush not implemented")
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package transport defines various transports that can be used with
|
||||
// RemoteReporter to send spans out of process. Transport is responsible
|
||||
// for serializing the spans into a specific format suitable for sending
|
||||
// to the tracing backend. Examples may include Thrift over UDP, Thrift
|
||||
// or JSON over HTTP, Thrift over Kafka, etc.
|
||||
//
|
||||
// Implementations are NOT required to be thread-safe; the RemoteReporter
|
||||
// is expected to only call methods on the Transport from the same go-routine.
|
||||
package transport
|
||||
-155
@@ -1,155 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package transport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/apache/thrift/lib/go/thrift"
|
||||
|
||||
"github.com/uber/jaeger-client-go"
|
||||
j "github.com/uber/jaeger-client-go/thrift-gen/jaeger"
|
||||
)
|
||||
|
||||
// Default timeout for http request in seconds
|
||||
const defaultHTTPTimeout = time.Second * 5
|
||||
|
||||
// HTTPTransport implements Transport by forwarding spans to a http server.
|
||||
type HTTPTransport struct {
|
||||
url string
|
||||
client *http.Client
|
||||
batchSize int
|
||||
spans []*j.Span
|
||||
process *j.Process
|
||||
httpCredentials *HTTPBasicAuthCredentials
|
||||
}
|
||||
|
||||
// HTTPBasicAuthCredentials stores credentials for HTTP basic auth.
|
||||
type HTTPBasicAuthCredentials struct {
|
||||
username string
|
||||
password string
|
||||
}
|
||||
|
||||
// HTTPOption sets a parameter for the HttpCollector
|
||||
type HTTPOption func(c *HTTPTransport)
|
||||
|
||||
// HTTPTimeout sets maximum timeout for http request.
|
||||
func HTTPTimeout(duration time.Duration) HTTPOption {
|
||||
return func(c *HTTPTransport) { c.client.Timeout = duration }
|
||||
}
|
||||
|
||||
// HTTPBatchSize sets the maximum batch size, after which a collect will be
|
||||
// triggered. The default batch size is 100 spans.
|
||||
func HTTPBatchSize(n int) HTTPOption {
|
||||
return func(c *HTTPTransport) { c.batchSize = n }
|
||||
}
|
||||
|
||||
// HTTPBasicAuth sets the credentials required to perform HTTP basic auth
|
||||
func HTTPBasicAuth(username string, password string) HTTPOption {
|
||||
return func(c *HTTPTransport) {
|
||||
c.httpCredentials = &HTTPBasicAuthCredentials{username: username, password: password}
|
||||
}
|
||||
}
|
||||
|
||||
// NewHTTPTransport returns a new HTTP-backend transport. url should be an http
|
||||
// url of the collector to handle POST request, typically something like:
|
||||
// http://hostname:14268/api/traces?format=jaeger.thrift
|
||||
func NewHTTPTransport(url string, options ...HTTPOption) *HTTPTransport {
|
||||
c := &HTTPTransport{
|
||||
url: url,
|
||||
client: &http.Client{Timeout: defaultHTTPTimeout},
|
||||
batchSize: 100,
|
||||
spans: []*j.Span{},
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(c)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Append implements Transport.
|
||||
func (c *HTTPTransport) Append(span *jaeger.Span) (int, error) {
|
||||
if c.process == nil {
|
||||
c.process = jaeger.BuildJaegerProcessThrift(span)
|
||||
}
|
||||
jSpan := jaeger.BuildJaegerThrift(span)
|
||||
c.spans = append(c.spans, jSpan)
|
||||
if len(c.spans) >= c.batchSize {
|
||||
return c.Flush()
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Flush implements Transport.
|
||||
func (c *HTTPTransport) Flush() (int, error) {
|
||||
count := len(c.spans)
|
||||
if count == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
err := c.send(c.spans)
|
||||
c.spans = c.spans[:0]
|
||||
return count, err
|
||||
}
|
||||
|
||||
// Close implements Transport.
|
||||
func (c *HTTPTransport) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *HTTPTransport) send(spans []*j.Span) error {
|
||||
batch := &j.Batch{
|
||||
Spans: spans,
|
||||
Process: c.process,
|
||||
}
|
||||
body, err := serializeThrift(batch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest("POST", c.url, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-thrift")
|
||||
|
||||
if c.httpCredentials != nil {
|
||||
req.SetBasicAuth(c.httpCredentials.username, c.httpCredentials.password)
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
return fmt.Errorf("error from collector: %d", resp.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func serializeThrift(obj thrift.TStruct) (*bytes.Buffer, error) {
|
||||
t := thrift.NewTMemoryBuffer()
|
||||
p := thrift.NewTBinaryProtocolTransport(t)
|
||||
if err := obj.Write(p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t.Buffer, nil
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package zipkin provides various Transports that can be used
|
||||
// with RemoteReporter for submitting traces to Zipkin backend.
|
||||
package zipkin
|
||||
-166
@@ -1,166 +0,0 @@
|
||||
// Copyright (c) 2017 The OpenTracing Authors
|
||||
// Copyright (c) 2016 Bas van Beek
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package zipkin
|
||||
|
||||
// This code is adapted from 'collector-http.go' from
|
||||
// https://github.com/openzipkin/zipkin-go-opentracing/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/apache/thrift/lib/go/thrift"
|
||||
|
||||
"github.com/uber/jaeger-client-go"
|
||||
"github.com/uber/jaeger-client-go/log"
|
||||
"github.com/uber/jaeger-client-go/thrift-gen/zipkincore"
|
||||
)
|
||||
|
||||
// Default timeout for http request in seconds
|
||||
const defaultHTTPTimeout = time.Second * 5
|
||||
|
||||
// HTTPTransport implements Transport by forwarding spans to a http server.
|
||||
type HTTPTransport struct {
|
||||
logger jaeger.Logger
|
||||
url string
|
||||
client *http.Client
|
||||
batchSize int
|
||||
batch []*zipkincore.Span
|
||||
httpCredentials *HTTPBasicAuthCredentials
|
||||
}
|
||||
|
||||
// HTTPBasicAuthCredentials stores credentials for HTTP basic auth.
|
||||
type HTTPBasicAuthCredentials struct {
|
||||
username string
|
||||
password string
|
||||
}
|
||||
|
||||
// HTTPOption sets a parameter for the HttpCollector
|
||||
type HTTPOption func(c *HTTPTransport)
|
||||
|
||||
// HTTPLogger sets the logger used to report errors in the collection
|
||||
// process. By default, a no-op logger is used, i.e. no errors are logged
|
||||
// anywhere. It's important to set this option in a production service.
|
||||
func HTTPLogger(logger jaeger.Logger) HTTPOption {
|
||||
return func(c *HTTPTransport) { c.logger = logger }
|
||||
}
|
||||
|
||||
// HTTPTimeout sets maximum timeout for http request.
|
||||
func HTTPTimeout(duration time.Duration) HTTPOption {
|
||||
return func(c *HTTPTransport) { c.client.Timeout = duration }
|
||||
}
|
||||
|
||||
// HTTPBatchSize sets the maximum batch size, after which a collect will be
|
||||
// triggered. The default batch size is 100 spans.
|
||||
func HTTPBatchSize(n int) HTTPOption {
|
||||
return func(c *HTTPTransport) { c.batchSize = n }
|
||||
}
|
||||
|
||||
// HTTPBasicAuth sets the credentials required to perform HTTP basic auth
|
||||
func HTTPBasicAuth(username string, password string) HTTPOption {
|
||||
return func(c *HTTPTransport) {
|
||||
c.httpCredentials = &HTTPBasicAuthCredentials{username: username, password: password}
|
||||
}
|
||||
}
|
||||
|
||||
// NewHTTPTransport returns a new HTTP-backend transport. url should be an http
|
||||
// url to handle post request, typically something like:
|
||||
// http://hostname:9411/api/v1/spans
|
||||
func NewHTTPTransport(url string, options ...HTTPOption) (*HTTPTransport, error) {
|
||||
c := &HTTPTransport{
|
||||
logger: log.NullLogger,
|
||||
url: url,
|
||||
client: &http.Client{Timeout: defaultHTTPTimeout},
|
||||
batchSize: 100,
|
||||
batch: []*zipkincore.Span{},
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(c)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Append implements Transport.
|
||||
func (c *HTTPTransport) Append(span *jaeger.Span) (int, error) {
|
||||
zSpan := jaeger.BuildZipkinThrift(span)
|
||||
c.batch = append(c.batch, zSpan)
|
||||
if len(c.batch) >= c.batchSize {
|
||||
return c.Flush()
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Flush implements Transport.
|
||||
func (c *HTTPTransport) Flush() (int, error) {
|
||||
count := len(c.batch)
|
||||
if count == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
err := c.send(c.batch)
|
||||
c.batch = c.batch[:0]
|
||||
return count, err
|
||||
}
|
||||
|
||||
// Close implements Transport.
|
||||
func (c *HTTPTransport) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func httpSerialize(spans []*zipkincore.Span) (*bytes.Buffer, error) {
|
||||
t := thrift.NewTMemoryBuffer()
|
||||
p := thrift.NewTBinaryProtocolTransport(t)
|
||||
if err := p.WriteListBegin(thrift.STRUCT, len(spans)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, s := range spans {
|
||||
if err := s.Write(p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := p.WriteListEnd(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t.Buffer, nil
|
||||
}
|
||||
|
||||
func (c *HTTPTransport) send(spans []*zipkincore.Span) error {
|
||||
body, err := httpSerialize(spans)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest("POST", c.url, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-thrift")
|
||||
|
||||
if c.httpCredentials != nil {
|
||||
req.SetBasicAuth(c.httpCredentials.username, c.httpCredentials.password)
|
||||
}
|
||||
|
||||
_, err = c.client.Do(req)
|
||||
|
||||
return err
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
make crossdock
|
||||
|
||||
export REPO=jaegertracing/xdock-go
|
||||
export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)
|
||||
export TAG=`if [ "$BRANCH" == "master" ]; then echo "latest"; else echo "${BRANCH///}"; fi`
|
||||
echo "TRAVIS_BRANCH=$TRAVIS_BRANCH, REPO=$REPO, PR=$PR, BRANCH=$BRANCH, TAG=$TAG"
|
||||
|
||||
# Only push the docker container to Docker Hub for master branch
|
||||
if [[ "$BRANCH" == "master" && "$TRAVIS_SECURE_ENV_VARS" == "true" ]]; then echo 'upload to Docker Hub'; else echo 'skip docker upload for PR'; exit 0; fi
|
||||
|
||||
docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||
|
||||
set -x
|
||||
|
||||
docker build -f crossdock/Dockerfile -t $REPO:$COMMIT .
|
||||
|
||||
docker tag $REPO:$COMMIT $REPO:$TAG
|
||||
docker tag $REPO:$COMMIT $REPO:travis-$TRAVIS_BUILD_NUMBER
|
||||
docker push $REPO
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
docker version
|
||||
|
||||
# Install docker-compose
|
||||
sudo rm -f /usr/local/bin/docker-compose
|
||||
curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
chmod +x docker-compose
|
||||
sudo mv docker-compose /usr/local/bin
|
||||
docker-compose version
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
# Zipkin compatibility features
|
||||
|
||||
## `NewZipkinB3HTTPHeaderPropagator()`
|
||||
|
||||
Adds support for injecting and extracting Zipkin B3 Propagation HTTP headers,
|
||||
for use with other Zipkin collectors.
|
||||
|
||||
```go
|
||||
|
||||
// ...
|
||||
import (
|
||||
"github.com/uber/jaeger-client-go/zipkin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// ...
|
||||
zipkinPropagator := zipkin.NewZipkinB3HTTPHeaderPropagator()
|
||||
injector := jaeger.TracerOptions.Injector(opentracing.HTTPHeaders, zipkinPropagator)
|
||||
extractor := jaeger.TracerOptions.Extractor(opentracing.HTTPHeaders, zipkinPropagator)
|
||||
|
||||
// Zipkin shares span ID between client and server spans; it must be enabled via the following option.
|
||||
zipkinSharedRPCSpan := jaeger.TracerOptions.ZipkinSharedRPCSpan(true)
|
||||
|
||||
// create Jaeger tracer
|
||||
tracer, closer := jaeger.NewTracer(
|
||||
"myService",
|
||||
mySampler, // as usual
|
||||
myReporter // as usual
|
||||
injector,
|
||||
extractor,
|
||||
zipkinSharedRPCSpan,
|
||||
)
|
||||
}
|
||||
```
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package zipkin comprises Zipkin functionality for Zipkin compatiblity.
|
||||
package zipkin
|
||||
-95
@@ -1,95 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package zipkin
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
|
||||
"github.com/uber/jaeger-client-go"
|
||||
)
|
||||
|
||||
// Propagator is an Injector and Extractor
|
||||
type Propagator struct{}
|
||||
|
||||
// NewZipkinB3HTTPHeaderPropagator creates a Propagator for extracting and injecting
|
||||
// Zipkin HTTP B3 headers into SpanContexts.
|
||||
func NewZipkinB3HTTPHeaderPropagator() Propagator {
|
||||
return Propagator{}
|
||||
}
|
||||
|
||||
// Inject conforms to the Injector interface for decoding Zipkin HTTP B3 headers
|
||||
func (p Propagator) Inject(
|
||||
sc jaeger.SpanContext,
|
||||
abstractCarrier interface{},
|
||||
) error {
|
||||
textMapWriter, ok := abstractCarrier.(opentracing.TextMapWriter)
|
||||
if !ok {
|
||||
return opentracing.ErrInvalidCarrier
|
||||
}
|
||||
|
||||
// TODO this needs to change to support 128bit IDs
|
||||
textMapWriter.Set("x-b3-traceid", strconv.FormatUint(sc.TraceID().Low, 16))
|
||||
if sc.ParentID() != 0 {
|
||||
textMapWriter.Set("x-b3-parentspanid", strconv.FormatUint(uint64(sc.ParentID()), 16))
|
||||
}
|
||||
textMapWriter.Set("x-b3-spanid", strconv.FormatUint(uint64(sc.SpanID()), 16))
|
||||
if sc.IsSampled() {
|
||||
textMapWriter.Set("x-b3-sampled", "1")
|
||||
} else {
|
||||
textMapWriter.Set("x-b3-sampled", "0")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Extract conforms to the Extractor interface for encoding Zipkin HTTP B3 headers
|
||||
func (p Propagator) Extract(abstractCarrier interface{}) (jaeger.SpanContext, error) {
|
||||
textMapReader, ok := abstractCarrier.(opentracing.TextMapReader)
|
||||
if !ok {
|
||||
return jaeger.SpanContext{}, opentracing.ErrInvalidCarrier
|
||||
}
|
||||
var traceID uint64
|
||||
var spanID uint64
|
||||
var parentID uint64
|
||||
sampled := false
|
||||
err := textMapReader.ForeachKey(func(rawKey, value string) error {
|
||||
key := strings.ToLower(rawKey) // TODO not necessary for plain TextMap
|
||||
var err error
|
||||
if key == "x-b3-traceid" {
|
||||
traceID, err = strconv.ParseUint(value, 16, 64)
|
||||
} else if key == "x-b3-parentspanid" {
|
||||
parentID, err = strconv.ParseUint(value, 16, 64)
|
||||
} else if key == "x-b3-spanid" {
|
||||
spanID, err = strconv.ParseUint(value, 16, 64)
|
||||
} else if key == "x-b3-sampled" && value == "1" {
|
||||
sampled = true
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return jaeger.SpanContext{}, err
|
||||
}
|
||||
if traceID == 0 {
|
||||
return jaeger.SpanContext{}, opentracing.ErrSpanContextNotFound
|
||||
}
|
||||
return jaeger.NewSpanContext(
|
||||
jaeger.TraceID{Low: traceID},
|
||||
jaeger.SpanID(spanID),
|
||||
jaeger.SpanID(parentID),
|
||||
sampled, nil), nil
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package xkit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
"github.com/go-kit/kit/log/level"
|
||||
)
|
||||
|
||||
// LoggerOption sets a parameter for the Logger.
|
||||
type LoggerOption func(*Logger)
|
||||
|
||||
// MessageKey sets the key for the actual log message. By default, it's "msg".
|
||||
func MessageKey(key string) LoggerOption {
|
||||
return func(l *Logger) { l.messageKey = key }
|
||||
}
|
||||
|
||||
// Logger wraps a go-kit logger instance in a Jaeger client compatible one.
|
||||
type Logger struct {
|
||||
infoLogger log.Logger
|
||||
errorLogger log.Logger
|
||||
|
||||
messageKey string
|
||||
}
|
||||
|
||||
// NewLogger creates a new Jaeger client logger from a go-kit one.
|
||||
func NewLogger(kitlogger log.Logger, options ...LoggerOption) *Logger {
|
||||
logger := &Logger{
|
||||
infoLogger: level.Info(kitlogger),
|
||||
errorLogger: level.Error(kitlogger),
|
||||
|
||||
messageKey: "msg",
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(logger)
|
||||
}
|
||||
|
||||
return logger
|
||||
}
|
||||
|
||||
// Error implements the github.com/uber/jaeger-client-go/log.Logger interface.
|
||||
func (l *Logger) Error(msg string) {
|
||||
l.errorLogger.Log(l.messageKey, msg)
|
||||
}
|
||||
|
||||
// Infof implements the github.com/uber/jaeger-client-go/log.Logger interface.
|
||||
func (l *Logger) Infof(msg string, args ...interface{}) {
|
||||
l.infoLogger.Log(l.messageKey, fmt.Sprintf(msg, args...))
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package expvar
|
||||
|
||||
import (
|
||||
"github.com/go-kit/kit/metrics"
|
||||
"github.com/go-kit/kit/metrics/expvar"
|
||||
|
||||
"github.com/uber/jaeger-lib/metrics/go-kit"
|
||||
)
|
||||
|
||||
// NewFactory creates a new metrics factory using go-kit expvar package.
|
||||
// buckets is the number of buckets to be used in histograms.
|
||||
func NewFactory(buckets int) xkit.Factory {
|
||||
return factory{
|
||||
buckets: buckets,
|
||||
}
|
||||
}
|
||||
|
||||
type factory struct {
|
||||
buckets int
|
||||
}
|
||||
|
||||
func (f factory) Counter(name string) metrics.Counter {
|
||||
return expvar.NewCounter(name)
|
||||
}
|
||||
|
||||
func (f factory) Histogram(name string) metrics.Histogram {
|
||||
return expvar.NewHistogram(name, f.buckets)
|
||||
}
|
||||
|
||||
func (f factory) Gauge(name string) metrics.Gauge {
|
||||
return expvar.NewGauge(name)
|
||||
}
|
||||
|
||||
func (f factory) Capabilities() xkit.Capabilities {
|
||||
return xkit.Capabilities{Tagging: false}
|
||||
}
|
||||
-161
@@ -1,161 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package xkit
|
||||
|
||||
import (
|
||||
kit "github.com/go-kit/kit/metrics"
|
||||
|
||||
"github.com/uber/jaeger-lib/metrics"
|
||||
)
|
||||
|
||||
// Factory provides a unified interface for creating named metrics
|
||||
// from various go-kit metrics implementations.
|
||||
type Factory interface {
|
||||
Counter(name string) kit.Counter
|
||||
Gauge(name string) kit.Gauge
|
||||
Histogram(name string) kit.Histogram
|
||||
Capabilities() Capabilities
|
||||
}
|
||||
|
||||
// Capabilities describes capabilities of a specific metrics factory.
|
||||
type Capabilities struct {
|
||||
// Tagging indicates whether the factory has the capability for tagged metrics
|
||||
Tagging bool
|
||||
}
|
||||
|
||||
// FactoryOption is a function that adjusts some parameters of the factory.
|
||||
type FactoryOption func(*factory)
|
||||
|
||||
// Wrap is used to create an adapter from xkit.Factory to metrics.Factory.
|
||||
func Wrap(namespace string, f Factory, options ...FactoryOption) metrics.Factory {
|
||||
factory := &factory{
|
||||
scope: namespace,
|
||||
factory: f,
|
||||
scopeSep: ".",
|
||||
tagsSep: ".",
|
||||
tagKVSep: "_",
|
||||
}
|
||||
for i := range options {
|
||||
options[i](factory)
|
||||
}
|
||||
return factory
|
||||
}
|
||||
|
||||
// ScopeSeparator returns an option that overrides default scope separator.
|
||||
func ScopeSeparator(scopeSep string) FactoryOption {
|
||||
return func(f *factory) {
|
||||
f.scopeSep = scopeSep
|
||||
}
|
||||
}
|
||||
|
||||
// TagsSeparator returns an option that overrides default tags separator.
|
||||
func TagsSeparator(tagsSep string) FactoryOption {
|
||||
return func(f *factory) {
|
||||
f.tagsSep = tagsSep
|
||||
}
|
||||
}
|
||||
|
||||
type factory struct {
|
||||
scope string
|
||||
tags map[string]string
|
||||
factory Factory
|
||||
scopeSep string
|
||||
tagsSep string
|
||||
tagKVSep string
|
||||
}
|
||||
|
||||
func (f *factory) subScope(name string) string {
|
||||
if f.scope == "" {
|
||||
return name
|
||||
}
|
||||
if name == "" {
|
||||
return f.scope
|
||||
}
|
||||
return f.scope + f.scopeSep + name
|
||||
}
|
||||
|
||||
// nameAndTagsList returns a name and tags list for the new metrics.
|
||||
// The name is a concatenation of nom and the current factory scope.
|
||||
// The tags list is a flattened list of passed tags merged with factory tags.
|
||||
// If the underlying factory does not support tags, then the tags are
|
||||
// transformed into a string and appended to the name.
|
||||
func (f *factory) nameAndTagsList(nom string, tags map[string]string) (name string, tagsList []string) {
|
||||
mergedTags := f.mergeTags(tags)
|
||||
name = f.subScope(nom)
|
||||
tagsList = f.tagsList(mergedTags)
|
||||
if len(tagsList) == 0 || f.factory.Capabilities().Tagging {
|
||||
return
|
||||
}
|
||||
name = metrics.GetKey(name, mergedTags, f.tagsSep, f.tagKVSep)
|
||||
tagsList = nil
|
||||
return
|
||||
}
|
||||
|
||||
func (f *factory) Counter(name string, tags map[string]string) metrics.Counter {
|
||||
name, tagsList := f.nameAndTagsList(name, tags)
|
||||
counter := f.factory.Counter(name)
|
||||
if len(tagsList) > 0 {
|
||||
counter = counter.With(tagsList...)
|
||||
}
|
||||
return NewCounter(counter)
|
||||
}
|
||||
|
||||
func (f *factory) Timer(name string, tags map[string]string) metrics.Timer {
|
||||
name, tagsList := f.nameAndTagsList(name, tags)
|
||||
hist := f.factory.Histogram(name)
|
||||
if len(tagsList) > 0 {
|
||||
hist = hist.With(tagsList...)
|
||||
}
|
||||
return NewTimer(hist)
|
||||
}
|
||||
|
||||
func (f *factory) Gauge(name string, tags map[string]string) metrics.Gauge {
|
||||
name, tagsList := f.nameAndTagsList(name, tags)
|
||||
gauge := f.factory.Gauge(name)
|
||||
if len(tagsList) > 0 {
|
||||
gauge = gauge.With(tagsList...)
|
||||
}
|
||||
return NewGauge(gauge)
|
||||
}
|
||||
|
||||
func (f *factory) Namespace(name string, tags map[string]string) metrics.Factory {
|
||||
return &factory{
|
||||
scope: f.subScope(name),
|
||||
tags: f.mergeTags(tags),
|
||||
factory: f.factory,
|
||||
scopeSep: f.scopeSep,
|
||||
tagsSep: f.tagsSep,
|
||||
tagKVSep: f.tagKVSep,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *factory) tagsList(a map[string]string) []string {
|
||||
ret := make([]string, 0, 2*len(a))
|
||||
for k, v := range a {
|
||||
ret = append(ret, k, v)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (f *factory) mergeTags(tags map[string]string) map[string]string {
|
||||
ret := make(map[string]string, len(f.tags)+len(tags))
|
||||
for k, v := range f.tags {
|
||||
ret[k] = v
|
||||
}
|
||||
for k, v := range tags {
|
||||
ret[k] = v
|
||||
}
|
||||
return ret
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package influx
|
||||
|
||||
import (
|
||||
"github.com/go-kit/kit/metrics"
|
||||
"github.com/go-kit/kit/metrics/influx"
|
||||
|
||||
"github.com/uber/jaeger-lib/metrics/go-kit"
|
||||
)
|
||||
|
||||
// NewFactory creates a new metrics factory using go-kit influx package.
|
||||
func NewFactory(client *influx.Influx) xkit.Factory {
|
||||
return factory{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
type factory struct {
|
||||
client *influx.Influx
|
||||
}
|
||||
|
||||
func (f factory) Counter(name string) metrics.Counter {
|
||||
return f.client.NewCounter(name)
|
||||
}
|
||||
|
||||
func (f factory) Histogram(name string) metrics.Histogram {
|
||||
return f.client.NewHistogram(name)
|
||||
}
|
||||
|
||||
func (f factory) Gauge(name string) metrics.Gauge {
|
||||
return f.client.NewGauge(name)
|
||||
}
|
||||
|
||||
func (f factory) Capabilities() xkit.Capabilities {
|
||||
return xkit.Capabilities{Tagging: true}
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package xkit
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
kit "github.com/go-kit/kit/metrics"
|
||||
)
|
||||
|
||||
// Counter is an adapter from go-kit Counter to jaeger-lib Counter
|
||||
type Counter struct {
|
||||
counter kit.Counter
|
||||
}
|
||||
|
||||
// NewCounter creates a new Counter
|
||||
func NewCounter(counter kit.Counter) *Counter {
|
||||
return &Counter{counter: counter}
|
||||
}
|
||||
|
||||
// Inc adds the given value to the counter.
|
||||
func (c *Counter) Inc(delta int64) {
|
||||
c.counter.Add(float64(delta))
|
||||
}
|
||||
|
||||
// Gauge is an adapter from go-kit Gauge to jaeger-lib Gauge
|
||||
type Gauge struct {
|
||||
gauge kit.Gauge
|
||||
}
|
||||
|
||||
// NewGauge creates a new Gauge
|
||||
func NewGauge(gauge kit.Gauge) *Gauge {
|
||||
return &Gauge{gauge: gauge}
|
||||
}
|
||||
|
||||
// Update the gauge to the value passed in.
|
||||
func (g *Gauge) Update(value int64) {
|
||||
g.gauge.Set(float64(value))
|
||||
}
|
||||
|
||||
// Timer is an adapter from go-kit Histogram to jaeger-lib Timer
|
||||
type Timer struct {
|
||||
hist kit.Histogram
|
||||
}
|
||||
|
||||
// NewTimer creates a new Timer
|
||||
func NewTimer(hist kit.Histogram) *Timer {
|
||||
return &Timer{hist: hist}
|
||||
}
|
||||
|
||||
// Record saves the time passed in.
|
||||
func (t *Timer) Record(delta time.Duration) {
|
||||
t.hist.Observe(delta.Seconds())
|
||||
}
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-kit/kit/metrics"
|
||||
kitprom "github.com/go-kit/kit/metrics/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/uber/jaeger-lib/metrics/go-kit"
|
||||
)
|
||||
|
||||
var normalizer = strings.NewReplacer(
|
||||
".", "_",
|
||||
"-", "_",
|
||||
)
|
||||
|
||||
// NewFactory creates a new metrics factory using go-kit prometheus package.
|
||||
// buckets define the buckets into which histogram observations are counted.
|
||||
// If buckets == nil, the default value prometheus.DefBuckets is used.
|
||||
func NewFactory(namespace, subsystem string, buckets []float64) xkit.Factory {
|
||||
return &factory{
|
||||
namespace: namespace,
|
||||
subsystem: subsystem,
|
||||
buckets: buckets,
|
||||
}
|
||||
}
|
||||
|
||||
type factory struct {
|
||||
namespace string
|
||||
subsystem string
|
||||
buckets []float64
|
||||
}
|
||||
|
||||
func (f *factory) Counter(name string) metrics.Counter {
|
||||
opts := prometheus.CounterOpts{
|
||||
Namespace: f.namespace,
|
||||
Subsystem: f.subsystem,
|
||||
Name: normalizer.Replace(name),
|
||||
Help: name,
|
||||
}
|
||||
return kitprom.NewCounterFrom(opts, nil)
|
||||
}
|
||||
|
||||
func (f *factory) Histogram(name string) metrics.Histogram {
|
||||
opts := prometheus.HistogramOpts{
|
||||
Namespace: f.namespace,
|
||||
Subsystem: f.subsystem,
|
||||
Name: normalizer.Replace(name),
|
||||
Help: name,
|
||||
Buckets: f.buckets,
|
||||
}
|
||||
return kitprom.NewHistogramFrom(opts, nil)
|
||||
}
|
||||
|
||||
func (f *factory) Gauge(name string) metrics.Gauge {
|
||||
opts := prometheus.GaugeOpts{
|
||||
Namespace: f.namespace,
|
||||
Subsystem: f.subsystem,
|
||||
Name: normalizer.Replace(name),
|
||||
Help: name,
|
||||
}
|
||||
return kitprom.NewGaugeFrom(opts, nil)
|
||||
}
|
||||
|
||||
func (f *factory) Capabilities() xkit.Capabilities {
|
||||
return xkit.Capabilities{Tagging: true}
|
||||
}
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package multi
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/uber/jaeger-lib/metrics"
|
||||
)
|
||||
|
||||
// Factory is a metrics factory that dispatches to multiple metrics backends.
|
||||
type Factory struct {
|
||||
factories []metrics.Factory
|
||||
}
|
||||
|
||||
// New creates a new multi.Factory that will dispatch to multiple metrics backends.
|
||||
func New(factories ...metrics.Factory) *Factory {
|
||||
return &Factory{
|
||||
factories: factories,
|
||||
}
|
||||
}
|
||||
|
||||
type counter struct {
|
||||
counters []metrics.Counter
|
||||
}
|
||||
|
||||
func (c *counter) Inc(delta int64) {
|
||||
for _, counter := range c.counters {
|
||||
counter.Inc(delta)
|
||||
}
|
||||
}
|
||||
|
||||
// Counter implements metrics.Factory interface
|
||||
func (f *Factory) Counter(name string, tags map[string]string) metrics.Counter {
|
||||
counter := &counter{
|
||||
counters: make([]metrics.Counter, len(f.factories)),
|
||||
}
|
||||
for i, factory := range f.factories {
|
||||
counter.counters[i] = factory.Counter(name, tags)
|
||||
}
|
||||
return counter
|
||||
}
|
||||
|
||||
type timer struct {
|
||||
timers []metrics.Timer
|
||||
}
|
||||
|
||||
func (t *timer) Record(delta time.Duration) {
|
||||
for _, timer := range t.timers {
|
||||
timer.Record(delta)
|
||||
}
|
||||
}
|
||||
|
||||
// Timer implements metrics.Factory interface
|
||||
func (f *Factory) Timer(name string, tags map[string]string) metrics.Timer {
|
||||
timer := &timer{
|
||||
timers: make([]metrics.Timer, len(f.factories)),
|
||||
}
|
||||
for i, factory := range f.factories {
|
||||
timer.timers[i] = factory.Timer(name, tags)
|
||||
}
|
||||
return timer
|
||||
}
|
||||
|
||||
type gauge struct {
|
||||
gauges []metrics.Gauge
|
||||
}
|
||||
|
||||
func (t *gauge) Update(value int64) {
|
||||
for _, gauge := range t.gauges {
|
||||
gauge.Update(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Gauge implements metrics.Factory interface
|
||||
func (f *Factory) Gauge(name string, tags map[string]string) metrics.Gauge {
|
||||
gauge := &gauge{
|
||||
gauges: make([]metrics.Gauge, len(f.factories)),
|
||||
}
|
||||
for i, factory := range f.factories {
|
||||
gauge.gauges[i] = factory.Gauge(name, tags)
|
||||
}
|
||||
return gauge
|
||||
}
|
||||
|
||||
// Namespace implements metrics.Factory interface
|
||||
func (f *Factory) Namespace(name string, tags map[string]string) metrics.Factory {
|
||||
newFactory := &Factory{
|
||||
factories: make([]metrics.Factory, len(f.factories)),
|
||||
}
|
||||
for i, factory := range f.factories {
|
||||
newFactory.factories[i] = factory.Namespace(name, tags)
|
||||
}
|
||||
return newFactory
|
||||
}
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
// Copyright (c) 2017 The Jaeger Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
type vectorCache struct {
|
||||
registerer prometheus.Registerer
|
||||
lock sync.Mutex
|
||||
cVecs map[string]*prometheus.CounterVec
|
||||
gVecs map[string]*prometheus.GaugeVec
|
||||
hVecs map[string]*prometheus.HistogramVec
|
||||
}
|
||||
|
||||
func newVectorCache(registerer prometheus.Registerer) *vectorCache {
|
||||
return &vectorCache{
|
||||
registerer: registerer,
|
||||
cVecs: make(map[string]*prometheus.CounterVec),
|
||||
gVecs: make(map[string]*prometheus.GaugeVec),
|
||||
hVecs: make(map[string]*prometheus.HistogramVec),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *vectorCache) getOrMakeCounterVec(opts prometheus.CounterOpts, labelNames []string) *prometheus.CounterVec {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
cacheKey := c.getCacheKey(opts.Name, labelNames)
|
||||
cv, cvExists := c.cVecs[cacheKey]
|
||||
if !cvExists {
|
||||
cv = prometheus.NewCounterVec(opts, labelNames)
|
||||
c.registerer.MustRegister(cv)
|
||||
c.cVecs[cacheKey] = cv
|
||||
}
|
||||
return cv
|
||||
}
|
||||
|
||||
func (c *vectorCache) getOrMakeGaugeVec(opts prometheus.GaugeOpts, labelNames []string) *prometheus.GaugeVec {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
cacheKey := c.getCacheKey(opts.Name, labelNames)
|
||||
gv, gvExists := c.gVecs[cacheKey]
|
||||
if !gvExists {
|
||||
gv = prometheus.NewGaugeVec(opts, labelNames)
|
||||
c.registerer.MustRegister(gv)
|
||||
c.gVecs[cacheKey] = gv
|
||||
}
|
||||
return gv
|
||||
}
|
||||
|
||||
func (c *vectorCache) getOrMakeHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
cacheKey := c.getCacheKey(opts.Name, labelNames)
|
||||
hv, hvExists := c.hVecs[cacheKey]
|
||||
if !hvExists {
|
||||
hv = prometheus.NewHistogramVec(opts, labelNames)
|
||||
c.registerer.MustRegister(hv)
|
||||
c.hVecs[cacheKey] = hv
|
||||
}
|
||||
return hv
|
||||
}
|
||||
|
||||
func (c *vectorCache) getCacheKey(name string, labels []string) string {
|
||||
return strings.Join(append([]string{name}, labels...), "||")
|
||||
}
|
||||
-216
@@ -1,216 +0,0 @@
|
||||
// Copyright (c) 2017 The Jaeger Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/uber/jaeger-lib/metrics"
|
||||
)
|
||||
|
||||
// Factory implements metrics.Factory backed by Prometheus registry.
|
||||
type Factory struct {
|
||||
scope string
|
||||
tags map[string]string
|
||||
cache *vectorCache
|
||||
buckets []float64
|
||||
normalizer *strings.Replacer
|
||||
}
|
||||
|
||||
type options struct {
|
||||
registerer prometheus.Registerer
|
||||
buckets []float64
|
||||
}
|
||||
|
||||
// Option is a function that sets some option for the Factory constructor.
|
||||
type Option func(*options)
|
||||
|
||||
// WithRegisterer returns an option that sets the registerer.
|
||||
// If not used we fallback to prometheus.DefaultRegisterer.
|
||||
func WithRegisterer(registerer prometheus.Registerer) Option {
|
||||
return func(opts *options) {
|
||||
opts.registerer = registerer
|
||||
}
|
||||
}
|
||||
|
||||
// WithBuckets returns an option that sets the default buckets for histogram.
|
||||
// If not used, we fallback to default Prometheus buckets.
|
||||
func WithBuckets(buckets []float64) Option {
|
||||
return func(opts *options) {
|
||||
opts.buckets = buckets
|
||||
}
|
||||
}
|
||||
|
||||
func applyOptions(opts []Option) *options {
|
||||
options := new(options)
|
||||
for _, o := range opts {
|
||||
o(options)
|
||||
}
|
||||
if options.registerer == nil {
|
||||
options.registerer = prometheus.DefaultRegisterer
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
// New creates a Factory backed by Prometheus registry.
|
||||
// Typically the first argument should be prometheus.DefaultRegisterer.
|
||||
//
|
||||
// Parameter buckets defines the buckets into which Timer observations are counted.
|
||||
// Each element in the slice is the upper inclusive bound of a bucket. The
|
||||
// values must be sorted in strictly increasing order. There is no need
|
||||
// to add a highest bucket with +Inf bound, it will be added
|
||||
// implicitly. The default value is prometheus.DefBuckets.
|
||||
func New(opts ...Option) *Factory {
|
||||
options := applyOptions(opts)
|
||||
return newFactory(
|
||||
&Factory{ // dummy struct to be discarded
|
||||
cache: newVectorCache(options.registerer),
|
||||
buckets: options.buckets,
|
||||
normalizer: strings.NewReplacer(".", "_", "-", "_"),
|
||||
},
|
||||
"", // scope
|
||||
nil) // tags
|
||||
}
|
||||
|
||||
func newFactory(parent *Factory, scope string, tags map[string]string) *Factory {
|
||||
return &Factory{
|
||||
cache: parent.cache,
|
||||
buckets: parent.buckets,
|
||||
normalizer: parent.normalizer,
|
||||
scope: scope,
|
||||
tags: tags,
|
||||
}
|
||||
}
|
||||
|
||||
// Counter implements Counter of metrics.Factory.
|
||||
func (f *Factory) Counter(name string, tags map[string]string) metrics.Counter {
|
||||
name = f.subScope(name)
|
||||
tags = f.mergeTags(tags)
|
||||
labelNames := f.tagNames(tags)
|
||||
opts := prometheus.CounterOpts{
|
||||
Name: name,
|
||||
Help: name,
|
||||
}
|
||||
cv := f.cache.getOrMakeCounterVec(opts, labelNames)
|
||||
return &counter{
|
||||
counter: cv.WithLabelValues(f.tagsAsLabelValues(labelNames, tags)...),
|
||||
}
|
||||
}
|
||||
|
||||
// Gauge implements Gauge of metrics.Factory.
|
||||
func (f *Factory) Gauge(name string, tags map[string]string) metrics.Gauge {
|
||||
name = f.subScope(name)
|
||||
tags = f.mergeTags(tags)
|
||||
labelNames := f.tagNames(tags)
|
||||
opts := prometheus.GaugeOpts{
|
||||
Name: name,
|
||||
Help: name,
|
||||
}
|
||||
gv := f.cache.getOrMakeGaugeVec(opts, labelNames)
|
||||
return &gauge{
|
||||
gauge: gv.WithLabelValues(f.tagsAsLabelValues(labelNames, tags)...),
|
||||
}
|
||||
}
|
||||
|
||||
// Timer implements Timer of metrics.Factory.
|
||||
func (f *Factory) Timer(name string, tags map[string]string) metrics.Timer {
|
||||
name = f.subScope(name)
|
||||
tags = f.mergeTags(tags)
|
||||
labelNames := f.tagNames(tags)
|
||||
opts := prometheus.HistogramOpts{
|
||||
Name: name,
|
||||
Help: name,
|
||||
Buckets: f.buckets,
|
||||
}
|
||||
hv := f.cache.getOrMakeHistogramVec(opts, labelNames)
|
||||
return &timer{
|
||||
histogram: hv.WithLabelValues(f.tagsAsLabelValues(labelNames, tags)...),
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace implements Namespace of metrics.Factory.
|
||||
func (f *Factory) Namespace(name string, tags map[string]string) metrics.Factory {
|
||||
return newFactory(f, f.subScope(name), f.mergeTags(tags))
|
||||
}
|
||||
|
||||
type counter struct {
|
||||
counter prometheus.Counter
|
||||
}
|
||||
|
||||
func (c *counter) Inc(v int64) {
|
||||
c.counter.Add(float64(v))
|
||||
}
|
||||
|
||||
type gauge struct {
|
||||
gauge prometheus.Gauge
|
||||
}
|
||||
|
||||
func (g *gauge) Update(v int64) {
|
||||
g.gauge.Set(float64(v))
|
||||
}
|
||||
|
||||
type timer struct {
|
||||
histogram prometheus.Histogram
|
||||
}
|
||||
|
||||
func (t *timer) Record(v time.Duration) {
|
||||
t.histogram.Observe(float64(v.Nanoseconds()) / float64(time.Second/time.Nanosecond))
|
||||
}
|
||||
|
||||
func (f *Factory) subScope(name string) string {
|
||||
if f.scope == "" {
|
||||
return f.normalize(name)
|
||||
}
|
||||
if name == "" {
|
||||
return f.normalize(f.scope)
|
||||
}
|
||||
return f.normalize(f.scope + ":" + name)
|
||||
}
|
||||
|
||||
func (f *Factory) normalize(v string) string {
|
||||
return f.normalizer.Replace(v)
|
||||
}
|
||||
|
||||
func (f *Factory) mergeTags(tags map[string]string) map[string]string {
|
||||
ret := make(map[string]string, len(f.tags)+len(tags))
|
||||
for k, v := range f.tags {
|
||||
ret[k] = v
|
||||
}
|
||||
for k, v := range tags {
|
||||
ret[k] = v
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (f *Factory) tagNames(tags map[string]string) []string {
|
||||
ret := make([]string, 0, len(tags))
|
||||
for k := range tags {
|
||||
ret = append(ret, k)
|
||||
}
|
||||
sort.Strings(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (f *Factory) tagsAsLabelValues(labels []string, tags map[string]string) []string {
|
||||
ret := make([]string, 0, len(tags))
|
||||
for _, l := range labels {
|
||||
ret = append(ret, tags[l])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tally
|
||||
|
||||
import (
|
||||
"github.com/uber-go/tally"
|
||||
|
||||
"github.com/uber/jaeger-lib/metrics"
|
||||
)
|
||||
|
||||
// Wrap takes a tally Scope and returns jaeger-lib metrics.Factory.
|
||||
func Wrap(scope tally.Scope) metrics.Factory {
|
||||
return &factory{
|
||||
tally: scope,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO implement support for tags if tally.Scope does not support them
|
||||
type factory struct {
|
||||
tally tally.Scope
|
||||
}
|
||||
|
||||
func (f *factory) Counter(name string, tags map[string]string) metrics.Counter {
|
||||
scope := f.tally
|
||||
if len(tags) > 0 {
|
||||
scope = scope.Tagged(tags)
|
||||
}
|
||||
return NewCounter(scope.Counter(name))
|
||||
}
|
||||
|
||||
func (f *factory) Gauge(name string, tags map[string]string) metrics.Gauge {
|
||||
scope := f.tally
|
||||
if len(tags) > 0 {
|
||||
scope = scope.Tagged(tags)
|
||||
}
|
||||
return NewGauge(scope.Gauge(name))
|
||||
}
|
||||
|
||||
func (f *factory) Timer(name string, tags map[string]string) metrics.Timer {
|
||||
scope := f.tally
|
||||
if len(tags) > 0 {
|
||||
scope = scope.Tagged(tags)
|
||||
}
|
||||
return NewTimer(scope.Timer(name))
|
||||
}
|
||||
|
||||
func (f *factory) Namespace(name string, tags map[string]string) metrics.Factory {
|
||||
return &factory{
|
||||
tally: f.tally.SubScope(name).Tagged(tags),
|
||||
}
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tally
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/uber-go/tally"
|
||||
)
|
||||
|
||||
// Counter is an adapter from go-tally Counter to jaeger-lib Counter
|
||||
type Counter struct {
|
||||
counter tally.Counter
|
||||
}
|
||||
|
||||
// NewCounter creates a new Counter
|
||||
func NewCounter(counter tally.Counter) *Counter {
|
||||
return &Counter{counter: counter}
|
||||
}
|
||||
|
||||
// Inc adds the given value to the counter.
|
||||
func (c *Counter) Inc(delta int64) {
|
||||
c.counter.Inc(delta)
|
||||
}
|
||||
|
||||
// Gauge is an adapter from go-tally Gauge to jaeger-lib Gauge
|
||||
type Gauge struct {
|
||||
gauge tally.Gauge
|
||||
}
|
||||
|
||||
// NewGauge creates a new Gauge
|
||||
func NewGauge(gauge tally.Gauge) *Gauge {
|
||||
return &Gauge{gauge: gauge}
|
||||
}
|
||||
|
||||
// Update the gauge to the value passed in.
|
||||
func (g *Gauge) Update(value int64) {
|
||||
g.gauge.Update(float64(value))
|
||||
}
|
||||
|
||||
// Timer is an adapter from go-tally Histogram to jaeger-lib Timer
|
||||
type Timer struct {
|
||||
timer tally.Timer
|
||||
}
|
||||
|
||||
// NewTimer creates a new Timer
|
||||
func NewTimer(timer tally.Timer) *Timer {
|
||||
return &Timer{timer: timer}
|
||||
}
|
||||
|
||||
// Record saves the time passed in.
|
||||
func (t *Timer) Record(delta time.Duration) {
|
||||
t.timer.Record(delta)
|
||||
}
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/uber/jaeger-lib/metrics"
|
||||
)
|
||||
|
||||
// ExpectedMetric contains metrics under test.
|
||||
type ExpectedMetric struct {
|
||||
Name string
|
||||
Tags map[string]string
|
||||
Value int
|
||||
}
|
||||
|
||||
// TODO do something similar for Timers
|
||||
|
||||
// AssertCounterMetrics checks if counter metrics exist.
|
||||
func AssertCounterMetrics(t *testing.T, f *metrics.LocalFactory, expectedMetrics ...ExpectedMetric) {
|
||||
counters, _ := f.Snapshot()
|
||||
assertMetrics(t, counters, expectedMetrics...)
|
||||
}
|
||||
|
||||
// AssertGaugeMetrics checks if gauge metrics exist.
|
||||
func AssertGaugeMetrics(t *testing.T, f *metrics.LocalFactory, expectedMetrics ...ExpectedMetric) {
|
||||
_, gauges := f.Snapshot()
|
||||
assertMetrics(t, gauges, expectedMetrics...)
|
||||
}
|
||||
|
||||
func assertMetrics(t *testing.T, actualMetrics map[string]int64, expectedMetrics ...ExpectedMetric) {
|
||||
for _, expected := range expectedMetrics {
|
||||
key := metrics.GetKey(expected.Name, expected.Tags, "|", "=")
|
||||
assert.EqualValues(t,
|
||||
expected.Value,
|
||||
actualMetrics[key],
|
||||
"expected metric name: %s, tags: %+v", expected.Name, expected.Tags,
|
||||
)
|
||||
}
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sample
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// SayHello is a sample function
|
||||
func SayHello() {
|
||||
fmt.Println("Hello, playground")
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
COVER=.cover
|
||||
ROOT_PKG=github.com/uber/jaeger-lib/
|
||||
|
||||
if [[ -d "$COVER" ]]; then
|
||||
rm -rf "$COVER"
|
||||
fi
|
||||
mkdir -p "$COVER"
|
||||
|
||||
# If a package directory has a .nocover file, don't count it when calculating
|
||||
# coverage.
|
||||
filter=""
|
||||
for pkg in "$@"; do
|
||||
if [[ -f "$GOPATH/src/$pkg/.nocover" ]]; then
|
||||
if [[ -n "$filter" ]]; then
|
||||
filter="$filter, "
|
||||
fi
|
||||
filter="\"$pkg\": true"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$filter" = "" ]]; then
|
||||
# make up some name to avoid breaking jq's select(in({}))
|
||||
filter='"no-filter": true'
|
||||
fi
|
||||
|
||||
i=0
|
||||
for pkg in "$@"; do
|
||||
i=$((i + 1))
|
||||
|
||||
extracoverpkg=""
|
||||
if [[ -f "$GOPATH/src/$pkg/.extra-coverpkg" ]]; then
|
||||
extracoverpkg=$( \
|
||||
sed -e "s|^|$pkg/|g" < "$GOPATH/src/$pkg/.extra-coverpkg" \
|
||||
| tr '\n' ',')
|
||||
fi
|
||||
|
||||
coverpkg=$(go list -json "$pkg" | jq -r '
|
||||
.Deps
|
||||
| . + ["'"$pkg"'"]
|
||||
| map
|
||||
( select(startswith("'"$ROOT_PKG"'"))
|
||||
| select(contains("/vendor/") | not)
|
||||
| select(in({'"$filter"'}) | not)
|
||||
)
|
||||
| join(",")
|
||||
')
|
||||
if [[ -n "$extracoverpkg" ]]; then
|
||||
coverpkg="$extracoverpkg$coverpkg"
|
||||
fi
|
||||
|
||||
args=""
|
||||
if [[ -n "$coverpkg" ]]; then
|
||||
args="-coverprofile $COVER/cover.${i}.out" # -coverpkg $coverpkg"
|
||||
fi
|
||||
|
||||
echo go test -v -race "$pkg"
|
||||
go test $args -v -race "$pkg"
|
||||
done
|
||||
|
||||
gocovmerge "$COVER"/*.out > cover.out
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
python scripts/updateLicense.py $(go list -json $(glide nv) | jq -r '.Dir + "/" + (.GoFiles | .[])')
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RateLimiter is a filter used to check if a message that is worth itemCost units is within the rate limits.
|
||||
type RateLimiter interface {
|
||||
CheckCredit(itemCost float64) bool
|
||||
}
|
||||
|
||||
type rateLimiter struct {
|
||||
sync.Mutex
|
||||
|
||||
creditsPerSecond float64
|
||||
balance float64
|
||||
maxBalance float64
|
||||
lastTick time.Time
|
||||
|
||||
timeNow func() time.Time
|
||||
}
|
||||
|
||||
// NewRateLimiter creates a new rate limiter based on leaky bucket algorithm, formulated in terms of a
|
||||
// credits balance that is replenished every time CheckCredit() method is called (tick) by the amount proportional
|
||||
// to the time elapsed since the last tick, up to max of creditsPerSecond. A call to CheckCredit() takes a cost
|
||||
// of an item we want to pay with the balance. If the balance exceeds the cost of the item, the item is "purchased"
|
||||
// and the balance reduced, indicated by returned value of true. Otherwise the balance is unchanged and return false.
|
||||
//
|
||||
// This can be used to limit a rate of messages emitted by a service by instantiating the Rate Limiter with the
|
||||
// max number of messages a service is allowed to emit per second, and calling CheckCredit(1.0) for each message
|
||||
// to determine if the message is within the rate limit.
|
||||
//
|
||||
// It can also be used to limit the rate of traffic in bytes, by setting creditsPerSecond to desired throughput
|
||||
// as bytes/second, and calling CheckCredit() with the actual message size.
|
||||
func NewRateLimiter(creditsPerSecond, maxBalance float64) RateLimiter {
|
||||
return &rateLimiter{
|
||||
creditsPerSecond: creditsPerSecond,
|
||||
balance: maxBalance,
|
||||
maxBalance: maxBalance,
|
||||
lastTick: time.Now(),
|
||||
timeNow: time.Now}
|
||||
}
|
||||
|
||||
func (b *rateLimiter) CheckCredit(itemCost float64) bool {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
// calculate how much time passed since the last tick, and update current tick
|
||||
currentTime := b.timeNow()
|
||||
elapsedTime := currentTime.Sub(b.lastTick)
|
||||
b.lastTick = currentTime
|
||||
// calculate how much credit have we accumulated since the last tick
|
||||
b.balance += elapsedTime.Seconds() * b.creditsPerSecond
|
||||
if b.balance > b.maxBalance {
|
||||
b.balance = b.maxBalance
|
||||
}
|
||||
// if we have enough credits to pay for current item, then reduce balance and allow
|
||||
if b.balance >= itemCost {
|
||||
b.balance -= itemCost
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user