replace dep with go modules (#16017)
- guide shamelessly stolen from prometheus/prometheus - updates local interface of oauth exchange - updates local impl of hclogger - bump jaeger client version closes #16088
This commit is contained in:
+15
@@ -0,0 +1,15 @@
|
||||
*.out
|
||||
*.test
|
||||
*.xml
|
||||
*.swp
|
||||
.idea/
|
||||
.tmp/
|
||||
*.iml
|
||||
*.cov
|
||||
*.html
|
||||
*.log
|
||||
gen/thrift/js
|
||||
gen/thrift/py
|
||||
vendor/
|
||||
crossdock-main
|
||||
crossdock/jaeger-docker-compose.yml
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "idl"]
|
||||
path = idl
|
||||
url = https://github.com/uber/jaeger-idl.git
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
Changes by Version
|
||||
==================
|
||||
|
||||
2.16.0 (2019-03-24)
|
||||
-------------------
|
||||
|
||||
- Add baggage to B3 codec (#319) <Pavol Loffay>
|
||||
- Add support for 128bit trace ids to zipkin thrift spans. (#378) <Douglas Reid>
|
||||
- Update zipkin propagation logic to support 128bit traceIDs (#373) <Douglas Reid>
|
||||
- Accept "true" for the x-b3-sampled header (#356) <Adrian Bogatu>
|
||||
|
||||
- Allow setting of PoolSpans from Config object (#322) <Matthew Pound>
|
||||
- Make propagators public to allow wrapping (#379) <Ivan Babrou>
|
||||
- Change default metric namespace to use relevant separator for the metric backend (#364) <Gary Brown>
|
||||
- Change metrics prefix to jaeger_tracer and add descriptions (#346) <Gary Brown>
|
||||
- Bump OpenTracing to ^1.1.x (#383) <Yuri Shkuro>
|
||||
- Upgrade jaeger-lib to v2.0.0 (#359) <Gary Brown>
|
||||
- Avoid defer when generating random number (#358) <Gary Brown>
|
||||
- Use a pool of rand.Source to reduce lock contention when creating span ids (#357) <Gary Brown>
|
||||
- Make JAEGER_ENDPOINT take priority over JAEGER_AGENT_XXX (#342) <Eundoo Song>
|
||||
|
||||
|
||||
2.15.0 (2018-10-10)
|
||||
-------------------
|
||||
|
||||
- Fix FollowsFrom spans ignoring baggage/debug header from dummy parent context (#313) <Zvi Cahana>
|
||||
- Make maximum annotation length configurable in tracer options (#318) <Eric Chang>
|
||||
- Support more environment variables in configuration (#323) <Daneyon Hansen>
|
||||
- Print error on Sampler Query failure (#328) <Goutham Veeramachaneni>
|
||||
- Add an HTTPOption to support custom http.RoundTripper (#333) <Michael Puncel>
|
||||
- Return an error when an HTTP error code is seen in zipkin HTTP transport (#331) <Michael Puncel>
|
||||
|
||||
|
||||
2.14.0 (2018-04-30)
|
||||
-------------------
|
||||
|
||||
- Support throttling for debug traces (#274) <Isaac Hier>
|
||||
- Remove dependency on Apache Thrift (#303) <Yuri Shkuro>
|
||||
- Remove dependency on tchannel (#295) (#294) <Yuri Shkuro>
|
||||
- Test with Go 1.9 (#298) <Yuri Shkuro>
|
||||
|
||||
|
||||
2.13.0 (2018-04-15)
|
||||
-------------------
|
||||
|
||||
- Use value receiver for config.NewTracer() (#283) <Yuri Shkuro>
|
||||
- Lock span during jaeger thrift conversion (#273) <Won Jun Jang>
|
||||
- Fix the RemotelyControlledSampler so that it terminates go-routine on Close() (#260) <Scott Kidder> <Yuri Shkuro>
|
||||
- Added support for client configuration via env vars (#275) <Juraci Paixão Kröhling>
|
||||
- Allow overriding sampler in the Config (#270) <Mike Kabischev>
|
||||
|
||||
|
||||
2.12.0 (2018-03-14)
|
||||
-------------------
|
||||
|
||||
- Use lock when retrieving span.Context() (#268)
|
||||
- Add Configuration support for custom Injector and Extractor (#263) <Martin Liu>
|
||||
|
||||
|
||||
2.11.2 (2018-01-12)
|
||||
-------------------
|
||||
|
||||
- Add Gopkg.toml to allow using the lib with `dep`
|
||||
|
||||
|
||||
2.11.1 (2018-01-03)
|
||||
-------------------
|
||||
|
||||
- Do not enqueue spans after Reporter is closed (#235, #245)
|
||||
- Change default flush interval to 1sec (#243)
|
||||
|
||||
|
||||
2.11.0 (2017-11-27)
|
||||
-------------------
|
||||
|
||||
- Normalize metric names and tags to be compatible with Prometheus (#222)
|
||||
|
||||
|
||||
2.10.0 (2017-11-14)
|
||||
-------------------
|
||||
|
||||
- Support custom tracing headers (#176)
|
||||
- Add BaggageRestrictionManager (#178) and RemoteBaggageRestrictionManager (#182)
|
||||
- Do not coerce baggage keys to lower case (#196)
|
||||
- Log span name when span cannot be reported (#198)
|
||||
- Add option to enable gen128Bit for tracer (#193) and allow custom generator for high bits of trace ID (#219)
|
||||
|
||||
|
||||
2.9.0 (2017-07-29)
|
||||
------------------
|
||||
|
||||
- Pin thrift <= 0.10 (#179)
|
||||
- Introduce a parallel interface ContribObserver (#159)
|
||||
|
||||
|
||||
2.8.0 (2017-07-05)
|
||||
------------------
|
||||
|
||||
- Drop `jaeger.` prefix from `jaeger.hostname` process-level tag
|
||||
- Add options to set tracer tags
|
||||
|
||||
|
||||
2.7.0 (2017-06-21)
|
||||
------------------
|
||||
|
||||
- Fix rate limiter balance [#135](https://github.com/uber/jaeger-client-go/pull/135) [#140](https://github.com/uber/jaeger-client-go/pull/140)
|
||||
- Default client to send Jaeger.thrift [#147](https://github.com/uber/jaeger-client-go/pull/147)
|
||||
- Save baggage in span [#153](https://github.com/uber/jaeger-client-go/pull/153)
|
||||
- Move reporter.queueLength to the top of the struct to guarantee 64bit alignment [#158](https://github.com/uber/jaeger-client-go/pull/158)
|
||||
- Support HTTP transport with jaeger.thrift [#161](https://github.com/uber/jaeger-client-go/pull/161)
|
||||
|
||||
|
||||
2.6.0 (2017-03-28)
|
||||
------------------
|
||||
|
||||
- Add config option to initialize RPC Metrics feature
|
||||
|
||||
|
||||
2.5.0 (2017-03-23)
|
||||
------------------
|
||||
|
||||
- Split request latency metric by success/failure [#123](https://github.com/uber/jaeger-client-go/pull/123)
|
||||
- Add mutex to adaptive sampler and fix race condition [#124](https://github.com/uber/jaeger-client-go/pull/124)
|
||||
- Fix rate limiter panic [#125](https://github.com/uber/jaeger-client-go/pull/125)
|
||||
|
||||
|
||||
2.4.0 (2017-03-21)
|
||||
------------------
|
||||
|
||||
- Remove `_ms` suffix from request latency metric name [#121](https://github.com/uber/jaeger-client-go/pull/121)
|
||||
- Rename all metrics to "request" and "http_request" and use tags for other dimensions [#121](https://github.com/uber/jaeger-client-go/pull/121)
|
||||
|
||||
|
||||
2.3.0 (2017-03-20)
|
||||
------------------
|
||||
|
||||
- Make Span type public to allow access to non-std methods for testing [#117](https://github.com/uber/jaeger-client-go/pull/117)
|
||||
- Add a structured way to extract traces for logging with zap [#118](https://github.com/uber/jaeger-client-go/pull/118)
|
||||
|
||||
|
||||
2.2.1 (2017-03-14)
|
||||
------------------
|
||||
|
||||
- Fix panic caused by updating the remote sampler from adaptive sampler to any other sampler type (https://github.com/uber/jaeger-client-go/pull/111)
|
||||
|
||||
|
||||
2.2.0 (2017-03-10)
|
||||
------------------
|
||||
|
||||
- Introduce Observer and SpanObserver (https://github.com/uber/jaeger-client-go/pull/94)
|
||||
- Add RPC metrics emitter as Observer/SpanObserver (https://github.com/uber/jaeger-client-go/pull/103)
|
||||
|
||||
|
||||
2.1.2 (2017-02-27)
|
||||
-------------------
|
||||
|
||||
- Fix leaky bucket bug (https://github.com/uber/jaeger-client-go/pull/99)
|
||||
- Fix zap logger Infof (https://github.com/uber/jaeger-client-go/pull/100)
|
||||
- Add tracer initialization godoc examples
|
||||
|
||||
|
||||
2.1.1 (2017-02-21)
|
||||
-------------------
|
||||
|
||||
- Fix inefficient usage of zap.Logger
|
||||
|
||||
|
||||
2.1.0 (2017-02-17)
|
||||
-------------------
|
||||
|
||||
- Add adapter for zap.Logger (https://github.com/uber-go/zap)
|
||||
- Move logging API to ./log/ package
|
||||
|
||||
|
||||
2.0.0 (2017-02-08)
|
||||
-------------------
|
||||
|
||||
- Support Adaptive Sampling
|
||||
- Support 128bit Trace IDs
|
||||
- Change trace/span IDs from uint64 to strong types TraceID and SpanID
|
||||
- Add Zipkin HTTP B3 Propagation format support #72
|
||||
- Rip out existing metrics and use github.com/uber/jaeger-lib/metrics
|
||||
- Change API for tracer, reporter, sampler initialization
|
||||
|
||||
|
||||
1.6.0 (2016-10-14)
|
||||
-------------------
|
||||
|
||||
- Add Zipkin HTTP transport
|
||||
- Support external baggage via jaeger-baggage header
|
||||
- Unpin Thrift version, keep to master
|
||||
|
||||
|
||||
1.5.1 (2016-09-27)
|
||||
-------------------
|
||||
|
||||
- Relax dependency on opentracing to ^1
|
||||
|
||||
|
||||
1.5.0 (2016-09-27)
|
||||
-------------------
|
||||
|
||||
- Upgrade to opentracing-go 1.0
|
||||
- Support KV logging for Spans
|
||||
|
||||
|
||||
1.4.0 (2016-09-14)
|
||||
-------------------
|
||||
|
||||
- Support debug traces via HTTP header "jaeger-debug-id"
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
# How to Contribute to Jaeger
|
||||
|
||||
We'd love your help!
|
||||
|
||||
Jaeger is [Apache 2.0 licensed](LICENSE) and accepts contributions via GitHub
|
||||
pull requests. This document outlines some of the conventions on development
|
||||
workflow, commit message formatting, contact points and other resources to make
|
||||
it easier to get your contribution accepted.
|
||||
|
||||
We gratefully welcome improvements to documentation as well as to code.
|
||||
|
||||
# Certificate of Origin
|
||||
|
||||
By contributing to this project you agree to the [Developer Certificate of
|
||||
Origin](https://developercertificate.org/) (DCO). This document was created
|
||||
by the Linux Kernel community and is a simple statement that you, as a
|
||||
contributor, have the legal right to make the contribution. See the [DCO](DCO)
|
||||
file for details.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This library uses [glide](https://github.com/Masterminds/glide) to manage dependencies.
|
||||
|
||||
To get started, make sure you clone the Git repository into the correct location
|
||||
`github.com/uber/jaeger-client-go` relative to `$GOPATH`:
|
||||
|
||||
```
|
||||
mkdir -p $GOPATH/src/github.com/uber
|
||||
cd $GOPATH/src/github.com/uber
|
||||
git clone git@github.com:jaegertracing/jaeger-client-go.git jaeger-client-go
|
||||
cd jaeger-client-go
|
||||
```
|
||||
|
||||
Then install dependencies and run the tests:
|
||||
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
glide install
|
||||
make test
|
||||
```
|
||||
|
||||
## Imports grouping
|
||||
|
||||
This projects follows the following pattern for grouping imports in Go files:
|
||||
* imports from standard library
|
||||
* imports from other projects
|
||||
* imports from `jaeger-client-go` project
|
||||
|
||||
For example:
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/uber/jaeger-lib/metrics"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/uber/jaeger-client-go/config"
|
||||
)
|
||||
```
|
||||
|
||||
## Making A Change
|
||||
|
||||
*Before making any significant changes, please [open an
|
||||
issue](https://github.com/jaegertracing/jaeger-client-go/issues).* Discussing your proposed
|
||||
changes ahead of time will make the contribution process smooth for everyone.
|
||||
|
||||
Once we've discussed your changes and you've got your code ready, make sure
|
||||
that tests are passing (`make test` or `make cover`) and open your PR. Your
|
||||
pull request is most likely to be accepted if it:
|
||||
|
||||
* Includes tests for new functionality.
|
||||
* Follows the guidelines in [Effective
|
||||
Go](https://golang.org/doc/effective_go.html) and the [Go team's common code
|
||||
review comments](https://github.com/golang/go/wiki/CodeReviewComments).
|
||||
* Has a [good commit message](https://chris.beams.io/posts/git-commit/):
|
||||
* Separate subject from body with a blank line
|
||||
* Limit the subject line to 50 characters
|
||||
* Capitalize the subject line
|
||||
* Do not end the subject line with a period
|
||||
* Use the imperative mood in the subject line
|
||||
* Wrap the body at 72 characters
|
||||
* Use the body to explain _what_ and _why_ instead of _how_
|
||||
* Each commit must be signed by the author ([see below](#sign-your-work)).
|
||||
|
||||
## License
|
||||
|
||||
By contributing your code, you agree to license your contribution under the terms
|
||||
of the [Apache License](LICENSE).
|
||||
|
||||
If you are adding a new file it should have a header like below. The easiest
|
||||
way to add such header is to run `make fmt`.
|
||||
|
||||
```
|
||||
// Copyright (c) 2017 The Jaeger Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
```
|
||||
|
||||
## Sign your work
|
||||
|
||||
The sign-off is a simple line at the end of the explanation for the
|
||||
patch, which certifies that you wrote it or otherwise have the right to
|
||||
pass it on as an open-source patch. The rules are pretty simple: if you
|
||||
can certify the below (from
|
||||
[developercertificate.org](http://developercertificate.org/)):
|
||||
|
||||
```
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
660 York Street, Suite 102,
|
||||
San Francisco, CA 94110 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
||||
|
||||
then you just add a line to every git commit message:
|
||||
|
||||
Signed-off-by: Joe Smith <joe@gmail.com>
|
||||
|
||||
using your real name (sorry, no pseudonyms or anonymous contributions.)
|
||||
|
||||
You can add the sign off when creating the git commit via `git commit -s`.
|
||||
|
||||
If you want this to be automatic you can set up some aliases:
|
||||
|
||||
```
|
||||
git config --add alias.amend "commit -s --amend"
|
||||
git config --add alias.c "commit -s"
|
||||
```
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
660 York Street, Suite 102,
|
||||
San Francisco, CA 94110 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
|
||||
name = "github.com/beorn7/perks"
|
||||
packages = ["quantile"]
|
||||
pruneopts = "UT"
|
||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4c4c33075b704791d6a7f09dfb55c66769e8a1dc6adf87026292d274fe8ad113"
|
||||
name = "github.com/codahale/hdrhistogram"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3a0bb77429bd3a61596f5e8a3172445844342120"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:a382acd6150713655ded76ab5fbcbc7924a7808dab4312dda5d1f23dd8ce5277"
|
||||
name = "github.com/crossdock/crossdock-go"
|
||||
packages = [
|
||||
".",
|
||||
"assert",
|
||||
"require",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "049aabb0122b03bc9bd30cab8f3f91fb60166361"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = "UT"
|
||||
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:318f1c959a8a740366fce4b1e1eb2fd914036b4af58fbd0a003349b305f118ad"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = ["proto"]
|
||||
pruneopts = "UT"
|
||||
revision = "b5d812f8a3706043e23a9cd5babf2e5423744d30"
|
||||
version = "v1.3.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
packages = ["pbutil"]
|
||||
pruneopts = "UT"
|
||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:727b8f567a30d0739d6c26b9472b3422b351c93cf62095164c845a54b16fc18e"
|
||||
name = "github.com/opentracing/opentracing-go"
|
||||
packages = [
|
||||
".",
|
||||
"ext",
|
||||
"harness",
|
||||
"log",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "659c90643e714681897ec2521c60567dd21da733"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
|
||||
version = "v0.8.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
pruneopts = "UT"
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b6221ec0f8903b556e127c449e7106b63e6867170c2d10a7c058623d086f2081"
|
||||
name = "github.com/prometheus/client_golang"
|
||||
packages = ["prometheus"]
|
||||
pruneopts = "UT"
|
||||
revision = "c5b7fccd204277076155f10851dad72b76a49317"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
|
||||
name = "github.com/prometheus/client_model"
|
||||
packages = ["go"]
|
||||
pruneopts = "UT"
|
||||
revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:35cf6bdf68db765988baa9c4f10cc5d7dda1126a54bd62e252dbcd0b1fc8da90"
|
||||
name = "github.com/prometheus/common"
|
||||
packages = [
|
||||
"expfmt",
|
||||
"internal/bitbucket.org/ww/goautoneg",
|
||||
"model",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:c31163bd62461e0c5f7ddc7363e39ef8d9e929693e77b5c11c709b05f9cb9219"
|
||||
name = "github.com/prometheus/procfs"
|
||||
packages = [
|
||||
".",
|
||||
"internal/util",
|
||||
"iostats",
|
||||
"nfs",
|
||||
"xfs",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "55ae3d9d557340b5bc24cd8aa5f6fa2c2ab31352"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8ff03ccc603abb0d7cce94d34b613f5f6251a9e1931eba1a3f9888a9029b055c"
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = [
|
||||
"assert",
|
||||
"require",
|
||||
"suite",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3c1a69cdae3501bf75e76d0d86dc6f2b0a7421bc205c0cb7b96b19eed464a34d"
|
||||
name = "github.com/uber-go/atomic"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
|
||||
version = "v1.3.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f5c5ad1e08141e18aee1b9c37729d93d06805840421ccfc9d407787ffe969ce6"
|
||||
name = "github.com/uber/jaeger-lib"
|
||||
packages = [
|
||||
"metrics",
|
||||
"metrics/metricstest",
|
||||
"metrics/prometheus",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "0e30338a695636fe5bcf7301e8030ce8dd2a8530"
|
||||
version = "v2.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3c1a69cdae3501bf75e76d0d86dc6f2b0a7421bc205c0cb7b96b19eed464a34d"
|
||||
name = "go.uber.org/atomic"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
|
||||
version = "v1.3.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:60bf2a5e347af463c42ed31a493d817f8a72f102543060ed992754e689805d1a"
|
||||
name = "go.uber.org/multierr"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c52caf7bd44f92e54627a31b85baf06a68333a196b3d8d241480a774733dcf8b"
|
||||
name = "go.uber.org/zap"
|
||||
packages = [
|
||||
".",
|
||||
"buffer",
|
||||
"internal/bufferpool",
|
||||
"internal/color",
|
||||
"internal/exit",
|
||||
"zapcore",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
|
||||
version = "v1.9.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f8b491a7c25030a895a0e579742d07136e6958e77ef2d46e769db8eec4e58fcd"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
"context/ctxhttp",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "addf6b3196f61cd44ce5a76657913698c73479d0"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/crossdock/crossdock-go",
|
||||
"github.com/opentracing/opentracing-go",
|
||||
"github.com/opentracing/opentracing-go/ext",
|
||||
"github.com/opentracing/opentracing-go/harness",
|
||||
"github.com/opentracing/opentracing-go/log",
|
||||
"github.com/pkg/errors",
|
||||
"github.com/prometheus/client_golang/prometheus",
|
||||
"github.com/stretchr/testify/assert",
|
||||
"github.com/stretchr/testify/require",
|
||||
"github.com/stretchr/testify/suite",
|
||||
"github.com/uber-go/atomic",
|
||||
"github.com/uber/jaeger-lib/metrics",
|
||||
"github.com/uber/jaeger-lib/metrics/metricstest",
|
||||
"github.com/uber/jaeger-lib/metrics/prometheus",
|
||||
"go.uber.org/zap",
|
||||
"go.uber.org/zap/zapcore",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
[[constraint]]
|
||||
name = "github.com/crossdock/crossdock-go"
|
||||
branch = "master"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/opentracing/opentracing-go"
|
||||
version = "^1.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/prometheus/client_golang"
|
||||
version = "0.8.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "^1.1.3"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/uber-go/atomic"
|
||||
version = "^1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/uber/jaeger-lib"
|
||||
version = "^2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "go.uber.org/zap"
|
||||
version = "^1"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
PROJECT_ROOT=github.com/uber/jaeger-client-go
|
||||
PACKAGES := $(shell glide novendor | grep -v -e ./thrift-gen/... -e ./thrift/...)
|
||||
# all .go files that don't exist in hidden directories
|
||||
ALL_SRC := $(shell find . -name "*.go" | grep -v -e vendor -e thrift-gen -e ./thrift/ \
|
||||
-e ".*/\..*" \
|
||||
-e ".*/_.*" \
|
||||
-e ".*/mocks.*")
|
||||
|
||||
-include crossdock/rules.mk
|
||||
|
||||
export GO15VENDOREXPERIMENT=1
|
||||
|
||||
RACE=-race
|
||||
GOTEST=go test -v $(RACE)
|
||||
GOLINT=golint
|
||||
GOVET=go vet
|
||||
GOFMT=gofmt
|
||||
FMT_LOG=fmt.log
|
||||
LINT_LOG=lint.log
|
||||
|
||||
THRIFT_VER=0.9.3
|
||||
THRIFT_IMG=thrift:$(THRIFT_VER)
|
||||
THRIFT=docker run -v "${PWD}:/data" $(THRIFT_IMG) thrift
|
||||
THRIFT_GO_ARGS=thrift_import="github.com/apache/thrift/lib/go/thrift"
|
||||
THRIFT_GEN_DIR=thrift-gen
|
||||
|
||||
PASS=$(shell printf "\033[32mPASS\033[0m")
|
||||
FAIL=$(shell printf "\033[31mFAIL\033[0m")
|
||||
COLORIZE=sed ''/PASS/s//$(PASS)/'' | sed ''/FAIL/s//$(FAIL)/''
|
||||
|
||||
.DEFAULT_GOAL := test-and-lint
|
||||
|
||||
.PHONY: test-and-lint
|
||||
test-and-lint: test fmt lint
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
ifeq ($(USE_DEP),true)
|
||||
dep check
|
||||
endif
|
||||
bash -c "set -e; set -o pipefail; $(GOTEST) $(PACKAGES) | $(COLORIZE)"
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
$(GOFMT) -e -s -l -w $(ALL_SRC)
|
||||
./scripts/updateLicenses.sh
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
$(GOVET) $(PACKAGES)
|
||||
@cat /dev/null > $(LINT_LOG)
|
||||
@$(foreach pkg, $(PACKAGES), $(GOLINT) $(pkg) | grep -v crossdock/thrift >> $(LINT_LOG) || true;)
|
||||
@[ ! -s "$(LINT_LOG)" ] || (echo "Lint Failures" | cat - $(LINT_LOG) && false)
|
||||
@$(GOFMT) -e -s -l $(ALL_SRC) > $(FMT_LOG)
|
||||
./scripts/updateLicenses.sh >> $(FMT_LOG)
|
||||
@[ ! -s "$(FMT_LOG)" ] || (echo "go fmt or license check failures, run 'make fmt'" | cat - $(FMT_LOG) && false)
|
||||
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
glide --version || go get github.com/Masterminds/glide
|
||||
ifeq ($(USE_DEP),true)
|
||||
dep ensure
|
||||
else
|
||||
glide install
|
||||
endif
|
||||
|
||||
|
||||
.PHONY: cover
|
||||
cover:
|
||||
./scripts/cover.sh $(shell go list $(PACKAGES))
|
||||
go tool cover -html=cover.out -o cover.html
|
||||
|
||||
|
||||
# This is not part of the regular test target because we don't want to slow it
|
||||
# down.
|
||||
.PHONY: test-examples
|
||||
test-examples:
|
||||
make -C examples
|
||||
|
||||
# TODO at the moment we're not generating tchan_*.go files
|
||||
thrift: idl-submodule thrift-image
|
||||
$(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/agent.thrift
|
||||
$(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/sampling.thrift
|
||||
$(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/jaeger.thrift
|
||||
$(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/zipkincore.thrift
|
||||
$(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/baggage.thrift
|
||||
$(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/crossdock/thrift/ /data/idl/thrift/crossdock/tracetest.thrift
|
||||
sed -i '' 's|"zipkincore"|"$(PROJECT_ROOT)/thrift-gen/zipkincore"|g' $(THRIFT_GEN_DIR)/agent/*.go
|
||||
sed -i '' 's|"jaeger"|"$(PROJECT_ROOT)/thrift-gen/jaeger"|g' $(THRIFT_GEN_DIR)/agent/*.go
|
||||
sed -i '' 's|"github.com/apache/thrift/lib/go/thrift"|"github.com/uber/jaeger-client-go/thrift"|g' \
|
||||
$(THRIFT_GEN_DIR)/*/*.go crossdock/thrift/tracetest/*.go
|
||||
rm -rf thrift-gen/*/*-remote
|
||||
rm -rf crossdock/thrift/*/*-remote
|
||||
rm -rf thrift-gen/jaeger/collector.go
|
||||
|
||||
idl-submodule:
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
thrift-image:
|
||||
$(THRIFT) -version
|
||||
|
||||
.PHONY: install-dep-ci
|
||||
install-dep-ci:
|
||||
- curl -L -s https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 -o $$GOPATH/bin/dep
|
||||
- chmod +x $$GOPATH/bin/dep
|
||||
|
||||
.PHONY: install-ci
|
||||
install-ci: install-dep-ci install
|
||||
go get github.com/wadey/gocovmerge
|
||||
go get github.com/mattn/goveralls
|
||||
go get golang.org/x/tools/cmd/cover
|
||||
go get golang.org/x/lint/golint
|
||||
|
||||
.PHONY: test-ci
|
||||
test-ci:
|
||||
@./scripts/cover.sh $(shell go list $(PACKAGES))
|
||||
ifeq ($(CI_SKIP_LINT),true)
|
||||
echo 'skipping lint'
|
||||
else
|
||||
make lint
|
||||
endif
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
[![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![OpenTracing 1.0 Enabled][ot-img]][ot-url]
|
||||
|
||||
# Jaeger Bindings for Go OpenTracing API
|
||||
|
||||
Instrumentation library that implements an
|
||||
[OpenTracing](http://opentracing.io) Tracer for Jaeger (https://jaegertracing.io).
|
||||
|
||||
**IMPORTANT**: The library's import path is based on its original location under `github.com/uber`. Do not try to import it as `github.com/jaegertracing`, it will not compile. We might revisit this in the next major release.
|
||||
* :white_check_mark: `import "github.com/uber/jaeger-client-go"`
|
||||
* :x: `import "github.com/jaegertracing/jaeger-client-go"`
|
||||
|
||||
## How to Contribute
|
||||
|
||||
Please see [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
## Installation
|
||||
|
||||
We recommended using a dependency manager like [glide](https://github.com/Masterminds/glide)
|
||||
and [semantic versioning](http://semver.org/) when including this library into an application.
|
||||
For example, Jaeger backend imports this library like this:
|
||||
|
||||
```yaml
|
||||
- package: github.com/uber/jaeger-client-go
|
||||
version: ^2.7.0
|
||||
```
|
||||
|
||||
If you instead want to use the latest version in `master`, you can pull it via `go get`.
|
||||
Note that during `go get` you may see build errors due to incompatible dependencies, which is why
|
||||
we recommend using semantic versions for dependencies. The error may be fixed by running
|
||||
`make install` (it will install `glide` if you don't have it):
|
||||
|
||||
```shell
|
||||
go get -u github.com/uber/jaeger-client-go/
|
||||
cd $GOPATH/src/github.com/uber/jaeger-client-go/
|
||||
git submodule update --init --recursive
|
||||
make install
|
||||
```
|
||||
|
||||
## Initialization
|
||||
|
||||
See tracer initialization examples in [godoc](https://godoc.org/github.com/uber/jaeger-client-go/config#pkg-examples)
|
||||
and [config/example_test.go](./config/example_test.go).
|
||||
|
||||
### Environment variables
|
||||
|
||||
The tracer can be initialized with values coming from environment variables. None of the env vars are required
|
||||
and all of them can be overriden via direct setting of the property on the configuration object.
|
||||
|
||||
Property| Description
|
||||
--- | ---
|
||||
JAEGER_SERVICE_NAME | The service name
|
||||
JAEGER_AGENT_HOST | The hostname for communicating with agent via UDP
|
||||
JAEGER_AGENT_PORT | The port for communicating with agent via UDP
|
||||
JAEGER_ENDPOINT | The HTTP endpoint for sending spans directly to a collector, i.e. http://jaeger-collector:14268/api/traces
|
||||
JAEGER_USER | Username to send as part of "Basic" authentication to the collector endpoint
|
||||
JAEGER_PASSWORD | Password to send as part of "Basic" authentication to the collector endpoint
|
||||
JAEGER_REPORTER_LOG_SPANS | Whether the reporter should also log the spans
|
||||
JAEGER_REPORTER_MAX_QUEUE_SIZE | The reporter's maximum queue size
|
||||
JAEGER_REPORTER_FLUSH_INTERVAL | The reporter's flush interval, with units, e.g. "500ms" or "2s" ([valid units][timeunits])
|
||||
JAEGER_SAMPLER_TYPE | The sampler type
|
||||
JAEGER_SAMPLER_PARAM | The sampler parameter (number)
|
||||
JAEGER_SAMPLER_MANAGER_HOST_PORT | The HTTP endpoint when using the remote sampler, i.e. http://jaeger-agent:5778/sampling
|
||||
JAEGER_SAMPLER_MAX_OPERATIONS | The maximum number of operations that the sampler will keep track of
|
||||
JAEGER_SAMPLER_REFRESH_INTERVAL | How often the remotely controlled sampler will poll jaeger-agent for the appropriate sampling strategy, with units, e.g. "1m" or "30s" ([valid units][timeunits])
|
||||
JAEGER_TAGS | A comma separated list of `name = value` tracer level tags, which get added to all reported spans. The value can also refer to an environment variable using the format `${envVarName:default}`, where the `:default` is optional, and identifies a value to be used if the environment variable cannot be found
|
||||
JAEGER_DISABLED | Whether the tracer is disabled or not. If true, the default `opentracing.NoopTracer` is used.
|
||||
JAEGER_RPC_METRICS | Whether to store RPC metrics
|
||||
|
||||
By default, the client sends traces via UDP to the agent at `localhost:6831`. Use `JAEGER_AGENT_HOST` and
|
||||
`JAEGER_AGENT_PORT` to send UDP traces to a different `host:port`. If `JAEGER_ENDPOINT` is set, the client sends traces
|
||||
to the endpoint via `HTTP`, making the `JAEGER_AGENT_HOST` and `JAEGER_AGENT_PORT` unused. If `JAEGER_ENDPOINT` is
|
||||
secured, HTTP basic authentication can be performed by setting the `JAEGER_USER` and `JAEGER_PASSWORD` environment
|
||||
variables.
|
||||
|
||||
### Closing the tracer via `io.Closer`
|
||||
|
||||
The constructor function for Jaeger Tracer returns the tracer itself and an `io.Closer` instance.
|
||||
It is recommended to structure your `main()` so that it calls the `Close()` function on the closer
|
||||
before exiting, e.g.
|
||||
|
||||
```go
|
||||
tracer, closer, err := cfg.NewTracer(...)
|
||||
defer closer.Close()
|
||||
```
|
||||
|
||||
This is especially useful for command-line tools that enable tracing, as well as
|
||||
for the long-running apps that support graceful shutdown. For example, if your deployment
|
||||
system sends SIGTERM instead of killing the process and you trap that signal to do a graceful
|
||||
exit, then having `defer closer.Closer()` ensures that all buffered spans are flushed.
|
||||
|
||||
### Metrics & Monitoring
|
||||
|
||||
The tracer emits a number of different metrics, defined in
|
||||
[metrics.go](metrics.go). The monitoring backend is expected to support
|
||||
tag-based metric names, e.g. instead of `statsd`-style string names
|
||||
like `counters.my-service.jaeger.spans.started.sampled`, the metrics
|
||||
are defined by a short name and a collection of key/value tags, for
|
||||
example: `name:jaeger.traces, state:started, sampled:y`. See [metrics.go](./metrics.go)
|
||||
file for the full list and descriptions of emitted metrics.
|
||||
|
||||
The monitoring backend is represented by the `metrics.Factory` interface from package
|
||||
[`"github.com/uber/jaeger-lib/metrics"`](https://github.com/jaegertracing/jaeger-lib/tree/master/metrics). An implementation
|
||||
of that interface can be passed as an option to either the Configuration object or the Tracer
|
||||
constructor, for example:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/uber/jaeger-client-go/config"
|
||||
"github.com/uber/jaeger-lib/metrics/prometheus"
|
||||
)
|
||||
|
||||
metricsFactory := prometheus.New()
|
||||
tracer, closer, err := config.Configuration{
|
||||
ServiceName: "your-service-name",
|
||||
}.NewTracer(
|
||||
config.Metrics(metricsFactory),
|
||||
)
|
||||
```
|
||||
|
||||
By default, a no-op `metrics.NullFactory` is used.
|
||||
|
||||
### Logging
|
||||
|
||||
The tracer can be configured with an optional logger, which will be
|
||||
used to log communication errors, or log spans if a logging reporter
|
||||
option is specified in the configuration. The logging API is abstracted
|
||||
by the [Logger](logger.go) interface. A logger instance implementing
|
||||
this interface can be set on the `Config` object before calling the
|
||||
`New` method.
|
||||
|
||||
Besides the [zap](https://github.com/uber-go/zap) implementation
|
||||
bundled with this package there is also a [go-kit](https://github.com/go-kit/kit)
|
||||
one in the [jaeger-lib](https://github.com/jaegertracing/jaeger-lib) repository.
|
||||
|
||||
## Instrumentation for Tracing
|
||||
|
||||
Since this tracer is fully compliant with OpenTracing API 1.0,
|
||||
all code instrumentation should only use the API itself, as described
|
||||
in the [opentracing-go](https://github.com/opentracing/opentracing-go) documentation.
|
||||
|
||||
## Features
|
||||
|
||||
### Reporters
|
||||
|
||||
A "reporter" is a component that receives the finished spans and reports
|
||||
them to somewhere. Under normal circumstances, the Tracer
|
||||
should use the default `RemoteReporter`, which sends the spans out of
|
||||
process via configurable "transport". For testing purposes, one can
|
||||
use an `InMemoryReporter` that accumulates spans in a buffer and
|
||||
allows to retrieve them for later verification. Also available are
|
||||
`NullReporter`, a no-op reporter that does nothing, a `LoggingReporter`
|
||||
which logs all finished spans using their `String()` method, and a
|
||||
`CompositeReporter` that can be used to combine more than one reporter
|
||||
into one, e.g. to attach a logging reporter to the main remote reporter.
|
||||
|
||||
### Span Reporting Transports
|
||||
|
||||
The remote reporter uses "transports" to actually send the spans out
|
||||
of process. Currently the supported transports include:
|
||||
* [Jaeger Thrift](https://github.com/jaegertracing/jaeger-idl/blob/master/thrift/agent.thrift) over UDP or HTTP,
|
||||
* [Zipkin Thrift](https://github.com/jaegertracing/jaeger-idl/blob/master/thrift/zipkincore.thrift) over HTTP.
|
||||
|
||||
### Sampling
|
||||
|
||||
The tracer does not record all spans, but only those that have the
|
||||
sampling bit set in the `flags`. When a new trace is started and a new
|
||||
unique ID is generated, a sampling decision is made whether this trace
|
||||
should be sampled. The sampling decision is propagated to all downstream
|
||||
calls via the `flags` field of the trace context. The following samplers
|
||||
are available:
|
||||
1. `RemotelyControlledSampler` uses one of the other simpler samplers
|
||||
and periodically updates it by polling an external server. This
|
||||
allows dynamic control of the sampling strategies.
|
||||
1. `ConstSampler` always makes the same sampling decision for all
|
||||
trace IDs. it can be configured to either sample all traces, or
|
||||
to sample none.
|
||||
1. `ProbabilisticSampler` uses a fixed sampling rate as a probability
|
||||
for a given trace to be sampled. The actual decision is made by
|
||||
comparing the trace ID with a random number multiplied by the
|
||||
sampling rate.
|
||||
1. `RateLimitingSampler` can be used to allow only a certain fixed
|
||||
number of traces to be sampled per second.
|
||||
|
||||
### Baggage Injection
|
||||
|
||||
The OpenTracing spec allows for [baggage][baggage], which are key value pairs that are added
|
||||
to the span context and propagated throughout the trace. An external process can inject baggage
|
||||
by setting the special HTTP Header `jaeger-baggage` on a request:
|
||||
|
||||
```sh
|
||||
curl -H "jaeger-baggage: key1=value1, key2=value2" http://myhost.com
|
||||
```
|
||||
|
||||
Baggage can also be programatically set inside your service:
|
||||
|
||||
```go
|
||||
if span := opentracing.SpanFromContext(ctx); span != nil {
|
||||
span.SetBaggageItem("key", "value")
|
||||
}
|
||||
```
|
||||
|
||||
Another service downstream of that can retrieve the baggage in a similar way:
|
||||
|
||||
```go
|
||||
if span := opentracing.SpanFromContext(ctx); span != nil {
|
||||
val := span.BaggageItem("key")
|
||||
println(val)
|
||||
}
|
||||
```
|
||||
|
||||
### Debug Traces (Forced Sampling)
|
||||
|
||||
#### Programmatically
|
||||
|
||||
The OpenTracing API defines a `sampling.priority` standard tag that
|
||||
can be used to affect the sampling of a span and its children:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
)
|
||||
|
||||
span := opentracing.SpanFromContext(ctx)
|
||||
ext.SamplingPriority.Set(span, 1)
|
||||
```
|
||||
|
||||
#### Via HTTP Headers
|
||||
|
||||
Jaeger Tracer also understands a special HTTP Header `jaeger-debug-id`,
|
||||
which can be set in the incoming request, e.g.
|
||||
|
||||
```sh
|
||||
curl -H "jaeger-debug-id: some-correlation-id" http://myhost.com
|
||||
```
|
||||
|
||||
When Jaeger sees this header in the request that otherwise has no
|
||||
tracing context, it ensures that the new trace started for this
|
||||
request will be sampled in the "debug" mode (meaning it should survive
|
||||
all downsampling that might happen in the collection pipeline), and the
|
||||
root span will have a tag as if this statement was executed:
|
||||
|
||||
```go
|
||||
span.SetTag("jaeger-debug-id", "some-correlation-id")
|
||||
```
|
||||
|
||||
This allows using Jaeger UI to find the trace by this tag.
|
||||
|
||||
### Zipkin HTTP B3 compatible header propagation
|
||||
|
||||
Jaeger Tracer supports Zipkin B3 Propagation HTTP headers, which are used
|
||||
by a lot of Zipkin tracers. This means that you can use Jaeger in conjunction with e.g. [these OpenZipkin tracers](https://github.com/openzipkin).
|
||||
|
||||
However it is not the default propagation format, see [here](zipkin/README.md#NewZipkinB3HTTPHeaderPropagator) how to set it up.
|
||||
|
||||
## License
|
||||
|
||||
[Apache 2.0 License](LICENSE).
|
||||
|
||||
|
||||
[doc-img]: https://godoc.org/github.com/uber/jaeger-client-go?status.svg
|
||||
[doc]: https://godoc.org/github.com/uber/jaeger-client-go
|
||||
[ci-img]: https://travis-ci.org/jaegertracing/jaeger-client-go.svg?branch=master
|
||||
[ci]: https://travis-ci.org/jaegertracing/jaeger-client-go
|
||||
[cov-img]: https://codecov.io/gh/jaegertracing/jaeger-client-go/branch/master/graph/badge.svg
|
||||
[cov]: https://codecov.io/gh/jaegertracing/jaeger-client-go
|
||||
[ot-img]: https://img.shields.io/badge/OpenTracing--1.0-enabled-blue.svg
|
||||
[ot-url]: http://opentracing.io
|
||||
[baggage]: https://github.com/opentracing/specification/blob/master/specification.md#set-a-baggage-item
|
||||
[timeunits]: https://golang.org/pkg/time/#ParseDuration
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
# Release Process
|
||||
|
||||
1. Create a PR "Preparing for release X.Y.Z" against master branch
|
||||
* Alter CHANGELOG.md from `<placeholder_version> (unreleased)` to `<X.Y.Z> (YYYY-MM-DD)`
|
||||
* Update `JaegerClientVersion` in constants.go to `Go-X.Y.Z`
|
||||
2. Create a release "Release X.Y.Z" on Github
|
||||
* Create Tag `vX.Y.Z`
|
||||
* Copy CHANGELOG.md into the release notes
|
||||
3. Create a PR "Back to development" against master branch
|
||||
* Add `<next_version> (unreleased)` to CHANGELOG.md
|
||||
* Update `JaegerClientVersion` in constants.go to `Go-<next_version>dev`
|
||||
+27
-3
@@ -27,6 +27,8 @@ import (
|
||||
"github.com/uber/jaeger-client-go/internal/baggage/remote"
|
||||
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
|
||||
@@ -108,6 +110,18 @@ type ReporterConfig struct {
|
||||
// LocalAgentHostPort instructs reporter to send spans to jaeger-agent at this address
|
||||
// Can be set by exporting an environment variable named JAEGER_AGENT_HOST / JAEGER_AGENT_PORT
|
||||
LocalAgentHostPort string `yaml:"localAgentHostPort"`
|
||||
|
||||
// CollectorEndpoint instructs reporter to send spans to jaeger-collector at this URL
|
||||
// Can be set by exporting an environment variable named JAEGER_ENDPOINT
|
||||
CollectorEndpoint string `yaml:"collectorEndpoint"`
|
||||
|
||||
// User instructs reporter to include a user for basic http authentication when sending spans to jaeger-collector.
|
||||
// Can be set by exporting an environment variable named JAEGER_USER
|
||||
User string `yaml:"user"`
|
||||
|
||||
// Password instructs reporter to include a password for basic http authentication when sending spans to
|
||||
// jaeger-collector. Can be set by exporting an environment variable named JAEGER_PASSWORD
|
||||
Password string `yaml:"password"`
|
||||
}
|
||||
|
||||
// BaggageRestrictionsConfig configures the baggage restrictions manager which can be used to whitelist
|
||||
@@ -179,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
|
||||
@@ -217,7 +231,9 @@ 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),
|
||||
}
|
||||
|
||||
for _, tag := range opts.tags {
|
||||
@@ -344,7 +360,7 @@ func (sc *SamplerConfig) NewSampler(
|
||||
return nil, fmt.Errorf("Unknown sampler type %v", sc.Type)
|
||||
}
|
||||
|
||||
// NewReporter instantiates a new reporter that submits spans to tcollector
|
||||
// NewReporter instantiates a new reporter that submits spans to the collector
|
||||
func (rc *ReporterConfig) NewReporter(
|
||||
serviceName string,
|
||||
metrics *jaeger.Metrics,
|
||||
@@ -368,5 +384,13 @@ func (rc *ReporterConfig) NewReporter(
|
||||
}
|
||||
|
||||
func (rc *ReporterConfig) newTransport() (jaeger.Transport, error) {
|
||||
return jaeger.NewUDPTransport(rc.LocalAgentHostPort, 0)
|
||||
switch {
|
||||
case rc.CollectorEndpoint != "" && rc.User != "" && rc.Password != "":
|
||||
return transport.NewHTTPTransport(rc.CollectorEndpoint, transport.HTTPBatchSize(1),
|
||||
transport.HTTPBasicAuth(rc.User, rc.Password)), nil
|
||||
case rc.CollectorEndpoint != "":
|
||||
return transport.NewHTTPTransport(rc.CollectorEndpoint, transport.HTTPBatchSize(1)), nil
|
||||
default:
|
||||
return jaeger.NewUDPTransport(rc.LocalAgentHostPort, 0)
|
||||
}
|
||||
}
|
||||
|
||||
+32
-16
@@ -16,12 +16,13 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/uber/jaeger-client-go"
|
||||
@@ -41,6 +42,9 @@ const (
|
||||
envReporterMaxQueueSize = "JAEGER_REPORTER_MAX_QUEUE_SIZE"
|
||||
envReporterFlushInterval = "JAEGER_REPORTER_FLUSH_INTERVAL"
|
||||
envReporterLogSpans = "JAEGER_REPORTER_LOG_SPANS"
|
||||
envEndpoint = "JAEGER_ENDPOINT"
|
||||
envUser = "JAEGER_USER"
|
||||
envPassword = "JAEGER_PASSWORD"
|
||||
envAgentHost = "JAEGER_AGENT_HOST"
|
||||
envAgentPort = "JAEGER_AGENT_PORT"
|
||||
)
|
||||
@@ -155,23 +159,35 @@ func reporterConfigFromEnv() (*ReporterConfig, error) {
|
||||
}
|
||||
}
|
||||
|
||||
host := jaeger.DefaultUDPSpanServerHost
|
||||
if e := os.Getenv(envAgentHost); e != "" {
|
||||
host = e
|
||||
}
|
||||
|
||||
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)
|
||||
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, 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
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
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)
|
||||
}
|
||||
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
+17
-1
@@ -33,7 +33,9 @@ type Options struct {
|
||||
contribObservers []jaeger.ContribObserver
|
||||
observers []jaeger.Observer
|
||||
gen128Bit bool
|
||||
poolSpans bool
|
||||
zipkinSharedRPCSpan bool
|
||||
maxTagValueLength int
|
||||
tags []opentracing.Tag
|
||||
injectors map[interface{}]jaeger.Injector
|
||||
extractors map[interface{}]jaeger.Extractor
|
||||
@@ -77,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) {
|
||||
@@ -92,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.
|
||||
@@ -101,6 +110,13 @@ func ZipkinSharedRPCSpan(zipkinSharedRPCSpan bool) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// MaxTagValueLength can be provided to override the default max tag value length.
|
||||
func MaxTagValueLength(maxTagValueLength int) Option {
|
||||
return func(c *Options) {
|
||||
c.maxTagValueLength = maxTagValueLength
|
||||
}
|
||||
}
|
||||
|
||||
// Tag creates an option that adds a tracer-level tag.
|
||||
func Tag(key string, value interface{}) Option {
|
||||
return func(c *Options) {
|
||||
|
||||
+4
-1
@@ -16,7 +16,7 @@ package jaeger
|
||||
|
||||
const (
|
||||
// JaegerClientVersion is the version of the client library reported as Span tag.
|
||||
JaegerClientVersion = "Go-2.14.0"
|
||||
JaegerClientVersion = "Go-2.16.0"
|
||||
|
||||
// JaegerClientVersionTagKey is the name of the tag used to report client version.
|
||||
JaegerClientVersionTagKey = "jaeger.version"
|
||||
@@ -82,4 +82,7 @@ const (
|
||||
|
||||
// DefaultUDPSpanServerPort is the default port to send the spans to, via UDP
|
||||
DefaultUDPSpanServerPort = 6831
|
||||
|
||||
// DefaultMaxTagValueLength is the default max length of byte array or string allowed in the tag value.
|
||||
DefaultMaxTagValueLength = 256
|
||||
)
|
||||
|
||||
+1
-1
@@ -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 != ""
|
||||
}
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
hash: 92cc8f956428fc65bee07d809a752f34376aece141c934eff02aefa08d450b72
|
||||
updated: 2019-03-23T18:26:09.960887-04:00
|
||||
imports:
|
||||
- name: github.com/beorn7/perks
|
||||
version: 3a771d992973f24aa725d07868b467d1ddfceafb
|
||||
subpackages:
|
||||
- quantile
|
||||
- name: github.com/codahale/hdrhistogram
|
||||
version: 3a0bb77429bd3a61596f5e8a3172445844342120
|
||||
- name: github.com/crossdock/crossdock-go
|
||||
version: 049aabb0122b03bc9bd30cab8f3f91fb60166361
|
||||
subpackages:
|
||||
- assert
|
||||
- require
|
||||
- name: github.com/davecgh/go-spew
|
||||
version: d8f796af33cc11cb798c1aaeb27a4ebc5099927d
|
||||
subpackages:
|
||||
- spew
|
||||
- name: github.com/golang/protobuf
|
||||
version: bbd03ef6da3a115852eaf24c8a1c46aeb39aa175
|
||||
subpackages:
|
||||
- proto
|
||||
- name: github.com/matttproud/golang_protobuf_extensions
|
||||
version: c12348ce28de40eed0136aa2b644d0ee0650e56c
|
||||
subpackages:
|
||||
- pbutil
|
||||
- name: github.com/opentracing/opentracing-go
|
||||
version: 659c90643e714681897ec2521c60567dd21da733
|
||||
subpackages:
|
||||
- ext
|
||||
- harness
|
||||
- log
|
||||
- name: github.com/pkg/errors
|
||||
version: ba968bfe8b2f7e042a574c888954fccecfa385b4
|
||||
- name: github.com/pmezard/go-difflib
|
||||
version: 792786c7400a136282c1664665ae0a8db921c6c2
|
||||
subpackages:
|
||||
- difflib
|
||||
- name: github.com/prometheus/client_golang
|
||||
version: c5b7fccd204277076155f10851dad72b76a49317
|
||||
subpackages:
|
||||
- prometheus
|
||||
- name: github.com/prometheus/client_model
|
||||
version: 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c
|
||||
subpackages:
|
||||
- go
|
||||
- name: github.com/prometheus/common
|
||||
version: 38c53a9f4bfcd932d1b00bfc65e256a7fba6b37a
|
||||
subpackages:
|
||||
- expfmt
|
||||
- internal/bitbucket.org/ww/goautoneg
|
||||
- model
|
||||
- name: github.com/prometheus/procfs
|
||||
version: 780932d4fbbe0e69b84c34c20f5c8d0981e109ea
|
||||
subpackages:
|
||||
- internal/util
|
||||
- nfs
|
||||
- xfs
|
||||
- name: github.com/stretchr/testify
|
||||
version: f35b8ab0b5a2cef36673838d662e249dd9c94686
|
||||
subpackages:
|
||||
- assert
|
||||
- require
|
||||
- suite
|
||||
- name: github.com/uber/jaeger-lib
|
||||
version: 0e30338a695636fe5bcf7301e8030ce8dd2a8530
|
||||
subpackages:
|
||||
- metrics
|
||||
- metrics/metricstest
|
||||
- metrics/prometheus
|
||||
- name: go.uber.org/atomic
|
||||
version: 1ea20fb1cbb1cc08cbd0d913a96dead89aa18289
|
||||
- name: go.uber.org/multierr
|
||||
version: 3c4937480c32f4c13a875a1829af76c98ca3d40a
|
||||
- name: go.uber.org/zap
|
||||
version: ff33455a0e382e8a81d14dd7c922020b6b5e7982
|
||||
subpackages:
|
||||
- buffer
|
||||
- internal/bufferpool
|
||||
- internal/color
|
||||
- internal/exit
|
||||
- zapcore
|
||||
- name: golang.org/x/net
|
||||
version: 49bb7cea24b1df9410e1712aa6433dae904ff66a
|
||||
subpackages:
|
||||
- context
|
||||
- context/ctxhttp
|
||||
testImports:
|
||||
- name: github.com/uber-go/atomic
|
||||
version: 8474b86a5a6f79c443ce4b2992817ff32cf208b8
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package: github.com/uber/jaeger-client-go
|
||||
import:
|
||||
- package: github.com/opentracing/opentracing-go
|
||||
version: ^1.1
|
||||
subpackages:
|
||||
- ext
|
||||
- log
|
||||
- package: github.com/crossdock/crossdock-go
|
||||
- package: github.com/uber/jaeger-lib
|
||||
version: ^2.0.0
|
||||
subpackages:
|
||||
- metrics
|
||||
- package: github.com/pkg/errors
|
||||
version: ~0.8.0
|
||||
testImport:
|
||||
- package: github.com/stretchr/testify
|
||||
subpackages:
|
||||
- assert
|
||||
- require
|
||||
- suite
|
||||
- package: github.com/prometheus/client_golang
|
||||
version: v0.8.0
|
||||
+2
-1
@@ -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
|
||||
}
|
||||
|
||||
+9
-9
@@ -38,7 +38,7 @@ func BuildJaegerThrift(span *Span) *j.Span {
|
||||
Flags: int32(span.context.flags),
|
||||
StartTime: startTime,
|
||||
Duration: duration,
|
||||
Tags: buildTags(span.tags),
|
||||
Tags: buildTags(span.tags, span.tracer.options.maxTagValueLength),
|
||||
Logs: buildLogs(span.logs),
|
||||
References: buildReferences(span.references),
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func BuildJaegerProcessThrift(span *Span) *j.Process {
|
||||
func buildJaegerProcessThrift(tracer *Tracer) *j.Process {
|
||||
process := &j.Process{
|
||||
ServiceName: tracer.serviceName,
|
||||
Tags: buildTags(tracer.tags),
|
||||
Tags: buildTags(tracer.tags, tracer.options.maxTagValueLength),
|
||||
}
|
||||
if tracer.process.UUID != "" {
|
||||
process.Tags = append(process.Tags, &j.Tag{Key: TracerUUIDTagKey, VStr: &tracer.process.UUID, VType: j.TagType_STRING})
|
||||
@@ -63,10 +63,10 @@ func buildJaegerProcessThrift(tracer *Tracer) *j.Process {
|
||||
return process
|
||||
}
|
||||
|
||||
func buildTags(tags []Tag) []*j.Tag {
|
||||
func buildTags(tags []Tag, maxTagValueLength int) []*j.Tag {
|
||||
jTags := make([]*j.Tag, 0, len(tags))
|
||||
for _, tag := range tags {
|
||||
jTag := buildTag(&tag)
|
||||
jTag := buildTag(&tag, maxTagValueLength)
|
||||
jTags = append(jTags, jTag)
|
||||
}
|
||||
return jTags
|
||||
@@ -84,16 +84,16 @@ func buildLogs(logs []opentracing.LogRecord) []*j.Log {
|
||||
return jLogs
|
||||
}
|
||||
|
||||
func buildTag(tag *Tag) *j.Tag {
|
||||
func buildTag(tag *Tag, maxTagValueLength int) *j.Tag {
|
||||
jTag := &j.Tag{Key: tag.key}
|
||||
switch value := tag.value.(type) {
|
||||
case string:
|
||||
vStr := truncateString(value)
|
||||
vStr := truncateString(value, maxTagValueLength)
|
||||
jTag.VStr = &vStr
|
||||
jTag.VType = j.TagType_STRING
|
||||
case []byte:
|
||||
if len(value) > maxAnnotationLength {
|
||||
value = value[:maxAnnotationLength]
|
||||
if len(value) > maxTagValueLength {
|
||||
value = value[:maxTagValueLength]
|
||||
}
|
||||
jTag.VBinary = value
|
||||
jTag.VType = j.TagType_BINARY
|
||||
@@ -150,7 +150,7 @@ func buildTag(tag *Tag) *j.Tag {
|
||||
jTag.VBool = &vBool
|
||||
jTag.VType = j.TagType_BOOL
|
||||
default:
|
||||
vStr := truncateString(stringify(value))
|
||||
vStr := truncateString(stringify(value), maxTagValueLength)
|
||||
jTag.VStr = &vStr
|
||||
jTag.VType = j.TagType_STRING
|
||||
}
|
||||
|
||||
+26
-26
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+24
-15
@@ -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):]
|
||||
}
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
An Observer that can be used to emit RPC metrics
|
||||
================================================
|
||||
|
||||
It can be attached to the tracer during tracer construction.
|
||||
See `ExampleObserver` function in [observer_test.go](./observer_test.go).
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
@@ -511,6 +511,7 @@ func (s *RemotelyControlledSampler) updateSampler() {
|
||||
res, err := s.manager.GetSamplingStrategy(s.serviceName)
|
||||
if err != nil {
|
||||
s.metrics.SamplerQueryFailure.Inc(1)
|
||||
s.logger.Infof("Unable to query sampling strategy: %v", err)
|
||||
return
|
||||
}
|
||||
s.Lock()
|
||||
|
||||
+3
@@ -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() {
|
||||
}
|
||||
|
||||
+90
@@ -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>"
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
# Apache Thrift
|
||||
|
||||
This is a partial copy of Apache Thrift v0.10 (https://github.com/apache/thrift/commit/b2a4d4ae21c789b689dd162deb819665567f481c).
|
||||
|
||||
It is vendored code to avoid compatibility issues introduced in Thrift v0.11.
|
||||
|
||||
See https://github.com/jaegertracing/jaeger-client-go/pull/303.
|
||||
+32
-8
@@ -17,6 +17,7 @@ package jaeger
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
@@ -50,6 +51,7 @@ type Tracer struct {
|
||||
gen128Bit bool // whether to generate 128bit trace IDs
|
||||
zipkinSharedRPCSpan bool
|
||||
highTraceIDGenerator func() uint64 // custom high trace ID generator
|
||||
maxTagValueLength int
|
||||
// more options to come
|
||||
}
|
||||
// pool for Span objects
|
||||
@@ -95,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
|
||||
@@ -121,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 {
|
||||
@@ -152,6 +163,9 @@ func NewTracer(
|
||||
t.logger.Error("Overriding high trace ID generator but not generating " +
|
||||
"128 bit trace IDs, consider enabling the \"Gen128Bit\" option")
|
||||
}
|
||||
if t.options.maxTagValueLength == 0 {
|
||||
t.options.maxTagValueLength = DefaultMaxTagValueLength
|
||||
}
|
||||
t.process = Process{
|
||||
Service: serviceName,
|
||||
UUID: strconv.FormatUint(t.randomNumber(), 16),
|
||||
@@ -194,6 +208,12 @@ func (t *Tracer) startSpanWithOptions(
|
||||
options.StartTime = t.timeNow()
|
||||
}
|
||||
|
||||
// Predicate whether the given span context is a valid reference
|
||||
// which may be used as parent / debug ID / baggage items source
|
||||
isValidReference := func(ctx SpanContext) bool {
|
||||
return ctx.IsValid() || ctx.isDebugIDContainerOnly() || len(ctx.baggage) != 0
|
||||
}
|
||||
|
||||
var references []Reference
|
||||
var parent SpanContext
|
||||
var hasParent bool // need this because `parent` is a value, not reference
|
||||
@@ -205,7 +225,7 @@ func (t *Tracer) startSpanWithOptions(
|
||||
reflect.ValueOf(ref.ReferencedContext)))
|
||||
continue
|
||||
}
|
||||
if !(ctx.IsValid() || ctx.isDebugIDContainerOnly() || len(ctx.baggage) != 0) {
|
||||
if !isValidReference(ctx) {
|
||||
continue
|
||||
}
|
||||
references = append(references, Reference{Type: ref.Type, Context: ctx})
|
||||
@@ -214,7 +234,7 @@ func (t *Tracer) startSpanWithOptions(
|
||||
hasParent = ref.Type == opentracing.ChildOfRef
|
||||
}
|
||||
}
|
||||
if !hasParent && parent.IsValid() {
|
||||
if !hasParent && isValidReference(parent) {
|
||||
// If ChildOfRef wasn't found but a FollowFromRef exists, use the context from
|
||||
// the FollowFromRef as the parent
|
||||
hasParent = true
|
||||
@@ -299,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
|
||||
}
|
||||
|
||||
+8
-2
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -128,6 +128,12 @@ func (tracerOptions) HighTraceIDGenerator(highTraceIDGenerator func() uint64) Tr
|
||||
}
|
||||
}
|
||||
|
||||
func (tracerOptions) MaxTagValueLength(maxTagValueLength int) TracerOption {
|
||||
return func(tracer *Tracer) {
|
||||
tracer.options.maxTagValueLength = maxTagValueLength
|
||||
}
|
||||
}
|
||||
|
||||
func (tracerOptions) ZipkinSharedRPCSpan(zipkinSharedRPCSpan bool) TracerOption {
|
||||
return func(tracer *Tracer) {
|
||||
tracer.options.zipkinSharedRPCSpan = zipkinSharedRPCSpan
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package transport defines various transports that can be used with
|
||||
// RemoteReporter to send spans out of process. Transport is responsible
|
||||
// for serializing the spans into a specific format suitable for sending
|
||||
// to the tracing backend. Examples may include Thrift over UDP, Thrift
|
||||
// or JSON over HTTP, Thrift over Kafka, etc.
|
||||
//
|
||||
// Implementations are NOT required to be thread-safe; the RemoteReporter
|
||||
// is expected to only call methods on the Transport from the same go-routine.
|
||||
package transport
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package transport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/uber/jaeger-client-go/thrift"
|
||||
|
||||
"github.com/uber/jaeger-client-go"
|
||||
j "github.com/uber/jaeger-client-go/thrift-gen/jaeger"
|
||||
)
|
||||
|
||||
// Default timeout for http request in seconds
|
||||
const defaultHTTPTimeout = time.Second * 5
|
||||
|
||||
// HTTPTransport implements Transport by forwarding spans to a http server.
|
||||
type HTTPTransport struct {
|
||||
url string
|
||||
client *http.Client
|
||||
batchSize int
|
||||
spans []*j.Span
|
||||
process *j.Process
|
||||
httpCredentials *HTTPBasicAuthCredentials
|
||||
}
|
||||
|
||||
// HTTPBasicAuthCredentials stores credentials for HTTP basic auth.
|
||||
type HTTPBasicAuthCredentials struct {
|
||||
username string
|
||||
password string
|
||||
}
|
||||
|
||||
// HTTPOption sets a parameter for the HttpCollector
|
||||
type HTTPOption func(c *HTTPTransport)
|
||||
|
||||
// HTTPTimeout sets maximum timeout for http request.
|
||||
func HTTPTimeout(duration time.Duration) HTTPOption {
|
||||
return func(c *HTTPTransport) { c.client.Timeout = duration }
|
||||
}
|
||||
|
||||
// HTTPBatchSize sets the maximum batch size, after which a collect will be
|
||||
// triggered. The default batch size is 100 spans.
|
||||
func HTTPBatchSize(n int) HTTPOption {
|
||||
return func(c *HTTPTransport) { c.batchSize = n }
|
||||
}
|
||||
|
||||
// HTTPBasicAuth sets the credentials required to perform HTTP basic auth
|
||||
func HTTPBasicAuth(username string, password string) HTTPOption {
|
||||
return func(c *HTTPTransport) {
|
||||
c.httpCredentials = &HTTPBasicAuthCredentials{username: username, password: password}
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPRoundTripper configures the underlying Transport on the *http.Client
|
||||
// that is used
|
||||
func HTTPRoundTripper(transport http.RoundTripper) HTTPOption {
|
||||
return func(c *HTTPTransport) {
|
||||
c.client.Transport = transport
|
||||
}
|
||||
}
|
||||
|
||||
// NewHTTPTransport returns a new HTTP-backend transport. url should be an http
|
||||
// url of the collector to handle POST request, typically something like:
|
||||
// http://hostname:14268/api/traces?format=jaeger.thrift
|
||||
func NewHTTPTransport(url string, options ...HTTPOption) *HTTPTransport {
|
||||
c := &HTTPTransport{
|
||||
url: url,
|
||||
client: &http.Client{Timeout: defaultHTTPTimeout},
|
||||
batchSize: 100,
|
||||
spans: []*j.Span{},
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(c)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Append implements Transport.
|
||||
func (c *HTTPTransport) Append(span *jaeger.Span) (int, error) {
|
||||
if c.process == nil {
|
||||
c.process = jaeger.BuildJaegerProcessThrift(span)
|
||||
}
|
||||
jSpan := jaeger.BuildJaegerThrift(span)
|
||||
c.spans = append(c.spans, jSpan)
|
||||
if len(c.spans) >= c.batchSize {
|
||||
return c.Flush()
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Flush implements Transport.
|
||||
func (c *HTTPTransport) Flush() (int, error) {
|
||||
count := len(c.spans)
|
||||
if count == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
err := c.send(c.spans)
|
||||
c.spans = c.spans[:0]
|
||||
return count, err
|
||||
}
|
||||
|
||||
// Close implements Transport.
|
||||
func (c *HTTPTransport) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *HTTPTransport) send(spans []*j.Span) error {
|
||||
batch := &j.Batch{
|
||||
Spans: spans,
|
||||
Process: c.process,
|
||||
}
|
||||
body, err := serializeThrift(batch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest("POST", c.url, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-thrift")
|
||||
|
||||
if c.httpCredentials != nil {
|
||||
req.SetBasicAuth(c.httpCredentials.username, c.httpCredentials.password)
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
return fmt.Errorf("error from collector: %d", resp.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func serializeThrift(obj thrift.TStruct) (*bytes.Buffer, error) {
|
||||
t := thrift.NewTMemoryBuffer()
|
||||
p := thrift.NewTBinaryProtocolTransport(t)
|
||||
if err := obj.Write(p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t.Buffer, nil
|
||||
}
|
||||
+17
-14
@@ -27,9 +27,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// maxAnnotationLength is the max length of byte array or string allowed in the annotations
|
||||
maxAnnotationLength = 256
|
||||
|
||||
// Zipkin UI does not work well with non-string tag values
|
||||
allowPackedNumbers = false
|
||||
)
|
||||
@@ -51,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,
|
||||
@@ -98,7 +101,7 @@ func buildAnnotations(span *zipkinSpan, endpoint *z.Endpoint) []*z.Annotation {
|
||||
Timestamp: utils.TimeToMicrosecondsSinceEpochInt64(log.Timestamp),
|
||||
Host: endpoint}
|
||||
if content, err := spanlog.MaterializeWithJSON(log.Fields); err == nil {
|
||||
anno.Value = truncateString(string(content))
|
||||
anno.Value = truncateString(string(content), span.tracer.options.maxTagValueLength)
|
||||
} else {
|
||||
anno.Value = err.Error()
|
||||
}
|
||||
@@ -148,21 +151,21 @@ func buildBinaryAnnotations(span *zipkinSpan, endpoint *z.Endpoint) []*z.BinaryA
|
||||
if _, ok := specialTagHandlers[tag.key]; ok {
|
||||
continue
|
||||
}
|
||||
if anno := buildBinaryAnnotation(tag.key, tag.value, nil); anno != nil {
|
||||
if anno := buildBinaryAnnotation(tag.key, tag.value, span.tracer.options.maxTagValueLength, nil); anno != nil {
|
||||
annotations = append(annotations, anno)
|
||||
}
|
||||
}
|
||||
return annotations
|
||||
}
|
||||
|
||||
func buildBinaryAnnotation(key string, val interface{}, endpoint *z.Endpoint) *z.BinaryAnnotation {
|
||||
func buildBinaryAnnotation(key string, val interface{}, maxTagValueLength int, endpoint *z.Endpoint) *z.BinaryAnnotation {
|
||||
bann := &z.BinaryAnnotation{Key: key, Host: endpoint}
|
||||
if value, ok := val.(string); ok {
|
||||
bann.Value = []byte(truncateString(value))
|
||||
bann.Value = []byte(truncateString(value, maxTagValueLength))
|
||||
bann.AnnotationType = z.AnnotationType_STRING
|
||||
} else if value, ok := val.([]byte); ok {
|
||||
if len(value) > maxAnnotationLength {
|
||||
value = value[:maxAnnotationLength]
|
||||
if len(value) > maxTagValueLength {
|
||||
value = value[:maxTagValueLength]
|
||||
}
|
||||
bann.Value = value
|
||||
bann.AnnotationType = z.AnnotationType_BYTES
|
||||
@@ -180,7 +183,7 @@ func buildBinaryAnnotation(key string, val interface{}, endpoint *z.Endpoint) *z
|
||||
bann.AnnotationType = z.AnnotationType_BOOL
|
||||
} else {
|
||||
value := stringify(val)
|
||||
bann.Value = []byte(truncateString(value))
|
||||
bann.Value = []byte(truncateString(value, maxTagValueLength))
|
||||
bann.AnnotationType = z.AnnotationType_STRING
|
||||
}
|
||||
return bann
|
||||
@@ -193,12 +196,12 @@ func stringify(value interface{}) string {
|
||||
return fmt.Sprintf("%+v", value)
|
||||
}
|
||||
|
||||
func truncateString(value string) string {
|
||||
func truncateString(value string, maxLength int) string {
|
||||
// we ignore the problem of utf8 runes possibly being sliced in the middle,
|
||||
// as it is rather expensive to iterate through each tag just to find rune
|
||||
// boundaries.
|
||||
if len(value) > maxAnnotationLength {
|
||||
return value[:maxAnnotationLength]
|
||||
if len(value) > maxLength {
|
||||
return value[:maxLength]
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
+51
-8
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
-337
@@ -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,
|
||||
}
|
||||
}
|
||||
+64
-12
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user