plugin/metrics: Switch to using promhttp instead of deprecated Handler (#1312)

prometheus.Handler is deprecated according to the godoc for the package so
instead we're using promhttp.

Additionally, we are exposing the Registry that metrics is using so other
plugins that are not inside of coredns can read the registry. Otherwise, if
we kept using the Default one, there's no way to access that from outside
of the coredns repo since it is vendored.
This commit is contained in:
James Hartig
2017-12-14 13:19:03 -05:00
committed by Miek Gieben
parent 1919913c98
commit 671d170619
6728 changed files with 1994787 additions and 16 deletions

View File

@@ -0,0 +1,43 @@
package events
import (
"bytes"
"fmt"
"golang.org/x/net/trace"
"github.com/openzipkin/zipkin-go-opentracing"
)
// NetTraceIntegrator can be passed into a zipkintracer as NewSpanEventListener
// and causes all traces to be registered with the net/trace endpoint.
var NetTraceIntegrator = func() func(zipkintracer.SpanEvent) {
var tr trace.Trace
return func(e zipkintracer.SpanEvent) {
switch t := e.(type) {
case zipkintracer.EventCreate:
tr = trace.New("tracing", t.OperationName)
tr.SetMaxEvents(1000)
case zipkintracer.EventFinish:
tr.Finish()
case zipkintracer.EventTag:
tr.LazyPrintf("%s:%v", t.Key, t.Value)
case zipkintracer.EventLogFields:
var buf bytes.Buffer
for i, f := range t.Fields {
if i > 0 {
buf.WriteByte(' ')
}
fmt.Fprintf(&buf, "%s:%v", f.Key(), f.Value())
}
tr.LazyPrintf("%s", buf.String())
case zipkintracer.EventLog:
if t.Payload != nil {
tr.LazyPrintf("%s (payload %v)", t.Event, t.Payload)
} else {
tr.LazyPrintf("%s", t.Event)
}
}
}
}

View File

@@ -0,0 +1,10 @@
# builds the Cli and Svc1 & Svc2 projects
all: clean
@go get -v ./...
@go build -v -o build/svc1 ./svc1/cmd
@go build -v -o build/svc2 ./svc2/cmd
@go build -v -o build/cli ./cli
clean:
@rm -rf build

View File

@@ -0,0 +1,35 @@
## Zipkin tracing using OpenTracing API
This directory contains a super simple command line client and two HTTP services
which are instrumented using the OpenTracing API using the
[zipkin-go-opentracing](https://github.com/openzipkin/zipkin-go-opentracing)
tracer.
The code is a quick hack to solely demonstrate the usage of
[OpenTracing](http://opentracing.io) with a [Zipkin](http://zipkin.io) backend.
```
note: the examples will only compile with Go 1.7 or higher
```
## Usage:
Build `svc1`, `svc2` and `cli` with `make` and start both compiled services
found in the newly created `build` subdirectory.
When you call the `cli` program it will trigger two calls to `svc1` of which one
call will be proxied from `svc1` over to `svc2` to handle the method and by that
generating a couple of spans across services.
Methods have been instrumented with some examples of
[OpenTracing](http://opentracing.io) Tags which will be transformed into
[Zipkin](http://zipkin.io) binary annotations and
[OpenTracing](http://opentracing.io) LogEvents which will be transformed into
[Zipkin](http://zipkin.io) annotations.
The most interesting piece of code is found in `examples/middleware` which is
kind of the missing link for people looking for a tracing framework. I advise
you to seriously look into using [Go kit](https://gokit.io) and use its
abstractions and OpenTracing middleware with which this Tracer is fully
compatible, instead of rolling your own. If you still want to roll your own you
can use `examples/middleware` as a starting point.

View File

@@ -0,0 +1,89 @@
// +build go1.7
package main
import (
"context"
"fmt"
"os"
opentracing "github.com/opentracing/opentracing-go"
zipkin "github.com/openzipkin/zipkin-go-opentracing"
"github.com/openzipkin/zipkin-go-opentracing/examples/cli_with_2_services/svc1"
)
const (
// Our service name.
serviceName = "cli"
// Host + port of our service.
hostPort = "0.0.0.0:0"
// Endpoint to send Zipkin spans to.
zipkinHTTPEndpoint = "http://localhost:9411/api/v1/spans"
// Debug mode.
debug = false
// Base endpoint of our SVC1 service.
svc1Endpoint = "http://localhost:61001"
// same span can be set to true for RPC style spans (Zipkin V1) vs Node style (OpenTracing)
sameSpan = true
// make Tracer generate 128 bit traceID's for root spans.
traceID128Bit = true
)
//ci
func main() {
// Create our HTTP collector.
collector, err := zipkin.NewHTTPCollector(zipkinHTTPEndpoint)
if err != nil {
fmt.Printf("unable to create Zipkin HTTP collector: %+v\n", err)
os.Exit(-1)
}
// Create our recorder.
recorder := zipkin.NewRecorder(collector, debug, hostPort, serviceName)
// Create our tracer.
tracer, err := zipkin.NewTracer(
recorder,
zipkin.ClientServerSameSpan(sameSpan),
zipkin.TraceID128Bit(traceID128Bit),
)
if err != nil {
fmt.Printf("unable to create Zipkin tracer: %+v\n", err)
os.Exit(-1)
}
// Explicitly set our tracer to be the default tracer.
opentracing.InitGlobalTracer(tracer)
// Create Client to svc1 Service
client := svc1.NewHTTPClient(tracer, svc1Endpoint)
// Create Root Span for duration of the interaction with svc1
span := opentracing.StartSpan("Run")
// Put root span in context so it will be used in our calls to the client.
ctx := opentracing.ContextWithSpan(context.Background(), span)
// Call the Concat Method
span.LogEvent("Call Concat")
res1, err := client.Concat(ctx, "Hello", " World!")
fmt.Printf("Concat: %s Err: %+v\n", res1, err)
// Call the Sum Method
span.LogEvent("Call Sum")
res2, err := client.Sum(ctx, 10, 20)
fmt.Printf("Sum: %d Err: %+v\n", res2, err)
// Finish our CLI span
span.Finish()
// Close collector to ensure spans are sent before exiting.
collector.Close()
}

View File

@@ -0,0 +1,78 @@
// +build go1.7
package main
import (
"fmt"
"net/http"
"os"
opentracing "github.com/opentracing/opentracing-go"
zipkin "github.com/openzipkin/zipkin-go-opentracing"
"github.com/openzipkin/zipkin-go-opentracing/examples/cli_with_2_services/svc1"
"github.com/openzipkin/zipkin-go-opentracing/examples/cli_with_2_services/svc2"
)
const (
// Our service name.
serviceName = "svc1"
// Host + port of our service.
hostPort = "127.0.0.1:61001"
// Endpoint to send Zipkin spans to.
zipkinHTTPEndpoint = "http://localhost:9411/api/v1/spans"
// Debug mode.
debug = false
// Base endpoint of our SVC2 service.
svc2Endpoint = "http://localhost:61002"
// same span can be set to true for RPC style spans (Zipkin V1) vs Node style (OpenTracing)
sameSpan = true
// make Tracer generate 128 bit traceID's for root spans.
traceID128Bit = true
)
//svc1
func main() {
// create collector.
collector, err := zipkin.NewHTTPCollector(zipkinHTTPEndpoint)
if err != nil {
fmt.Printf("unable to create Zipkin HTTP collector: %+v\n", err)
os.Exit(-1)
}
// create recorder.
recorder := zipkin.NewRecorder(collector, debug, hostPort, serviceName)
// create tracer.
tracer, err := zipkin.NewTracer(
recorder,
zipkin.ClientServerSameSpan(sameSpan),
zipkin.TraceID128Bit(traceID128Bit),
)
if err != nil {
fmt.Printf("unable to create Zipkin tracer: %+v\n", err)
os.Exit(-1)
}
// explicitly set our tracer to be the default tracer.
opentracing.InitGlobalTracer(tracer)
// create the client to svc2
svc2Client := svc2.NewHTTPClient(tracer, svc2Endpoint)
// create the service implementation
service := svc1.NewService(svc2Client)
// create the HTTP Server Handler for the service
handler := svc1.NewHTTPHandler(tracer, service)
// start the service
fmt.Printf("Starting %s on %s\n", serviceName, hostPort)
http.ListenAndServe(hostPort, handler)
}

View File

@@ -0,0 +1,125 @@
// +build go1.7
package svc1
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
opentracing "github.com/opentracing/opentracing-go"
"github.com/openzipkin/zipkin-go-opentracing/examples/middleware"
)
// client is our actual client implementation
type client struct {
baseURL string
httpClient *http.Client
tracer opentracing.Tracer
traceRequest middleware.RequestFunc
}
// Concat implements our Service interface.
func (c *client) Concat(ctx context.Context, a, b string) (string, error) {
// create new span using span found in context as parent (if none is found,
// our span becomes the trace root).
span, ctx := opentracing.StartSpanFromContext(ctx, "Concat")
defer span.Finish()
// assemble URL query
url := fmt.Sprintf(
"%s/concat/?a=%s&b=%s", c.baseURL, url.QueryEscape(a), url.QueryEscape(b),
)
// create the HTTP request
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
// use our middleware to propagate our trace
req = c.traceRequest(req.WithContext(ctx))
// execute the HTTP request
resp, err := c.httpClient.Do(req)
if err != nil {
// annotate our span with the error condition
span.SetTag("error", err.Error())
return "", err
}
defer resp.Body.Close()
// read the http response body
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
// annotate our span with the error condition
span.SetTag("error", err.Error())
return "", err
}
// return the result
return string(data), nil
}
// Sum implements our Service interface.
func (c *client) Sum(ctx context.Context, a, b int64) (int64, error) {
// create new span using span found in context as parent (if none is found,
// our span becomes the trace root).
span, ctx := opentracing.StartSpanFromContext(ctx, "Sum")
defer span.Finish()
// assemble URL query
url := fmt.Sprintf("%s/sum/?a=%d&b=%d", c.baseURL, a, b)
// create the HTTP request
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return 0, err
}
// use our middleware to propagate our trace
req = c.traceRequest(req.WithContext(ctx))
// execute the HTTP request
resp, err := c.httpClient.Do(req)
if err != nil {
// annotate our span with the error condition
span.SetTag("error", err.Error())
return 0, err
}
defer resp.Body.Close()
// read the http response body
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
// annotate our span with the error condition
span.SetTag("error", err.Error())
return 0, err
}
// convert html response to expected result type (int64)
result, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
// annotate our span with the error condition
span.SetTag("error", err.Error())
return 0, err
}
// return the result
return result, nil
}
// NewHTTPClient returns a new client instance to our svc1 using the HTTP
// transport.
func NewHTTPClient(tracer opentracing.Tracer, baseURL string) Service {
return &client{
baseURL: baseURL,
httpClient: &http.Client{},
tracer: tracer,
traceRequest: middleware.ToHTTPRequest(tracer),
}
}

View File

@@ -0,0 +1,84 @@
// +build go1.7
package svc1
import (
"fmt"
"net/http"
"strconv"
opentracing "github.com/opentracing/opentracing-go"
"github.com/openzipkin/zipkin-go-opentracing/examples/middleware"
)
type httpService struct {
service Service
}
// concatHandler is our HTTP HandlerFunc for a Concat request.
func (s *httpService) concatHandler(w http.ResponseWriter, req *http.Request) {
// parse query parameters
v := req.URL.Query()
result, err := s.service.Concat(req.Context(), v.Get("a"), v.Get("b"))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// return the result
w.Write([]byte(result))
}
// sumHandler is our HTTP Handlerfunc for a Sum request.
func (s *httpService) sumHandler(w http.ResponseWriter, req *http.Request) {
// parse query parameters
v := req.URL.Query()
a, err := strconv.ParseInt(v.Get("a"), 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
b, err := strconv.ParseInt(v.Get("b"), 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// call our Sum binding
result, err := s.service.Sum(req.Context(), a, b)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// return the result
w.Write([]byte(fmt.Sprintf("%d", result)))
}
// NewHTTPHandler returns a new HTTP handler our svc1.
func NewHTTPHandler(tracer opentracing.Tracer, service Service) http.Handler {
// Create our HTTP Service.
svc := &httpService{service: service}
// Create the mux.
mux := http.NewServeMux()
// Create the Concat handler.
var concatHandler http.Handler
concatHandler = http.HandlerFunc(svc.concatHandler)
// Wrap the Concat handler with our tracing middleware.
concatHandler = middleware.FromHTTPRequest(tracer, "Concat")(concatHandler)
// Create the Sum handler.
var sumHandler http.Handler
sumHandler = http.HandlerFunc(svc.sumHandler)
// Wrap the Sum handler with our tracing middleware.
sumHandler = middleware.FromHTTPRequest(tracer, "Sum")(sumHandler)
// Wire up the mux.
mux.Handle("/concat/", concatHandler)
mux.Handle("/sum/", sumHandler)
// Return the mux.
return mux
}

View File

@@ -0,0 +1,50 @@
// +build go1.7
package svc1
import (
"context"
opentracing "github.com/opentracing/opentracing-go"
"github.com/openzipkin/zipkin-go-opentracing/examples/cli_with_2_services/svc2"
)
// svc1 is our actual service implementation
type svc1 struct {
svc2Client svc2.Service
}
func (s *svc1) Concat(ctx context.Context, a, b string) (string, error) {
// test for length overflow
if len(a)+len(b) > StrMaxSize {
// pull span from context (has already been created by our middleware)
span := opentracing.SpanFromContext(ctx)
span.SetTag("error", ErrMaxSize.Error())
return "", ErrMaxSize
}
return a + b, nil
}
func (s *svc1) Sum(ctx context.Context, a, b int64) (int64, error) {
// pull span from context (has already been created by our middleware)
span := opentracing.SpanFromContext(ctx)
span.SetTag("proxy-to", "svc2")
// proxy request to svc2
result, err := s.svc2Client.Sum(ctx, a, b)
if err != nil {
span.SetTag("error", err.Error())
return 0, err
}
return result, nil
}
// NewService returns a new implementation of our Service.
func NewService(svc2Client svc2.Service) Service {
return &svc1{
svc2Client: svc2Client,
}
}

View File

@@ -0,0 +1,24 @@
// +build go1.7
package svc1
import (
"context"
"errors"
)
// Service constants
const (
StrMaxSize = 1024
)
// Service errors
var (
ErrMaxSize = errors.New("maximum size of 1024 bytes exceeded")
)
// Service interface
type Service interface {
Concat(ctx context.Context, a, b string) (string, error)
Sum(ctx context.Context, a, b int64) (int64, error)
}

View File

@@ -0,0 +1,71 @@
// +build go1.7
package main
import (
"fmt"
"net/http"
"os"
opentracing "github.com/opentracing/opentracing-go"
zipkin "github.com/openzipkin/zipkin-go-opentracing"
"github.com/openzipkin/zipkin-go-opentracing/examples/cli_with_2_services/svc2"
)
const (
// Our service name.
serviceName = "svc2"
// Host + port of our service.
hostPort = "127.0.0.1:61002"
// Endpoint to send Zipkin spans to.
zipkinHTTPEndpoint = "http://localhost:9411/api/v1/spans"
// Debug mode.
debug = false
// same span can be set to true for RPC style spans (Zipkin V1) vs Node style (OpenTracing)
sameSpan = true
// make Tracer generate 128 bit traceID's for root spans.
traceID128Bit = true
)
//svc2
func main() {
// create collector.
collector, err := zipkin.NewHTTPCollector(zipkinHTTPEndpoint)
if err != nil {
fmt.Printf("unable to create Zipkin HTTP collector: %+v\n", err)
os.Exit(-1)
}
// create recorder.
recorder := zipkin.NewRecorder(collector, debug, hostPort, serviceName)
// create tracer.
tracer, err := zipkin.NewTracer(
recorder,
zipkin.ClientServerSameSpan(sameSpan),
zipkin.TraceID128Bit(traceID128Bit),
)
if err != nil {
fmt.Printf("unable to create Zipkin tracer: %+v\n", err)
os.Exit(-1)
}
// explicitly set our tracer to be the default tracer.
opentracing.InitGlobalTracer(tracer)
// create the service implementation
service := svc2.NewService()
// create the HTTP Server Handler for the service
handler := svc2.NewHTTPHandler(tracer, service)
// start the service
fmt.Printf("Starting %s on %s\n", serviceName, hostPort)
http.ListenAndServe(hostPort, handler)
}

View File

@@ -0,0 +1,82 @@
// +build go1.7
package svc2
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"strconv"
opentracing "github.com/opentracing/opentracing-go"
"github.com/openzipkin/zipkin-go-opentracing/examples/middleware"
)
// client is our actual client implementation
type client struct {
baseURL string
httpClient *http.Client
tracer opentracing.Tracer
traceRequest middleware.RequestFunc
}
// Sum implements our Service interface.
func (c *client) Sum(ctx context.Context, a int64, b int64) (int64, error) {
// create new span using span found in context as parent (if none is found,
// our span becomes the trace root).
span, ctx := opentracing.StartSpanFromContext(ctx, "Sum")
defer span.Finish()
// assemble URL query
url := fmt.Sprintf("%s/sum/?a=%d&b=%d", c.baseURL, a, b)
// create the HTTP request
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return 0, err
}
// use our middleware to propagate our trace
req = c.traceRequest(req.WithContext(ctx))
// execute the HTTP request
resp, err := c.httpClient.Do(req)
if err != nil {
// annotate our span with the error condition
span.SetTag("error", err.Error())
return 0, err
}
defer resp.Body.Close()
// read the http response body
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
// annotate our span with the error condition
span.SetTag("error", err.Error())
return 0, err
}
// convert html response to expected result type (int64)
result, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
// annotate our span with the error condition
span.SetTag("error", err.Error())
return 0, err
}
// return the result
return result, nil
}
// NewHTTPClient returns a new client instance to our svc2 using the HTTP
// transport.
func NewHTTPClient(tracer opentracing.Tracer, baseURL string) Service {
return &client{
baseURL: baseURL,
httpClient: &http.Client{},
tracer: tracer,
traceRequest: middleware.ToHTTPRequest(tracer),
}
}

View File

@@ -0,0 +1,63 @@
// +build go1.7
package svc2
import (
"fmt"
"net/http"
"strconv"
opentracing "github.com/opentracing/opentracing-go"
"github.com/openzipkin/zipkin-go-opentracing/examples/middleware"
)
type httpService struct {
service Service
}
// sumHandler is our HTTP Handlerfunc for a Sum request.
func (s *httpService) sumHandler(w http.ResponseWriter, req *http.Request) {
// parse query parameters
v := req.URL.Query()
a, err := strconv.ParseInt(v.Get("a"), 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
b, err := strconv.ParseInt(v.Get("b"), 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// call our Sum binding
result, err := s.service.Sum(req.Context(), a, b)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// return the result
w.Write([]byte(fmt.Sprintf("%d", result)))
}
// NewHTTPHandler returns a new HTTP handler our svc2.
func NewHTTPHandler(tracer opentracing.Tracer, service Service) http.Handler {
// Create our HTTP Service.
svc := &httpService{service: service}
// Create the mux.
mux := http.NewServeMux()
// Create the Sum handler.
var sumHandler http.Handler
sumHandler = http.HandlerFunc(svc.sumHandler)
// Wrap the Sum handler with our tracing middleware.
sumHandler = middleware.FromHTTPRequest(tracer, "Sum")(sumHandler)
// Wire up the mux.
mux.Handle("/sum/", sumHandler)
// Return the mux.
return mux
}

View File

@@ -0,0 +1,78 @@
// +build go1.7
package svc2
import (
"context"
"time"
opentracing "github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
)
// svc2 is our actual service implementation.
type svc2 struct{}
// NewService returns a new implementation of our Service.
func NewService() Service {
return &svc2{}
}
// Sum implements our Service interface.
func (s *svc2) Sum(ctx context.Context, a int64, b int64) (int64, error) {
// We love starting up slow
time.Sleep(5 * time.Millisecond)
// Pull span from context.
span := opentracing.SpanFromContext(ctx)
// Example binary annotations.
span.SetTag("service", "svc2")
span.SetTag("string", "some value")
span.SetTag("int", 123)
span.SetTag("bool", true)
// Example annotation
span.LogEvent("MyEventAnnotation")
// Let's wait a little so it shows up nicely in our tracing graphics.
time.Sleep(10 * time.Millisecond)
// Let's assume we want to trace a call we do to a database.
s.fakeDBCall(span)
// Check for Int overflow condition.
if (b > 0 && a > (Int64Max-b)) || (b < 0 && a < (Int64Min-b)) {
span.SetTag("error", ErrIntOverflow.Error())
return 0, ErrIntOverflow
}
// calculate and return the result (all that boilerplate for this?) ;)
return a + b, nil
}
func (s *svc2) fakeDBCall(span opentracing.Span) {
resourceSpan := opentracing.StartSpan(
"myComplexQuery",
opentracing.ChildOf(span.Context()),
)
defer resourceSpan.Finish()
// mark span as resource type
ext.SpanKind.Set(resourceSpan, "resource")
// name of the resource we try to reach
ext.PeerService.Set(resourceSpan, "PostgreSQL")
// hostname of the resource
ext.PeerHostname.Set(resourceSpan, "localhost")
// port of the resource
ext.PeerPort.Set(resourceSpan, 3306)
// let's binary annotate the query we run
resourceSpan.SetTag(
"query", "SELECT recipes FROM cookbook WHERE topic = 'world domination'",
)
// Let's assume the query is going to take some time. Finding the right
// world domination recipes is like searching for a needle in a haystack.
time.Sleep(20 * time.Millisecond)
// sweet... all done
}

View File

@@ -0,0 +1,24 @@
// +build go1.7
package svc2
import (
"context"
"errors"
)
// Service constants
const (
Int64Max = 1<<63 - 1
Int64Min = -(Int64Max + 1)
)
// Service errors
var (
ErrIntOverflow = errors.New("integer overflow occurred")
)
// Service interface to our svc2 service.
type Service interface {
Sum(ctx context.Context, a int64, b int64) (int64, error)
}

View File

@@ -0,0 +1,101 @@
// +build go1.7
// Package middleware provides some usable transport middleware to deal with
// propagating Zipkin traces across service boundaries.
package middleware
import (
"fmt"
"net"
"net/http"
"strconv"
opentracing "github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore"
)
// RequestFunc is a middleware function for outgoing HTTP requests.
type RequestFunc func(req *http.Request) *http.Request
// ToHTTPRequest returns a RequestFunc that injects an OpenTracing Span found in
// context into the HTTP Headers. If no such Span can be found, the RequestFunc
// is a noop.
func ToHTTPRequest(tracer opentracing.Tracer) RequestFunc {
return func(req *http.Request) *http.Request {
// Retrieve the Span from context.
if span := opentracing.SpanFromContext(req.Context()); span != nil {
// We are going to use this span in a client request, so mark as such.
ext.SpanKindRPCClient.Set(span)
// Add some standard OpenTracing tags, useful in an HTTP request.
ext.HTTPMethod.Set(span, req.Method)
span.SetTag(zipkincore.HTTP_HOST, req.URL.Host)
span.SetTag(zipkincore.HTTP_PATH, req.URL.Path)
ext.HTTPUrl.Set(
span,
fmt.Sprintf("%s://%s%s", req.URL.Scheme, req.URL.Host, req.URL.Path),
)
// Add information on the peer service we're about to contact.
if host, portString, err := net.SplitHostPort(req.URL.Host); err == nil {
ext.PeerHostname.Set(span, host)
if port, err := strconv.Atoi(portString); err != nil {
ext.PeerPort.Set(span, uint16(port))
}
} else {
ext.PeerHostname.Set(span, req.URL.Host)
}
// Inject the Span context into the outgoing HTTP Request.
if err := tracer.Inject(
span.Context(),
opentracing.TextMap,
opentracing.HTTPHeadersCarrier(req.Header),
); err != nil {
fmt.Printf("error encountered while trying to inject span: %+v\n", err)
}
}
return req
}
}
// HandlerFunc is a middleware function for incoming HTTP requests.
type HandlerFunc func(next http.Handler) http.Handler
// FromHTTPRequest returns a Middleware HandlerFunc that tries to join with an
// OpenTracing trace found in the HTTP request headers and starts a new Span
// called `operationName`. If no trace could be found in the HTTP request
// headers, the Span will be a trace root. The Span is incorporated in the
// HTTP Context object and can be retrieved with
// opentracing.SpanFromContext(ctx).
func FromHTTPRequest(tracer opentracing.Tracer, operationName string,
) HandlerFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
// Try to join to a trace propagated in `req`.
wireContext, err := tracer.Extract(
opentracing.TextMap,
opentracing.HTTPHeadersCarrier(req.Header),
)
if err != nil {
fmt.Printf("error encountered while trying to extract span: %+v\n", err)
}
// create span
span := tracer.StartSpan(operationName, ext.RPCServerOption(wireContext))
defer span.Finish()
// store span in context
ctx := opentracing.ContextWithSpan(req.Context(), span)
// update request context to include our new span
req = req.WithContext(ctx)
// next middleware or actual request handler
next.ServeHTTP(w, req)
})
}
}

View File

@@ -0,0 +1,154 @@
// Autogenerated by Thrift Compiler (1.0.0-dev)
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
package main
import (
"context"
"flag"
"fmt"
"math"
"net"
"net/url"
"os"
"strconv"
"strings"
"github.com/apache/thrift/lib/go/thrift"
"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/scribe"
)
func Usage() {
fmt.Fprintln(os.Stderr, "Usage of ", os.Args[0], " [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:")
flag.PrintDefaults()
fmt.Fprintln(os.Stderr, "\nFunctions:")
fmt.Fprintln(os.Stderr, " ResultCode Log( messages)")
fmt.Fprintln(os.Stderr)
os.Exit(0)
}
func main() {
flag.Usage = Usage
var host string
var port int
var protocol string
var urlString string
var framed bool
var useHttp bool
var parsedUrl url.URL
var trans thrift.TTransport
_ = strconv.Atoi
_ = math.Abs
flag.Usage = Usage
flag.StringVar(&host, "h", "localhost", "Specify host and port")
flag.IntVar(&port, "p", 9090, "Specify port")
flag.StringVar(&protocol, "P", "binary", "Specify the protocol (binary, compact, simplejson, json)")
flag.StringVar(&urlString, "u", "", "Specify the url")
flag.BoolVar(&framed, "framed", false, "Use framed transport")
flag.BoolVar(&useHttp, "http", false, "Use http")
flag.Parse()
if len(urlString) > 0 {
parsedUrl, err := url.Parse(urlString)
if err != nil {
fmt.Fprintln(os.Stderr, "Error parsing URL: ", err)
flag.Usage()
}
host = parsedUrl.Host
useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == "http"
} else if useHttp {
_, err := url.Parse(fmt.Sprint("http://", host, ":", port))
if err != nil {
fmt.Fprintln(os.Stderr, "Error parsing URL: ", err)
flag.Usage()
}
}
cmd := flag.Arg(0)
var err error
if useHttp {
trans, err = thrift.NewTHttpClient(parsedUrl.String())
} else {
portStr := fmt.Sprint(port)
if strings.Contains(host, ":") {
host, portStr, err = net.SplitHostPort(host)
if err != nil {
fmt.Fprintln(os.Stderr, "error with host:", err)
os.Exit(1)
}
}
trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr))
if err != nil {
fmt.Fprintln(os.Stderr, "error resolving address:", err)
os.Exit(1)
}
if framed {
trans = thrift.NewTFramedTransport(trans)
}
}
if err != nil {
fmt.Fprintln(os.Stderr, "Error creating transport", err)
os.Exit(1)
}
defer trans.Close()
var protocolFactory thrift.TProtocolFactory
switch protocol {
case "compact":
protocolFactory = thrift.NewTCompactProtocolFactory()
break
case "simplejson":
protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
break
case "json":
protocolFactory = thrift.NewTJSONProtocolFactory()
break
case "binary", "":
protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
break
default:
fmt.Fprintln(os.Stderr, "Invalid protocol specified: ", protocol)
Usage()
os.Exit(1)
}
iprot := protocolFactory.GetProtocol(trans)
oprot := protocolFactory.GetProtocol(trans)
client := scribe.NewScribeClient(thrift.NewTStandardClient(iprot, oprot))
if err := trans.Open(); err != nil {
fmt.Fprintln(os.Stderr, "Error opening socket to ", host, ":", port, " ", err)
os.Exit(1)
}
switch cmd {
case "Log":
if flag.NArg() - 1 != 1 {
fmt.Fprintln(os.Stderr, "Log requires 1 args")
flag.Usage()
}
arg5 := flag.Arg(1)
mbTrans6 := thrift.NewTMemoryBufferLen(len(arg5))
defer mbTrans6.Close()
_, err7 := mbTrans6.WriteString(arg5)
if err7 != nil {
Usage()
return
}
factory8 := thrift.NewTSimpleJSONProtocolFactory()
jsProt9 := factory8.GetProtocol(mbTrans6)
containerStruct0 := scribe.NewScribeLogArgs()
err10 := containerStruct0.ReadField1(jsProt9)
if err10 != nil {
Usage()
return
}
argvalue0 := containerStruct0.Messages
value0 := argvalue0
fmt.Print(client.Log(context.Background(), value0))
fmt.Print("\n")
break
case "":
Usage()
break
default:
fmt.Fprintln(os.Stderr, "Invalid function ", cmd)
}
}