Update tracing dependencies

This commit is contained in:
Ludovic Fernandez 2019-04-05 11:58:06 +02:00 committed by Traefiker Bot
parent 4919b638f9
commit ed12366d52
98 changed files with 3371 additions and 2808 deletions

35
Gopkg.lock generated
View file

@ -184,12 +184,12 @@
version = "v1.0.1"
[[projects]]
digest = "1:9752dad5e89cd779096bf2477a4ded16bea7ac62de453c8d6b4bf841d51a8512"
digest = "1:b39cf81d5f440b9c0757a25058432d33af867e5201109bf53621356d9dab4b73"
name = "github.com/apache/thrift"
packages = ["lib/go/thrift"]
pruneopts = "NUT"
revision = "b2a4d4ae21c789b689dd162deb819665567f481c"
version = "0.10.0"
revision = "384647d290e2e4a55a14b1b7ef1b7e66293a2c33"
version = "v0.12.0"
[[projects]]
branch = "master"
@ -1243,7 +1243,7 @@
version = "v1.0.0"
[[projects]]
digest = "1:7da29c22bcc5c2ffb308324377dc00b5084650348c2799e573ed226d8cc9faf0"
digest = "1:6846140b3f116579680eefdc17145f2bcf064b68deb9febf86b4419a454049af"
name = "github.com/opentracing/opentracing-go"
packages = [
".",
@ -1251,12 +1251,12 @@
"log",
]
pruneopts = "NUT"
revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38"
version = "v1.0.2"
revision = "659c90643e714681897ec2521c60567dd21da733"
version = "v1.1.0"
[[projects]]
digest = "1:07c44a0ce6012eafd2f05b715d30852d576aeda7798b8760a2ff51b1e90eb753"
name = "github.com/openzipkin/zipkin-go-opentracing"
digest = "1:0f4793617dc898d3ee99fe1abab076d3976a9d17d14f8327af2dc3f1ec0fd92c"
name = "github.com/openzipkin-contrib/zipkin-go-opentracing"
packages = [
".",
"flag",
@ -1266,7 +1266,8 @@
"wire",
]
pruneopts = "NUT"
revision = "1f5c07e90700ae93ddcba0c7af7d9c7201646ccc"
revision = "f0f479ad013a498e4cbfb369414e5d3880903779"
version = "v0.3.5"
[[projects]]
digest = "1:b52f6b7059f06a11ab6ab039714dda0d93878d9227f84c84ca9b6f046bfb5fef"
@ -1507,7 +1508,7 @@
revision = "1dc93a7db3567a5ccf865106afac88278ba940cf"
[[projects]]
digest = "1:7d3a890e525da3b7014d26dd1d4a0e4d31a479995007cd11989ad31db132e66c"
digest = "1:dc5b63bdf6fd3b22c970e06ad4fb686f6d08104f50f414644d5ac5e267a7934a"
name = "github.com/uber/jaeger-client-go"
packages = [
".",
@ -1530,16 +1531,18 @@
"zipkin",
]
pruneopts = "NUT"
revision = "1a782e2da844727691fef1757c72eb190c2909f0"
version = "v2.15.0"
revision = "2f47546e3facd43297739439600bcf43f44cce5d"
source = "github.com/jaegertracing/jaeger-client-go"
version = "v2.16.0"
[[projects]]
digest = "1:0f09db8429e19d57c8346ad76fbbc679341fa86073d3b8fb5ac919f0357d8f4c"
digest = "1:c9d69a04f7fa171f50360bbcc32196b4de8ab8837ef772f6302d0140a1e3e7f6"
name = "github.com/uber/jaeger-lib"
packages = ["metrics"]
pruneopts = "NUT"
revision = "ed3a127ec5fef7ae9ea95b01b542c47fbd999ce5"
version = "v1.5.0"
revision = "0e30338a695636fe5bcf7301e8030ce8dd2a8530"
source = "github.com/jaegertracing/jaeger-lib"
version = "v2.0.0"
[[projects]]
digest = "1:fb6d90081ae53fdb35d0fffa7d82a555df936bbc6db9a93126795655b2317604"
@ -2220,7 +2223,7 @@
"github.com/opentracing/opentracing-go",
"github.com/opentracing/opentracing-go/ext",
"github.com/opentracing/opentracing-go/log",
"github.com/openzipkin/zipkin-go-opentracing",
"github.com/openzipkin-contrib/zipkin-go-opentracing",
"github.com/patrickmn/go-cache",
"github.com/prometheus/client_golang/prometheus",
"github.com/prometheus/client_golang/prometheus/promhttp",

View file

@ -172,11 +172,13 @@ required = [
[[constraint]]
name = "github.com/uber/jaeger-client-go"
version = "2.15.0"
source = "github.com/jaegertracing/jaeger-client-go"
version = "2.16.0"
[[constraint]]
name = "github.com/uber/jaeger-lib"
version = "1.3.0"
source = "github.com/jaegertracing/jaeger-lib"
version = "2.0.0"
[[constraint]]
branch = "v1"

View file

@ -1,7 +1,5 @@
zipkin:
# Fix zipkin version 2.4.2
# due to a bug in latest version https://github.com/openzipkin/zipkin/releases/tag/2.4.4
image: openzipkin/zipkin:2.4.2
image: openzipkin/zipkin:2.12.6
environment:
STORAGE_TYPE: mem
JAVA_OPTS: -Dlogging.level.zipkin=DEBUG

View file

@ -6,7 +6,7 @@ import (
"github.com/containous/traefik/pkg/log"
"github.com/opentracing/opentracing-go"
zipkin "github.com/openzipkin/zipkin-go-opentracing"
zipkin "github.com/openzipkin-contrib/zipkin-go-opentracing"
)
// Name sets the name of this tracer.

View file

@ -1,5 +1,5 @@
Apache Thrift
Copyright 2006-2010 The Apache Software Foundation.
Copyright 2006-2017 The Apache Software Foundation.
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
The Apache Software Foundation (http://www.apache.org/).

View file

@ -30,11 +30,22 @@ const (
PROTOCOL_ERROR = 7
)
var defaultApplicationExceptionMessage = map[int32]string{
UNKNOWN_APPLICATION_EXCEPTION: "unknown application exception",
UNKNOWN_METHOD: "unknown method",
INVALID_MESSAGE_TYPE_EXCEPTION: "invalid message type",
WRONG_METHOD_NAME: "wrong method name",
BAD_SEQUENCE_ID: "bad sequence ID",
MISSING_RESULT: "missing result",
INTERNAL_ERROR: "unknown internal error",
PROTOCOL_ERROR: "unknown protocol error",
}
// Application level Thrift exception
type TApplicationException interface {
TException
TypeId() int32
Read(iprot TProtocol) (TApplicationException, error)
Read(iprot TProtocol) error
Write(oprot TProtocol) error
}
@ -44,7 +55,10 @@ type tApplicationException struct {
}
func (e tApplicationException) Error() string {
return e.message
if e.message != "" {
return e.message
}
return defaultApplicationExceptionMessage[e.type_]
}
func NewTApplicationException(type_ int32, message string) TApplicationException {
@ -55,10 +69,11 @@ func (p *tApplicationException) TypeId() int32 {
return p.type_
}
func (p *tApplicationException) Read(iprot TProtocol) (TApplicationException, error) {
func (p *tApplicationException) Read(iprot TProtocol) error {
// TODO: this should really be generated by the compiler
_, err := iprot.ReadStructBegin()
if err != nil {
return nil, err
return err
}
message := ""
@ -67,7 +82,7 @@ func (p *tApplicationException) Read(iprot TProtocol) (TApplicationException, er
for {
_, ttype, id, err := iprot.ReadFieldBegin()
if err != nil {
return nil, err
return err
}
if ttype == STOP {
break
@ -76,33 +91,40 @@ func (p *tApplicationException) Read(iprot TProtocol) (TApplicationException, er
case 1:
if ttype == STRING {
if message, err = iprot.ReadString(); err != nil {
return nil, err
return err
}
} else {
if err = SkipDefaultDepth(iprot, ttype); err != nil {
return nil, err
return err
}
}
case 2:
if ttype == I32 {
if type_, err = iprot.ReadI32(); err != nil {
return nil, err
return err
}
} else {
if err = SkipDefaultDepth(iprot, ttype); err != nil {
return nil, err
return err
}
}
default:
if err = SkipDefaultDepth(iprot, ttype); err != nil {
return nil, err
return err
}
}
if err = iprot.ReadFieldEnd(); err != nil {
return nil, err
return err
}
}
return NewTApplicationException(type_, message), iprot.ReadStructEnd()
if err := iprot.ReadStructEnd(); err != nil {
return err
}
p.message = message
p.type_ = type_
return nil
}
func (p *tApplicationException) Write(oprot TProtocol) (err error) {

View file

@ -21,6 +21,7 @@ package thrift
import (
"bytes"
"context"
"encoding/binary"
"errors"
"fmt"
@ -447,9 +448,6 @@ func (p *TBinaryProtocol) ReadBinary() ([]byte, error) {
if size < 0 {
return nil, invalidDataLength
}
if uint64(size) > p.trans.RemainingBytes() {
return nil, invalidDataLength
}
isize := int(size)
buf := make([]byte, isize)
@ -457,8 +455,8 @@ func (p *TBinaryProtocol) ReadBinary() ([]byte, error) {
return buf, NewTProtocolException(err)
}
func (p *TBinaryProtocol) Flush() (err error) {
return NewTProtocolException(p.trans.Flush())
func (p *TBinaryProtocol) Flush(ctx context.Context) (err error) {
return NewTProtocolException(p.trans.Flush(ctx))
}
func (p *TBinaryProtocol) Skip(fieldType TType) (err error) {
@ -480,9 +478,6 @@ func (p *TBinaryProtocol) readStringBody(size int32) (value string, err error) {
if size < 0 {
return "", nil
}
if uint64(size) > p.trans.RemainingBytes() {
return "", invalidDataLength
}
var (
buf bytes.Buffer

View file

@ -21,6 +21,7 @@ package thrift
import (
"bufio"
"context"
)
type TBufferedTransportFactory struct {
@ -32,8 +33,8 @@ type TBufferedTransport struct {
tp TTransport
}
func (p *TBufferedTransportFactory) GetTransport(trans TTransport) TTransport {
return NewTBufferedTransport(trans, p.size)
func (p *TBufferedTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
return NewTBufferedTransport(trans, p.size), nil
}
func NewTBufferedTransportFactory(bufferSize int) *TBufferedTransportFactory {
@ -78,12 +79,12 @@ func (p *TBufferedTransport) Write(b []byte) (int, error) {
return n, err
}
func (p *TBufferedTransport) Flush() error {
func (p *TBufferedTransport) Flush(ctx context.Context) error {
if err := p.ReadWriter.Flush(); err != nil {
p.ReadWriter.Writer.Reset(p.tp)
return err
}
return p.tp.Flush()
return p.tp.Flush(ctx)
}
func (p *TBufferedTransport) RemainingBytes() (num_bytes uint64) {

View file

@ -0,0 +1,85 @@
package thrift
import (
"context"
"fmt"
)
type TClient interface {
Call(ctx context.Context, method string, args, result TStruct) error
}
type TStandardClient struct {
seqId int32
iprot, oprot TProtocol
}
// TStandardClient implements TClient, and uses the standard message format for Thrift.
// It is not safe for concurrent use.
func NewTStandardClient(inputProtocol, outputProtocol TProtocol) *TStandardClient {
return &TStandardClient{
iprot: inputProtocol,
oprot: outputProtocol,
}
}
func (p *TStandardClient) Send(ctx context.Context, oprot TProtocol, seqId int32, method string, args TStruct) error {
if err := oprot.WriteMessageBegin(method, CALL, seqId); err != nil {
return err
}
if err := args.Write(oprot); err != nil {
return err
}
if err := oprot.WriteMessageEnd(); err != nil {
return err
}
return oprot.Flush(ctx)
}
func (p *TStandardClient) Recv(iprot TProtocol, seqId int32, method string, result TStruct) error {
rMethod, rTypeId, rSeqId, err := iprot.ReadMessageBegin()
if err != nil {
return err
}
if method != rMethod {
return NewTApplicationException(WRONG_METHOD_NAME, fmt.Sprintf("%s: wrong method name", method))
} else if seqId != rSeqId {
return NewTApplicationException(BAD_SEQUENCE_ID, fmt.Sprintf("%s: out of order sequence response", method))
} else if rTypeId == EXCEPTION {
var exception tApplicationException
if err := exception.Read(iprot); err != nil {
return err
}
if err := iprot.ReadMessageEnd(); err != nil {
return err
}
return &exception
} else if rTypeId != REPLY {
return NewTApplicationException(INVALID_MESSAGE_TYPE_EXCEPTION, fmt.Sprintf("%s: invalid message type", method))
}
if err := result.Read(iprot); err != nil {
return err
}
return iprot.ReadMessageEnd()
}
func (p *TStandardClient) Call(ctx context.Context, method string, args, result TStruct) error {
p.seqId++
seqId := p.seqId
if err := p.Send(ctx, p.oprot, seqId, method, args); err != nil {
return err
}
// method is oneway
if result == nil {
return nil
}
return p.Recv(p.iprot, seqId, method, result)
}

View file

@ -20,6 +20,7 @@
package thrift
import (
"context"
"encoding/binary"
"fmt"
"io"
@ -561,9 +562,6 @@ func (p *TCompactProtocol) ReadString() (value string, err error) {
if length < 0 {
return "", invalidDataLength
}
if uint64(length) > p.trans.RemainingBytes() {
return "", invalidDataLength
}
if length == 0 {
return "", nil
@ -590,17 +588,14 @@ func (p *TCompactProtocol) ReadBinary() (value []byte, err error) {
if length < 0 {
return nil, invalidDataLength
}
if uint64(length) > p.trans.RemainingBytes() {
return nil, invalidDataLength
}
buf := make([]byte, length)
_, e = io.ReadFull(p.trans, buf)
return buf, NewTProtocolException(e)
}
func (p *TCompactProtocol) Flush() (err error) {
return NewTProtocolException(p.trans.Flush())
func (p *TCompactProtocol) Flush(ctx context.Context) (err error) {
return NewTProtocolException(p.trans.Flush(ctx))
}
func (p *TCompactProtocol) Skip(fieldType TType) (err error) {
@ -806,7 +801,7 @@ func (p *TCompactProtocol) getTType(t tCompactType) (TType, error) {
case COMPACT_STRUCT:
return STRUCT, nil
}
return STOP, TException(fmt.Errorf("don't know what type: %s", t&0x0f))
return STOP, TException(fmt.Errorf("don't know what type: %v", t&0x0f))
}
// Given a TType value, find the appropriate TCompactProtocol.Types constant.

View file

@ -19,12 +19,6 @@
package thrift
// A processor is a generic object which operates upon an input stream and
// writes to some output stream.
type TProcessor interface {
Process(in, out TProtocol) (bool, TException)
}
import "context"
type TProcessorFunction interface {
Process(seqId int32, in, out TProtocol) (bool, TException)
}
var defaultCtx = context.Background()

View file

@ -20,6 +20,7 @@
package thrift
import (
"context"
"log"
)
@ -258,8 +259,8 @@ func (tdp *TDebugProtocol) Skip(fieldType TType) (err error) {
log.Printf("%sSkip(fieldType=%#v) (err=%#v)", tdp.LogPrefix, fieldType, err)
return
}
func (tdp *TDebugProtocol) Flush() (err error) {
err = tdp.Delegate.Flush()
func (tdp *TDebugProtocol) Flush(ctx context.Context) (err error) {
err = tdp.Delegate.Flush(ctx)
log.Printf("%sFlush() (err=%#v)", tdp.LogPrefix, err)
return
}

View file

@ -22,6 +22,7 @@ package thrift
import (
"bufio"
"bytes"
"context"
"encoding/binary"
"fmt"
"io"
@ -48,11 +49,15 @@ func NewTFramedTransportFactory(factory TTransportFactory) TTransportFactory {
}
func NewTFramedTransportFactoryMaxLength(factory TTransportFactory, maxLength uint32) TTransportFactory {
return &tFramedTransportFactory{factory: factory, maxLength: maxLength}
return &tFramedTransportFactory{factory: factory, maxLength: maxLength}
}
func (p *tFramedTransportFactory) GetTransport(base TTransport) TTransport {
return NewTFramedTransportMaxLength(p.factory.GetTransport(base), p.maxLength)
func (p *tFramedTransportFactory) GetTransport(base TTransport) (TTransport, error) {
tt, err := p.factory.GetTransport(base)
if err != nil {
return nil, err
}
return NewTFramedTransportMaxLength(tt, p.maxLength), nil
}
func NewTFramedTransport(transport TTransport) *TFramedTransport {
@ -131,21 +136,23 @@ func (p *TFramedTransport) WriteString(s string) (n int, err error) {
return p.buf.WriteString(s)
}
func (p *TFramedTransport) Flush() error {
func (p *TFramedTransport) Flush(ctx context.Context) error {
size := p.buf.Len()
buf := p.buffer[:4]
binary.BigEndian.PutUint32(buf, uint32(size))
_, err := p.transport.Write(buf)
if err != nil {
p.buf.Truncate(0)
return NewTTransportExceptionFromError(err)
}
if size > 0 {
if n, err := p.buf.WriteTo(p.transport); err != nil {
print("Error while flushing write buffer of size ", size, " to transport, only wrote ", n, " bytes: ", err.Error(), "\n")
p.buf.Truncate(0)
return NewTTransportExceptionFromError(err)
}
}
err = p.transport.Flush()
err = p.transport.Flush(ctx)
return NewTTransportExceptionFromError(err)
}
@ -164,4 +171,3 @@ func (p *TFramedTransport) readFrameHeader() (uint32, error) {
func (p *TFramedTransport) RemainingBytes() (num_bytes uint64) {
return uint64(p.frameSize)
}

View file

@ -21,6 +21,7 @@ package thrift
import (
"bytes"
"context"
"io"
"io/ioutil"
"net/http"
@ -46,27 +47,16 @@ type THttpClient struct {
type THttpClientTransportFactory struct {
options THttpClientOptions
url string
isPost bool
}
func (p *THttpClientTransportFactory) GetTransport(trans TTransport) TTransport {
func (p *THttpClientTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
if trans != nil {
t, ok := trans.(*THttpClient)
if ok && t.url != nil {
if t.requestBuffer != nil {
t2, _ := NewTHttpPostClientWithOptions(t.url.String(), p.options)
return t2
}
t2, _ := NewTHttpClientWithOptions(t.url.String(), p.options)
return t2
return NewTHttpClientWithOptions(t.url.String(), p.options)
}
}
if p.isPost {
s, _ := NewTHttpPostClientWithOptions(p.url, p.options)
return s
}
s, _ := NewTHttpClientWithOptions(p.url, p.options)
return s
return NewTHttpClientWithOptions(p.url, p.options)
}
type THttpClientOptions struct {
@ -79,39 +69,10 @@ func NewTHttpClientTransportFactory(url string) *THttpClientTransportFactory {
}
func NewTHttpClientTransportFactoryWithOptions(url string, options THttpClientOptions) *THttpClientTransportFactory {
return &THttpClientTransportFactory{url: url, isPost: false, options: options}
}
func NewTHttpPostClientTransportFactory(url string) *THttpClientTransportFactory {
return NewTHttpPostClientTransportFactoryWithOptions(url, THttpClientOptions{})
}
func NewTHttpPostClientTransportFactoryWithOptions(url string, options THttpClientOptions) *THttpClientTransportFactory {
return &THttpClientTransportFactory{url: url, isPost: true, options: options}
return &THttpClientTransportFactory{url: url, options: options}
}
func NewTHttpClientWithOptions(urlstr string, options THttpClientOptions) (TTransport, error) {
parsedURL, err := url.Parse(urlstr)
if err != nil {
return nil, err
}
response, err := http.Get(urlstr)
if err != nil {
return nil, err
}
client := options.Client
if client == nil {
client = DefaultHttpClient
}
httpHeader := map[string][]string{"Content-Type": []string{"application/x-thrift"}}
return &THttpClient{client: client, response: response, url: parsedURL, header: httpHeader}, nil
}
func NewTHttpClient(urlstr string) (TTransport, error) {
return NewTHttpClientWithOptions(urlstr, THttpClientOptions{})
}
func NewTHttpPostClientWithOptions(urlstr string, options THttpClientOptions) (TTransport, error) {
parsedURL, err := url.Parse(urlstr)
if err != nil {
return nil, err
@ -121,12 +82,12 @@ func NewTHttpPostClientWithOptions(urlstr string, options THttpClientOptions) (T
if client == nil {
client = DefaultHttpClient
}
httpHeader := map[string][]string{"Content-Type": []string{"application/x-thrift"}}
httpHeader := map[string][]string{"Content-Type": {"application/x-thrift"}}
return &THttpClient{client: client, url: parsedURL, requestBuffer: bytes.NewBuffer(buf), header: httpHeader}, nil
}
func NewTHttpPostClient(urlstr string) (TTransport, error) {
return NewTHttpPostClientWithOptions(urlstr, THttpClientOptions{})
func NewTHttpClient(urlstr string) (TTransport, error) {
return NewTHttpClientWithOptions(urlstr, THttpClientOptions{})
}
// Set the HTTP Header for this specific Thrift Transport
@ -221,7 +182,7 @@ func (p *THttpClient) WriteString(s string) (n int, err error) {
return p.requestBuffer.WriteString(s)
}
func (p *THttpClient) Flush() error {
func (p *THttpClient) Flush(ctx context.Context) error {
// Close any previous response body to avoid leaking connections.
p.closeResponse()
@ -230,6 +191,9 @@ func (p *THttpClient) Flush() error {
return NewTTransportExceptionFromError(err)
}
req.Header = p.header
if ctx != nil {
req = req.WithContext(ctx)
}
response, err := p.client.Do(req)
if err != nil {
return NewTTransportExceptionFromError(err)
@ -256,3 +220,23 @@ func (p *THttpClient) RemainingBytes() (num_bytes uint64) {
const maxSize = ^uint64(0)
return maxSize // the thruth is, we just don't know unless framed is used
}
// Deprecated: Use NewTHttpClientTransportFactory instead.
func NewTHttpPostClientTransportFactory(url string) *THttpClientTransportFactory {
return NewTHttpClientTransportFactoryWithOptions(url, THttpClientOptions{})
}
// Deprecated: Use NewTHttpClientTransportFactoryWithOptions instead.
func NewTHttpPostClientTransportFactoryWithOptions(url string, options THttpClientOptions) *THttpClientTransportFactory {
return NewTHttpClientTransportFactoryWithOptions(url, options)
}
// Deprecated: Use NewTHttpClientWithOptions instead.
func NewTHttpPostClientWithOptions(urlstr string, options THttpClientOptions) (TTransport, error) {
return NewTHttpClientWithOptions(urlstr, options)
}
// Deprecated: Use NewTHttpClient instead.
func NewTHttpPostClient(urlstr string) (TTransport, error) {
return NewTHttpClientWithOptions(urlstr, THttpClientOptions{})
}

View file

@ -19,16 +19,45 @@
package thrift
import "net/http"
import (
"compress/gzip"
"io"
"net/http"
"strings"
)
// NewThriftHandlerFunc is a function that create a ready to use Apache Thrift Handler function
func NewThriftHandlerFunc(processor TProcessor,
inPfactory, outPfactory TProtocolFactory) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
return gz(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/x-thrift")
transport := NewStreamTransport(r.Body, w)
processor.Process(inPfactory.GetProtocol(transport), outPfactory.GetProtocol(transport))
processor.Process(r.Context(), inPfactory.GetProtocol(transport), outPfactory.GetProtocol(transport))
})
}
// gz transparently compresses the HTTP response if the client supports it.
func gz(handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
handler(w, r)
return
}
w.Header().Set("Content-Encoding", "gzip")
gz := gzip.NewWriter(w)
defer gz.Close()
gzw := gzipResponseWriter{Writer: gz, ResponseWriter: w}
handler(gzw, r)
}
}
type gzipResponseWriter struct {
io.Writer
http.ResponseWriter
}
func (w gzipResponseWriter) Write(b []byte) (int, error) {
return w.Writer.Write(b)
}

View file

@ -21,6 +21,7 @@ package thrift
import (
"bufio"
"context"
"io"
)
@ -38,38 +39,38 @@ type StreamTransportFactory struct {
isReadWriter bool
}
func (p *StreamTransportFactory) GetTransport(trans TTransport) TTransport {
func (p *StreamTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
if trans != nil {
t, ok := trans.(*StreamTransport)
if ok {
if t.isReadWriter {
return NewStreamTransportRW(t.Reader.(io.ReadWriter))
return NewStreamTransportRW(t.Reader.(io.ReadWriter)), nil
}
if t.Reader != nil && t.Writer != nil {
return NewStreamTransport(t.Reader, t.Writer)
return NewStreamTransport(t.Reader, t.Writer), nil
}
if t.Reader != nil && t.Writer == nil {
return NewStreamTransportR(t.Reader)
return NewStreamTransportR(t.Reader), nil
}
if t.Reader == nil && t.Writer != nil {
return NewStreamTransportW(t.Writer)
return NewStreamTransportW(t.Writer), nil
}
return &StreamTransport{}
return &StreamTransport{}, nil
}
}
if p.isReadWriter {
return NewStreamTransportRW(p.Reader.(io.ReadWriter))
return NewStreamTransportRW(p.Reader.(io.ReadWriter)), nil
}
if p.Reader != nil && p.Writer != nil {
return NewStreamTransport(p.Reader, p.Writer)
return NewStreamTransport(p.Reader, p.Writer), nil
}
if p.Reader != nil && p.Writer == nil {
return NewStreamTransportR(p.Reader)
return NewStreamTransportR(p.Reader), nil
}
if p.Reader == nil && p.Writer != nil {
return NewStreamTransportW(p.Writer)
return NewStreamTransportW(p.Writer), nil
}
return &StreamTransport{}
return &StreamTransport{}, nil
}
func NewStreamTransportFactory(reader io.Reader, writer io.Writer, isReadWriter bool) *StreamTransportFactory {
@ -138,7 +139,7 @@ func (p *StreamTransport) Close() error {
}
// Flushes the underlying output stream if not null.
func (p *StreamTransport) Flush() error {
func (p *StreamTransport) Flush(ctx context.Context) error {
if p.Writer == nil {
return NewTTransportException(NOT_OPEN, "Cannot flush null outputStream")
}
@ -209,6 +210,5 @@ func (p *StreamTransport) WriteString(s string) (n int, err error) {
func (p *StreamTransport) RemainingBytes() (num_bytes uint64) {
const maxSize = ^uint64(0)
return maxSize // the thruth is, we just don't know unless framed is used
return maxSize // the thruth is, we just don't know unless framed is used
}

View file

@ -20,6 +20,7 @@
package thrift
import (
"context"
"encoding/base64"
"fmt"
)
@ -438,10 +439,10 @@ func (p *TJSONProtocol) ReadBinary() ([]byte, error) {
return v, p.ParsePostValue()
}
func (p *TJSONProtocol) Flush() (err error) {
func (p *TJSONProtocol) Flush(ctx context.Context) (err error) {
err = p.writer.Flush()
if err == nil {
err = p.trans.Flush()
err = p.trans.Flush(ctx)
}
return NewTProtocolException(err)
}

View file

@ -21,6 +21,7 @@ package thrift
import (
"bytes"
"context"
)
// Memory buffer-based implementation of the TTransport interface.
@ -33,14 +34,14 @@ type TMemoryBufferTransportFactory struct {
size int
}
func (p *TMemoryBufferTransportFactory) GetTransport(trans TTransport) TTransport {
func (p *TMemoryBufferTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
if trans != nil {
t, ok := trans.(*TMemoryBuffer)
if ok && t.size > 0 {
return NewTMemoryBufferLen(t.size)
return NewTMemoryBufferLen(t.size), nil
}
}
return NewTMemoryBufferLen(p.size)
return NewTMemoryBufferLen(p.size), nil
}
func NewTMemoryBufferTransportFactory(size int) *TMemoryBufferTransportFactory {
@ -70,7 +71,7 @@ func (p *TMemoryBuffer) Close() error {
}
// Flushing a memory buffer is a no-op
func (p *TMemoryBuffer) Flush() error {
func (p *TMemoryBuffer) Flush(ctx context.Context) error {
return nil
}

View file

@ -20,6 +20,7 @@
package thrift
import (
"context"
"fmt"
"strings"
)
@ -127,7 +128,7 @@ func (t *TMultiplexedProcessor) RegisterProcessor(name string, processor TProces
t.serviceProcessorMap[name] = processor
}
func (t *TMultiplexedProcessor) Process(in, out TProtocol) (bool, TException) {
func (t *TMultiplexedProcessor) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
name, typeId, seqid, err := in.ReadMessageBegin()
if err != nil {
return false, err
@ -140,7 +141,7 @@ func (t *TMultiplexedProcessor) Process(in, out TProtocol) (bool, TException) {
if len(v) != 2 {
if t.DefaultProcessor != nil {
smb := NewStoredMessageProtocol(in, name, typeId, seqid)
return t.DefaultProcessor.Process(smb, out)
return t.DefaultProcessor.Process(ctx, smb, out)
}
return false, fmt.Errorf("Service name not found in message name: %s. Did you forget to use a TMultiplexProtocol in your client?", name)
}
@ -149,7 +150,7 @@ func (t *TMultiplexedProcessor) Process(in, out TProtocol) (bool, TException) {
return false, fmt.Errorf("Service name not found: %s. Did you forget to call registerProcessor()?", v[0])
}
smb := NewStoredMessageProtocol(in, v[1], typeId, seqid)
return actualProcessor.Process(smb, out)
return actualProcessor.Process(ctx, smb, out)
}
//Protocol that use stored message for ReadMessageBegin

View file

@ -19,6 +19,18 @@
package thrift
import "context"
// A processor is a generic object which operates upon an input stream and
// writes to some output stream.
type TProcessor interface {
Process(ctx context.Context, in, out TProtocol) (bool, TException)
}
type TProcessorFunction interface {
Process(ctx context.Context, seqId int32, in, out TProtocol) (bool, TException)
}
// The default processor factory just returns a singleton
// instance.
type TProcessorFactory interface {

View file

@ -20,7 +20,9 @@
package thrift
import (
"context"
"errors"
"fmt"
)
const (
@ -73,7 +75,7 @@ type TProtocol interface {
ReadBinary() (value []byte, err error)
Skip(fieldType TType) (err error)
Flush() (err error)
Flush(ctx context.Context) (err error)
Transport() TTransport
}
@ -88,9 +90,9 @@ func SkipDefaultDepth(prot TProtocol, typeId TType) (err error) {
// Skips over the next data element from the provided input TProtocol object.
func Skip(self TProtocol, fieldType TType, maxDepth int) (err error) {
if maxDepth <= 0 {
return NewTProtocolExceptionWithType( DEPTH_LIMIT, errors.New("Depth limit exceeded"))
if maxDepth <= 0 {
return NewTProtocolExceptionWithType(DEPTH_LIMIT, errors.New("Depth limit exceeded"))
}
switch fieldType {
@ -170,6 +172,8 @@ func Skip(self TProtocol, fieldType TType, maxDepth int) (err error) {
}
}
return self.ReadListEnd()
default:
return NewTProtocolExceptionWithType(INVALID_DATA, errors.New(fmt.Sprintf("Unknown data type %d", fieldType)))
}
return nil
}

View file

@ -60,7 +60,7 @@ func NewTProtocolException(err error) TProtocolException {
if err == nil {
return nil
}
if e,ok := err.(TProtocolException); ok {
if e, ok := err.(TProtocolException); ok {
return e
}
if _, ok := err.(base64.CorruptInputError); ok {
@ -75,4 +75,3 @@ func NewTProtocolExceptionWithType(errType int, err error) TProtocolException {
}
return &tProtocolException{errType, err.Error()}
}

View file

@ -66,4 +66,3 @@ func writeByte(w io.Writer, c byte) error {
_, err := w.Write(v[0:1])
return err
}

View file

@ -19,6 +19,10 @@
package thrift
import (
"context"
)
type TSerializer struct {
Transport *TMemoryBuffer
Protocol TProtocol
@ -38,35 +42,35 @@ func NewTSerializer() *TSerializer {
protocol}
}
func (t *TSerializer) WriteString(msg TStruct) (s string, err error) {
func (t *TSerializer) WriteString(ctx context.Context, msg TStruct) (s string, err error) {
t.Transport.Reset()
if err = msg.Write(t.Protocol); err != nil {
return
}
if err = t.Protocol.Flush(); err != nil {
if err = t.Protocol.Flush(ctx); err != nil {
return
}
if err = t.Transport.Flush(); err != nil {
if err = t.Transport.Flush(ctx); err != nil {
return
}
return t.Transport.String(), nil
}
func (t *TSerializer) Write(msg TStruct) (b []byte, err error) {
func (t *TSerializer) Write(ctx context.Context, msg TStruct) (b []byte, err error) {
t.Transport.Reset()
if err = msg.Write(t.Protocol); err != nil {
return
}
if err = t.Protocol.Flush(); err != nil {
if err = t.Protocol.Flush(ctx); err != nil {
return
}
if err = t.Transport.Flush(); err != nil {
if err = t.Transport.Flush(ctx); err != nil {
return
}

View file

@ -47,7 +47,14 @@ func NewTServerSocketTimeout(listenAddr string, clientTimeout time.Duration) (*T
return &TServerSocket{addr: addr, clientTimeout: clientTimeout}, nil
}
// Creates a TServerSocket from a net.Addr
func NewTServerSocketFromAddrTimeout(addr net.Addr, clientTimeout time.Duration) *TServerSocket {
return &TServerSocket{addr: addr, clientTimeout: clientTimeout}
}
func (p *TServerSocket) Listen() error {
p.mu.Lock()
defer p.mu.Unlock()
if p.IsListening() {
return nil
}
@ -67,10 +74,15 @@ func (p *TServerSocket) Accept() (TTransport, error) {
if interrupted {
return nil, errTransportInterrupted
}
if p.listener == nil {
p.mu.Lock()
listener := p.listener
p.mu.Unlock()
if listener == nil {
return nil, NewTTransportException(NOT_OPEN, "No underlying server socket")
}
conn, err := p.listener.Accept()
conn, err := listener.Accept()
if err != nil {
return nil, NewTTransportExceptionFromError(err)
}
@ -84,6 +96,8 @@ func (p *TServerSocket) IsListening() bool {
// Connects the socket, creating a new socket object if necessary.
func (p *TServerSocket) Open() error {
p.mu.Lock()
defer p.mu.Unlock()
if p.IsListening() {
return NewTTransportException(ALREADY_OPEN, "Server socket already open")
}
@ -103,20 +117,21 @@ func (p *TServerSocket) Addr() net.Addr {
}
func (p *TServerSocket) Close() error {
defer func() {
p.listener = nil
}()
var err error
p.mu.Lock()
if p.IsListening() {
return p.listener.Close()
err = p.listener.Close()
p.listener = nil
}
return nil
p.mu.Unlock()
return err
}
func (p *TServerSocket) Interrupt() error {
p.mu.Lock()
p.interrupted = true
p.Close()
p.mu.Unlock()
p.Close()
return nil
}

View file

@ -22,6 +22,7 @@ package thrift
import (
"bufio"
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
@ -552,7 +553,7 @@ func (p *TSimpleJSONProtocol) ReadBinary() ([]byte, error) {
return v, p.ParsePostValue()
}
func (p *TSimpleJSONProtocol) Flush() (err error) {
func (p *TSimpleJSONProtocol) Flush(ctx context.Context) (err error) {
return NewTProtocolException(p.writer.Flush())
}
@ -1064,7 +1065,7 @@ func (p *TSimpleJSONProtocol) ParseListEnd() error {
for _, char := range line {
switch char {
default:
e := fmt.Errorf("Expecting end of list \"]\", but found: \"", line, "\"")
e := fmt.Errorf("Expecting end of list \"]\", but found: \"%v\"", line)
return NewTProtocolExceptionWithType(INVALID_DATA, e)
case ' ', '\n', '\r', '\t', rune(JSON_RBRACKET[0]):
break

View file

@ -23,11 +23,18 @@ import (
"log"
"runtime/debug"
"sync"
"sync/atomic"
)
// Simple, non-concurrent server for testing.
/*
* This is not a typical TSimpleServer as it is not blocked after accept a socket.
* It is more like a TThreadedServer that can handle different connections in different goroutines.
* This will work if golang user implements a conn-pool like thing in client side.
*/
type TSimpleServer struct {
quit chan struct{}
closed int32
wg sync.WaitGroup
mu sync.Mutex
processorFactory TProcessorFactory
serverTransport TServerTransport
@ -87,7 +94,6 @@ func NewTSimpleServerFactory6(processorFactory TProcessorFactory, serverTranspor
outputTransportFactory: outputTransportFactory,
inputProtocolFactory: inputProtocolFactory,
outputProtocolFactory: outputProtocolFactory,
quit: make(chan struct{}, 1),
}
}
@ -119,23 +125,37 @@ func (p *TSimpleServer) Listen() error {
return p.serverTransport.Listen()
}
func (p *TSimpleServer) innerAccept() (int32, error) {
client, err := p.serverTransport.Accept()
p.mu.Lock()
defer p.mu.Unlock()
closed := atomic.LoadInt32(&p.closed)
if closed != 0 {
return closed, nil
}
if err != nil {
return 0, err
}
if client != nil {
p.wg.Add(1)
go func() {
defer p.wg.Done()
if err := p.processRequests(client); err != nil {
log.Println("error processing request:", err)
}
}()
}
return 0, nil
}
func (p *TSimpleServer) AcceptLoop() error {
for {
client, err := p.serverTransport.Accept()
closed, err := p.innerAccept()
if err != nil {
select {
case <-p.quit:
return nil
default:
}
return err
}
if client != nil {
go func() {
if err := p.processRequests(client); err != nil {
log.Println("error processing request:", err)
}
}()
if closed != 0 {
return nil
}
}
}
@ -149,21 +169,28 @@ func (p *TSimpleServer) Serve() error {
return nil
}
var once sync.Once
func (p *TSimpleServer) Stop() error {
q := func() {
p.quit <- struct{}{}
p.serverTransport.Interrupt()
p.mu.Lock()
defer p.mu.Unlock()
if atomic.LoadInt32(&p.closed) != 0 {
return nil
}
once.Do(q)
atomic.StoreInt32(&p.closed, 1)
p.serverTransport.Interrupt()
p.wg.Wait()
return nil
}
func (p *TSimpleServer) processRequests(client TTransport) error {
processor := p.processorFactory.GetProcessor(client)
inputTransport := p.inputTransportFactory.GetTransport(client)
outputTransport := p.outputTransportFactory.GetTransport(client)
inputTransport, err := p.inputTransportFactory.GetTransport(client)
if err != nil {
return err
}
outputTransport, err := p.outputTransportFactory.GetTransport(client)
if err != nil {
return err
}
inputProtocol := p.inputProtocolFactory.GetProtocol(inputTransport)
outputProtocol := p.outputProtocolFactory.GetProtocol(outputTransport)
defer func() {
@ -171,6 +198,7 @@ func (p *TSimpleServer) processRequests(client TTransport) error {
log.Printf("panic in processor: %s: %s", e, debug.Stack())
}
}()
if inputTransport != nil {
defer inputTransport.Close()
}
@ -178,17 +206,20 @@ func (p *TSimpleServer) processRequests(client TTransport) error {
defer outputTransport.Close()
}
for {
ok, err := processor.Process(inputProtocol, outputProtocol)
if atomic.LoadInt32(&p.closed) != 0 {
return nil
}
ok, err := processor.Process(defaultCtx, inputProtocol, outputProtocol)
if err, ok := err.(TTransportException); ok && err.TypeId() == END_OF_FILE {
return nil
} else if err != nil {
log.Printf("error processing request: %s", err)
return err
}
if err, ok := err.(TApplicationException); ok && err.TypeId() == UNKNOWN_METHOD {
continue
}
if !ok {
if !ok {
break
}
}

View file

@ -20,6 +20,7 @@
package thrift
import (
"context"
"net"
"time"
)
@ -148,7 +149,7 @@ func (p *TSocket) Write(buf []byte) (int, error) {
return p.conn.Write(buf)
}
func (p *TSocket) Flush() error {
func (p *TSocket) Flush(ctx context.Context) error {
return nil
}
@ -161,6 +162,5 @@ func (p *TSocket) Interrupt() error {
func (p *TSocket) RemainingBytes() (num_bytes uint64) {
const maxSize = ^uint64(0)
return maxSize // the thruth is, we just don't know unless framed is used
return maxSize // the thruth is, we just don't know unless framed is used
}

View file

@ -20,9 +20,9 @@
package thrift
import (
"crypto/tls"
"net"
"time"
"crypto/tls"
)
type TSSLServerSocket struct {
@ -38,6 +38,9 @@ func NewTSSLServerSocket(listenAddr string, cfg *tls.Config) (*TSSLServerSocket,
}
func NewTSSLServerSocketTimeout(listenAddr string, cfg *tls.Config, clientTimeout time.Duration) (*TSSLServerSocket, error) {
if cfg.MinVersion == 0 {
cfg.MinVersion = tls.VersionTLS10
}
addr, err := net.ResolveTCPAddr("tcp", listenAddr)
if err != nil {
return nil, err

View file

@ -20,6 +20,7 @@
package thrift
import (
"context"
"crypto/tls"
"net"
"time"
@ -48,6 +49,9 @@ func NewTSSLSocket(hostPort string, cfg *tls.Config) (*TSSLSocket, error) {
// NewTSSLSocketTimeout creates a net.Conn-backed TTransport, given a host and port
// it also accepts a tls Configuration and a timeout as a time.Duration
func NewTSSLSocketTimeout(hostPort string, cfg *tls.Config, timeout time.Duration) (*TSSLSocket, error) {
if cfg.MinVersion == 0 {
cfg.MinVersion = tls.VersionTLS10
}
return &TSSLSocket{hostPort: hostPort, timeout: timeout, cfg: cfg}, nil
}
@ -87,7 +91,8 @@ func (p *TSSLSocket) Open() error {
// If we have a hostname, we need to pass the hostname to tls.Dial for
// certificate hostname checks.
if p.hostPort != "" {
if p.conn, err = tls.Dial("tcp", p.hostPort, p.cfg); err != nil {
if p.conn, err = tls.DialWithDialer(&net.Dialer{
Timeout: p.timeout}, "tcp", p.hostPort, p.cfg); err != nil {
return NewTTransportException(NOT_OPEN, err.Error())
}
} else {
@ -103,7 +108,8 @@ func (p *TSSLSocket) Open() error {
if len(p.addr.String()) == 0 {
return NewTTransportException(NOT_OPEN, "Cannot open bad address.")
}
if p.conn, err = tls.Dial(p.addr.Network(), p.addr.String(), p.cfg); err != nil {
if p.conn, err = tls.DialWithDialer(&net.Dialer{
Timeout: p.timeout}, p.addr.Network(), p.addr.String(), p.cfg); err != nil {
return NewTTransportException(NOT_OPEN, err.Error())
}
}
@ -153,7 +159,7 @@ func (p *TSSLSocket) Write(buf []byte) (int, error) {
return p.conn.Write(buf)
}
func (p *TSSLSocket) Flush() error {
func (p *TSSLSocket) Flush(ctx context.Context) error {
return nil
}
@ -166,6 +172,5 @@ func (p *TSSLSocket) Interrupt() error {
func (p *TSSLSocket) RemainingBytes() (num_bytes uint64) {
const maxSize = ^uint64(0)
return maxSize // the thruth is, we just don't know unless framed is used
return maxSize // the thruth is, we just don't know unless framed is used
}

View file

@ -20,6 +20,7 @@
package thrift
import (
"context"
"errors"
"io"
)
@ -30,15 +31,18 @@ type Flusher interface {
Flush() (err error)
}
type ContextFlusher interface {
Flush(ctx context.Context) (err error)
}
type ReadSizeProvider interface {
RemainingBytes() (num_bytes uint64)
}
// Encapsulates the I/O layer
type TTransport interface {
io.ReadWriteCloser
Flusher
ContextFlusher
ReadSizeProvider
// Opens the transport for communication
@ -52,7 +56,6 @@ type stringWriter interface {
WriteString(s string) (n int, err error)
}
// This is "enchanced" transport with extra capabilities. You need to use one of these
// to construct protocol.
// Notably, TSocket does not implement this interface, and it is always a mistake to use
@ -62,7 +65,6 @@ type TRichTransport interface {
io.ByteReader
io.ByteWriter
stringWriter
Flusher
ContextFlusher
ReadSizeProvider
}

View file

@ -24,14 +24,14 @@ package thrift
// a ServerTransport and then may want to mutate them (i.e. create
// a BufferedTransport from the underlying base transport)
type TTransportFactory interface {
GetTransport(trans TTransport) TTransport
GetTransport(trans TTransport) (TTransport, error)
}
type tTransportFactory struct{}
// Return a wrapped instance of the base Transport.
func (p *tTransportFactory) GetTransport(trans TTransport) TTransport {
return trans
func (p *tTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
return trans, nil
}
func NewTTransportFactory() TTransportFactory {

View file

@ -21,13 +21,15 @@ package thrift
import (
"compress/zlib"
"context"
"io"
"log"
)
// TZlibTransportFactory is a factory for TZlibTransport instances
type TZlibTransportFactory struct {
level int
level int
factory TTransportFactory
}
// TZlibTransport is a TTransport implementation that makes use of zlib compression.
@ -38,14 +40,27 @@ type TZlibTransport struct {
}
// GetTransport constructs a new instance of NewTZlibTransport
func (p *TZlibTransportFactory) GetTransport(trans TTransport) TTransport {
t, _ := NewTZlibTransport(trans, p.level)
return t
func (p *TZlibTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
if p.factory != nil {
// wrap other factory
var err error
trans, err = p.factory.GetTransport(trans)
if err != nil {
return nil, err
}
}
return NewTZlibTransport(trans, p.level)
}
// NewTZlibTransportFactory constructs a new instance of NewTZlibTransportFactory
func NewTZlibTransportFactory(level int) *TZlibTransportFactory {
return &TZlibTransportFactory{level: level}
return &TZlibTransportFactory{level: level, factory: nil}
}
// NewTZlibTransportFactory constructs a new instance of TZlibTransportFactory
// as a wrapper over existing transport factory
func NewTZlibTransportFactoryWithFactory(level int, factory TTransportFactory) *TZlibTransportFactory {
return &TZlibTransportFactory{level: level, factory: factory}
}
// NewTZlibTransport constructs a new instance of TZlibTransport
@ -77,11 +92,11 @@ func (z *TZlibTransport) Close() error {
}
// Flush flushes the writer and its underlying transport.
func (z *TZlibTransport) Flush() error {
func (z *TZlibTransport) Flush(ctx context.Context) error {
if err := z.writer.Flush(); err != nil {
return err
}
return z.transport.Flush()
return z.transport.Flush(ctx)
}
// IsOpen returns true if the transport is open

239
vendor/github.com/apache/thrift/tutorial/hs/LICENSE generated vendored Normal file
View file

@ -0,0 +1,239 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
--------------------------------------------------
SOFTWARE DISTRIBUTED WITH THRIFT:
The Apache Thrift software includes a number of subcomponents with
separate copyright notices and license terms. Your use of the source
code for the these subcomponents is subject to the terms and
conditions of the following licenses.
--------------------------------------------------
Portions of the following files are licensed under the MIT License:
lib/erl/src/Makefile.am
Please see doc/otp-base-license.txt for the full terms of this license.
--------------------------------------------------
For the aclocal/ax_boost_base.m4 and contrib/fb303/aclocal/ax_boost_base.m4 components:
# Copyright (c) 2007 Thomas Porschberg <thomas@randspringer.de>
#
# Copying and distribution of this file, with or without
# modification, are permitted in any medium without royalty provided
# the copyright notice and this notice are preserved.
--------------------------------------------------
For the lib/nodejs/lib/thrift/json_parse.js:
/*
json_parse.js
2015-05-02
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
(By Douglas Crockford <douglas@crockford.com>)
--------------------------------------------------

View file

@ -1,21 +1,201 @@
The MIT License (MIT)
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Copyright (c) 2016 The OpenTracing Authors
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
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:
1. Definitions.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
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.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2016 The OpenTracing 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.

View file

@ -1,6 +1,6 @@
package ext
import opentracing "github.com/opentracing/opentracing-go"
import "github.com/opentracing/opentracing-go"
// These constants define common tag names recommended for better portability across
// tracing systems and languages/platforms.
@ -74,7 +74,7 @@ var (
PeerHostname = stringTagName("peer.hostname")
// PeerHostIPv4 records IP v4 host address of the peer
PeerHostIPv4 = uint32TagName("peer.ipv4")
PeerHostIPv4 = ipv4Tag("peer.ipv4")
// PeerHostIPv6 records IP v6 host address of the peer
PeerHostIPv6 = stringTagName("peer.ipv6")
@ -196,3 +196,15 @@ type boolTagName string
func (tag boolTagName) Set(span opentracing.Span, value bool) {
span.SetTag(string(tag), value)
}
type ipv4Tag string
// Set adds IP v4 host address of the peer as an uint32 value to the `span`, keep this for backward and zipkin compatibility
func (tag ipv4Tag) Set(span opentracing.Span, value uint32) {
span.SetTag(string(tag), value)
}
// SetString records IP v4 host address of the peer as a .-separated tuple to the `span`. E.g., "127.0.0.1"
func (tag ipv4Tag) SetString(span opentracing.Span, value string) {
span.SetTag(string(tag), value)
}

View file

@ -1,7 +1,12 @@
package opentracing
type registeredTracer struct {
tracer Tracer
isRegistered bool
}
var (
globalTracer Tracer = NoopTracer{}
globalTracer = registeredTracer{NoopTracer{}, false}
)
// SetGlobalTracer sets the [singleton] opentracing.Tracer returned by
@ -11,22 +16,27 @@ var (
// Prior to calling `SetGlobalTracer`, any Spans started via the `StartSpan`
// (etc) globals are noops.
func SetGlobalTracer(tracer Tracer) {
globalTracer = tracer
globalTracer = registeredTracer{tracer, true}
}
// GlobalTracer returns the global singleton `Tracer` implementation.
// Before `SetGlobalTracer()` is called, the `GlobalTracer()` is a noop
// implementation that drops all data handed to it.
func GlobalTracer() Tracer {
return globalTracer
return globalTracer.tracer
}
// StartSpan defers to `Tracer.StartSpan`. See `GlobalTracer()`.
func StartSpan(operationName string, opts ...StartSpanOption) Span {
return globalTracer.StartSpan(operationName, opts...)
return globalTracer.tracer.StartSpan(operationName, opts...)
}
// InitGlobalTracer is deprecated. Please use SetGlobalTracer.
func InitGlobalTracer(tracer Tracer) {
SetGlobalTracer(tracer)
}
// IsGlobalTracerRegistered returns a `bool` to indicate if a tracer has been globally registered
func IsGlobalTracerRegistered() bool {
return globalTracer.isRegistered
}

View file

@ -1,6 +1,6 @@
package opentracing
import "golang.org/x/net/context"
import "context"
type contextKey struct{}
@ -41,17 +41,20 @@ func SpanFromContext(ctx context.Context) Span {
// ...
// }
func StartSpanFromContext(ctx context.Context, operationName string, opts ...StartSpanOption) (Span, context.Context) {
return startSpanFromContextWithTracer(ctx, GlobalTracer(), operationName, opts...)
return StartSpanFromContextWithTracer(ctx, GlobalTracer(), operationName, opts...)
}
// startSpanFromContextWithTracer is factored out for testing purposes.
func startSpanFromContextWithTracer(ctx context.Context, tracer Tracer, operationName string, opts ...StartSpanOption) (Span, context.Context) {
var span Span
// StartSpanFromContextWithTracer starts and returns a span with `operationName`
// using a span found within the context as a ChildOfRef. If that doesn't exist
// it creates a root span. It also returns a context.Context object built
// around the returned span.
//
// It's behavior is identical to StartSpanFromContext except that it takes an explicit
// tracer as opposed to using the global tracer.
func StartSpanFromContextWithTracer(ctx context.Context, tracer Tracer, operationName string, opts ...StartSpanOption) (Span, context.Context) {
if parentSpan := SpanFromContext(ctx); parentSpan != nil {
opts = append(opts, ChildOf(parentSpan.Context()))
span = tracer.StartSpan(operationName, opts...)
} else {
span = tracer.StartSpan(operationName, opts...)
}
span := tracer.StartSpan(operationName, opts...)
return span, ContextWithSpan(ctx, span)
}

View file

@ -20,6 +20,7 @@ const (
errorType
objectType
lazyLoggerType
noopType
)
// Field instances are constructed via LogBool, LogString, and so on.
@ -152,6 +153,25 @@ func Lazy(ll LazyLogger) Field {
}
}
// Noop creates a no-op log field that should be ignored by the tracer.
// It can be used to capture optional fields, for example those that should
// only be logged in non-production environment:
//
// func customerField(order *Order) log.Field {
// if os.Getenv("ENVIRONMENT") == "dev" {
// return log.String("customer", order.Customer.ID)
// }
// return log.Noop()
// }
//
// span.LogFields(log.String("event", "purchase"), customerField(order))
//
func Noop() Field {
return Field{
fieldType: noopType,
}
}
// Encoder allows access to the contents of a Field (via a call to
// Field.Marshal).
//
@ -203,6 +223,8 @@ func (lf Field) Marshal(visitor Encoder) {
visitor.EmitObject(lf.key, lf.interfaceVal)
case lazyLoggerType:
visitor.EmitLazyLogger(lf.interfaceVal.(LazyLogger))
case noopType:
// intentionally left blank
}
}
@ -234,6 +256,8 @@ func (lf Field) Value() interface{} {
return math.Float64frombits(uint64(lf.numericVal))
case errorType, objectType, lazyLoggerType:
return lf.interfaceVal
case noopType:
return nil
default:
return nil
}

View file

@ -72,18 +72,18 @@ const (
//
// For Tracer.Extract(): the carrier must be a `TextMapReader`.
//
// See HTTPHeaderCarrier for an implementation of both TextMapWriter
// See HTTPHeadersCarrier for an implementation of both TextMapWriter
// and TextMapReader that defers to an http.Header instance for storage.
// For example, Inject():
//
// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
// err := span.Tracer().Inject(
// span, opentracing.HTTPHeaders, carrier)
// span.Context(), opentracing.HTTPHeaders, carrier)
//
// Or Extract():
//
// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
// span, err := tracer.Extract(
// clientContext, err := tracer.Extract(
// opentracing.HTTPHeaders, carrier)
//
HTTPHeaders
@ -144,15 +144,15 @@ func (c TextMapCarrier) Set(key, val string) {
//
// Example usage for server side:
//
// carrier := opentracing.HttpHeadersCarrier(httpReq.Header)
// spanContext, err := tracer.Extract(opentracing.HttpHeaders, carrier)
// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
// clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)
//
// Example usage for client side:
//
// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
// err := tracer.Inject(
// span.Context(),
// opentracing.HttpHeaders,
// opentracing.HTTPHeaders,
// carrier)
//
type HTTPHeadersCarrier http.Header
@ -160,7 +160,7 @@ type HTTPHeadersCarrier http.Header
// Set conforms to the TextMapWriter interface.
func (c HTTPHeadersCarrier) Set(key, val string) {
h := http.Header(c)
h.Add(key, val)
h.Set(key, val)
}
// ForeachKey conforms to the TextMapReader interface.

View file

@ -41,6 +41,8 @@ type Span interface {
Context() SpanContext
// Sets or changes the operation name.
//
// Returns a reference to this Span for chaining.
SetOperationName(operationName string) Span
// Adds a tag to the span.
@ -51,6 +53,8 @@ type Span interface {
// other tag value types is undefined at the OpenTracing level. If a
// tracing system does not know how to handle a particular value type, it
// may ignore the tag, but shall not panic.
//
// Returns a reference to this Span for chaining.
SetTag(key string, value interface{}) Span
// LogFields is an efficient and type-checked way to record key:value

View file

@ -30,7 +30,7 @@ type Tracer interface {
// sp := tracer.StartSpan(
// "GetFeed",
// opentracing.ChildOf(parentSpan.Context()),
// opentracing.Tag("user_agent", loggedReq.UserAgent),
// opentracing.Tag{"user_agent", loggedReq.UserAgent},
// opentracing.StartTime(loggedReq.Timestamp),
// )
//
@ -44,8 +44,7 @@ type Tracer interface {
// and each has an expected carrier type.
//
// Other packages may declare their own `format` values, much like the keys
// used by `context.Context` (see
// https://godoc.org/golang.org/x/net/context#WithValue).
// used by `context.Context` (see https://godoc.org/context#WithValue).
//
// Example usage (sans error handling):
//

View file

@ -3,12 +3,11 @@ package zipkintracer
import (
"bytes"
"net/http"
"sync"
"time"
"github.com/apache/thrift/lib/go/thrift"
"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore"
"github.com/openzipkin-contrib/zipkin-go-opentracing/thrift/gen-go/zipkincore"
)
// Default timeout for http request in seconds
@ -29,12 +28,9 @@ type HTTPCollector struct {
batchInterval time.Duration
batchSize int
maxBacklog int
batch []*zipkincore.Span
spanc chan *zipkincore.Span
quit chan struct{}
shutdown chan error
sendMutex *sync.Mutex
batchMutex *sync.Mutex
reqCallback RequestCallback
}
@ -100,25 +96,32 @@ func NewHTTPCollector(url string, options ...HTTPOption) (Collector, error) {
batchInterval: defaultHTTPBatchInterval * time.Second,
batchSize: defaultHTTPBatchSize,
maxBacklog: defaultHTTPMaxBacklog,
batch: []*zipkincore.Span{},
spanc: make(chan *zipkincore.Span),
quit: make(chan struct{}, 1),
shutdown: make(chan error, 1),
sendMutex: &sync.Mutex{},
batchMutex: &sync.Mutex{},
}
for _, option := range options {
option(c)
}
// spanc can immediately accept maxBacklog spans and everything else is dropped.
c.spanc = make(chan *zipkincore.Span, c.maxBacklog)
go c.loop()
return c, nil
}
// Collect implements Collector.
// attempts a non blocking send on the channel.
func (c *HTTPCollector) Collect(s *zipkincore.Span) error {
c.spanc <- s
select {
case c.spanc <- s:
// Accepted.
case <-c.quit:
// Collector concurrently closed.
default:
c.logger.Log("msg", "queue full, disposing spans.", "size", len(c.spanc))
}
return nil
}
@ -153,55 +156,35 @@ func (c *HTTPCollector) loop() {
)
defer ticker.Stop()
// The following loop is single threaded
// allocate enough space so we don't have to reallocate.
batch := make([]*zipkincore.Span, 0, c.batchSize)
for {
select {
case span := <-c.spanc:
currentBatchSize := c.append(span)
if currentBatchSize >= c.batchSize {
batch = append(batch, span)
if len(batch) == c.batchSize {
c.send(batch)
batch = batch[0:0]
nextSend = time.Now().Add(c.batchInterval)
go c.send()
}
case <-tickc:
if time.Now().After(nextSend) {
if len(batch) > 0 {
c.send(batch)
batch = batch[0:0]
}
nextSend = time.Now().Add(c.batchInterval)
go c.send()
}
case <-c.quit:
c.shutdown <- c.send()
c.shutdown <- c.send(batch)
return
}
}
}
func (c *HTTPCollector) append(span *zipkincore.Span) (newBatchSize int) {
c.batchMutex.Lock()
defer c.batchMutex.Unlock()
c.batch = append(c.batch, span)
if len(c.batch) > c.maxBacklog {
dispose := len(c.batch) - c.maxBacklog
c.logger.Log("msg", "backlog too long, disposing spans.", "count", dispose)
c.batch = c.batch[dispose:]
}
newBatchSize = len(c.batch)
return
}
func (c *HTTPCollector) send() error {
// in order to prevent sending the same batch twice
c.sendMutex.Lock()
defer c.sendMutex.Unlock()
// Select all current spans in the batch to be sent
c.batchMutex.Lock()
sendBatch := c.batch[:]
c.batchMutex.Unlock()
// Do not send an empty batch
if len(sendBatch) == 0 {
return nil
}
func (c *HTTPCollector) send(sendBatch []*zipkincore.Span) error {
req, err := http.NewRequest(
"POST",
c.url,
@ -214,15 +197,15 @@ func (c *HTTPCollector) send() error {
if c.reqCallback != nil {
c.reqCallback(req)
}
if _, err = c.client.Do(req); err != nil {
resp, err := c.client.Do(req)
if err != nil {
c.logger.Log("err", err.Error())
return err
}
// Remove sent spans from the batch
c.batchMutex.Lock()
c.batch = c.batch[len(sendBatch):]
c.batchMutex.Unlock()
resp.Body.Close()
// non 2xx code
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
c.logger.Log("err", "HTTP POST span failed", "code", resp.Status)
}
return nil
}

View file

@ -4,7 +4,7 @@ import (
"github.com/Shopify/sarama"
"github.com/apache/thrift/lib/go/thrift"
"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore"
"github.com/openzipkin-contrib/zipkin-go-opentracing/thrift/gen-go/zipkincore"
)
// defaultKafkaTopic sets the standard Kafka topic our Collector will publish

View file

@ -1,6 +1,7 @@
package zipkintracer
import (
"context"
"encoding/base64"
"fmt"
"net"
@ -9,8 +10,8 @@ import (
"github.com/apache/thrift/lib/go/thrift"
"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/scribe"
"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore"
"github.com/openzipkin-contrib/zipkin-go-opentracing/thrift/gen-go/scribe"
"github.com/openzipkin-contrib/zipkin-go-opentracing/thrift/gen-go/zipkincore"
)
const defaultScribeCategory = "zipkin"
@ -112,8 +113,13 @@ func NewScribeCollector(addr string, timeout time.Duration, options ...ScribeOpt
// Collect implements Collector.
func (c *ScribeCollector) Collect(s *zipkincore.Span) error {
c.spanc <- s
return nil // accepted
select {
case c.spanc <- s:
// Accepted.
case <-c.quit:
// Collector concurrently closed.
}
return nil
}
// Close implements Collector.
@ -198,7 +204,7 @@ func (c *ScribeCollector) send() error {
return err
}
}
if rc, err := c.client.Log(sendBatch); err != nil {
if rc, err := c.client.Log(context.Background(), sendBatch); err != nil {
c.client = nil
_ = c.logger.Log("err", fmt.Sprintf("during Log: %v", err))
return err

View file

@ -3,7 +3,7 @@ package zipkintracer
import (
"strings"
"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore"
"github.com/openzipkin-contrib/zipkin-go-opentracing/thrift/gen-go/zipkincore"
)
// Collector represents a Zipkin trace collector, which is probably a set of
@ -47,6 +47,11 @@ func (c MultiCollector) aggregateErrors(f func(c Collector) error) error {
e.errs[i] = err
}
}
if e == nil {
return nil
}
return e
}

View file

@ -1,8 +1,8 @@
package zipkintracer
import (
"github.com/openzipkin/zipkin-go-opentracing/flag"
"github.com/openzipkin/zipkin-go-opentracing/types"
"github.com/openzipkin-contrib/zipkin-go-opentracing/flag"
"github.com/openzipkin-contrib/zipkin-go-opentracing/types"
)
// SpanContext holds the basic Span metadata.

View file

@ -1,8 +1,8 @@
package zipkintracer
import (
opentracing "github.com/opentracing/opentracing-go"
otobserver "github.com/opentracing-contrib/go-observer"
opentracing "github.com/opentracing/opentracing-go"
)
// observer is a dispatcher to other observers

View file

@ -3,8 +3,8 @@ package zipkintracer
import (
opentracing "github.com/opentracing/opentracing-go"
"github.com/openzipkin/zipkin-go-opentracing/flag"
"github.com/openzipkin/zipkin-go-opentracing/types"
"github.com/openzipkin-contrib/zipkin-go-opentracing/flag"
"github.com/openzipkin-contrib/zipkin-go-opentracing/types"
)
type accessorPropagator struct {

View file

@ -2,6 +2,7 @@ package zipkintracer
import (
"encoding/binary"
"fmt"
"io"
"strconv"
"strings"
@ -9,9 +10,9 @@ import (
"github.com/gogo/protobuf/proto"
opentracing "github.com/opentracing/opentracing-go"
"github.com/openzipkin/zipkin-go-opentracing/flag"
"github.com/openzipkin/zipkin-go-opentracing/types"
"github.com/openzipkin/zipkin-go-opentracing/wire"
"github.com/openzipkin-contrib/zipkin-go-opentracing/flag"
"github.com/openzipkin-contrib/zipkin-go-opentracing/types"
"github.com/openzipkin-contrib/zipkin-go-opentracing/wire"
)
type textMapPropagator struct {
@ -25,12 +26,11 @@ const (
prefixTracerState = "x-b3-" // we default to interop with non-opentracing zipkin tracers
prefixBaggage = "ot-baggage-"
tracerStateFieldCount = 3 // not 5, X-B3-ParentSpanId is optional and we allow optional Sampled header
zipkinTraceID = prefixTracerState + "traceid"
zipkinSpanID = prefixTracerState + "spanid"
zipkinParentSpanID = prefixTracerState + "parentspanid"
zipkinSampled = prefixTracerState + "sampled"
zipkinFlags = prefixTracerState + "flags"
zipkinTraceID = prefixTracerState + "traceid"
zipkinSpanID = prefixTracerState + "spanid"
zipkinParentSpanID = prefixTracerState + "parentspanid"
zipkinSampled = prefixTracerState + "sampled"
zipkinFlags = prefixTracerState + "flags"
)
func (p *textMapPropagator) Inject(
@ -45,14 +45,23 @@ func (p *textMapPropagator) Inject(
if !ok {
return opentracing.ErrInvalidCarrier
}
carrier.Set(zipkinTraceID, sc.TraceID.ToHex())
carrier.Set(zipkinSpanID, strconv.FormatUint(sc.SpanID, 16))
carrier.Set(zipkinSampled, strconv.FormatBool(sc.Sampled))
if sc.ParentSpanID != nil {
// we only set ParentSpanID header if there is a parent span
carrier.Set(zipkinParentSpanID, strconv.FormatUint(*sc.ParentSpanID, 16))
// only inject IDs if both trace ID and span ID are present
if !sc.TraceID.Empty() && sc.SpanID > 0 {
carrier.Set(zipkinTraceID, sc.TraceID.ToHex())
carrier.Set(zipkinSpanID, fmt.Sprintf("%016x", sc.SpanID))
if sc.ParentSpanID != nil {
// we only set ParentSpanID header if there is a parent span
carrier.Set(zipkinParentSpanID, fmt.Sprintf("%016x", *sc.ParentSpanID))
}
}
if sc.Sampled {
carrier.Set(zipkinSampled, "1")
} else {
carrier.Set(zipkinSampled, "0")
}
// we only need to inject the debug flag if set. see flag package for details.
flags := sc.Flags & flag.Debug
carrier.Set(zipkinFlags, strconv.FormatUint(uint64(flags), 10))
@ -80,6 +89,8 @@ func (p *textMapPropagator) Extract(
err error
)
decodedBaggage := make(map[string]string)
var traceIDFound, spanIDFound bool
err = carrier.ForeachKey(func(k, v string) error {
switch strings.ToLower(k) {
case zipkinTraceID:
@ -87,11 +98,21 @@ func (p *textMapPropagator) Extract(
if err != nil {
return opentracing.ErrSpanContextCorrupted
}
// mark TraceID as found
if !traceIDFound {
requiredFieldCount++
traceIDFound = true
}
case zipkinSpanID:
spanID, err = strconv.ParseUint(v, 16, 64)
if err != nil {
return opentracing.ErrSpanContextCorrupted
}
// mark SpanID as found
if !spanIDFound {
requiredFieldCount++
spanIDFound = true
}
case zipkinParentSpanID:
var id uint64
id, err = strconv.ParseUint(v, 16, 64)
@ -120,19 +141,15 @@ func (p *textMapPropagator) Extract(
if strings.HasPrefix(lowercaseK, prefixBaggage) {
decodedBaggage[strings.TrimPrefix(lowercaseK, prefixBaggage)] = v
}
// Balance off the requiredFieldCount++ just below...
requiredFieldCount--
}
requiredFieldCount++
return nil
})
if err != nil {
return nil, err
}
if requiredFieldCount < tracerStateFieldCount {
if requiredFieldCount == 0 {
return nil, opentracing.ErrSpanContextNotFound
}
// required fields must both be present or neither be present
if requiredFieldCount != 0 && requiredFieldCount != 2 {
return nil, opentracing.ErrSpanContextCorrupted
}

View file

@ -8,8 +8,8 @@ import (
"github.com/opentracing/opentracing-go/ext"
"github.com/opentracing/opentracing-go/log"
"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore"
otobserver "github.com/opentracing-contrib/go-observer"
"github.com/openzipkin-contrib/zipkin-go-opentracing/thrift/gen-go/zipkincore"
)
// Span provides access to the essential details of the span, for use

View file

@ -0,0 +1,7 @@
// Autogenerated by Thrift Compiler (1.0.0-dev)
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
package scribe
var GoUnusedProtection__ int;

View file

@ -1,10 +1,12 @@
// Autogenerated by Thrift Compiler (0.9.3)
// Autogenerated by Thrift Compiler (1.0.0-dev)
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
package scribe
import (
"bytes"
"context"
"reflect"
"fmt"
"github.com/apache/thrift/lib/go/thrift"
)
@ -12,7 +14,11 @@ import (
// (needed to ensure safety because of naive import list construction.)
var _ = thrift.ZERO
var _ = fmt.Printf
var _ = context.Background
var _ = reflect.DeepEqual
var _ = bytes.Equal
func init() {
}

View file

@ -0,0 +1,551 @@
// Autogenerated by Thrift Compiler (1.0.0-dev)
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
package scribe
import (
"bytes"
"context"
"reflect"
"database/sql/driver"
"errors"
"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 _ = context.Background
var _ = reflect.DeepEqual
var _ = bytes.Equal
type ResultCode int64
const (
ResultCode_OK ResultCode = 0
ResultCode_TRY_LATER ResultCode = 1
)
func (p ResultCode) String() string {
switch p {
case ResultCode_OK: return "OK"
case ResultCode_TRY_LATER: return "TRY_LATER"
}
return "<UNSET>"
}
func ResultCodeFromString(s string) (ResultCode, error) {
switch s {
case "OK": return ResultCode_OK, nil
case "TRY_LATER": return ResultCode_TRY_LATER, nil
}
return ResultCode(0), fmt.Errorf("not a valid ResultCode string")
}
func ResultCodePtr(v ResultCode) *ResultCode { return &v }
func (p ResultCode) MarshalText() ([]byte, error) {
return []byte(p.String()), nil
}
func (p *ResultCode) UnmarshalText(text []byte) error {
q, err := ResultCodeFromString(string(text))
if (err != nil) {
return err
}
*p = q
return nil
}
func (p *ResultCode) Scan(value interface{}) error {
v, ok := value.(int64)
if !ok {
return errors.New("Scan value is not int64")
}
*p = ResultCode(v)
return nil
}
func (p * ResultCode) Value() (driver.Value, error) {
if p == nil {
return nil, nil
}
return int64(*p), nil
}
// Attributes:
// - Category
// - Message
type LogEntry struct {
Category string `thrift:"category,1" db:"category" json:"category"`
Message string `thrift:"message,2" db:"message" json:"message"`
}
func NewLogEntry() *LogEntry {
return &LogEntry{}
}
func (p *LogEntry) GetCategory() string {
return p.Category
}
func (p *LogEntry) GetMessage() string {
return p.Message
}
func (p *LogEntry) 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 fieldTypeId == thrift.STRING {
if err := p.ReadField1(iprot); err != nil {
return err
}
} else {
if err := iprot.Skip(fieldTypeId); err != nil {
return err
}
}
case 2:
if fieldTypeId == thrift.STRING {
if err := p.ReadField2(iprot); err != nil {
return err
}
} else {
if err := iprot.Skip(fieldTypeId); 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 *LogEntry) ReadField1(iprot thrift.TProtocol) error {
if v, err := iprot.ReadString(); err != nil {
return thrift.PrependError("error reading field 1: ", err)
} else {
p.Category = v
}
return nil
}
func (p *LogEntry) ReadField2(iprot thrift.TProtocol) error {
if v, err := iprot.ReadString(); err != nil {
return thrift.PrependError("error reading field 2: ", err)
} else {
p.Message = v
}
return nil
}
func (p *LogEntry) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("LogEntry"); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) }
if p != nil {
if err := p.writeField1(oprot); err != nil { return err }
if err := p.writeField2(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 *LogEntry) writeField1(oprot thrift.TProtocol) (err error) {
if err := oprot.WriteFieldBegin("category", thrift.STRING, 1); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:category: ", p), err) }
if err := oprot.WriteString(string(p.Category)); err != nil {
return thrift.PrependError(fmt.Sprintf("%T.category (1) field write error: ", p), err) }
if err := oprot.WriteFieldEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field end error 1:category: ", p), err) }
return err
}
func (p *LogEntry) writeField2(oprot thrift.TProtocol) (err error) {
if err := oprot.WriteFieldBegin("message", thrift.STRING, 2); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:message: ", p), err) }
if err := oprot.WriteString(string(p.Message)); err != nil {
return thrift.PrependError(fmt.Sprintf("%T.message (2) field write error: ", p), err) }
if err := oprot.WriteFieldEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field end error 2:message: ", p), err) }
return err
}
func (p *LogEntry) String() string {
if p == nil {
return "<nil>"
}
return fmt.Sprintf("LogEntry(%+v)", *p)
}
type Scribe interface {
// Parameters:
// - Messages
Log(ctx context.Context, messages []*LogEntry) (r ResultCode, err error)
}
type ScribeClient struct {
c thrift.TClient
}
func NewScribeClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *ScribeClient {
return &ScribeClient{
c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t)),
}
}
func NewScribeClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *ScribeClient {
return &ScribeClient{
c: thrift.NewTStandardClient(iprot, oprot),
}
}
func NewScribeClient(c thrift.TClient) *ScribeClient {
return &ScribeClient{
c: c,
}
}
func (p *ScribeClient) Client_() thrift.TClient {
return p.c
}
// Parameters:
// - Messages
func (p *ScribeClient) Log(ctx context.Context, messages []*LogEntry) (r ResultCode, err error) {
var _args0 ScribeLogArgs
_args0.Messages = messages
var _result1 ScribeLogResult
if err = p.Client_().Call(ctx, "Log", &_args0, &_result1); err != nil {
return
}
return _result1.GetSuccess(), nil
}
type ScribeProcessor struct {
processorMap map[string]thrift.TProcessorFunction
handler Scribe
}
func (p *ScribeProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {
p.processorMap[key] = processor
}
func (p *ScribeProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) {
processor, ok = p.processorMap[key]
return processor, ok
}
func (p *ScribeProcessor) ProcessorMap() map[string]thrift.TProcessorFunction {
return p.processorMap
}
func NewScribeProcessor(handler Scribe) *ScribeProcessor {
self2 := &ScribeProcessor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)}
self2.processorMap["Log"] = &scribeProcessorLog{handler:handler}
return self2
}
func (p *ScribeProcessor) Process(ctx context.Context, 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(ctx, seqId, iprot, oprot)
}
iprot.Skip(thrift.STRUCT)
iprot.ReadMessageEnd()
x3 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function " + name)
oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId)
x3.Write(oprot)
oprot.WriteMessageEnd()
oprot.Flush(ctx)
return false, x3
}
type scribeProcessorLog struct {
handler Scribe
}
func (p *scribeProcessorLog) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
args := ScribeLogArgs{}
if err = args.Read(iprot); err != nil {
iprot.ReadMessageEnd()
x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())
oprot.WriteMessageBegin("Log", thrift.EXCEPTION, seqId)
x.Write(oprot)
oprot.WriteMessageEnd()
oprot.Flush(ctx)
return false, err
}
iprot.ReadMessageEnd()
result := ScribeLogResult{}
var retval ResultCode
var err2 error
if retval, err2 = p.handler.Log(ctx, args.Messages); err2 != nil {
x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing Log: " + err2.Error())
oprot.WriteMessageBegin("Log", thrift.EXCEPTION, seqId)
x.Write(oprot)
oprot.WriteMessageEnd()
oprot.Flush(ctx)
return true, err2
} else {
result.Success = &retval
}
if err2 = oprot.WriteMessageBegin("Log", 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(ctx); err == nil && err2 != nil {
err = err2
}
if err != nil {
return
}
return true, err
}
// HELPER FUNCTIONS AND STRUCTURES
// Attributes:
// - Messages
type ScribeLogArgs struct {
Messages []*LogEntry `thrift:"messages,1" db:"messages" json:"messages"`
}
func NewScribeLogArgs() *ScribeLogArgs {
return &ScribeLogArgs{}
}
func (p *ScribeLogArgs) GetMessages() []*LogEntry {
return p.Messages
}
func (p *ScribeLogArgs) 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 fieldTypeId == thrift.LIST {
if err := p.ReadField1(iprot); err != nil {
return err
}
} else {
if err := iprot.Skip(fieldTypeId); 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 *ScribeLogArgs) ReadField1(iprot thrift.TProtocol) error {
_, size, err := iprot.ReadListBegin()
if err != nil {
return thrift.PrependError("error reading list begin: ", err)
}
tSlice := make([]*LogEntry, 0, size)
p.Messages = tSlice
for i := 0; i < size; i ++ {
_elem4 := &LogEntry{}
if err := _elem4.Read(iprot); err != nil {
return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem4), err)
}
p.Messages = append(p.Messages, _elem4)
}
if err := iprot.ReadListEnd(); err != nil {
return thrift.PrependError("error reading list end: ", err)
}
return nil
}
func (p *ScribeLogArgs) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("Log_args"); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) }
if p != nil {
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 *ScribeLogArgs) writeField1(oprot thrift.TProtocol) (err error) {
if err := oprot.WriteFieldBegin("messages", thrift.LIST, 1); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:messages: ", p), err) }
if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Messages)); err != nil {
return thrift.PrependError("error writing list begin: ", err)
}
for _, v := range p.Messages {
if err := v.Write(oprot); err != nil {
return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err)
}
}
if err := oprot.WriteListEnd(); err != nil {
return thrift.PrependError("error writing list end: ", err)
}
if err := oprot.WriteFieldEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field end error 1:messages: ", p), err) }
return err
}
func (p *ScribeLogArgs) String() string {
if p == nil {
return "<nil>"
}
return fmt.Sprintf("ScribeLogArgs(%+v)", *p)
}
// Attributes:
// - Success
type ScribeLogResult struct {
Success *ResultCode `thrift:"success,0" db:"success" json:"success,omitempty"`
}
func NewScribeLogResult() *ScribeLogResult {
return &ScribeLogResult{}
}
var ScribeLogResult_Success_DEFAULT ResultCode
func (p *ScribeLogResult) GetSuccess() ResultCode {
if !p.IsSetSuccess() {
return ScribeLogResult_Success_DEFAULT
}
return *p.Success
}
func (p *ScribeLogResult) IsSetSuccess() bool {
return p.Success != nil
}
func (p *ScribeLogResult) 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 fieldTypeId == thrift.I32 {
if err := p.ReadField0(iprot); err != nil {
return err
}
} else {
if err := iprot.Skip(fieldTypeId); 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 *ScribeLogResult) ReadField0(iprot thrift.TProtocol) error {
if v, err := iprot.ReadI32(); err != nil {
return thrift.PrependError("error reading field 0: ", err)
} else {
temp := ResultCode(v)
p.Success = &temp
}
return nil
}
func (p *ScribeLogResult) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("Log_result"); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) }
if p != nil {
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 *ScribeLogResult) writeField0(oprot thrift.TProtocol) (err error) {
if p.IsSetSuccess() {
if err := oprot.WriteFieldBegin("success", thrift.I32, 0); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) }
if err := oprot.WriteI32(int32(*p.Success)); err != nil {
return thrift.PrependError(fmt.Sprintf("%T.success (0) field write error: ", p), 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 *ScribeLogResult) String() string {
if p == nil {
return "<nil>"
}
return fmt.Sprintf("ScribeLogResult(%+v)", *p)
}

View file

@ -0,0 +1,7 @@
// Autogenerated by Thrift Compiler (1.0.0-dev)
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
package zipkincore
var GoUnusedProtection__ int;

View file

@ -1,10 +1,12 @@
// Autogenerated by Thrift Compiler (0.9.3)
// Autogenerated by Thrift Compiler (1.0.0-dev)
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
package zipkincore
import (
"bytes"
"context"
"reflect"
"fmt"
"github.com/apache/thrift/lib/go/thrift"
)
@ -12,6 +14,8 @@ import (
// (needed to ensure safety because of naive import list construction.)
var _ = thrift.ZERO
var _ = fmt.Printf
var _ = context.Background
var _ = reflect.DeepEqual
var _ = bytes.Equal
const CLIENT_SEND = "cs"
@ -38,3 +42,4 @@ const SERVER_ADDR = "sa"
func init() {
}

File diff suppressed because it is too large Load diff

View file

@ -7,8 +7,8 @@ import (
opentracing "github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/openzipkin/zipkin-go-opentracing/flag"
otobserver "github.com/opentracing-contrib/go-observer"
"github.com/openzipkin-contrib/zipkin-go-opentracing/flag"
)
// ErrInvalidEndpoint will be thrown if hostPort parameter is corrupted or host

View file

@ -27,11 +27,9 @@ func TraceIDFromHex(h string) (t TraceID, err error) {
// ToHex outputs the 128-bit traceID as hex string.
func (t TraceID) ToHex() string {
if t.High == 0 {
return strconv.FormatUint(t.Low, 16)
return fmt.Sprintf("%016x", t.Low)
}
return fmt.Sprintf(
"%016s%016s", strconv.FormatUint(t.High, 16), strconv.FormatUint(t.Low, 16),
)
return fmt.Sprintf("%016x%016x", t.High, t.Low)
}
// Empty returns if TraceID has zero value

View file

@ -1,8 +1,8 @@
package wire
import (
"github.com/openzipkin/zipkin-go-opentracing/flag"
"github.com/openzipkin/zipkin-go-opentracing/types"
"github.com/openzipkin-contrib/zipkin-go-opentracing/flag"
"github.com/openzipkin-contrib/zipkin-go-opentracing/types"
)
// ProtobufCarrier is a DelegatingCarrier that uses protocol buffers as the

View file

@ -1,6 +1,6 @@
package wire
//go:generate protoc --gogofaster_out=$GOPATH/src/github.com/openzipkin/zipkin-go-opentracing/wire wire.proto
//go:generate protoc --gogofaster_out=$GOPATH/src wire.proto
// Run `go get github.com/gogo/protobuf/protoc-gen-gogofaster` to install the
// gogofaster generator binary.

View file

@ -624,24 +624,26 @@ var (
func init() { proto.RegisterFile("wire.proto", fileDescriptorWire) }
var fileDescriptorWire = []byte{
// 300 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0xcf, 0x2c, 0x4a,
0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xa9, 0xca, 0x2c, 0xc8, 0xce, 0xcc, 0x2b, 0x29,
0x4a, 0x4c, 0x4e, 0x2d, 0x8a, 0x4f, 0xcf, 0xd7, 0x03, 0xc9, 0x29, 0x5d, 0x63, 0xe2, 0xe2, 0x0e,
0x01, 0x0b, 0x05, 0x97, 0x24, 0x96, 0xa4, 0x0a, 0x49, 0x72, 0x71, 0x80, 0x55, 0xc4, 0x67, 0xa6,
0x48, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x05, 0xb1, 0x83, 0xf9, 0x9e, 0x29, 0x42, 0xe2, 0x5c, 0xec,
0xc5, 0x05, 0x89, 0x79, 0x20, 0x19, 0x26, 0xb0, 0x0c, 0x1b, 0x88, 0xeb, 0x99, 0x22, 0x24, 0xc1,
0xc5, 0x5e, 0x9c, 0x98, 0x5b, 0x90, 0x93, 0x9a, 0x22, 0xc1, 0xac, 0xc0, 0xa8, 0xc1, 0x11, 0x04,
0xe3, 0x0a, 0x45, 0x70, 0xf1, 0x26, 0x25, 0xa6, 0xa7, 0x27, 0xa6, 0xa7, 0xc6, 0x67, 0x96, 0xa4,
0xe6, 0x16, 0x4b, 0xb0, 0x28, 0x30, 0x6b, 0x70, 0x1b, 0x19, 0xeb, 0x61, 0x73, 0x8b, 0x1e, 0x92,
0x3b, 0xf4, 0x9c, 0x20, 0xda, 0x3c, 0x41, 0xba, 0x5c, 0xf3, 0x4a, 0x8a, 0x2a, 0x83, 0x78, 0x92,
0x90, 0x84, 0x84, 0x94, 0xb8, 0x78, 0x61, 0xee, 0x8c, 0xcf, 0xc8, 0x4c, 0xcf, 0x90, 0x10, 0x01,
0x3b, 0x89, 0x1b, 0xea, 0x58, 0x8f, 0xcc, 0xf4, 0x0c, 0x21, 0x15, 0x2e, 0xbe, 0x82, 0xc4, 0xa2,
0xd4, 0xbc, 0x92, 0x78, 0x98, 0xbb, 0x45, 0xc1, 0x8a, 0x78, 0x20, 0xa2, 0xc1, 0x10, 0xd7, 0x8b,
0x70, 0xb1, 0xa6, 0xe5, 0x24, 0xa6, 0x17, 0x4b, 0x88, 0x81, 0x25, 0x21, 0x1c, 0x29, 0x7b, 0x2e,
0x41, 0x0c, 0x27, 0x08, 0x09, 0x70, 0x31, 0x67, 0xa7, 0x56, 0x82, 0xc3, 0x85, 0x33, 0x08, 0xc4,
0x04, 0x69, 0x2e, 0x4b, 0xcc, 0x29, 0x4d, 0x05, 0x87, 0x08, 0x67, 0x10, 0x84, 0x63, 0xc5, 0x64,
0xc1, 0xe8, 0x24, 0x76, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31,
0x4e, 0x78, 0x2c, 0xc7, 0x10, 0xc5, 0x02, 0xf2, 0x64, 0x12, 0x1b, 0x38, 0x36, 0x8c, 0x01, 0x01,
0x00, 0x00, 0xff, 0xff, 0xb5, 0x5e, 0x0d, 0x33, 0x9b, 0x01, 0x00, 0x00,
// 325 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x91, 0xcf, 0x4a, 0x03, 0x31,
0x18, 0xc4, 0x4d, 0xab, 0xfd, 0xf3, 0xb5, 0x15, 0x0d, 0x55, 0x57, 0x0f, 0x4b, 0x29, 0x1e, 0x7a,
0xe9, 0x56, 0xec, 0x45, 0xbc, 0x08, 0x05, 0xc1, 0x5e, 0xb7, 0x1e, 0xc4, 0xcb, 0x92, 0xed, 0xc6,
0x6c, 0x68, 0x9b, 0x84, 0x6c, 0xaa, 0xd4, 0xa7, 0xf0, 0xb1, 0x3c, 0x7a, 0xf2, 0x2c, 0xf5, 0x45,
0x24, 0x89, 0x85, 0x82, 0x9e, 0x76, 0x67, 0xe6, 0x1b, 0xf8, 0x31, 0x01, 0x78, 0xe1, 0x9a, 0x46,
0x4a, 0x4b, 0x23, 0x71, 0xfb, 0x95, 0xab, 0x19, 0x17, 0x46, 0x93, 0x29, 0xd5, 0x09, 0x93, 0x91,
0xcd, 0xba, 0x9f, 0x25, 0x68, 0xdc, 0x3b, 0x6b, 0x62, 0x88, 0xa1, 0xf8, 0x14, 0x6a, 0xee, 0x22,
0xe1, 0x59, 0x80, 0x3a, 0xa8, 0x57, 0x89, 0xab, 0x4e, 0x8f, 0x33, 0x7c, 0x02, 0xd5, 0x42, 0x11,
0x61, 0x93, 0x92, 0x4b, 0x2a, 0x56, 0x8e, 0x33, 0x1c, 0x40, 0xb5, 0x20, 0x0b, 0x35, 0xa7, 0x59,
0x50, 0xee, 0xa0, 0x5e, 0x2d, 0xde, 0x48, 0xfc, 0x00, 0xad, 0x94, 0x30, 0x46, 0x18, 0x4d, 0xb8,
0xa1, 0x8b, 0x22, 0xd8, 0xed, 0x94, 0x7b, 0x8d, 0xcb, 0x61, 0xf4, 0x1f, 0x4b, 0xb4, 0xc5, 0x11,
0x8d, 0x7c, 0x6d, 0x6c, 0x5b, 0xb7, 0xc2, 0xe8, 0x55, 0xdc, 0x4c, 0xb7, 0x2c, 0xdc, 0x85, 0xd6,
0x86, 0x33, 0xc9, 0x39, 0xcb, 0x83, 0xb6, 0x43, 0x6a, 0xfc, 0xc2, 0xde, 0x71, 0x96, 0xe3, 0x73,
0xd8, 0x57, 0x44, 0x53, 0x61, 0x92, 0x0d, 0xf7, 0x91, 0x3b, 0x6a, 0x7a, 0x77, 0xe2, 0xe9, 0xdb,
0xb0, 0xf7, 0x34, 0x27, 0xac, 0x08, 0x8e, 0x5d, 0xe8, 0xc5, 0xd9, 0x0d, 0x1c, 0xfe, 0x41, 0xc0,
0x07, 0x50, 0x9e, 0xd1, 0x95, 0xdb, 0xa5, 0x1e, 0xdb, 0x5f, 0x5b, 0x7e, 0x26, 0xf3, 0x25, 0x75,
0x8b, 0xd4, 0x63, 0x2f, 0xae, 0x4b, 0x57, 0x68, 0x34, 0x7a, 0x5f, 0x87, 0xe8, 0x63, 0x1d, 0xa2,
0xaf, 0x75, 0x88, 0xde, 0xbe, 0xc3, 0x9d, 0xc7, 0x0b, 0xc6, 0x4d, 0xbe, 0x4c, 0xa3, 0xa9, 0x5c,
0x0c, 0xa4, 0xa2, 0xc2, 0x6f, 0x30, 0xf0, 0x9f, 0x3e, 0x93, 0x7d, 0x6b, 0x5a, 0x7e, 0x2e, 0xd8,
0xc0, 0x0e, 0x92, 0x56, 0xdc, 0xcb, 0x0d, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x3a, 0xab, 0xcc,
0x6b, 0xc7, 0x01, 0x00, 0x00,
}

View file

@ -6,7 +6,7 @@ import (
"strconv"
"strings"
"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore"
"github.com/openzipkin-contrib/zipkin-go-opentracing/thrift/gen-go/zipkincore"
)
// makeEndpoint takes the hostport and service name that represent this Zipkin

View file

@ -3,7 +3,6 @@ package zipkintracer
import (
"encoding/binary"
"fmt"
"math"
"net"
"strconv"
"time"
@ -11,8 +10,8 @@ import (
otext "github.com/opentracing/opentracing-go/ext"
"github.com/opentracing/opentracing-go/log"
"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore"
"github.com/openzipkin/zipkin-go-opentracing/flag"
"github.com/openzipkin-contrib/zipkin-go-opentracing/flag"
"github.com/openzipkin-contrib/zipkin-go-opentracing/thrift/gen-go/zipkincore"
)
var (
@ -162,6 +161,7 @@ func (r *Recorder) RecordSpan(sp RawSpan) {
default:
annotateBinary(span, zipkincore.LOCAL_COMPONENT, r.endpoint.GetServiceName(), r.endpoint)
}
delete(sp.Tags, string(otext.SpanKind))
} else {
annotateBinary(span, zipkincore.LOCAL_COMPONENT, r.endpoint.GetServiceName(), r.endpoint)
}
@ -202,86 +202,17 @@ func annotate(span *zipkincore.Span, timestamp time.Time, value string, host *zi
// annotateBinary annotates the span with a key and a value that will be []byte
// encoded.
func annotateBinary(span *zipkincore.Span, key string, value interface{}, host *zipkincore.Endpoint) {
var a zipkincore.AnnotationType
var b []byte
// We are not using zipkincore.AnnotationType_I16 for types that could fit
// as reporting on it seems to be broken on the zipkin web interface
// (however, we can properly extract the number from zipkin storage
// directly). int64 has issues with negative numbers but seems ok for
// positive numbers needing more than 32 bit.
switch v := value.(type) {
case bool:
a = zipkincore.AnnotationType_BOOL
b = []byte("\x00")
if v {
b = []byte("\x01")
if b, ok := value.(bool); ok {
if b {
value = "true"
} else {
value = "false"
}
case []byte:
a = zipkincore.AnnotationType_BYTES
b = v
case byte:
a = zipkincore.AnnotationType_I32
b = make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(v))
case int8:
a = zipkincore.AnnotationType_I32
b = make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(v))
case int16:
a = zipkincore.AnnotationType_I32
b = make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(v))
case uint16:
a = zipkincore.AnnotationType_I32
b = make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(v))
case int32:
a = zipkincore.AnnotationType_I32
b = make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(v))
case uint32:
a = zipkincore.AnnotationType_I32
b = make([]byte, 4)
binary.BigEndian.PutUint32(b, v)
case int64:
a = zipkincore.AnnotationType_I64
b = make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(v))
case int:
a = zipkincore.AnnotationType_I32
b = make([]byte, 8)
binary.BigEndian.PutUint32(b, uint32(v))
case uint:
a = zipkincore.AnnotationType_I32
b = make([]byte, 8)
binary.BigEndian.PutUint32(b, uint32(v))
case uint64:
a = zipkincore.AnnotationType_I64
b = make([]byte, 8)
binary.BigEndian.PutUint64(b, v)
case float32:
a = zipkincore.AnnotationType_DOUBLE
b = make([]byte, 8)
bits := math.Float64bits(float64(v))
binary.BigEndian.PutUint64(b, bits)
case float64:
a = zipkincore.AnnotationType_DOUBLE
b = make([]byte, 8)
bits := math.Float64bits(v)
binary.BigEndian.PutUint64(b, bits)
case string:
a = zipkincore.AnnotationType_STRING
b = []byte(v)
default:
// we have no handler for type's value, but let's get a string
// representation of it.
a = zipkincore.AnnotationType_STRING
b = []byte(fmt.Sprintf("%+v", value))
}
span.BinaryAnnotations = append(span.BinaryAnnotations, &zipkincore.BinaryAnnotation{
Key: key,
Value: b,
AnnotationType: a,
Value: []byte(fmt.Sprintf("%+v", value)),
AnnotationType: zipkincore.AnnotationType_STRING,
Host: host,
})
}

View file

@ -1,431 +0,0 @@
// Autogenerated by Thrift Compiler (0.9.3)
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
package scribe
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 Scribe interface {
// Parameters:
// - Messages
Log(messages []*LogEntry) (r ResultCode, err error)
}
type ScribeClient struct {
Transport thrift.TTransport
ProtocolFactory thrift.TProtocolFactory
InputProtocol thrift.TProtocol
OutputProtocol thrift.TProtocol
SeqId int32
}
func NewScribeClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *ScribeClient {
return &ScribeClient{Transport: t,
ProtocolFactory: f,
InputProtocol: f.GetProtocol(t),
OutputProtocol: f.GetProtocol(t),
SeqId: 0,
}
}
func NewScribeClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *ScribeClient {
return &ScribeClient{Transport: t,
ProtocolFactory: nil,
InputProtocol: iprot,
OutputProtocol: oprot,
SeqId: 0,
}
}
// Parameters:
// - Messages
func (p *ScribeClient) Log(messages []*LogEntry) (r ResultCode, err error) {
if err = p.sendLog(messages); err != nil {
return
}
return p.recvLog()
}
func (p *ScribeClient) sendLog(messages []*LogEntry) (err error) {
oprot := p.OutputProtocol
if oprot == nil {
oprot = p.ProtocolFactory.GetProtocol(p.Transport)
p.OutputProtocol = oprot
}
p.SeqId++
if err = oprot.WriteMessageBegin("Log", thrift.CALL, p.SeqId); err != nil {
return
}
args := ScribeLogArgs{
Messages: messages,
}
if err = args.Write(oprot); err != nil {
return
}
if err = oprot.WriteMessageEnd(); err != nil {
return
}
return oprot.Flush()
}
func (p *ScribeClient) recvLog() (value ResultCode, 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 != "Log" {
err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "Log failed: wrong method name")
return
}
if p.SeqId != seqId {
err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "Log 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, "Log failed: invalid message type")
return
}
result := ScribeLogResult{}
if err = result.Read(iprot); err != nil {
return
}
if err = iprot.ReadMessageEnd(); err != nil {
return
}
value = result.GetSuccess()
return
}
type ScribeProcessor struct {
processorMap map[string]thrift.TProcessorFunction
handler Scribe
}
func (p *ScribeProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {
p.processorMap[key] = processor
}
func (p *ScribeProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) {
processor, ok = p.processorMap[key]
return processor, ok
}
func (p *ScribeProcessor) ProcessorMap() map[string]thrift.TProcessorFunction {
return p.processorMap
}
func NewScribeProcessor(handler Scribe) *ScribeProcessor {
self2 := &ScribeProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)}
self2.processorMap["Log"] = &scribeProcessorLog{handler: handler}
return self2
}
func (p *ScribeProcessor) 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()
x3 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name)
oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId)
x3.Write(oprot)
oprot.WriteMessageEnd()
oprot.Flush()
return false, x3
}
type scribeProcessorLog struct {
handler Scribe
}
func (p *scribeProcessorLog) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
args := ScribeLogArgs{}
if err = args.Read(iprot); err != nil {
iprot.ReadMessageEnd()
x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())
oprot.WriteMessageBegin("Log", thrift.EXCEPTION, seqId)
x.Write(oprot)
oprot.WriteMessageEnd()
oprot.Flush()
return false, err
}
iprot.ReadMessageEnd()
result := ScribeLogResult{}
var retval ResultCode
var err2 error
if retval, err2 = p.handler.Log(args.Messages); err2 != nil {
x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing Log: "+err2.Error())
oprot.WriteMessageBegin("Log", thrift.EXCEPTION, seqId)
x.Write(oprot)
oprot.WriteMessageEnd()
oprot.Flush()
return true, err2
} else {
result.Success = &retval
}
if err2 = oprot.WriteMessageBegin("Log", 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:
// - Messages
type ScribeLogArgs struct {
Messages []*LogEntry `thrift:"messages,1" json:"messages"`
}
func NewScribeLogArgs() *ScribeLogArgs {
return &ScribeLogArgs{}
}
func (p *ScribeLogArgs) GetMessages() []*LogEntry {
return p.Messages
}
func (p *ScribeLogArgs) 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 *ScribeLogArgs) readField1(iprot thrift.TProtocol) error {
_, size, err := iprot.ReadListBegin()
if err != nil {
return thrift.PrependError("error reading list begin: ", err)
}
tSlice := make([]*LogEntry, 0, size)
p.Messages = tSlice
for i := 0; i < size; i++ {
_elem4 := &LogEntry{}
if err := _elem4.Read(iprot); err != nil {
return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem4), err)
}
p.Messages = append(p.Messages, _elem4)
}
if err := iprot.ReadListEnd(); err != nil {
return thrift.PrependError("error reading list end: ", err)
}
return nil
}
func (p *ScribeLogArgs) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("Log_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 *ScribeLogArgs) writeField1(oprot thrift.TProtocol) (err error) {
if err := oprot.WriteFieldBegin("messages", thrift.LIST, 1); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:messages: ", p), err)
}
if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Messages)); err != nil {
return thrift.PrependError("error writing list begin: ", err)
}
for _, v := range p.Messages {
if err := v.Write(oprot); err != nil {
return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err)
}
}
if err := oprot.WriteListEnd(); err != nil {
return thrift.PrependError("error writing list end: ", err)
}
if err := oprot.WriteFieldEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field end error 1:messages: ", p), err)
}
return err
}
func (p *ScribeLogArgs) String() string {
if p == nil {
return "<nil>"
}
return fmt.Sprintf("ScribeLogArgs(%+v)", *p)
}
// Attributes:
// - Success
type ScribeLogResult struct {
Success *ResultCode `thrift:"success,0" json:"success,omitempty"`
}
func NewScribeLogResult() *ScribeLogResult {
return &ScribeLogResult{}
}
var ScribeLogResult_Success_DEFAULT ResultCode
func (p *ScribeLogResult) GetSuccess() ResultCode {
if !p.IsSetSuccess() {
return ScribeLogResult_Success_DEFAULT
}
return *p.Success
}
func (p *ScribeLogResult) IsSetSuccess() bool {
return p.Success != nil
}
func (p *ScribeLogResult) 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 *ScribeLogResult) readField0(iprot thrift.TProtocol) error {
if v, err := iprot.ReadI32(); err != nil {
return thrift.PrependError("error reading field 0: ", err)
} else {
temp := ResultCode(v)
p.Success = &temp
}
return nil
}
func (p *ScribeLogResult) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("Log_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 *ScribeLogResult) writeField0(oprot thrift.TProtocol) (err error) {
if p.IsSetSuccess() {
if err := oprot.WriteFieldBegin("success", thrift.I32, 0); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err)
}
if err := oprot.WriteI32(int32(*p.Success)); err != nil {
return thrift.PrependError(fmt.Sprintf("%T.success (0) field write error: ", p), 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 *ScribeLogResult) String() string {
if p == nil {
return "<nil>"
}
return fmt.Sprintf("ScribeLogResult(%+v)", *p)
}

View file

@ -1,185 +0,0 @@
// Autogenerated by Thrift Compiler (0.9.3)
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
package scribe
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
var GoUnusedProtection__ int
type ResultCode int64
const (
ResultCode_OK ResultCode = 0
ResultCode_TRY_LATER ResultCode = 1
)
func (p ResultCode) String() string {
switch p {
case ResultCode_OK:
return "OK"
case ResultCode_TRY_LATER:
return "TRY_LATER"
}
return "<UNSET>"
}
func ResultCodeFromString(s string) (ResultCode, error) {
switch s {
case "OK":
return ResultCode_OK, nil
case "TRY_LATER":
return ResultCode_TRY_LATER, nil
}
return ResultCode(0), fmt.Errorf("not a valid ResultCode string")
}
func ResultCodePtr(v ResultCode) *ResultCode { return &v }
func (p ResultCode) MarshalText() ([]byte, error) {
return []byte(p.String()), nil
}
func (p *ResultCode) UnmarshalText(text []byte) error {
q, err := ResultCodeFromString(string(text))
if err != nil {
return err
}
*p = q
return nil
}
// Attributes:
// - Category
// - Message
type LogEntry struct {
Category string `thrift:"category,1" json:"category"`
Message string `thrift:"message,2" json:"message"`
}
func NewLogEntry() *LogEntry {
return &LogEntry{}
}
func (p *LogEntry) GetCategory() string {
return p.Category
}
func (p *LogEntry) GetMessage() string {
return p.Message
}
func (p *LogEntry) 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
}
case 2:
if err := p.readField2(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 *LogEntry) readField1(iprot thrift.TProtocol) error {
if v, err := iprot.ReadString(); err != nil {
return thrift.PrependError("error reading field 1: ", err)
} else {
p.Category = v
}
return nil
}
func (p *LogEntry) readField2(iprot thrift.TProtocol) error {
if v, err := iprot.ReadString(); err != nil {
return thrift.PrependError("error reading field 2: ", err)
} else {
p.Message = v
}
return nil
}
func (p *LogEntry) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("LogEntry"); 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 := p.writeField2(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 *LogEntry) writeField1(oprot thrift.TProtocol) (err error) {
if err := oprot.WriteFieldBegin("category", thrift.STRING, 1); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:category: ", p), err)
}
if err := oprot.WriteString(string(p.Category)); err != nil {
return thrift.PrependError(fmt.Sprintf("%T.category (1) field write error: ", p), err)
}
if err := oprot.WriteFieldEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field end error 1:category: ", p), err)
}
return err
}
func (p *LogEntry) writeField2(oprot thrift.TProtocol) (err error) {
if err := oprot.WriteFieldBegin("message", thrift.STRING, 2); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:message: ", p), err)
}
if err := oprot.WriteString(string(p.Message)); err != nil {
return thrift.PrependError(fmt.Sprintf("%T.message (2) field write error: ", p), err)
}
if err := oprot.WriteFieldEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field end error 2:message: ", p), err)
}
return err
}
func (p *LogEntry) String() string {
if p == nil {
return "<nil>"
}
return fmt.Sprintf("LogEntry(%+v)", *p)
}

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,7 @@ import (
throttler "github.com/uber/jaeger-client-go/internal/throttler/remote"
"github.com/uber/jaeger-client-go/rpcmetrics"
"github.com/uber/jaeger-client-go/transport"
"github.com/uber/jaeger-lib/metrics"
)
const defaultSamplingProbability = 0.001
@ -192,7 +193,7 @@ func (c Configuration) NewTracer(options ...Option) (opentracing.Tracer, io.Clos
if c.RPCMetrics {
Observer(
rpcmetrics.NewObserver(
opts.metrics.Namespace("jaeger-rpc", map[string]string{"component": "jaeger"}),
opts.metrics.Namespace(metrics.NSOptions{Name: "jaeger-rpc", Tags: map[string]string{"component": "jaeger"}}),
rpcmetrics.DefaultNameNormalizer,
),
)(&opts) // adds to c.observers
@ -230,6 +231,7 @@ func (c Configuration) NewTracer(options ...Option) (opentracing.Tracer, io.Clos
jaeger.TracerOptions.Logger(opts.logger),
jaeger.TracerOptions.CustomHeaderKeys(c.Headers),
jaeger.TracerOptions.Gen128Bit(opts.gen128Bit),
jaeger.TracerOptions.PoolSpans(opts.poolSpans),
jaeger.TracerOptions.ZipkinSharedRPCSpan(opts.zipkinSharedRPCSpan),
jaeger.TracerOptions.MaxTagValueLength(opts.maxTagValueLength),
}

View file

@ -22,7 +22,7 @@ import (
"strings"
"time"
opentracing "github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/uber/jaeger-client-go"
@ -159,46 +159,35 @@ func reporterConfigFromEnv() (*ReporterConfig, error) {
}
}
host := jaeger.DefaultUDPSpanServerHost
ep := os.Getenv(envEndpoint)
if e := os.Getenv(envAgentHost); e != "" {
if ep != "" {
return nil, errors.Errorf("cannot set env vars %s and %s together", envAgentHost, envEndpoint)
}
host = e
}
port := jaeger.DefaultUDPSpanServerPort
if e := os.Getenv(envAgentPort); e != "" {
if ep != "" {
return nil, errors.Errorf("cannot set env vars %s and %s together", envAgentPort, envEndpoint)
}
if value, err := strconv.ParseInt(e, 10, 0); err == nil {
port = int(value)
} else {
return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envAgentPort, e)
}
}
// the side effect of this is that we are building the default value, even if none of the env vars
// were not explicitly passed
rc.LocalAgentHostPort = fmt.Sprintf("%s:%d", host, port)
if ep != "" {
u, err := url.ParseRequestURI(ep)
if e := os.Getenv(envEndpoint); e != "" {
u, err := url.ParseRequestURI(e)
if err != nil {
return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envEndpoint, ep)
return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envEndpoint, e)
}
rc.CollectorEndpoint = u.String()
user := os.Getenv(envUser)
pswd := os.Getenv(envPassword)
if user != "" && pswd == "" || user == "" && pswd != "" {
return nil, errors.Errorf("you must set %s and %s env vars together", envUser, envPassword)
}
rc.User = user
rc.Password = pswd
} else {
host := jaeger.DefaultUDPSpanServerHost
if e := os.Getenv(envAgentHost); e != "" {
host = e
}
rc.CollectorEndpoint = fmt.Sprintf("%s", u)
}
user := os.Getenv(envUser)
pswd := os.Getenv(envPassword)
if user != "" && pswd == "" || user == "" && pswd != "" {
return nil, errors.Errorf("you must set %s and %s env vars together", envUser, envPassword)
port := jaeger.DefaultUDPSpanServerPort
if e := os.Getenv(envAgentPort); e != "" {
if value, err := strconv.ParseInt(e, 10, 0); err == nil {
port = int(value)
} else {
return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envAgentPort, e)
}
}
rc.LocalAgentHostPort = fmt.Sprintf("%s:%d", host, port)
}
rc.User = user
rc.Password = pswd
return rc, nil
}

View file

@ -33,6 +33,7 @@ type Options struct {
contribObservers []jaeger.ContribObserver
observers []jaeger.Observer
gen128Bit bool
poolSpans bool
zipkinSharedRPCSpan bool
maxTagValueLength int
tags []opentracing.Tag
@ -78,7 +79,7 @@ func Observer(observer jaeger.Observer) Option {
}
}
// ContribObserver can be registered with the Tracer to recieve notifications
// ContribObserver can be registered with the Tracer to receive notifications
// about new spans.
func ContribObserver(observer jaeger.ContribObserver) Option {
return func(c *Options) {
@ -93,6 +94,13 @@ func Gen128Bit(gen128Bit bool) Option {
}
}
// PoolSpans specifies whether to pool spans
func PoolSpans(poolSpans bool) Option {
return func(c *Options) {
c.poolSpans = poolSpans
}
}
// ZipkinSharedRPCSpan creates an option that enables sharing span ID between client
// and server spans a la zipkin. If false, client and server spans will be assigned
// different IDs.

View file

@ -16,7 +16,7 @@ package jaeger
const (
// JaegerClientVersion is the version of the client library reported as Span tag.
JaegerClientVersion = "Go-2.15.0"
JaegerClientVersion = "Go-2.16.0"
// JaegerClientVersionTagKey is the name of the tag used to report client version.
JaegerClientVersionTagKey = "jaeger.version"

View file

@ -198,7 +198,7 @@ func (c SpanContext) WithBaggageItem(key, value string) SpanContext {
// extract method, but now it returns a dummy context with only debugID filled in.
//
// See JaegerDebugHeader in constants.go
// See textMapPropagator#Extract
// See TextMapPropagator#Extract
func (c *SpanContext) isDebugIDContainerOnly() bool {
return !c.traceID.IsValid() && c.debugID != ""
}

View file

@ -38,7 +38,8 @@ type HeadersConfig struct {
TraceBaggageHeaderPrefix string `yaml:"traceBaggageHeaderPrefix"`
}
func (c *HeadersConfig) applyDefaults() *HeadersConfig {
// ApplyDefaults sets missing configuration keys to default values
func (c *HeadersConfig) ApplyDefaults() *HeadersConfig {
if c.JaegerBaggageHeader == "" {
c.JaegerBaggageHeader = JaegerBaggageHeader
}

View file

@ -21,83 +21,83 @@ import (
// Metrics is a container of all stats emitted by Jaeger tracer.
type Metrics struct {
// Number of traces started by this tracer as sampled
TracesStartedSampled metrics.Counter `metric:"traces" tags:"state=started,sampled=y"`
TracesStartedSampled metrics.Counter `metric:"traces" tags:"state=started,sampled=y" help:"Number of traces started by this tracer as sampled"`
// Number of traces started by this tracer as not sampled
TracesStartedNotSampled metrics.Counter `metric:"traces" tags:"state=started,sampled=n"`
TracesStartedNotSampled metrics.Counter `metric:"traces" tags:"state=started,sampled=n" help:"Number of traces started by this tracer as not sampled"`
// Number of externally started sampled traces this tracer joined
TracesJoinedSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=y"`
TracesJoinedSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=y" help:"Number of externally started sampled traces this tracer joined"`
// Number of externally started not-sampled traces this tracer joined
TracesJoinedNotSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=n"`
TracesJoinedNotSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=n" help:"Number of externally started not-sampled traces this tracer joined"`
// Number of sampled spans started by this tracer
SpansStartedSampled metrics.Counter `metric:"started_spans" tags:"sampled=y"`
SpansStartedSampled metrics.Counter `metric:"started_spans" tags:"sampled=y" help:"Number of sampled spans started by this tracer"`
// Number of unsampled spans started by this tracer
SpansStartedNotSampled metrics.Counter `metric:"started_spans" tags:"sampled=n"`
SpansStartedNotSampled metrics.Counter `metric:"started_spans" tags:"sampled=n" help:"Number of unsampled spans started by this tracer"`
// Number of spans finished by this tracer
SpansFinished metrics.Counter `metric:"finished_spans"`
SpansFinished metrics.Counter `metric:"finished_spans" help:"Number of spans finished by this tracer"`
// Number of errors decoding tracing context
DecodingErrors metrics.Counter `metric:"span_context_decoding_errors"`
DecodingErrors metrics.Counter `metric:"span_context_decoding_errors" help:"Number of errors decoding tracing context"`
// Number of spans successfully reported
ReporterSuccess metrics.Counter `metric:"reporter_spans" tags:"result=ok"`
ReporterSuccess metrics.Counter `metric:"reporter_spans" tags:"result=ok" help:"Number of spans successfully reported"`
// Number of spans not reported due to a Sender failure
ReporterFailure metrics.Counter `metric:"reporter_spans" tags:"result=err"`
ReporterFailure metrics.Counter `metric:"reporter_spans" tags:"result=err" help:"Number of spans not reported due to a Sender failure"`
// Number of spans dropped due to internal queue overflow
ReporterDropped metrics.Counter `metric:"reporter_spans" tags:"result=dropped"`
ReporterDropped metrics.Counter `metric:"reporter_spans" tags:"result=dropped" help:"Number of spans dropped due to internal queue overflow"`
// Current number of spans in the reporter queue
ReporterQueueLength metrics.Gauge `metric:"reporter_queue_length"`
ReporterQueueLength metrics.Gauge `metric:"reporter_queue_length" help:"Current number of spans in the reporter queue"`
// Number of times the Sampler succeeded to retrieve sampling strategy
SamplerRetrieved metrics.Counter `metric:"sampler_queries" tags:"result=ok"`
SamplerRetrieved metrics.Counter `metric:"sampler_queries" tags:"result=ok" help:"Number of times the Sampler succeeded to retrieve sampling strategy"`
// Number of times the Sampler failed to retrieve sampling strategy
SamplerQueryFailure metrics.Counter `metric:"sampler_queries" tags:"result=err"`
SamplerQueryFailure metrics.Counter `metric:"sampler_queries" tags:"result=err" help:"Number of times the Sampler failed to retrieve sampling strategy"`
// Number of times the Sampler succeeded to retrieve and update sampling strategy
SamplerUpdated metrics.Counter `metric:"sampler_updates" tags:"result=ok"`
SamplerUpdated metrics.Counter `metric:"sampler_updates" tags:"result=ok" help:"Number of times the Sampler succeeded to retrieve and update sampling strategy"`
// Number of times the Sampler failed to update sampling strategy
SamplerUpdateFailure metrics.Counter `metric:"sampler_updates" tags:"result=err"`
SamplerUpdateFailure metrics.Counter `metric:"sampler_updates" tags:"result=err" help:"Number of times the Sampler failed to update sampling strategy"`
// Number of times baggage was successfully written or updated on spans.
BaggageUpdateSuccess metrics.Counter `metric:"baggage_updates" tags:"result=ok"`
BaggageUpdateSuccess metrics.Counter `metric:"baggage_updates" tags:"result=ok" help:"Number of times baggage was successfully written or updated on spans"`
// Number of times baggage failed to write or update on spans.
BaggageUpdateFailure metrics.Counter `metric:"baggage_updates" tags:"result=err"`
BaggageUpdateFailure metrics.Counter `metric:"baggage_updates" tags:"result=err" help:"Number of times baggage failed to write or update on spans"`
// Number of times baggage was truncated as per baggage restrictions.
BaggageTruncate metrics.Counter `metric:"baggage_truncations"`
BaggageTruncate metrics.Counter `metric:"baggage_truncations" help:"Number of times baggage was truncated as per baggage restrictions"`
// Number of times baggage restrictions were successfully updated.
BaggageRestrictionsUpdateSuccess metrics.Counter `metric:"baggage_restrictions_updates" tags:"result=ok"`
BaggageRestrictionsUpdateSuccess metrics.Counter `metric:"baggage_restrictions_updates" tags:"result=ok" help:"Number of times baggage restrictions were successfully updated"`
// Number of times baggage restrictions failed to update.
BaggageRestrictionsUpdateFailure metrics.Counter `metric:"baggage_restrictions_updates" tags:"result=err"`
BaggageRestrictionsUpdateFailure metrics.Counter `metric:"baggage_restrictions_updates" tags:"result=err" help:"Number of times baggage restrictions failed to update"`
// Number of times debug spans were throttled.
ThrottledDebugSpans metrics.Counter `metric:"throttled_debug_spans"`
ThrottledDebugSpans metrics.Counter `metric:"throttled_debug_spans" help:"Number of times debug spans were throttled"`
// Number of times throttler successfully updated.
ThrottlerUpdateSuccess metrics.Counter `metric:"throttler_updates" tags:"result=ok"`
ThrottlerUpdateSuccess metrics.Counter `metric:"throttler_updates" tags:"result=ok" help:"Number of times throttler successfully updated"`
// Number of times throttler failed to update.
ThrottlerUpdateFailure metrics.Counter `metric:"throttler_updates" tags:"result=err"`
ThrottlerUpdateFailure metrics.Counter `metric:"throttler_updates" tags:"result=err" help:"Number of times throttler failed to update"`
}
// NewMetrics creates a new Metrics struct and initializes it.
func NewMetrics(factory metrics.Factory, globalTags map[string]string) *Metrics {
m := &Metrics{}
// TODO the namespace "jaeger" should be configurable (e.g. in all-in-one "jaeger-client" would make more sense)
metrics.Init(m, factory.Namespace("jaeger", nil), globalTags)
// TODO the namespace "jaeger" should be configurable
metrics.MustInit(m, factory.Namespace(metrics.NSOptions{Name: "jaeger"}).Namespace(metrics.NSOptions{Name: "tracer"}), globalTags)
return m
}

View file

@ -51,15 +51,17 @@ type Extractor interface {
Extract(carrier interface{}) (SpanContext, error)
}
type textMapPropagator struct {
// TextMapPropagator is a combined Injector and Extractor for TextMap format
type TextMapPropagator struct {
headerKeys *HeadersConfig
metrics Metrics
encodeValue func(string) string
decodeValue func(string) string
}
func newTextMapPropagator(headerKeys *HeadersConfig, metrics Metrics) *textMapPropagator {
return &textMapPropagator{
// NewTextMapPropagator creates a combined Injector and Extractor for TextMap format
func NewTextMapPropagator(headerKeys *HeadersConfig, metrics Metrics) *TextMapPropagator {
return &TextMapPropagator{
headerKeys: headerKeys,
metrics: metrics,
encodeValue: func(val string) string {
@ -71,8 +73,9 @@ func newTextMapPropagator(headerKeys *HeadersConfig, metrics Metrics) *textMapPr
}
}
func newHTTPHeaderPropagator(headerKeys *HeadersConfig, metrics Metrics) *textMapPropagator {
return &textMapPropagator{
// NewHTTPHeaderPropagator creates a combined Injector and Extractor for HTTPHeaders format
func NewHTTPHeaderPropagator(headerKeys *HeadersConfig, metrics Metrics) *TextMapPropagator {
return &TextMapPropagator{
headerKeys: headerKeys,
metrics: metrics,
encodeValue: func(val string) string {
@ -88,19 +91,22 @@ func newHTTPHeaderPropagator(headerKeys *HeadersConfig, metrics Metrics) *textMa
}
}
type binaryPropagator struct {
// BinaryPropagator is a combined Injector and Extractor for Binary format
type BinaryPropagator struct {
tracer *Tracer
buffers sync.Pool
}
func newBinaryPropagator(tracer *Tracer) *binaryPropagator {
return &binaryPropagator{
// NewBinaryPropagator creates a combined Injector and Extractor for Binary format
func NewBinaryPropagator(tracer *Tracer) *BinaryPropagator {
return &BinaryPropagator{
tracer: tracer,
buffers: sync.Pool{New: func() interface{} { return &bytes.Buffer{} }},
}
}
func (p *textMapPropagator) Inject(
// Inject implements Injector of TextMapPropagator
func (p *TextMapPropagator) Inject(
sc SpanContext,
abstractCarrier interface{},
) error {
@ -121,7 +127,8 @@ func (p *textMapPropagator) Inject(
return nil
}
func (p *textMapPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) {
// Extract implements Extractor of TextMapPropagator
func (p *TextMapPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) {
textMapReader, ok := abstractCarrier.(opentracing.TextMapReader)
if !ok {
return emptyContext, opentracing.ErrInvalidCarrier
@ -166,7 +173,8 @@ func (p *textMapPropagator) Extract(abstractCarrier interface{}) (SpanContext, e
return ctx, nil
}
func (p *binaryPropagator) Inject(
// Inject implements Injector of BinaryPropagator
func (p *BinaryPropagator) Inject(
sc SpanContext,
abstractCarrier interface{},
) error {
@ -207,7 +215,8 @@ func (p *binaryPropagator) Inject(
return nil
}
func (p *binaryPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) {
// Extract implements Extractor of BinaryPropagator
func (p *BinaryPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) {
carrier, ok := abstractCarrier.(io.Reader)
if !ok {
return emptyContext, opentracing.ErrInvalidCarrier
@ -269,7 +278,7 @@ func (p *binaryPropagator) Extract(abstractCarrier interface{}) (SpanContext, er
// is converted to map[string]string { "key1" : "value1",
// "key2" : "value2",
// "key3" : "value3" }
func (p *textMapPropagator) parseCommaSeparatedMap(value string) map[string]string {
func (p *TextMapPropagator) parseCommaSeparatedMap(value string) map[string]string {
baggage := make(map[string]string)
value, err := url.QueryUnescape(value)
if err != nil {
@ -289,12 +298,12 @@ func (p *textMapPropagator) parseCommaSeparatedMap(value string) map[string]stri
// Converts a baggage item key into an http header format,
// by prepending TraceBaggageHeaderPrefix and encoding the key string
func (p *textMapPropagator) addBaggageKeyPrefix(key string) string {
func (p *TextMapPropagator) addBaggageKeyPrefix(key string) string {
// TODO encodeBaggageKeyAsHeader add caching and escaping
return fmt.Sprintf("%v%v", p.headerKeys.TraceBaggageHeaderPrefix, key)
}
func (p *textMapPropagator) removeBaggageKeyPrefix(key string) string {
func (p *TextMapPropagator) removeBaggageKeyPrefix(key string) string {
// TODO decodeBaggageHeaderKey add caching and escaping
return key[len(p.headerKeys.TraceBaggageHeaderPrefix):]
}

View file

@ -34,7 +34,7 @@ type Metrics struct {
// RequestCountFailures is a counter of the number of times any failure has been observed.
RequestCountFailures metrics.Counter `metric:"requests" tags:"error=true"`
// RequestLatencySuccess is a latency histogram of succesful requests.
// RequestLatencySuccess is a latency histogram of successful requests.
RequestLatencySuccess metrics.Timer `metric:"request_latency" tags:"error=false"`
// RequestLatencyFailures is a latency histogram of failed requests.

View file

@ -18,6 +18,8 @@ const CLIENT_SEND = "cs"
const CLIENT_RECV = "cr"
const SERVER_SEND = "ss"
const SERVER_RECV = "sr"
const MESSAGE_SEND = "ms"
const MESSAGE_RECV = "mr"
const WIRE_SEND = "ws"
const WIRE_RECV = "wr"
const CLIENT_SEND_FRAGMENT = "csf"
@ -27,6 +29,7 @@ const SERVER_RECV_FRAGMENT = "srf"
const LOCAL_COMPONENT = "lc"
const CLIENT_ADDR = "ca"
const SERVER_ADDR = "sa"
const MESSAGE_ADDR = "ma"
func init() {
}

View file

@ -103,10 +103,12 @@ func (p *AnnotationType) UnmarshalText(text []byte) error {
// - ServiceName: Service name in lowercase, such as "memcache" or "zipkin-web"
//
// Conventionally, when the service name isn't known, service_name = "unknown".
// - Ipv6: IPv6 host address packed into 16 bytes. Ex Inet6Address.getBytes()
type Endpoint struct {
Ipv4 int32 `thrift:"ipv4,1" json:"ipv4"`
Port int16 `thrift:"port,2" json:"port"`
ServiceName string `thrift:"service_name,3" json:"service_name"`
Ipv6 []byte `thrift:"ipv6,4" json:"ipv6,omitempty"`
}
func NewEndpoint() *Endpoint {
@ -124,6 +126,16 @@ func (p *Endpoint) GetPort() int16 {
func (p *Endpoint) GetServiceName() string {
return p.ServiceName
}
var Endpoint_Ipv6_DEFAULT []byte
func (p *Endpoint) GetIpv6() []byte {
return p.Ipv6
}
func (p *Endpoint) IsSetIpv6() bool {
return p.Ipv6 != nil
}
func (p *Endpoint) Read(iprot thrift.TProtocol) error {
if _, err := iprot.ReadStructBegin(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
@ -150,6 +162,10 @@ func (p *Endpoint) Read(iprot thrift.TProtocol) error {
if err := p.readField3(iprot); err != nil {
return err
}
case 4:
if err := p.readField4(iprot); err != nil {
return err
}
default:
if err := iprot.Skip(fieldTypeId); err != nil {
return err
@ -192,6 +208,15 @@ func (p *Endpoint) readField3(iprot thrift.TProtocol) error {
return nil
}
func (p *Endpoint) readField4(iprot thrift.TProtocol) error {
if v, err := iprot.ReadBinary(); err != nil {
return thrift.PrependError("error reading field 4: ", err)
} else {
p.Ipv6 = v
}
return nil
}
func (p *Endpoint) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("Endpoint"); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
@ -205,6 +230,9 @@ func (p *Endpoint) Write(oprot thrift.TProtocol) error {
if err := p.writeField3(oprot); err != nil {
return err
}
if err := p.writeField4(oprot); err != nil {
return err
}
if err := oprot.WriteFieldStop(); err != nil {
return thrift.PrependError("write field stop error: ", err)
}
@ -253,6 +281,21 @@ func (p *Endpoint) writeField3(oprot thrift.TProtocol) (err error) {
return err
}
func (p *Endpoint) writeField4(oprot thrift.TProtocol) (err error) {
if p.IsSetIpv6() {
if err := oprot.WriteFieldBegin("ipv6", thrift.STRING, 4); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:ipv6: ", p), err)
}
if err := oprot.WriteBinary(p.Ipv6); err != nil {
return thrift.PrependError(fmt.Sprintf("%T.ipv6 (4) field write error: ", p), err)
}
if err := oprot.WriteFieldEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field end error 4:ipv6: ", p), err)
}
}
return err
}
func (p *Endpoint) String() string {
if p == nil {
return "<nil>"
@ -707,6 +750,8 @@ func (p *BinaryAnnotation) String() string {
// this field non-atomically is implementation-specific.
//
// This field is i64 vs i32 to support spans longer than 35 minutes.
// - TraceIDHigh: Optional unique 8-byte additional identifier for a trace. If non zero, this
// means the trace uses 128 bit traceIds instead of 64 bit.
type Span struct {
TraceID int64 `thrift:"trace_id,1" json:"trace_id"`
// unused field # 2
@ -719,6 +764,7 @@ type Span struct {
Debug bool `thrift:"debug,9" json:"debug,omitempty"`
Timestamp *int64 `thrift:"timestamp,10" json:"timestamp,omitempty"`
Duration *int64 `thrift:"duration,11" json:"duration,omitempty"`
TraceIDHigh *int64 `thrift:"trace_id_high,12" json:"trace_id_high,omitempty"`
}
func NewSpan() *Span {
@ -777,6 +823,15 @@ func (p *Span) GetDuration() int64 {
}
return *p.Duration
}
var Span_TraceIDHigh_DEFAULT int64
func (p *Span) GetTraceIDHigh() int64 {
if !p.IsSetTraceIDHigh() {
return Span_TraceIDHigh_DEFAULT
}
return *p.TraceIDHigh
}
func (p *Span) IsSetParentID() bool {
return p.ParentID != nil
}
@ -793,6 +848,10 @@ func (p *Span) IsSetDuration() bool {
return p.Duration != nil
}
func (p *Span) IsSetTraceIDHigh() bool {
return p.TraceIDHigh != nil
}
func (p *Span) Read(iprot thrift.TProtocol) error {
if _, err := iprot.ReadStructBegin(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
@ -843,6 +902,10 @@ func (p *Span) Read(iprot thrift.TProtocol) error {
if err := p.readField11(iprot); err != nil {
return err
}
case 12:
if err := p.readField12(iprot); err != nil {
return err
}
default:
if err := iprot.Skip(fieldTypeId); err != nil {
return err
@ -961,6 +1024,15 @@ func (p *Span) readField11(iprot thrift.TProtocol) error {
return nil
}
func (p *Span) readField12(iprot thrift.TProtocol) error {
if v, err := iprot.ReadI64(); err != nil {
return thrift.PrependError("error reading field 12: ", err)
} else {
p.TraceIDHigh = &v
}
return nil
}
func (p *Span) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("Span"); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
@ -992,6 +1064,9 @@ func (p *Span) Write(oprot thrift.TProtocol) error {
if err := p.writeField11(oprot); err != nil {
return err
}
if err := p.writeField12(oprot); err != nil {
return err
}
if err := oprot.WriteFieldStop(); err != nil {
return thrift.PrependError("write field stop error: ", err)
}
@ -1142,6 +1217,21 @@ func (p *Span) writeField11(oprot thrift.TProtocol) (err error) {
return err
}
func (p *Span) writeField12(oprot thrift.TProtocol) (err error) {
if p.IsSetTraceIDHigh() {
if err := oprot.WriteFieldBegin("trace_id_high", thrift.I64, 12); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 12:trace_id_high: ", p), err)
}
if err := oprot.WriteI64(int64(*p.TraceIDHigh)); err != nil {
return thrift.PrependError(fmt.Sprintf("%T.trace_id_high (12) field write error: ", p), err)
}
if err := oprot.WriteFieldEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field end error 12:trace_id_high: ", p), err)
}
}
return err
}
func (p *Span) String() string {
if p == nil {
return "<nil>"

View file

@ -17,6 +17,7 @@ package jaeger
import (
"fmt"
"io"
"math/rand"
"os"
"reflect"
"strconv"
@ -96,13 +97,13 @@ func NewTracer(
}
// register default injectors/extractors unless they are already provided via options
textPropagator := newTextMapPropagator(getDefaultHeadersConfig(), t.metrics)
textPropagator := NewTextMapPropagator(getDefaultHeadersConfig(), t.metrics)
t.addCodec(opentracing.TextMap, textPropagator, textPropagator)
httpHeaderPropagator := newHTTPHeaderPropagator(getDefaultHeadersConfig(), t.metrics)
httpHeaderPropagator := NewHTTPHeaderPropagator(getDefaultHeadersConfig(), t.metrics)
t.addCodec(opentracing.HTTPHeaders, httpHeaderPropagator, httpHeaderPropagator)
binaryPropagator := newBinaryPropagator(t)
binaryPropagator := NewBinaryPropagator(t)
t.addCodec(opentracing.Binary, binaryPropagator, binaryPropagator)
// TODO remove after TChannel supports OpenTracing
@ -122,9 +123,18 @@ func NewTracer(
}
if t.randomNumber == nil {
rng := utils.NewRand(time.Now().UnixNano())
seedGenerator := utils.NewRand(time.Now().UnixNano())
pool := sync.Pool{
New: func() interface{} {
return rand.NewSource(seedGenerator.Int63())
},
}
t.randomNumber = func() uint64 {
return uint64(rng.Int63())
generator := pool.Get().(rand.Source)
number := uint64(generator.Int63())
pool.Put(generator)
return number
}
}
if t.timeNow == nil {
@ -309,7 +319,11 @@ func (t *Tracer) Extract(
carrier interface{},
) (opentracing.SpanContext, error) {
if extractor, ok := t.extractors[format]; ok {
return extractor.Extract(carrier)
spanCtx, err := extractor.Extract(carrier)
if err != nil {
return nil, err // ensure returned spanCtx is nil
}
return spanCtx, nil
}
return nil, opentracing.ErrUnsupportedFormat
}

View file

@ -51,10 +51,10 @@ func (tracerOptions) CustomHeaderKeys(headerKeys *HeadersConfig) TracerOption {
if headerKeys == nil {
return
}
textPropagator := newTextMapPropagator(headerKeys.applyDefaults(), tracer.metrics)
textPropagator := NewTextMapPropagator(headerKeys.ApplyDefaults(), tracer.metrics)
tracer.addCodec(opentracing.TextMap, textPropagator, textPropagator)
httpHeaderPropagator := newHTTPHeaderPropagator(headerKeys.applyDefaults(), tracer.metrics)
httpHeaderPropagator := NewHTTPHeaderPropagator(headerKeys.ApplyDefaults(), tracer.metrics)
tracer.addCodec(opentracing.HTTPHeaders, httpHeaderPropagator, httpHeaderPropagator)
}
}

View file

@ -12,5 +12,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package zipkin comprises Zipkin functionality for Zipkin compatiblity.
// Package zipkin comprises Zipkin functionality for Zipkin compatibility.
package zipkin

View file

@ -23,13 +23,30 @@ import (
"github.com/uber/jaeger-client-go"
)
// Option is a function that sets an option on Propagator
type Option func(propagator *Propagator)
// BaggagePrefix is a function that sets baggage prefix on Propagator
func BaggagePrefix(prefix string) Option {
return func(propagator *Propagator) {
propagator.baggagePrefix = prefix
}
}
// Propagator is an Injector and Extractor
type Propagator struct{}
type Propagator struct {
baggagePrefix string
}
// NewZipkinB3HTTPHeaderPropagator creates a Propagator for extracting and injecting
// Zipkin HTTP B3 headers into SpanContexts.
func NewZipkinB3HTTPHeaderPropagator() Propagator {
return Propagator{}
// Zipkin HTTP B3 headers into SpanContexts. Baggage is by default enabled and uses prefix
// 'baggage-'.
func NewZipkinB3HTTPHeaderPropagator(opts ...Option) Propagator {
p := Propagator{baggagePrefix: "baggage-"}
for _, opt := range opts {
opt(&p)
}
return p
}
// Inject conforms to the Injector interface for decoding Zipkin HTTP B3 headers
@ -42,8 +59,7 @@ func (p Propagator) Inject(
return opentracing.ErrInvalidCarrier
}
// TODO this needs to change to support 128bit IDs
textMapWriter.Set("x-b3-traceid", strconv.FormatUint(sc.TraceID().Low, 16))
textMapWriter.Set("x-b3-traceid", sc.TraceID().String())
if sc.ParentID() != 0 {
textMapWriter.Set("x-b3-parentspanid", strconv.FormatUint(uint64(sc.ParentID()), 16))
}
@ -53,6 +69,10 @@ func (p Propagator) Inject(
} else {
textMapWriter.Set("x-b3-sampled", "0")
}
sc.ForeachBaggageItem(func(k, v string) bool {
textMapWriter.Set(p.baggagePrefix+k, v)
return true
})
return nil
}
@ -62,21 +82,27 @@ func (p Propagator) Extract(abstractCarrier interface{}) (jaeger.SpanContext, er
if !ok {
return jaeger.SpanContext{}, opentracing.ErrInvalidCarrier
}
var traceID uint64
var traceID jaeger.TraceID
var spanID uint64
var parentID uint64
sampled := false
var baggage map[string]string
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)
traceID, err = jaeger.TraceIDFromString(value)
} 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" {
} else if key == "x-b3-sampled" && (value == "1" || value == "true") {
sampled = true
} else if strings.HasPrefix(key, p.baggagePrefix) {
if baggage == nil {
baggage = make(map[string]string)
}
baggage[key[len(p.baggagePrefix):]] = value
}
return err
})
@ -84,12 +110,12 @@ func (p Propagator) Extract(abstractCarrier interface{}) (jaeger.SpanContext, er
if err != nil {
return jaeger.SpanContext{}, err
}
if traceID == 0 {
if !traceID.IsValid() {
return jaeger.SpanContext{}, opentracing.ErrSpanContextNotFound
}
return jaeger.NewSpanContext(
jaeger.TraceID{Low: traceID},
traceID,
jaeger.SpanID(spanID),
jaeger.SpanID(parentID),
sampled, nil), nil
sampled, baggage), nil
}

View file

@ -48,13 +48,19 @@ func BuildZipkinThrift(s *Span) *z.Span {
if parentID != 0 {
ptrParentID = &parentID
}
traceIDHigh := int64(span.context.traceID.High)
var ptrTraceIDHigh *int64
if traceIDHigh != 0 {
ptrTraceIDHigh = &traceIDHigh
}
timestamp := utils.TimeToMicrosecondsSinceEpochInt64(span.startTime)
duration := span.duration.Nanoseconds() / int64(time.Microsecond)
endpoint := &z.Endpoint{
ServiceName: span.tracer.serviceName,
Ipv4: int32(span.tracer.hostIPv4)}
thriftSpan := &z.Span{
TraceID: int64(span.context.traceID.Low), // TODO upgrade zipkin thrift and use TraceIdHigh
TraceID: int64(span.context.traceID.Low),
TraceIDHigh: ptrTraceIDHigh,
ID: int64(span.context.spanID),
ParentID: ptrParentID,
Name: span.operationName,

View file

@ -14,14 +14,48 @@
package metrics
import (
"time"
)
// NSOptions defines the name and tags map associated with a factory namespace
type NSOptions struct {
Name string
Tags map[string]string
}
// Options defines the information associated with a metric
type Options struct {
Name string
Tags map[string]string
Help string
}
// TimerOptions defines the information associated with a metric
type TimerOptions struct {
Name string
Tags map[string]string
Help string
Buckets []time.Duration
}
// HistogramOptions defines the information associated with a metric
type HistogramOptions struct {
Name string
Tags map[string]string
Help string
Buckets []float64
}
// Factory creates new metrics
type Factory interface {
Counter(name string, tags map[string]string) Counter
Timer(name string, tags map[string]string) Timer
Gauge(name string, tags map[string]string) Gauge
Counter(metric Options) Counter
Timer(metric TimerOptions) Timer
Gauge(metric Options) Gauge
Histogram(metric HistogramOptions) Histogram
// Namespace returns a nested metrics factory.
Namespace(name string, tags map[string]string) Factory
Namespace(scope NSOptions) Factory
}
// NullFactory is a metrics factory that returns NullCounter, NullTimer, and NullGauge.
@ -29,7 +63,16 @@ var NullFactory Factory = nullFactory{}
type nullFactory struct{}
func (nullFactory) Counter(name string, tags map[string]string) Counter { return NullCounter }
func (nullFactory) Timer(name string, tags map[string]string) Timer { return NullTimer }
func (nullFactory) Gauge(name string, tags map[string]string) Gauge { return NullGauge }
func (nullFactory) Namespace(name string, tags map[string]string) Factory { return NullFactory }
func (nullFactory) Counter(options Options) Counter {
return NullCounter
}
func (nullFactory) Timer(options TimerOptions) Timer {
return NullTimer
}
func (nullFactory) Gauge(options Options) Gauge {
return NullGauge
}
func (nullFactory) Histogram(options HistogramOptions) Histogram {
return NullHistogram
}
func (nullFactory) Namespace(scope NSOptions) Factory { return NullFactory }

28
vendor/github.com/uber/jaeger-lib/metrics/histogram.go generated vendored Normal file
View file

@ -0,0 +1,28 @@
// Copyright (c) 2018 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 metrics
// Histogram that keeps track of a distribution of values.
type Histogram interface {
// Records the value passed in.
Record(float64)
}
// NullHistogram that does nothing
var NullHistogram Histogram = nullHistogram{}
type nullHistogram struct{}
func (nullHistogram) Record(float64) {}

35
vendor/github.com/uber/jaeger-lib/metrics/keys.go generated vendored Normal file
View file

@ -0,0 +1,35 @@
// 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 metrics
import (
"sort"
)
// GetKey converts name+tags into a single string of the form
// "name|tag1=value1|...|tagN=valueN", where tag names are
// sorted alphabetically.
func GetKey(name string, tags map[string]string, tagsSep string, tagKVSep string) string {
keys := make([]string, 0, len(tags))
for k := range tags {
keys = append(keys, k)
}
sort.Strings(keys)
key := name
for _, k := range keys {
key = key + tagsSep + k + tagKVSep + tags[k]
}
return key
}

View file

@ -1,337 +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 metrics
import (
"sort"
"sync"
"sync/atomic"
"time"
"github.com/codahale/hdrhistogram"
)
// This is intentionally very similar to github.com/codahale/metrics, the
// main difference being that counters/gauges are scoped to the provider
// rather than being global (to facilitate testing).
// A LocalBackend is a metrics provider which aggregates data in-vm, and
// allows exporting snapshots to shove the data into a remote collector
type LocalBackend struct {
cm sync.Mutex
gm sync.Mutex
tm sync.Mutex
counters map[string]*int64
gauges map[string]*int64
timers map[string]*localBackendTimer
stop chan struct{}
wg sync.WaitGroup
TagsSep string
TagKVSep string
}
// NewLocalBackend returns a new LocalBackend. The collectionInterval is the histogram
// time window for each timer.
func NewLocalBackend(collectionInterval time.Duration) *LocalBackend {
b := &LocalBackend{
counters: make(map[string]*int64),
gauges: make(map[string]*int64),
timers: make(map[string]*localBackendTimer),
stop: make(chan struct{}),
TagsSep: "|",
TagKVSep: "=",
}
if collectionInterval == 0 {
// Use one histogram time window for all timers
return b
}
b.wg.Add(1)
go b.runLoop(collectionInterval)
return b
}
// Clear discards accumulated stats
func (b *LocalBackend) Clear() {
b.cm.Lock()
defer b.cm.Unlock()
b.gm.Lock()
defer b.gm.Unlock()
b.tm.Lock()
defer b.tm.Unlock()
b.counters = make(map[string]*int64)
b.gauges = make(map[string]*int64)
b.timers = make(map[string]*localBackendTimer)
}
func (b *LocalBackend) runLoop(collectionInterval time.Duration) {
defer b.wg.Done()
ticker := time.NewTicker(collectionInterval)
for {
select {
case <-ticker.C:
b.tm.Lock()
timers := make(map[string]*localBackendTimer, len(b.timers))
for timerName, timer := range b.timers {
timers[timerName] = timer
}
b.tm.Unlock()
for _, t := range timers {
t.Lock()
t.hist.Rotate()
t.Unlock()
}
case <-b.stop:
ticker.Stop()
return
}
}
}
// IncCounter increments a counter value
func (b *LocalBackend) IncCounter(name string, tags map[string]string, delta int64) {
name = GetKey(name, tags, b.TagsSep, b.TagKVSep)
b.cm.Lock()
defer b.cm.Unlock()
counter := b.counters[name]
if counter == nil {
b.counters[name] = new(int64)
*b.counters[name] = delta
return
}
atomic.AddInt64(counter, delta)
}
// UpdateGauge updates the value of a gauge
func (b *LocalBackend) UpdateGauge(name string, tags map[string]string, value int64) {
name = GetKey(name, tags, b.TagsSep, b.TagKVSep)
b.gm.Lock()
defer b.gm.Unlock()
gauge := b.gauges[name]
if gauge == nil {
b.gauges[name] = new(int64)
*b.gauges[name] = value
return
}
atomic.StoreInt64(gauge, value)
}
// RecordTimer records a timing duration
func (b *LocalBackend) RecordTimer(name string, tags map[string]string, d time.Duration) {
name = GetKey(name, tags, b.TagsSep, b.TagKVSep)
timer := b.findOrCreateTimer(name)
timer.Lock()
timer.hist.Current.RecordValue(int64(d / time.Millisecond))
timer.Unlock()
}
func (b *LocalBackend) findOrCreateTimer(name string) *localBackendTimer {
b.tm.Lock()
defer b.tm.Unlock()
if t, ok := b.timers[name]; ok {
return t
}
t := &localBackendTimer{
hist: hdrhistogram.NewWindowed(5, 0, int64((5*time.Minute)/time.Millisecond), 1),
}
b.timers[name] = t
return t
}
type localBackendTimer struct {
sync.Mutex
hist *hdrhistogram.WindowedHistogram
}
var (
percentiles = map[string]float64{
"P50": 50,
"P75": 75,
"P90": 90,
"P95": 95,
"P99": 99,
"P999": 99.9,
}
)
// Snapshot captures a snapshot of the current counter and gauge values
func (b *LocalBackend) Snapshot() (counters, gauges map[string]int64) {
b.cm.Lock()
defer b.cm.Unlock()
counters = make(map[string]int64, len(b.counters))
for name, value := range b.counters {
counters[name] = atomic.LoadInt64(value)
}
b.gm.Lock()
defer b.gm.Unlock()
gauges = make(map[string]int64, len(b.gauges))
for name, value := range b.gauges {
gauges[name] = atomic.LoadInt64(value)
}
b.tm.Lock()
timers := make(map[string]*localBackendTimer)
for timerName, timer := range b.timers {
timers[timerName] = timer
}
b.tm.Unlock()
for timerName, timer := range timers {
timer.Lock()
hist := timer.hist.Merge()
timer.Unlock()
for name, q := range percentiles {
gauges[timerName+"."+name] = hist.ValueAtQuantile(q)
}
}
return
}
// Stop cleanly closes the background goroutine spawned by NewLocalBackend.
func (b *LocalBackend) Stop() {
close(b.stop)
b.wg.Wait()
}
// GetKey converts name+tags into a single string of the form
// "name|tag1=value1|...|tagN=valueN", where tag names are
// sorted alphabetically.
func GetKey(name string, tags map[string]string, tagsSep string, tagKVSep string) string {
keys := make([]string, 0, len(tags))
for k := range tags {
keys = append(keys, k)
}
sort.Strings(keys)
key := name
for _, k := range keys {
key = key + tagsSep + k + tagKVSep + tags[k]
}
return key
}
type stats struct {
name string
tags map[string]string
localBackend *LocalBackend
}
type localTimer struct {
stats
}
func (l *localTimer) Record(d time.Duration) {
l.localBackend.RecordTimer(l.name, l.tags, d)
}
type localCounter struct {
stats
}
func (l *localCounter) Inc(delta int64) {
l.localBackend.IncCounter(l.name, l.tags, delta)
}
type localGauge struct {
stats
}
func (l *localGauge) Update(value int64) {
l.localBackend.UpdateGauge(l.name, l.tags, value)
}
// LocalFactory stats factory that creates metrics that are stored locally
type LocalFactory struct {
*LocalBackend
namespace string
tags map[string]string
}
// NewLocalFactory returns a new LocalMetricsFactory
func NewLocalFactory(collectionInterval time.Duration) *LocalFactory {
return &LocalFactory{
LocalBackend: NewLocalBackend(collectionInterval),
}
}
// appendTags adds the tags to the namespace tags and returns a combined map.
func (l *LocalFactory) appendTags(tags map[string]string) map[string]string {
newTags := make(map[string]string)
for k, v := range l.tags {
newTags[k] = v
}
for k, v := range tags {
newTags[k] = v
}
return newTags
}
func (l *LocalFactory) newNamespace(name string) string {
if l.namespace == "" {
return name
}
if name == "" {
return l.namespace
}
return l.namespace + "." + name
}
// Counter returns a local stats counter
func (l *LocalFactory) Counter(name string, tags map[string]string) Counter {
return &localCounter{
stats{
name: l.newNamespace(name),
tags: l.appendTags(tags),
localBackend: l.LocalBackend,
},
}
}
// Timer returns a local stats timer.
func (l *LocalFactory) Timer(name string, tags map[string]string) Timer {
return &localTimer{
stats{
name: l.newNamespace(name),
tags: l.appendTags(tags),
localBackend: l.LocalBackend,
},
}
}
// Gauge returns a local stats gauge.
func (l *LocalFactory) Gauge(name string, tags map[string]string) Gauge {
return &localGauge{
stats{
name: l.newNamespace(name),
tags: l.appendTags(tags),
localBackend: l.LocalBackend,
},
}
}
// Namespace returns a new namespace.
func (l *LocalFactory) Namespace(name string, tags map[string]string) Factory {
return &LocalFactory{
namespace: l.newNamespace(name),
tags: l.appendTags(tags),
LocalBackend: l.LocalBackend,
}
}

View file

@ -17,23 +17,29 @@ package metrics
import (
"fmt"
"reflect"
"strconv"
"strings"
)
// Init initializes the passed in metrics and initializes its fields using the passed in factory.
func Init(metrics interface{}, factory Factory, globalTags map[string]string) {
if err := initMetrics(metrics, factory, globalTags); err != nil {
panic(err.Error())
}
}
// initMetrics uses reflection to initialize a struct containing metrics fields
// MustInit initializes the passed in metrics and initializes its fields using the passed in factory.
//
// It uses reflection to initialize a struct containing metrics fields
// by assigning new Counter/Gauge/Timer values with the metric name retrieved
// from the `metric` tag and stats tags retrieved from the `tags` tag.
//
// Note: all fields of the struct must be exported, have a `metric` tag, and be
// of type Counter or Gauge or Timer.
func initMetrics(m interface{}, factory Factory, globalTags map[string]string) error {
//
// Errors during Init lead to a panic.
func MustInit(metrics interface{}, factory Factory, globalTags map[string]string) {
if err := Init(metrics, factory, globalTags); err != nil {
panic(err.Error())
}
}
// Init does the same as Init, but returns an error instead of
// panicking.
func Init(m interface{}, factory Factory, globalTags map[string]string) error {
// Allow user to opt out of reporting metrics by passing in nil.
if factory == nil {
factory = NullFactory
@ -42,6 +48,7 @@ func initMetrics(m interface{}, factory Factory, globalTags map[string]string) e
counterPtrType := reflect.TypeOf((*Counter)(nil)).Elem()
gaugePtrType := reflect.TypeOf((*Gauge)(nil)).Elem()
timerPtrType := reflect.TypeOf((*Timer)(nil)).Elem()
histogramPtrType := reflect.TypeOf((*Histogram)(nil)).Elem()
v := reflect.ValueOf(m).Elem()
t := v.Type()
@ -50,6 +57,7 @@ func initMetrics(m interface{}, factory Factory, globalTags map[string]string) e
for k, v := range globalTags {
tags[k] = v
}
var buckets []float64
field := t.Field(i)
metric := field.Tag.Get("metric")
if metric == "" {
@ -67,13 +75,57 @@ func initMetrics(m interface{}, factory Factory, globalTags map[string]string) e
tags[tag[0]] = tag[1]
}
}
if bucketString := field.Tag.Get("buckets"); bucketString != "" {
if field.Type.AssignableTo(timerPtrType) {
// TODO: Parse timer duration buckets
return fmt.Errorf(
"Field [%s]: Buckets are not currently initialized for timer metrics",
field.Name)
} else if field.Type.AssignableTo(histogramPtrType) {
bucketValues := strings.Split(bucketString, ",")
for _, bucket := range bucketValues {
b, err := strconv.ParseFloat(bucket, 64)
if err != nil {
return fmt.Errorf(
"Field [%s]: Bucket [%s] could not be converted to float64 in 'buckets' string [%s]",
field.Name, bucket, bucketString)
}
buckets = append(buckets, b)
}
} else {
return fmt.Errorf(
"Field [%s]: Buckets should only be defined for Timer and Histogram metric types",
field.Name)
}
}
help := field.Tag.Get("help")
var obj interface{}
if field.Type.AssignableTo(counterPtrType) {
obj = factory.Counter(metric, tags)
obj = factory.Counter(Options{
Name: metric,
Tags: tags,
Help: help,
})
} else if field.Type.AssignableTo(gaugePtrType) {
obj = factory.Gauge(metric, tags)
obj = factory.Gauge(Options{
Name: metric,
Tags: tags,
Help: help,
})
} else if field.Type.AssignableTo(timerPtrType) {
obj = factory.Timer(metric, tags)
// TODO: Add buckets once parsed (see TODO above)
obj = factory.Timer(TimerOptions{
Name: metric,
Tags: tags,
Help: help,
})
} else if field.Type.AssignableTo(histogramPtrType) {
obj = factory.Histogram(HistogramOptions{
Name: metric,
Tags: tags,
Help: help,
Buckets: buckets,
})
} else {
return fmt.Errorf(
"Field %s is not a pointer to timer, gauge, or counter",