Remove already packaged gems from embedded gems (jaeger-client, opentracing and thrift)
This commit is contained in:
parent
8db93dc562
commit
af2cd3bde3
219 changed files with 0 additions and 21132 deletions
|
@ -1,12 +0,0 @@
|
|||
/.bundle/
|
||||
/.yardoc
|
||||
/Gemfile.lock
|
||||
/_yardoc/
|
||||
/coverage/
|
||||
/doc/
|
||||
/pkg/
|
||||
/spec/reports/
|
||||
/tmp/
|
||||
|
||||
# rspec failure tracking
|
||||
.rspec_status
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "idl"]
|
||||
path = idl
|
||||
url = https://github.com/jaegertracing/jaeger-idl.git
|
|
@ -1,2 +0,0 @@
|
|||
--format documentation
|
||||
--color
|
|
@ -1,50 +0,0 @@
|
|||
require: rubocop-rspec
|
||||
|
||||
AllCops:
|
||||
Exclude:
|
||||
- 'thrift/**/*'
|
||||
|
||||
Style/Documentation:
|
||||
Enabled: no
|
||||
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: no
|
||||
|
||||
RSpec/NestedGroups:
|
||||
Max: 4
|
||||
|
||||
RSpec/ExampleLength:
|
||||
Enabled: no
|
||||
|
||||
RSpec/MultipleExpectations:
|
||||
Enabled: no
|
||||
|
||||
RSpec/MessageSpies:
|
||||
Enabled: no
|
||||
|
||||
Metrics/BlockLength:
|
||||
Enabled: no
|
||||
|
||||
Metrics/MethodLength:
|
||||
Enabled: no
|
||||
|
||||
Metrics/AbcSize:
|
||||
Enabled: no
|
||||
|
||||
Metrics/ClassLength:
|
||||
Enabled: no
|
||||
|
||||
Metrics/ParameterLists:
|
||||
Enabled: no
|
||||
|
||||
Lint/UnusedMethodArgument:
|
||||
Enabled: no
|
||||
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: yes
|
||||
EnforcedStyle: always
|
||||
Include:
|
||||
- 'lib/**/*'
|
||||
|
||||
Metrics/LineLength:
|
||||
Max: 120
|
|
@ -1,14 +0,0 @@
|
|||
sudo: false
|
||||
|
||||
language: ruby
|
||||
rvm:
|
||||
- 2.5.0
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
before_install: gem install bundler -v 1.17.2
|
||||
|
||||
script:
|
||||
- bundle exec rake
|
||||
- make crossdock
|
|
@ -1,4 +0,0 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in jaeger-client.gemspec
|
||||
gemspec
|
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Indrek Juhkam
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -1 +0,0 @@
|
|||
-include crossdock/rules.mk
|
158
debian/gems-compat/jaeger-client-0.10.0/README.md
vendored
158
debian/gems-compat/jaeger-client-0.10.0/README.md
vendored
|
@ -1,158 +0,0 @@
|
|||
Jaeger::Client
|
||||
================
|
||||
[![Gem Version](https://badge.fury.io/rb/jaeger-client.svg)](https://rubygems.org/gems/jaeger-client)
|
||||
[![Build Status](https://travis-ci.org/salemove/jaeger-client-ruby.svg)](https://travis-ci.org/salemove/jaeger-client-ruby)
|
||||
|
||||
OpenTracing Tracer implementation for Jaeger in Ruby
|
||||
|
||||
## Installation
|
||||
|
||||
Add this line to your application's Gemfile:
|
||||
|
||||
```ruby
|
||||
gem 'jaeger-client'
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```ruby
|
||||
require 'jaeger/client'
|
||||
OpenTracing.global_tracer = Jaeger::Client.build(host: 'localhost', port: 6831, service_name: 'echo')
|
||||
|
||||
OpenTracing.start_active_span('span name') do
|
||||
# do something
|
||||
|
||||
OpenTracing.start_active_span('inner span name') do
|
||||
# do something else
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
See [opentracing-ruby](https://github.com/opentracing/opentracing-ruby) for more examples.
|
||||
|
||||
### Reporters
|
||||
|
||||
#### RemoteReporter (default)
|
||||
|
||||
RemoteReporter buffers spans in memory and sends them out of process using Sender.
|
||||
|
||||
There are two senders: `UdpSender` (default) and `HttpSender`.
|
||||
|
||||
To use `HttpSender`:
|
||||
|
||||
```ruby
|
||||
OpenTracing.global_tracer = Jaeger::Client.build(
|
||||
service_name: 'service_name',
|
||||
reporter: Jaeger::Reporters::RemoteReporter.new(
|
||||
sender: Jaeger::HttpSender.new(
|
||||
url: 'http://localhost:14268/api/traces',
|
||||
headers: { 'key' => 'value' }, # headers key is optional
|
||||
encoder: Jaeger::Encoders::ThriftEncoder.new(service_name: 'service_name')
|
||||
),
|
||||
flush_interval: 10
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
#### NullReporter
|
||||
|
||||
NullReporter ignores all spans.
|
||||
|
||||
```ruby
|
||||
OpenTracing.global_tracer = Jaeger::Client.build(
|
||||
service_name: 'service_name',
|
||||
reporter: Jaeger::Reporters::NullReporter.new
|
||||
)
|
||||
```
|
||||
|
||||
#### LoggingReporter
|
||||
|
||||
LoggingReporter prints some details about the span using `logger`. This is meant only for debugging. Do not parse and use this information for anything critical. The implemenation can change at any time.
|
||||
|
||||
```ruby
|
||||
OpenTracing.global_tracer = Jaeger::Client.build(
|
||||
service_name: 'service_name',
|
||||
reporter: Jaeger::Reporters::LoggingReporter.new
|
||||
)
|
||||
```
|
||||
|
||||
LoggingReporter can also use a custom logger. For this provide logger using `logger` keyword argument.
|
||||
|
||||
### Samplers
|
||||
|
||||
#### Const sampler
|
||||
|
||||
`Const` sampler always makes the same decision for new traces depending on the initialization value. Set `sampler` to: `Jaeger::Samplers::Const.new(true)` to mark all new traces as sampled.
|
||||
|
||||
#### Probabilistic sampler
|
||||
|
||||
`Probabilistic` sampler samples traces with probability equal to `rate` (must be between 0.0 and 1.0). This can be enabled by setting `Jaeger::Samplers::Probabilistic.new(rate: 0.1)`
|
||||
|
||||
#### RateLimiting sampler
|
||||
|
||||
`RateLimiting` sampler samples at most `max_traces_per_second`. The distribution of sampled traces follows burstiness of the service, i.e. a service with uniformly distributed requests will have those requests sampled uniformly as well, but if requests are bursty, especially sub-second, then a number of sequential requests can be sampled each second.
|
||||
|
||||
Set `sampler` to `Jaeger::Samplers::RateLimiting.new(max_traces_per_second: 100)`
|
||||
|
||||
#### GuaranteedThroughputProbabilistic sampler
|
||||
|
||||
`GuaranteedThroughputProbabilistic` is a sampler that guarantees a throughput by using a Probabilistic sampler and RateLimiting sampler The RateLimiting sampler is used to establish a lower_bound so that every operation is sampled at least once in the time interval defined by the lower_bound.
|
||||
|
||||
Set `sampler` to `Jaeger::Samplers::GuaranteedThroughputProbabilistic.new(lower_bound: 10, rate: 0.001)`
|
||||
|
||||
#### PerOperation sampler
|
||||
|
||||
`PerOperation` sampler leverages both Probabilistic sampler and RateLimiting sampler via the GuaranteedThroughputProbabilistic sampler. This sampler keeps track of all operations and delegates calls the the respective GuaranteedThroughputProbabilistic sampler.
|
||||
|
||||
Set `sampler` to
|
||||
```ruby
|
||||
Jaeger::Samplers::PerOperation.new(
|
||||
strategies: {
|
||||
per_operation_strategies: [
|
||||
{ operation: 'GET /articles', probabilistic_sampling: 0.5 },
|
||||
{ operation: 'POST /articles', probabilistic_sampling: 1.0 }
|
||||
],
|
||||
default_sampling_probability: 0.001,
|
||||
default_lower_bound_traces_per_second: 1.0 / (10.0 * 60.0)
|
||||
},
|
||||
max_operations: 1000
|
||||
)
|
||||
```
|
||||
|
||||
### 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 OpenZipkin tracers.
|
||||
|
||||
To set it up you need to change FORMAT_RACK injector and extractor.
|
||||
|
||||
```ruby
|
||||
OpenTracing.global_tracer = Jaeger::Client.build(
|
||||
service_name: 'service_name',
|
||||
injectors: {
|
||||
OpenTracing::FORMAT_RACK => [Jaeger::Injectors::B3RackCodec]
|
||||
},
|
||||
extractors: {
|
||||
OpenTracing::FORMAT_RACK => [Jaeger::Extractors::B3RackCodec]
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
It's also possible to set up multiple injectors and extractors. Each injector will be called in sequence. Note that if multiple injectors are using the same keys then the values will be overwritten.
|
||||
|
||||
If multiple extractors is used then the span context from the first match will be returned.
|
||||
|
||||
## Development
|
||||
|
||||
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
||||
|
||||
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
||||
|
||||
## Contributing
|
||||
|
||||
Bug reports and pull requests are welcome on GitHub at https://github.com/salemove/jaeger-client-ruby
|
||||
|
||||
|
||||
## License
|
||||
|
||||
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
require 'bundler/gem_tasks'
|
||||
require 'rspec/core/rake_task'
|
||||
require 'rubocop/rake_task'
|
||||
|
||||
RSpec::Core::RakeTask.new(:spec)
|
||||
|
||||
RuboCop::RakeTask.new(:rubocop)
|
||||
|
||||
task default: %i[rubocop spec]
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'bundler/setup'
|
||||
require 'jaeger/client'
|
||||
|
||||
# You can add fixtures and/or initialization code here to make experimenting
|
||||
# with your gem easier. You can also use a different console, if you like.
|
||||
|
||||
# (If you use this, don't forget to add pry to your Gemfile!)
|
||||
# require "pry"
|
||||
# Pry.start
|
||||
|
||||
require 'irb'
|
||||
IRB.start(__FILE__)
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
set -vx
|
||||
|
||||
bundle install
|
||||
|
||||
# Do any other automated setup that you need to do here
|
|
@ -1,29 +0,0 @@
|
|||
FROM ruby:2.5-alpine
|
||||
|
||||
ENV APP_HOME /app
|
||||
|
||||
# git is required by bundler to run jaeger gem with local path
|
||||
RUN apk add --no-cache git
|
||||
|
||||
# Add only files needed for installing gem dependencies. This allows us to
|
||||
# change other files without needing to install gems every time when building
|
||||
# the docker image.
|
||||
ADD Gemfile Gemfile.lock jaeger-client.gemspec $APP_HOME/
|
||||
ADD lib/jaeger/client/version.rb $APP_HOME/lib/jaeger/client/
|
||||
ADD crossdock/Gemfile crossdock/Gemfile.lock $APP_HOME/crossdock/
|
||||
|
||||
RUN apk add --no-cache --virtual .app-builddeps build-base \
|
||||
&& cd $APP_HOME && bundle install \
|
||||
&& cd $APP_HOME/crossdock && bundle install \
|
||||
&& apk del .app-builddeps
|
||||
|
||||
ADD . $APP_HOME
|
||||
|
||||
RUN chown -R nobody:nogroup $APP_HOME
|
||||
USER nobody
|
||||
|
||||
WORKDIR $APP_HOME/crossdock
|
||||
|
||||
CMD ["bundle", "exec", "./server"]
|
||||
|
||||
EXPOSE 8080-8082
|
|
@ -1,6 +0,0 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'jaeger-client', path: '../'
|
||||
gem 'rack'
|
||||
gem 'sinatra'
|
||||
gem 'webrick', '~> 1.4.2'
|
|
@ -1,35 +0,0 @@
|
|||
PATH
|
||||
remote: ..
|
||||
specs:
|
||||
jaeger-client (0.7.1)
|
||||
opentracing (~> 0.3)
|
||||
thrift
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
mustermann (1.0.3)
|
||||
opentracing (0.4.3)
|
||||
rack (2.0.6)
|
||||
rack-protection (2.0.4)
|
||||
rack
|
||||
sinatra (2.0.4)
|
||||
mustermann (~> 1.0)
|
||||
rack (~> 2.0)
|
||||
rack-protection (= 2.0.4)
|
||||
tilt (~> 2.0)
|
||||
thrift (0.11.0.0)
|
||||
tilt (2.0.9)
|
||||
webrick (1.4.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
jaeger-client!
|
||||
rack
|
||||
sinatra
|
||||
webrick (~> 1.4.2)
|
||||
|
||||
BUNDLED WITH
|
||||
1.16.2
|
|
@ -1,68 +0,0 @@
|
|||
version: '2'
|
||||
|
||||
services:
|
||||
crossdock:
|
||||
image: crossdock/crossdock
|
||||
links:
|
||||
- test_driver
|
||||
- go
|
||||
- python
|
||||
- java
|
||||
- ruby
|
||||
environment:
|
||||
- WAIT_FOR=test_driver,go,python,java,ruby
|
||||
- WAIT_FOR_TIMEOUT=60s
|
||||
|
||||
- CALL_TIMEOUT=60s
|
||||
|
||||
- AXIS_CLIENT=go
|
||||
|
||||
- AXIS_S1NAME=go,python,java,ruby
|
||||
- AXIS_SAMPLED=true,false
|
||||
- AXIS_S2NAME=go,python,java,ruby
|
||||
- AXIS_S2TRANSPORT=http
|
||||
- AXIS_S3NAME=go,python,java,ruby
|
||||
- AXIS_S3TRANSPORT=http
|
||||
|
||||
- BEHAVIOR_TRACE=client,s1name,sampled,s2name,s2transport,s3name,s3transport
|
||||
|
||||
- AXIS_TESTDRIVER=test_driver
|
||||
- AXIS_SERVICES=ruby
|
||||
|
||||
- BEHAVIOR_ENDTOEND=testdriver,services
|
||||
|
||||
- REPORT=compact
|
||||
go:
|
||||
image: jaegertracing/xdock-go
|
||||
ports:
|
||||
- "8080-8082"
|
||||
|
||||
java:
|
||||
image: jaegertracing/xdock-java
|
||||
depends_on:
|
||||
- jaeger-agent
|
||||
ports:
|
||||
- "8080-8082"
|
||||
|
||||
python:
|
||||
image: jaegertracing/xdock-py
|
||||
depends_on:
|
||||
- jaeger-agent
|
||||
ports:
|
||||
- "8080-8082"
|
||||
|
||||
ruby:
|
||||
build:
|
||||
context: ../.
|
||||
dockerfile: crossdock/Dockerfile
|
||||
ports:
|
||||
- "8080-8082"
|
||||
|
||||
test_driver:
|
||||
image: jaegertracing/test-driver
|
||||
depends_on:
|
||||
- jaeger-query
|
||||
- jaeger-collector
|
||||
- jaeger-agent
|
||||
ports:
|
||||
- "8080"
|
|
@ -1,48 +0,0 @@
|
|||
version: '2'
|
||||
|
||||
services:
|
||||
jaeger-collector:
|
||||
image: jaegertracing/jaeger-collector
|
||||
command: ["--cassandra.keyspace=jaeger_v1_dc1", "--cassandra.servers=cassandra", "--collector.zipkin.http-port=9411"]
|
||||
ports:
|
||||
- "14269"
|
||||
- "14268:14268"
|
||||
- "14267"
|
||||
- "14250"
|
||||
- "9411:9411"
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
- cassandra-schema
|
||||
|
||||
jaeger-query:
|
||||
image: jaegertracing/jaeger-query
|
||||
command: ["--cassandra.keyspace=jaeger_v1_dc1", "--cassandra.servers=cassandra"]
|
||||
ports:
|
||||
- "16686:16686"
|
||||
- "16687"
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
- cassandra-schema
|
||||
|
||||
jaeger-agent:
|
||||
image: jaegertracing/jaeger-agent
|
||||
# FIXME temporarily switching back to tchannel
|
||||
# https://github.com/jaegertracing/jaeger/issues/1229
|
||||
command: ["--reporter.tchannel.host-port=jaeger-collector:14267"]
|
||||
ports:
|
||||
- "5775:5775/udp"
|
||||
- "6831:6831/udp"
|
||||
- "6832:6832/udp"
|
||||
- "5778:5778"
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
- jaeger-collector
|
||||
|
||||
cassandra:
|
||||
image: cassandra:3.9
|
||||
|
||||
cassandra-schema:
|
||||
image: jaegertracing/jaeger-cassandra-schema
|
||||
depends_on:
|
||||
- cassandra
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
XDOCK_YAML=crossdock/docker-compose.yml
|
||||
TRACETEST_THRIFT=idl/thrift/crossdock/tracetest.thrift
|
||||
JAEGER_COMPOSE_URL=https://raw.githubusercontent.com/jaegertracing/jaeger/master/crossdock/jaeger-docker-compose.yml
|
||||
XDOCK_JAEGER_YAML=crossdock/jaeger-docker-compose.yml
|
||||
|
||||
.PHONY: clean-compile
|
||||
clean-compile:
|
||||
find . -name '*.pyc' -exec rm {} \;
|
||||
|
||||
.PHONY: docker
|
||||
docker: clean-compile crossdock-download-jaeger
|
||||
docker build -f crossdock/Dockerfile -t jaeger-client-ruby .
|
||||
|
||||
.PHONY: crossdock
|
||||
crossdock: ${TRACETEST_THRIFT} crossdock-download-jaeger
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) kill ruby
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) rm -f ruby
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) build ruby
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) run crossdock
|
||||
|
||||
.PHONY: crossdock-fresh
|
||||
crossdock-fresh: ${TRACETEST_THRIFT} crossdock-download-jaeger
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) kill
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) rm --force
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) pull
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) build
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) run crossdock
|
||||
|
||||
.PHONY: crossdock-logs crossdock-download-jaeger
|
||||
crossdock-logs:
|
||||
docker-compose -f $(XDOCK_YAML) -f $(XDOCK_JAEGER_YAML) logs
|
||||
|
||||
.PHONY: crossdock-download-jaeger
|
||||
crossdock-download-jaeger:
|
||||
curl -o $(XDOCK_JAEGER_YAML) $(JAEGER_COMPOSE_URL)
|
|
@ -1,173 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
$stdout.sync = true
|
||||
|
||||
require 'sinatra/base'
|
||||
require 'webrick'
|
||||
require 'jaeger/client'
|
||||
require 'net/http'
|
||||
require 'uri'
|
||||
|
||||
class HealthServer < Sinatra::Application
|
||||
get '/' do
|
||||
status 200
|
||||
end
|
||||
end
|
||||
|
||||
class HttpServer < Sinatra::Application
|
||||
post '/start_trace' do
|
||||
puts "Got request to start trace: #{trace_request}"
|
||||
|
||||
parent_context = tracer.extract(OpenTracing::FORMAT_RACK, request.env)
|
||||
server_span = tracer.start_span('/start_trace', child_of: parent_context)
|
||||
|
||||
server_span.set_baggage_item('crossdock-baggage-key', trace_request['baggage'])
|
||||
if trace_request.key?('sampled')
|
||||
server_span.set_tag('sampling.priority', trace_request['sampled'] ? 1 : 0)
|
||||
end
|
||||
|
||||
response = {
|
||||
span: observe_span(server_span),
|
||||
notImplementedError: ''
|
||||
}
|
||||
|
||||
if trace_request['downstream']
|
||||
downstream = trace_request['downstream']
|
||||
transport = downstream['transport']
|
||||
|
||||
response[:downstream] =
|
||||
if transport == 'HTTP'
|
||||
call_downstream_http(downstream, server_span)
|
||||
elsif transport == 'DUMMY'
|
||||
{ notImplementedError: 'Dummy has not been implemented' }
|
||||
else
|
||||
{ notImplementedError: "Unrecognized transport received: #{transport}" }
|
||||
end
|
||||
end
|
||||
|
||||
puts "Response: #{response}"
|
||||
|
||||
server_span.finish
|
||||
body JSON.dump(response)
|
||||
end
|
||||
|
||||
post '/join_trace' do
|
||||
puts 'Got request to join trace' \
|
||||
"\n Params: #{trace_request}" \
|
||||
"\n Headers: #{request_headers(request)}"
|
||||
|
||||
parent_context = tracer.extract(OpenTracing::FORMAT_RACK, request.env)
|
||||
server_span = tracer.start_span('/join_trace', child_of: parent_context)
|
||||
|
||||
response = {
|
||||
span: observe_span(server_span),
|
||||
notImplementedError: ''
|
||||
}
|
||||
|
||||
if trace_request['downstream']
|
||||
downstream = trace_request['downstream']
|
||||
transport = downstream['transport']
|
||||
|
||||
response[:downstream] =
|
||||
if transport == 'HTTP'
|
||||
call_downstream_http(downstream, server_span)
|
||||
elsif transport == 'DUMMY'
|
||||
{ notImplementedError: 'Dummy has not been implemented' }
|
||||
else
|
||||
{ notImplementedError: "Unrecognized transport received: #{transport}" }
|
||||
end
|
||||
end
|
||||
|
||||
puts "Response: #{response}"
|
||||
|
||||
server_span.finish
|
||||
body JSON.dump(response)
|
||||
end
|
||||
|
||||
post '/create_traces' do
|
||||
puts "Got request to create traces: #{trace_request}"
|
||||
|
||||
trace_request['count'].times do
|
||||
span = tracer.start_span(trace_request['operation'], tags: trace_request['tags'])
|
||||
span.finish
|
||||
end
|
||||
|
||||
status 200
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def tracer
|
||||
@tracer ||= Jaeger::Client.build(
|
||||
service_name: 'crossdock-ruby',
|
||||
host: 'jaeger-agent',
|
||||
port: 6831,
|
||||
flush_interval: 1,
|
||||
sampler: Jaeger::Samplers::Const.new(true)
|
||||
)
|
||||
end
|
||||
|
||||
def trace_request
|
||||
@trace_request ||= begin
|
||||
request.body.rewind
|
||||
JSON.parse(request.body.read)
|
||||
end
|
||||
end
|
||||
|
||||
def observe_span(span)
|
||||
if span
|
||||
{
|
||||
traceId: span.context.to_trace_id,
|
||||
sampled: span.context.sampled?,
|
||||
baggage: span.get_baggage_item('crossdock-baggage-key')
|
||||
}
|
||||
else
|
||||
{
|
||||
traceId: 'no span found',
|
||||
sampled: false,
|
||||
baggage: 'no span found'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def call_downstream_http(downstream, server_span)
|
||||
downstream_url = "http://#{downstream['host']}:#{downstream['port']}/join_trace"
|
||||
|
||||
client_span = tracer.start_span('client-span', child_of: server_span)
|
||||
|
||||
headers = { 'Content-Type' => 'application/json' }
|
||||
tracer.inject(client_span.context, OpenTracing::FORMAT_RACK, headers)
|
||||
|
||||
response = Net::HTTP.post(
|
||||
URI(downstream_url),
|
||||
JSON.dump(
|
||||
serverRole: downstream['serverRole'],
|
||||
downstream: downstream['downstream']
|
||||
),
|
||||
headers
|
||||
)
|
||||
|
||||
client_span.finish
|
||||
|
||||
if response.is_a?(Net::HTTPSuccess)
|
||||
JSON.parse(response.body)
|
||||
else
|
||||
{ error: response.body }
|
||||
end
|
||||
end
|
||||
|
||||
def request_headers(request)
|
||||
request.env.select do |key, _value|
|
||||
key.start_with?('HTTP_')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
threads = []
|
||||
threads << Thread.new do
|
||||
Rack::Handler::WEBrick.run(HealthServer, Port: 8080, Host: '0.0.0.0')
|
||||
end
|
||||
threads << Thread.new do
|
||||
Rack::Handler::WEBrick.run(HttpServer, Port: 8081, Host: '0.0.0.0')
|
||||
end
|
||||
threads.each(&:join)
|
|
@ -1,32 +0,0 @@
|
|||
lib = File.expand_path('lib', __dir__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
|
||||
require 'jaeger/client/version'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = 'jaeger-client'
|
||||
spec.version = Jaeger::Client::VERSION
|
||||
spec.authors = ['SaleMove TechMovers']
|
||||
spec.email = ['techmovers@salemove.com']
|
||||
|
||||
spec.summary = 'OpenTracing Tracer implementation for Jaeger in Ruby'
|
||||
spec.description = ''
|
||||
spec.homepage = 'https://github.com/salemove/jaeger-client-ruby'
|
||||
spec.license = 'MIT'
|
||||
|
||||
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
||||
f.match(%r{^(test|spec|features)/})
|
||||
end
|
||||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||
spec.require_paths = ['lib']
|
||||
|
||||
spec.add_development_dependency 'bundler', '~> 1.14'
|
||||
spec.add_development_dependency 'rake', '~> 10.0'
|
||||
spec.add_development_dependency 'rspec', '~> 3.0'
|
||||
spec.add_development_dependency 'rubocop', '~> 0.54.0'
|
||||
spec.add_development_dependency 'rubocop-rspec', '~> 1.24.0'
|
||||
spec.add_development_dependency 'timecop', '~> 0.9'
|
||||
|
||||
spec.add_dependency 'opentracing', '~> 0.3'
|
||||
spec.add_dependency 'thrift'
|
||||
end
|
|
@ -1,70 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
$LOAD_PATH.push(File.dirname(__FILE__) + '/../../thrift/gen-rb')
|
||||
|
||||
require 'opentracing'
|
||||
require 'jaeger/thrift/agent'
|
||||
require 'logger'
|
||||
|
||||
require_relative 'tracer'
|
||||
require_relative 'span'
|
||||
require_relative 'span_context'
|
||||
require_relative 'scope'
|
||||
require_relative 'scope_manager'
|
||||
require_relative 'trace_id'
|
||||
require_relative 'udp_sender'
|
||||
require_relative 'http_sender'
|
||||
require_relative 'reporters'
|
||||
require_relative 'client/version'
|
||||
require_relative 'samplers'
|
||||
require_relative 'encoders/thrift_encoder'
|
||||
require_relative 'injectors'
|
||||
require_relative 'extractors'
|
||||
require_relative 'rate_limiter'
|
||||
|
||||
module Jaeger
|
||||
module Client
|
||||
# We initially had everything under Jaeger::Client namespace. This however
|
||||
# was not very useful and was removed. These assignments are here for
|
||||
# backwards compatibility. Fine to remove in the next major version.
|
||||
UdpSender = Jaeger::UdpSender
|
||||
HttpSender = Jaeger::HttpSender
|
||||
Encoders = Jaeger::Encoders
|
||||
Samplers = Jaeger::Samplers
|
||||
Reporters = Jaeger::Reporters
|
||||
Injectors = Jaeger::Injectors
|
||||
Extractors = Jaeger::Extractors
|
||||
|
||||
DEFAULT_FLUSH_INTERVAL = 10
|
||||
|
||||
def self.build(host: '127.0.0.1',
|
||||
port: 6831,
|
||||
service_name:,
|
||||
flush_interval: DEFAULT_FLUSH_INTERVAL,
|
||||
sampler: Samplers::Const.new(true),
|
||||
logger: Logger.new(STDOUT),
|
||||
sender: nil,
|
||||
reporter: nil,
|
||||
injectors: {},
|
||||
extractors: {})
|
||||
encoder = Encoders::ThriftEncoder.new(service_name: service_name)
|
||||
|
||||
if sender
|
||||
warn '[DEPRECATION] Passing `sender` directly to Jaeger::Client.build is deprecated.' \
|
||||
'Please use `reporter` instead.'
|
||||
end
|
||||
|
||||
reporter ||= Reporters::RemoteReporter.new(
|
||||
sender: sender || UdpSender.new(host: host, port: port, encoder: encoder, logger: logger),
|
||||
flush_interval: flush_interval
|
||||
)
|
||||
|
||||
Tracer.new(
|
||||
reporter: reporter,
|
||||
sampler: sampler,
|
||||
injectors: Injectors.prepare(injectors),
|
||||
extractors: Extractors.prepare(extractors)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Client
|
||||
VERSION = '0.10.0'.freeze
|
||||
end
|
||||
end
|
|
@ -1,92 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Encoders
|
||||
class ThriftEncoder
|
||||
def initialize(service_name:)
|
||||
@service_name = service_name
|
||||
@tags = [
|
||||
Jaeger::Thrift::Tag.new(
|
||||
'key' => 'jaeger.version',
|
||||
'vType' => Jaeger::Thrift::TagType::STRING,
|
||||
'vStr' => 'Ruby-' + Jaeger::Client::VERSION
|
||||
),
|
||||
Jaeger::Thrift::Tag.new(
|
||||
'key' => 'hostname',
|
||||
'vType' => Jaeger::Thrift::TagType::STRING,
|
||||
'vStr' => Socket.gethostname
|
||||
)
|
||||
]
|
||||
ipv4 = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }
|
||||
unless ipv4.nil? # rubocop:disable Style/GuardClause
|
||||
@tags << Jaeger::Thrift::Tag.new(
|
||||
'key' => 'ip',
|
||||
'vType' => Jaeger::Thrift::TagType::STRING,
|
||||
'vStr' => ipv4.ip_address
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def encode(spans)
|
||||
Jaeger::Thrift::Batch.new(
|
||||
'process' => Jaeger::Thrift::Process.new(
|
||||
'serviceName' => @service_name,
|
||||
'tags' => @tags
|
||||
),
|
||||
'spans' => spans.map(&method(:encode_span))
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def encode_span(span)
|
||||
context = span.context
|
||||
start_ts, duration = build_timestamps(span)
|
||||
|
||||
Jaeger::Thrift::Span.new(
|
||||
'traceIdLow' => TraceId.uint64_id_to_int64(context.trace_id),
|
||||
'traceIdHigh' => 0,
|
||||
'spanId' => TraceId.uint64_id_to_int64(context.span_id),
|
||||
'parentSpanId' => TraceId.uint64_id_to_int64(context.parent_id),
|
||||
'operationName' => span.operation_name,
|
||||
'references' => build_references(span.references || []),
|
||||
'flags' => context.flags,
|
||||
'startTime' => start_ts,
|
||||
'duration' => duration,
|
||||
'tags' => span.tags,
|
||||
'logs' => span.logs
|
||||
)
|
||||
end
|
||||
|
||||
def build_references(references)
|
||||
references.map do |ref|
|
||||
Jaeger::Thrift::SpanRef.new(
|
||||
'refType' => span_ref_type(ref.type),
|
||||
'traceIdLow' => TraceId.uint64_id_to_int64(ref.context.trace_id),
|
||||
'traceIdHigh' => 0,
|
||||
'spanId' => TraceId.uint64_id_to_int64(ref.context.span_id)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def build_timestamps(span)
|
||||
start_ts = (span.start_time.to_f * 1_000_000).to_i
|
||||
end_ts = (span.end_time.to_f * 1_000_000).to_i
|
||||
duration = end_ts - start_ts
|
||||
[start_ts, duration]
|
||||
end
|
||||
|
||||
def span_ref_type(type)
|
||||
case type
|
||||
when OpenTracing::Reference::CHILD_OF
|
||||
Jaeger::Thrift::SpanRefType::CHILD_OF
|
||||
when OpenTracing::Reference::FOLLOWS_FROM
|
||||
Jaeger::Thrift::SpanRefType::FOLLOWS_FROM
|
||||
else
|
||||
warn "Jaeger::Client with format #{type} is not supported yet"
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,109 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Extractors
|
||||
class SerializedJaegerTrace
|
||||
def self.parse(trace)
|
||||
return nil if !trace || trace == ''
|
||||
|
||||
trace_arguments = trace.split(':').map(&TraceId.method(:base16_hex_id_to_uint64))
|
||||
return nil if trace_arguments.size != 4
|
||||
|
||||
trace_id, span_id, parent_id, flags = trace_arguments
|
||||
return nil if trace_id.zero? || span_id.zero?
|
||||
|
||||
SpanContext.new(
|
||||
trace_id: trace_id,
|
||||
parent_id: parent_id,
|
||||
span_id: span_id,
|
||||
flags: flags
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class JaegerTextMapCodec
|
||||
def self.extract(carrier)
|
||||
context = SerializedJaegerTrace.parse(carrier['uber-trace-id'])
|
||||
return nil unless context
|
||||
|
||||
carrier.each do |key, value|
|
||||
baggage_match = key.match(/\Auberctx-([\w-]+)\Z/)
|
||||
if baggage_match
|
||||
context.set_baggage_item(baggage_match[1], value)
|
||||
end
|
||||
end
|
||||
|
||||
context
|
||||
end
|
||||
end
|
||||
|
||||
class JaegerRackCodec
|
||||
def self.extract(carrier)
|
||||
serialized_trace = carrier['HTTP_UBER_TRACE_ID']
|
||||
serialized_trace = CGI.unescape(serialized_trace) if serialized_trace
|
||||
context = SerializedJaegerTrace.parse(serialized_trace)
|
||||
return nil unless context
|
||||
|
||||
carrier.each do |key, value|
|
||||
baggage_match = key.match(/\AHTTP_UBERCTX_(\w+)\Z/)
|
||||
if baggage_match
|
||||
key = baggage_match[1].downcase.tr('_', '-')
|
||||
context.set_baggage_item(key, CGI.unescape(value))
|
||||
end
|
||||
end
|
||||
|
||||
context
|
||||
end
|
||||
end
|
||||
|
||||
class JaegerBinaryCodec
|
||||
def self.extract(_carrier)
|
||||
warn 'Jaeger::Client with binary format is not supported yet'
|
||||
end
|
||||
end
|
||||
|
||||
class B3RackCodec
|
||||
def self.extract(carrier)
|
||||
trace_id = TraceId.base16_hex_id_to_uint64(carrier['HTTP_X_B3_TRACEID'])
|
||||
span_id = TraceId.base16_hex_id_to_uint64(carrier['HTTP_X_B3_SPANID'])
|
||||
parent_id = TraceId.base16_hex_id_to_uint64(carrier['HTTP_X_B3_PARENTSPANID'])
|
||||
flags = parse_flags(carrier['HTTP_X_B3_FLAGS'], carrier['HTTP_X_B3_SAMPLED'])
|
||||
|
||||
return nil if span_id.nil? || trace_id.nil?
|
||||
return nil if span_id.zero? || trace_id.zero?
|
||||
|
||||
SpanContext.new(
|
||||
trace_id: trace_id,
|
||||
parent_id: parent_id,
|
||||
span_id: span_id,
|
||||
flags: flags
|
||||
)
|
||||
end
|
||||
|
||||
# if the flags header is '1' then the sampled header should not be present
|
||||
def self.parse_flags(flags_header, sampled_header)
|
||||
if flags_header == '1'
|
||||
Jaeger::SpanContext::Flags::DEBUG
|
||||
else
|
||||
TraceId.base16_hex_id_to_uint64(sampled_header)
|
||||
end
|
||||
end
|
||||
private_class_method :parse_flags
|
||||
end
|
||||
|
||||
DEFAULT_EXTRACTORS = {
|
||||
OpenTracing::FORMAT_TEXT_MAP => JaegerTextMapCodec,
|
||||
OpenTracing::FORMAT_BINARY => JaegerBinaryCodec,
|
||||
OpenTracing::FORMAT_RACK => JaegerRackCodec
|
||||
}.freeze
|
||||
|
||||
def self.prepare(extractors)
|
||||
DEFAULT_EXTRACTORS.reduce(extractors) do |acc, (format, default)|
|
||||
provided_extractors = Array(extractors[format])
|
||||
provided_extractors += [default] if provided_extractors.empty?
|
||||
|
||||
acc.merge(format => provided_extractors)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,28 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'logger'
|
||||
|
||||
module Jaeger
|
||||
class HttpSender
|
||||
def initialize(url:, headers: {}, encoder:, logger: Logger.new(STDOUT))
|
||||
@encoder = encoder
|
||||
@logger = logger
|
||||
|
||||
@uri = URI(url)
|
||||
@uri.query = 'format=jaeger.thrift'
|
||||
|
||||
@transport = ::Thrift::HTTPClientTransport.new(@uri.to_s)
|
||||
@transport.add_headers(headers)
|
||||
|
||||
@serializer = ::Thrift::Serializer.new
|
||||
end
|
||||
|
||||
def send_spans(spans)
|
||||
batch = @encoder.encode(spans)
|
||||
@transport.write(@serializer.serialize(batch))
|
||||
@transport.flush
|
||||
rescue StandardError => error
|
||||
@logger.error("Failure while sending a batch of spans: #{error}")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,69 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Injectors
|
||||
def self.context_as_jaeger_string(span_context)
|
||||
[
|
||||
span_context.trace_id.to_s(16),
|
||||
span_context.span_id.to_s(16),
|
||||
span_context.parent_id.to_s(16),
|
||||
span_context.flags.to_s(16)
|
||||
].join(':')
|
||||
end
|
||||
|
||||
class JaegerTextMapCodec
|
||||
def self.inject(span_context, carrier)
|
||||
carrier['uber-trace-id'] = Injectors.context_as_jaeger_string(span_context)
|
||||
span_context.baggage.each do |key, value|
|
||||
carrier["uberctx-#{key}"] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class JaegerRackCodec
|
||||
def self.inject(span_context, carrier)
|
||||
carrier['uber-trace-id'] =
|
||||
CGI.escape(Injectors.context_as_jaeger_string(span_context))
|
||||
span_context.baggage.each do |key, value|
|
||||
carrier["uberctx-#{key}"] = CGI.escape(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class JaegerBinaryCodec
|
||||
def self.inject(_span_context, _carrier)
|
||||
warn 'Jaeger::Client with binary format is not supported yet'
|
||||
end
|
||||
end
|
||||
|
||||
class B3RackCodec
|
||||
def self.inject(span_context, carrier)
|
||||
carrier['x-b3-traceid'] = TraceId.to_hex(span_context.trace_id)
|
||||
carrier['x-b3-spanid'] = TraceId.to_hex(span_context.span_id)
|
||||
carrier['x-b3-parentspanid'] = TraceId.to_hex(span_context.parent_id)
|
||||
|
||||
# flags (for debug) and sampled headers are mutually exclusive
|
||||
if span_context.flags == Jaeger::SpanContext::Flags::DEBUG
|
||||
carrier['x-b3-flags'] = '1'
|
||||
else
|
||||
carrier['x-b3-sampled'] = span_context.flags.to_s(16)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DEFAULT_INJECTORS = {
|
||||
OpenTracing::FORMAT_TEXT_MAP => JaegerTextMapCodec,
|
||||
OpenTracing::FORMAT_BINARY => JaegerBinaryCodec,
|
||||
OpenTracing::FORMAT_RACK => JaegerRackCodec
|
||||
}.freeze
|
||||
|
||||
def self.prepare(extractors)
|
||||
DEFAULT_INJECTORS.reduce(extractors) do |acc, (format, default)|
|
||||
provided_extractors = Array(extractors[format])
|
||||
provided_extractors += [default] if provided_extractors.empty?
|
||||
|
||||
acc.merge(format => provided_extractors)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,61 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
# RateLimiter is based on leaky bucket algorithm, formulated in terms of a
|
||||
# credits balance that is replenished every time check_credit() method is
|
||||
# called (tick) by the amount proportional to the time elapsed since the
|
||||
# last tick, up to the max_balance. A call to check_credit() takes a cost
|
||||
# of an item we want to pay with the balance. If the balance exceeds the
|
||||
# cost of the item, the item is "purchased" and the balance reduced,
|
||||
# indicated by returned value of true. Otherwise the balance is unchanged
|
||||
# and return false.
|
||||
#
|
||||
# This can be used to limit a rate of messages emitted by a service by
|
||||
# instantiating the Rate Limiter with the max number of messages a service
|
||||
# is allowed to emit per second, and calling check_credit(1.0) for each
|
||||
# message to determine if the message is within the rate limit.
|
||||
#
|
||||
# It can also be used to limit the rate of traffic in bytes, by setting
|
||||
# credits_per_second to desired throughput as bytes/second, and calling
|
||||
# check_credit() with the actual message size.
|
||||
class RateLimiter
|
||||
def initialize(credits_per_second:, max_balance:)
|
||||
@credits_per_second = credits_per_second
|
||||
@max_balance = max_balance
|
||||
@balance = max_balance
|
||||
@last_tick = Time.now
|
||||
end
|
||||
|
||||
def check_credit(item_cost)
|
||||
update_balance
|
||||
|
||||
return false if @balance < item_cost
|
||||
|
||||
@balance -= item_cost
|
||||
true
|
||||
end
|
||||
|
||||
def update(credits_per_second:, max_balance:)
|
||||
update_balance
|
||||
|
||||
@credits_per_second = credits_per_second
|
||||
|
||||
# The new balance should be proportional to the old balance
|
||||
@balance = max_balance * @balance / @max_balance
|
||||
@max_balance = max_balance
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_balance
|
||||
current_time = Time.now
|
||||
elapsed_time = current_time - @last_tick
|
||||
@last_tick = current_time
|
||||
|
||||
@balance += elapsed_time * @credits_per_second
|
||||
return if @balance <= @max_balance
|
||||
|
||||
@balance = @max_balance
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'reporters/composite_reporter'
|
||||
require_relative 'reporters/in_memory_reporter'
|
||||
require_relative 'reporters/logging_reporter'
|
||||
require_relative 'reporters/null_reporter'
|
||||
require_relative 'reporters/remote_reporter'
|
|
@ -1,17 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Reporters
|
||||
class CompositeReporter
|
||||
def initialize(reporters:)
|
||||
@reporters = reporters
|
||||
end
|
||||
|
||||
def report(span)
|
||||
@reporters.each do |reporter|
|
||||
reporter.report(span)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Reporters
|
||||
class InMemoryReporter
|
||||
def initialize
|
||||
@spans = []
|
||||
@mutex = Mutex.new
|
||||
end
|
||||
|
||||
def report(span)
|
||||
@mutex.synchronize do
|
||||
@spans << span
|
||||
end
|
||||
end
|
||||
|
||||
def spans
|
||||
@mutex.synchronize do
|
||||
@spans
|
||||
end
|
||||
end
|
||||
|
||||
def clear
|
||||
@mutex.synchronize do
|
||||
@spans.clear
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Reporters
|
||||
class LoggingReporter
|
||||
def initialize(logger: Logger.new($stdout))
|
||||
@logger = logger
|
||||
end
|
||||
|
||||
def report(span)
|
||||
span_info = {
|
||||
operation_name: span.operation_name,
|
||||
start_time: span.start_time.iso8601,
|
||||
end_time: span.end_time.iso8601,
|
||||
trace_id: span.context.to_trace_id,
|
||||
span_id: span.context.to_span_id
|
||||
}
|
||||
@logger.info "Span reported: #{span_info}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Reporters
|
||||
class NullReporter
|
||||
def report(_span)
|
||||
# no-op
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,42 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative './remote_reporter/buffer'
|
||||
|
||||
module Jaeger
|
||||
module Reporters
|
||||
class RemoteReporter
|
||||
def initialize(sender:, flush_interval:)
|
||||
@sender = sender
|
||||
@flush_interval = flush_interval
|
||||
@buffer = Buffer.new
|
||||
end
|
||||
|
||||
def flush
|
||||
spans = @buffer.retrieve
|
||||
@sender.send_spans(spans) if spans.any?
|
||||
spans
|
||||
end
|
||||
|
||||
def report(span)
|
||||
return if !span.context.sampled? && !span.context.debug?
|
||||
|
||||
init_reporter_thread
|
||||
@buffer << span
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def init_reporter_thread
|
||||
return if @initializer_pid == Process.pid
|
||||
|
||||
@initializer_pid = Process.pid
|
||||
Thread.new do
|
||||
loop do
|
||||
flush
|
||||
sleep(@flush_interval)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,29 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Reporters
|
||||
class RemoteReporter
|
||||
class Buffer
|
||||
def initialize
|
||||
@buffer = []
|
||||
@mutex = Mutex.new
|
||||
end
|
||||
|
||||
def <<(element)
|
||||
@mutex.synchronize do
|
||||
@buffer << element
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def retrieve
|
||||
@mutex.synchronize do
|
||||
elements = @buffer.dup
|
||||
@buffer.clear
|
||||
elements
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'samplers/const'
|
||||
require_relative 'samplers/guaranteed_throughput_probabilistic'
|
||||
require_relative 'samplers/per_operation'
|
||||
require_relative 'samplers/probabilistic'
|
||||
require_relative 'samplers/rate_limiting'
|
|
@ -1,24 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Samplers
|
||||
# Const sampler
|
||||
#
|
||||
# A sampler that always makes the same decision for new traces depending
|
||||
# on the initialization value. Use `Jaeger::Samplers::Const.new(true)`
|
||||
# to mark all new traces as sampled.
|
||||
class Const
|
||||
def initialize(decision)
|
||||
@decision = decision
|
||||
@tags = {
|
||||
'sampler.type' => 'const',
|
||||
'sampler.param' => @decision ? 1 : 0
|
||||
}
|
||||
end
|
||||
|
||||
def sample?(*)
|
||||
[@decision, @tags]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Samplers
|
||||
# A sampler that leverages both Probabilistic sampler and RateLimiting
|
||||
# sampler. The RateLimiting is used as a guaranteed lower bound sampler
|
||||
# such that every operation is sampled at least once in a time interval
|
||||
# defined by the lower_bound. ie a lower_bound of 1.0 / (60 * 10) will
|
||||
# sample an operation at least once every 10 minutes.
|
||||
#
|
||||
# The Probabilistic sampler is given higher priority when tags are
|
||||
# emitted, ie. if is_sampled() for both samplers return true, the tags
|
||||
# for Probabilistic sampler will be used.
|
||||
class GuaranteedThroughputProbabilistic
|
||||
attr_reader :tags
|
||||
|
||||
def initialize(lower_bound:, rate:, lower_bound_sampler: nil)
|
||||
@probabilistic_sampler = Probabilistic.new(rate: rate)
|
||||
@lower_bound_sampler = lower_bound_sampler || RateLimiting.new(max_traces_per_second: lower_bound)
|
||||
@lower_bound_tags = {
|
||||
'sampler.type' => 'lowerbound',
|
||||
'sampler.param' => lower_bound
|
||||
}
|
||||
end
|
||||
|
||||
def sample?(*args)
|
||||
is_sampled, probabilistic_tags = @probabilistic_sampler.sample?(*args)
|
||||
if is_sampled
|
||||
# We still call lower_bound_sampler to update the rate limiter budget
|
||||
@lower_bound_sampler.sample?(*args)
|
||||
|
||||
return [is_sampled, probabilistic_tags]
|
||||
end
|
||||
|
||||
is_sampled, _tags = @lower_bound_sampler.sample?(*args)
|
||||
[is_sampled, @lower_bound_tags]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,47 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Samplers
|
||||
# A sampler that leverages both Probabilistic sampler and RateLimiting
|
||||
# sampler via the GuaranteedThroughputProbabilistic sampler. This sampler
|
||||
# keeps track of all operations and delegates calls the the respective
|
||||
# GuaranteedThroughputProbabilistic sampler.
|
||||
class PerOperation
|
||||
DEFAULT_SAMPLING_PROBABILITY = 0.001
|
||||
DEFAULT_LOWER_BOUND = 1.0 / (10.0 * 60.0) # sample once every 10 minutes'
|
||||
|
||||
def initialize(strategies:, max_operations:)
|
||||
@max_operations = max_operations
|
||||
@default_sampling_probability =
|
||||
strategies[:default_sampling_probability] || DEFAULT_SAMPLING_PROBABILITY
|
||||
@lower_bound = strategies[:default_lower_bound_traces_per_second] || DEFAULT_LOWER_BOUND
|
||||
|
||||
@default_sampler = Probabilistic.new(rate: @default_sampling_probability)
|
||||
@samplers = (strategies[:per_operation_strategies] || []).reduce({}) do |acc, strategy|
|
||||
operation = strategy.fetch(:operation)
|
||||
rate = strategy.fetch(:probabilistic_sampling)
|
||||
sampler = GuaranteedThroughputProbabilistic.new(
|
||||
lower_bound: @lower_bound,
|
||||
rate: rate
|
||||
)
|
||||
acc.merge(operation => sampler)
|
||||
end
|
||||
end
|
||||
|
||||
def sample?(opts)
|
||||
operation_name = opts.fetch(:operation_name)
|
||||
sampler = @samplers[operation_name]
|
||||
return sampler.sample?(opts) if sampler
|
||||
|
||||
return @default_sampler.sample?(opts) if @samplers.length >= @max_operations
|
||||
|
||||
sampler = GuaranteedThroughputProbabilistic.new(
|
||||
lower_bound: @lower_bound,
|
||||
rate: @default_sampling_probability
|
||||
)
|
||||
@samplers[operation_name] = sampler
|
||||
sampler.sample?(opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Samplers
|
||||
# Probabilistic sampler
|
||||
#
|
||||
# Sample a portion of traces using trace_id as the random decision
|
||||
class Probabilistic
|
||||
def initialize(rate: 0.001)
|
||||
if rate < 0.0 || rate > 1.0
|
||||
raise "Sampling rate must be between 0.0 and 1.0, got #{rate.inspect}"
|
||||
end
|
||||
|
||||
@boundary = TraceId::TRACE_ID_UPPER_BOUND * rate
|
||||
@tags = {
|
||||
'sampler.type' => 'probabilistic',
|
||||
'sampler.param' => rate
|
||||
}
|
||||
end
|
||||
|
||||
def sample?(trace_id:, **)
|
||||
[@boundary >= trace_id, @tags]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,33 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module Samplers
|
||||
# Samples at most max_traces_per_second. The distribution of sampled
|
||||
# traces follows burstiness of the service, i.e. a service with uniformly
|
||||
# distributed requests will have those requests sampled uniformly as
|
||||
# well, but if requests are bursty, especially sub-second, then a number
|
||||
# of sequential requests can be sampled each second.
|
||||
class RateLimiting
|
||||
attr_reader :tags
|
||||
|
||||
def initialize(max_traces_per_second: 10)
|
||||
if max_traces_per_second < 0.0
|
||||
raise "max_traces_per_second must not be negative, got #{max_traces_per_second}"
|
||||
end
|
||||
|
||||
@rate_limiter = RateLimiter.new(
|
||||
credits_per_second: max_traces_per_second,
|
||||
max_balance: [max_traces_per_second, 1.0].max
|
||||
)
|
||||
@tags = {
|
||||
'sampler.type' => 'ratelimiting',
|
||||
'sampler.param' => max_traces_per_second
|
||||
}
|
||||
end
|
||||
|
||||
def sample?(*)
|
||||
[@rate_limiter.check_credit(1.0), @tags]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,38 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
# Scope represents an OpenTracing Scope
|
||||
#
|
||||
# See http://www.opentracing.io for more information.
|
||||
class Scope
|
||||
def initialize(span, scope_stack, finish_on_close:)
|
||||
@span = span
|
||||
@scope_stack = scope_stack
|
||||
@finish_on_close = finish_on_close
|
||||
@closed = false
|
||||
end
|
||||
|
||||
# Return the Span scoped by this Scope
|
||||
#
|
||||
# @return [Span]
|
||||
attr_reader :span
|
||||
|
||||
# Close scope
|
||||
#
|
||||
# Mark the end of the active period for the current thread and Scope,
|
||||
# updating the ScopeManager#active in the process.
|
||||
def close
|
||||
raise "Tried to close already closed span: #{inspect}" if @closed
|
||||
@closed = true
|
||||
|
||||
@span.finish if @finish_on_close
|
||||
removed_scope = @scope_stack.pop
|
||||
|
||||
if removed_scope != self # rubocop:disable Style/GuardClause
|
||||
raise 'Removed non-active scope, ' \
|
||||
"removed: #{removed_scope.inspect}, "\
|
||||
"expected: #{inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,47 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'scope_manager/scope_stack'
|
||||
require_relative 'scope_manager/scope_identifier'
|
||||
|
||||
module Jaeger
|
||||
# ScopeManager represents an OpenTracing ScopeManager
|
||||
#
|
||||
# See http://www.opentracing.io for more information.
|
||||
#
|
||||
# The ScopeManager interface abstracts both the activation of Span instances
|
||||
# via ScopeManager#activate and access to an active Span/Scope via
|
||||
# ScopeManager#active
|
||||
#
|
||||
class ScopeManager
|
||||
def initialize
|
||||
@scope_stack = ScopeStack.new
|
||||
end
|
||||
|
||||
# Make a span instance active
|
||||
#
|
||||
# @param span [Span] the Span that should become active
|
||||
# @param finish_on_close [Boolean] whether the Span should automatically be
|
||||
# finished when Scope#close is called
|
||||
# @return [Scope] instance to control the end of the active period for the
|
||||
# Span. It is a programming error to neglect to call Scope#close on the
|
||||
# returned instance.
|
||||
def activate(span, finish_on_close: true)
|
||||
return active if active && active.span == span
|
||||
scope = Scope.new(span, @scope_stack, finish_on_close: finish_on_close)
|
||||
@scope_stack.push(scope)
|
||||
scope
|
||||
end
|
||||
|
||||
# Return active scope
|
||||
#
|
||||
# If there is a non-null Scope, its wrapped Span becomes an implicit parent
|
||||
# (as Reference#CHILD_OF) of any newly-created Span at
|
||||
# Tracer#start_active_span or Tracer#start_span time.
|
||||
#
|
||||
# @return [Scope] the currently active Scope which can be used to access the
|
||||
# currently active Span.
|
||||
def active
|
||||
@scope_stack.peek
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
class ScopeManager
|
||||
# @api private
|
||||
class ScopeIdentifier
|
||||
def self.generate
|
||||
# 65..90.chr are characters between A and Z
|
||||
"opentracing_#{(0...8).map { rand(65..90).chr }.join}".to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,33 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
class ScopeManager
|
||||
# @api private
|
||||
class ScopeStack
|
||||
def initialize
|
||||
# Generate a random identifier to use as the Thread.current key. This is
|
||||
# needed so that it would be possible to create multiple tracers in one
|
||||
# thread (mostly useful for testing purposes)
|
||||
@scope_identifier = ScopeIdentifier.generate
|
||||
end
|
||||
|
||||
def push(scope)
|
||||
store << scope
|
||||
end
|
||||
|
||||
def pop
|
||||
store.pop
|
||||
end
|
||||
|
||||
def peek
|
||||
store.last
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def store
|
||||
Thread.current[@scope_identifier] ||= []
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,98 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'span/thrift_tag_builder'
|
||||
require_relative 'span/thrift_log_builder'
|
||||
|
||||
module Jaeger
|
||||
class Span
|
||||
attr_accessor :operation_name
|
||||
|
||||
attr_reader :context, :start_time, :end_time, :references, :tags, :logs
|
||||
|
||||
# Creates a new {Span}
|
||||
#
|
||||
# @param context [SpanContext] the context of the span
|
||||
# @param operation_name [String] the operation name
|
||||
# @param reporter [#report] span reporter
|
||||
#
|
||||
# @return [Span] a new Span
|
||||
def initialize(context, operation_name, reporter, start_time: Time.now, references: [], tags: {})
|
||||
@context = context
|
||||
@operation_name = operation_name
|
||||
@reporter = reporter
|
||||
@start_time = start_time
|
||||
@references = references
|
||||
@tags = []
|
||||
@logs = []
|
||||
|
||||
tags.each { |key, value| set_tag(key, value) }
|
||||
end
|
||||
|
||||
# Set a tag value on this span
|
||||
#
|
||||
# @param key [String] the key of the tag
|
||||
# @param value [String, Numeric, Boolean] the value of the tag. If it's not
|
||||
# a String, Numeric, or Boolean it will be encoded with to_s
|
||||
def set_tag(key, value)
|
||||
if key == 'sampling.priority'
|
||||
if value.to_i > 0
|
||||
return self if @context.debug?
|
||||
|
||||
@context.flags = @context.flags | SpanContext::Flags::SAMPLED | SpanContext::Flags::DEBUG
|
||||
else
|
||||
@context.flags = @context.flags & ~SpanContext::Flags::SAMPLED
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
# Using Thrift::Tag to avoid unnecessary memory allocations
|
||||
@tags << ThriftTagBuilder.build(key, value)
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Set a baggage item on the span
|
||||
#
|
||||
# @param key [String] the key of the baggage item
|
||||
# @param value [String] the value of the baggage item
|
||||
def set_baggage_item(key, value)
|
||||
@context.set_baggage_item(key, value)
|
||||
self
|
||||
end
|
||||
|
||||
# Get a baggage item
|
||||
#
|
||||
# @param key [String] the key of the baggage item
|
||||
#
|
||||
# @return Value of the baggage item
|
||||
def get_baggage_item(key)
|
||||
@context.get_baggage_item(key)
|
||||
end
|
||||
|
||||
# Add a log entry to this span
|
||||
#
|
||||
# @deprecated Use {#log_kv} instead.
|
||||
def log(*args)
|
||||
warn 'Span#log is deprecated. Please use Span#log_kv instead.'
|
||||
log_kv(*args)
|
||||
end
|
||||
|
||||
# Add a log entry to this span
|
||||
#
|
||||
# @param timestamp [Time] time of the log
|
||||
# @param fields [Hash] Additional information to log
|
||||
def log_kv(timestamp: Time.now, **fields)
|
||||
# Using Thrift::Log to avoid unnecessary memory allocations
|
||||
@logs << ThriftLogBuilder.build(timestamp, fields)
|
||||
nil
|
||||
end
|
||||
|
||||
# Finish the {Span}
|
||||
#
|
||||
# @param end_time [Time] custom end time, if not now
|
||||
def finish(end_time: Time.now)
|
||||
@end_time = end_time
|
||||
@reporter.report(self)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,18 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
class Span
|
||||
class ThriftLogBuilder
|
||||
FIELDS = Jaeger::Thrift::Log::FIELDS
|
||||
TIMESTAMP = FIELDS[Jaeger::Thrift::Log::TIMESTAMP].fetch(:name)
|
||||
LOG_FIELDS = FIELDS[Jaeger::Thrift::Log::LOG_FIELDS].fetch(:name)
|
||||
|
||||
def self.build(timestamp, fields)
|
||||
Jaeger::Thrift::Log.new(
|
||||
TIMESTAMP => (timestamp.to_f * 1_000_000).to_i,
|
||||
LOG_FIELDS => fields.map { |key, value| ThriftTagBuilder.build(key, value) }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,43 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
class Span
|
||||
class ThriftTagBuilder
|
||||
FIELDS = Jaeger::Thrift::Tag::FIELDS
|
||||
KEY = FIELDS[Jaeger::Thrift::Tag::KEY].fetch(:name)
|
||||
VTYPE = FIELDS[Jaeger::Thrift::Tag::VTYPE].fetch(:name)
|
||||
VLONG = FIELDS[Jaeger::Thrift::Tag::VLONG].fetch(:name)
|
||||
VDOUBLE = FIELDS[Jaeger::Thrift::Tag::VDOUBLE].fetch(:name)
|
||||
VBOOL = FIELDS[Jaeger::Thrift::Tag::VBOOL].fetch(:name)
|
||||
VSTR = FIELDS[Jaeger::Thrift::Tag::VSTR].fetch(:name)
|
||||
|
||||
def self.build(key, value)
|
||||
if value.is_a?(Integer)
|
||||
Jaeger::Thrift::Tag.new(
|
||||
KEY => key.to_s,
|
||||
VTYPE => Jaeger::Thrift::TagType::LONG,
|
||||
VLONG => value
|
||||
)
|
||||
elsif value.is_a?(Float)
|
||||
Jaeger::Thrift::Tag.new(
|
||||
KEY => key.to_s,
|
||||
VTYPE => Jaeger::Thrift::TagType::DOUBLE,
|
||||
VDOUBLE => value
|
||||
)
|
||||
elsif value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
||||
Jaeger::Thrift::Tag.new(
|
||||
KEY => key.to_s,
|
||||
VTYPE => Jaeger::Thrift::TagType::BOOL,
|
||||
VBOOL => value
|
||||
)
|
||||
else
|
||||
Jaeger::Thrift::Tag.new(
|
||||
KEY => key.to_s,
|
||||
VTYPE => Jaeger::Thrift::TagType::STRING,
|
||||
VSTR => value.to_s
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,57 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
# SpanContext holds the data for a span that gets inherited to child spans
|
||||
class SpanContext
|
||||
module Flags
|
||||
NONE = 0x00
|
||||
SAMPLED = 0x01
|
||||
DEBUG = 0x02
|
||||
end
|
||||
|
||||
def self.create_from_parent_context(span_context)
|
||||
new(
|
||||
trace_id: span_context.trace_id,
|
||||
parent_id: span_context.span_id,
|
||||
span_id: TraceId.generate,
|
||||
flags: span_context.flags,
|
||||
baggage: span_context.baggage.dup
|
||||
)
|
||||
end
|
||||
|
||||
attr_reader :span_id, :parent_id, :trace_id, :baggage, :flags
|
||||
attr_writer :flags
|
||||
|
||||
def initialize(span_id:, parent_id: 0, trace_id:, flags:, baggage: {})
|
||||
@span_id = span_id
|
||||
@parent_id = parent_id
|
||||
@trace_id = trace_id
|
||||
@baggage = baggage
|
||||
@flags = flags
|
||||
end
|
||||
|
||||
def sampled?
|
||||
@flags & Flags::SAMPLED == Flags::SAMPLED
|
||||
end
|
||||
|
||||
def debug?
|
||||
@flags & Flags::DEBUG == Flags::DEBUG
|
||||
end
|
||||
|
||||
def to_trace_id
|
||||
@to_trace_id ||= @trace_id.to_s(16)
|
||||
end
|
||||
|
||||
def to_span_id
|
||||
@to_span_id ||= @span_id.to_s(16)
|
||||
end
|
||||
|
||||
def set_baggage_item(key, value)
|
||||
@baggage[key.to_s] = value.to_s
|
||||
end
|
||||
|
||||
def get_baggage_item(key)
|
||||
@baggage[key.to_s]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,39 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
module TraceId
|
||||
MAX_64BIT_SIGNED_INT = (1 << 63) - 1
|
||||
MAX_64BIT_UNSIGNED_INT = (1 << 64) - 1
|
||||
TRACE_ID_UPPER_BOUND = MAX_64BIT_UNSIGNED_INT + 1
|
||||
|
||||
def self.generate
|
||||
rand(TRACE_ID_UPPER_BOUND)
|
||||
end
|
||||
|
||||
def self.base16_hex_id_to_uint64(id)
|
||||
return nil unless id
|
||||
value = id.to_i(16)
|
||||
value > MAX_64BIT_UNSIGNED_INT || value < 0 ? 0 : value
|
||||
end
|
||||
|
||||
# Thrift defines ID fields as i64, which is signed, therefore we convert
|
||||
# large IDs (> 2^63) to negative longs
|
||||
def self.uint64_id_to_int64(id)
|
||||
id > MAX_64BIT_SIGNED_INT ? id - MAX_64BIT_UNSIGNED_INT - 1 : id
|
||||
end
|
||||
|
||||
# Convert an integer id into a 0 padded hex string.
|
||||
# If the string is shorter than 16 characters, it will be padded to 16.
|
||||
# If it is longer than 16 characters, it is padded to 32.
|
||||
def self.to_hex(id)
|
||||
hex_str = id.to_s(16)
|
||||
|
||||
# pad the string with '0's to 16 or 32 characters
|
||||
if hex_str.length > 16
|
||||
hex_str.rjust(32, '0')
|
||||
else
|
||||
hex_str.rjust(16, '0')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,195 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
class Tracer
|
||||
def initialize(reporter:, sampler:, injectors:, extractors:)
|
||||
@reporter = reporter
|
||||
@sampler = sampler
|
||||
@injectors = injectors
|
||||
@extractors = extractors
|
||||
@scope_manager = ScopeManager.new
|
||||
end
|
||||
|
||||
# @return [ScopeManager] the current ScopeManager, which may be a no-op
|
||||
# but may not be nil.
|
||||
attr_reader :scope_manager
|
||||
|
||||
# @return [Span, nil] the active span. This is a shorthand for
|
||||
# `scope_manager.active.span`, and nil will be returned if
|
||||
# Scope#active is nil.
|
||||
def active_span
|
||||
scope = scope_manager.active
|
||||
scope.span if scope
|
||||
end
|
||||
|
||||
# Starts a new span.
|
||||
#
|
||||
# This is similar to #start_active_span, but the returned Span will not
|
||||
# be registered via the ScopeManager.
|
||||
#
|
||||
# @param operation_name [String] The operation name for the Span
|
||||
# @param child_of [SpanContext, Span] SpanContext that acts as a parent to
|
||||
# the newly-started Span. If a Span instance is provided, its
|
||||
# context is automatically substituted. See [Reference] for more
|
||||
# information.
|
||||
#
|
||||
# If specified, the `references` parameter must be omitted.
|
||||
# @param references [Array<Reference>] An array of reference
|
||||
# objects that identify one or more parent SpanContexts.
|
||||
# @param start_time [Time] When the Span started, if not now
|
||||
# @param tags [Hash] Tags to assign to the Span at start time
|
||||
# @param ignore_active_scope [Boolean] whether to create an implicit
|
||||
# References#CHILD_OF reference to the ScopeManager#active.
|
||||
#
|
||||
# @return [Span] The newly-started Span
|
||||
def start_span(operation_name,
|
||||
child_of: nil,
|
||||
references: nil,
|
||||
start_time: Time.now,
|
||||
tags: {},
|
||||
ignore_active_scope: false,
|
||||
**)
|
||||
context, sampler_tags = prepare_span_context(
|
||||
operation_name: operation_name,
|
||||
child_of: child_of,
|
||||
references: references,
|
||||
ignore_active_scope: ignore_active_scope
|
||||
)
|
||||
Span.new(
|
||||
context,
|
||||
operation_name,
|
||||
@reporter,
|
||||
start_time: start_time,
|
||||
references: references,
|
||||
tags: tags.merge(sampler_tags)
|
||||
)
|
||||
end
|
||||
|
||||
# Creates a newly started and activated Scope
|
||||
#
|
||||
# If the Tracer's ScopeManager#active is not nil, no explicit references
|
||||
# are provided, and `ignore_active_scope` is false, then an inferred
|
||||
# References#CHILD_OF reference is created to the ScopeManager#active's
|
||||
# SpanContext when start_active is invoked.
|
||||
#
|
||||
# @param operation_name [String] The operation name for the Span
|
||||
# @param child_of [SpanContext, Span] SpanContext that acts as a parent to
|
||||
# the newly-started Span. If a Span instance is provided, its
|
||||
# context is automatically substituted. See [Reference] for more
|
||||
# information.
|
||||
#
|
||||
# If specified, the `references` parameter must be omitted.
|
||||
# @param references [Array<Reference>] An array of reference
|
||||
# objects that identify one or more parent SpanContexts.
|
||||
# @param start_time [Time] When the Span started, if not now
|
||||
# @param tags [Hash] Tags to assign to the Span at start time
|
||||
# @param ignore_active_scope [Boolean] whether to create an implicit
|
||||
# References#CHILD_OF reference to the ScopeManager#active.
|
||||
# @param finish_on_close [Boolean] whether span should automatically be
|
||||
# finished when Scope#close is called
|
||||
# @yield [Scope] If an optional block is passed to start_active it will
|
||||
# yield the newly-started Scope. If `finish_on_close` is true then the
|
||||
# Span will be finished automatically after the block is executed.
|
||||
# @return [Scope] The newly-started and activated Scope
|
||||
def start_active_span(operation_name,
|
||||
child_of: nil,
|
||||
references: nil,
|
||||
start_time: Time.now,
|
||||
tags: {},
|
||||
ignore_active_scope: false,
|
||||
finish_on_close: true,
|
||||
**)
|
||||
span = start_span(
|
||||
operation_name,
|
||||
child_of: child_of,
|
||||
references: references,
|
||||
start_time: start_time,
|
||||
tags: tags,
|
||||
ignore_active_scope: ignore_active_scope
|
||||
)
|
||||
scope = @scope_manager.activate(span, finish_on_close: finish_on_close)
|
||||
|
||||
if block_given?
|
||||
begin
|
||||
yield scope
|
||||
ensure
|
||||
scope.close
|
||||
end
|
||||
end
|
||||
|
||||
scope
|
||||
end
|
||||
|
||||
# Inject a SpanContext into the given carrier
|
||||
#
|
||||
# @param span_context [SpanContext]
|
||||
# @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
|
||||
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
||||
def inject(span_context, format, carrier)
|
||||
@injectors.fetch(format).each do |injector|
|
||||
injector.inject(span_context, carrier)
|
||||
end
|
||||
end
|
||||
|
||||
# Extract a SpanContext in the given format from the given carrier.
|
||||
#
|
||||
# @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
|
||||
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
||||
# @return [SpanContext] the extracted SpanContext or nil if none could be found
|
||||
def extract(format, carrier)
|
||||
@extractors
|
||||
.fetch(format)
|
||||
.lazy
|
||||
.map { |extractor| extractor.extract(carrier) }
|
||||
.reject(&:nil?)
|
||||
.first
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def prepare_span_context(operation_name:, child_of:, references:, ignore_active_scope:)
|
||||
context =
|
||||
context_from_child_of(child_of) ||
|
||||
context_from_references(references) ||
|
||||
context_from_active_scope(ignore_active_scope)
|
||||
|
||||
if context
|
||||
[SpanContext.create_from_parent_context(context), {}]
|
||||
else
|
||||
trace_id = TraceId.generate
|
||||
is_sampled, tags = @sampler.sample?(
|
||||
trace_id: trace_id,
|
||||
operation_name: operation_name
|
||||
)
|
||||
span_context = SpanContext.new(
|
||||
trace_id: trace_id,
|
||||
span_id: trace_id,
|
||||
flags: is_sampled ? SpanContext::Flags::SAMPLED : SpanContext::Flags::NONE
|
||||
)
|
||||
[span_context, tags]
|
||||
end
|
||||
end
|
||||
|
||||
def context_from_child_of(child_of)
|
||||
return nil unless child_of
|
||||
child_of.respond_to?(:context) ? child_of.context : child_of
|
||||
end
|
||||
|
||||
def context_from_references(references)
|
||||
return nil if !references || references.none?
|
||||
|
||||
# Prefer CHILD_OF reference if present
|
||||
ref = references.detect do |reference|
|
||||
reference.type == OpenTracing::Reference::CHILD_OF
|
||||
end
|
||||
(ref || references[0]).context
|
||||
end
|
||||
|
||||
def context_from_active_scope(ignore_active_scope)
|
||||
return if ignore_active_scope
|
||||
|
||||
active_scope = @scope_manager.active
|
||||
active_scope.span.context if active_scope
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative './udp_sender/transport'
|
||||
require 'socket'
|
||||
|
||||
module Jaeger
|
||||
class UdpSender
|
||||
def initialize(host:, port:, encoder:, logger:)
|
||||
@encoder = encoder
|
||||
@logger = logger
|
||||
|
||||
transport = Transport.new(host, port)
|
||||
protocol = ::Thrift::CompactProtocol.new(transport)
|
||||
@client = Jaeger::Thrift::Agent::Client.new(protocol)
|
||||
end
|
||||
|
||||
def send_spans(spans)
|
||||
batch = @encoder.encode(spans)
|
||||
@client.emitBatch(batch)
|
||||
rescue StandardError => error
|
||||
@logger.error("Failure while sending a batch of spans: #{error}")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Jaeger
|
||||
class UdpSender
|
||||
class Transport
|
||||
FLAGS = 0
|
||||
|
||||
def initialize(host, port)
|
||||
@socket = UDPSocket.new
|
||||
@host = host
|
||||
@port = port
|
||||
@buffer = ::Thrift::MemoryBufferTransport.new
|
||||
end
|
||||
|
||||
def write(str)
|
||||
@buffer.write(str)
|
||||
end
|
||||
|
||||
def flush
|
||||
data = @buffer.read(@buffer.available)
|
||||
send_bytes(data)
|
||||
end
|
||||
|
||||
def open; end
|
||||
|
||||
def close; end
|
||||
|
||||
private
|
||||
|
||||
def send_bytes(bytes)
|
||||
@socket.send(bytes, FLAGS, @host, @port)
|
||||
@socket.flush
|
||||
rescue Errno::ECONNREFUSED
|
||||
warn 'Unable to connect to Jaeger Agent'
|
||||
rescue StandardError => e
|
||||
warn "Unable to send spans: #{e.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,51 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'bundler'
|
||||
Bundler.setup
|
||||
|
||||
require 'jaeger/client'
|
||||
|
||||
host = ENV['JAEGER_HOST'] || '127.0.0.1'
|
||||
port = ENV['JAEGER_HOST'] || 6831
|
||||
|
||||
tracer1 = Jaeger::Client.build(host: host, port: port.to_i, service_name: 'test-service', flush_interval: 1)
|
||||
tracer2 = Jaeger::Client.build(host: host, port: port.to_i, service_name: 'downstream-service', flush_interval: 1)
|
||||
|
||||
rpc_span = tracer1.start_span(
|
||||
'receive request',
|
||||
tags: { 'span.kind' => 'server' }
|
||||
)
|
||||
sleep 0.1
|
||||
rpc_span.log_kv(event: 'woop di doop', count: 5)
|
||||
sleep 1
|
||||
|
||||
async_request_span = tracer1.start_span(
|
||||
'request async action',
|
||||
references: [
|
||||
OpenTracing::Reference.child_of(rpc_span.context)
|
||||
],
|
||||
tags: { 'span.kind' => 'producer' }
|
||||
)
|
||||
sleep 0.1
|
||||
|
||||
async_request_span.finish
|
||||
rpc_span.finish
|
||||
|
||||
sleep 0.5
|
||||
|
||||
async_span = tracer2.start_span(
|
||||
'async span started after rpc span',
|
||||
references: [
|
||||
OpenTracing::Reference.follows_from(async_request_span.context)
|
||||
],
|
||||
tags: {
|
||||
'span.kind' => 'consumer',
|
||||
'peer.service' => 'downstream-service'
|
||||
}
|
||||
)
|
||||
sleep 0.3 # emulate network delay
|
||||
async_span.finish
|
||||
|
||||
sleep 2
|
||||
|
||||
puts 'Finished'
|
|
@ -1,52 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'bundler'
|
||||
Bundler.setup
|
||||
|
||||
require 'jaeger/client'
|
||||
|
||||
host = ENV['JAEGER_HOST'] || '127.0.0.1'
|
||||
port = ENV['JAEGER_HOST'] || 6831
|
||||
|
||||
tracer1 = Jaeger::Client.build(host: host, port: port.to_i, service_name: 'test-service', flush_interval: 1)
|
||||
tracer2 = Jaeger::Client.build(host: host, port: port.to_i, service_name: 'downstream-service', flush_interval: 1)
|
||||
|
||||
outer_span = tracer1.start_span(
|
||||
'receive request',
|
||||
tags: { 'span.kind' => 'server' }
|
||||
)
|
||||
sleep 0.1
|
||||
outer_span.log_kv(event: 'woop di doop', count: 5)
|
||||
sleep 1
|
||||
|
||||
inner_span = tracer1.start_span(
|
||||
'fetch info from downstream',
|
||||
child_of: outer_span,
|
||||
tags: {
|
||||
'span.kind' => 'client',
|
||||
'peer.service' => 'downstream-service',
|
||||
'peer.ipv4' => '6.6.6.6',
|
||||
'peer.port' => 443
|
||||
}
|
||||
)
|
||||
inner_span.set_tag('error', false)
|
||||
sleep 0.3 # emulate network delay
|
||||
|
||||
downstream_span = tracer2.start_span(
|
||||
'downstream operation',
|
||||
child_of: inner_span,
|
||||
tags: { 'span.kind' => 'server' }
|
||||
)
|
||||
sleep 0.5
|
||||
downstream_span.finish
|
||||
|
||||
sleep 0.2 # emulate network delay
|
||||
|
||||
inner_span.finish
|
||||
|
||||
sleep 0.1 # doing something with fetched info
|
||||
outer_span.finish
|
||||
|
||||
sleep 2
|
||||
|
||||
puts 'Finished'
|
|
@ -1,32 +0,0 @@
|
|||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2016 Uber Technologies, Inc.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
include "jaeger.thrift"
|
||||
include "zipkincore.thrift"
|
||||
|
||||
namespace java com.uber.jaeger.agent.thrift
|
||||
namespace rb Jaeger.Thrift
|
||||
|
||||
service Agent {
|
||||
oneway void emitZipkinBatch(1: list<zipkincore.Span> spans)
|
||||
oneway void emitBatch(1: jaeger.Batch batch)
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'jaeger/thrift/agent_types'
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
module Agent
|
||||
class Client
|
||||
include ::Thrift::Client
|
||||
|
||||
def emitZipkinBatch(spans)
|
||||
send_emitZipkinBatch(spans)
|
||||
end
|
||||
|
||||
def send_emitZipkinBatch(spans)
|
||||
send_oneway_message('emitZipkinBatch', EmitZipkinBatch_args, :spans => spans)
|
||||
end
|
||||
def emitBatch(batch)
|
||||
send_emitBatch(batch)
|
||||
end
|
||||
|
||||
def send_emitBatch(batch)
|
||||
send_oneway_message('emitBatch', EmitBatch_args, :batch => batch)
|
||||
end
|
||||
end
|
||||
|
||||
class Processor
|
||||
include ::Thrift::Processor
|
||||
|
||||
def process_emitZipkinBatch(seqid, iprot, oprot)
|
||||
args = read_args(iprot, EmitZipkinBatch_args)
|
||||
@handler.emitZipkinBatch(args.spans)
|
||||
return
|
||||
end
|
||||
|
||||
def process_emitBatch(seqid, iprot, oprot)
|
||||
args = read_args(iprot, EmitBatch_args)
|
||||
@handler.emitBatch(args.batch)
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# HELPER FUNCTIONS AND STRUCTURES
|
||||
|
||||
class EmitZipkinBatch_args
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
SPANS = 1
|
||||
|
||||
FIELDS = {
|
||||
SPANS => {:type => ::Thrift::Types::LIST, :name => 'spans', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Zipkin::Span}}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class EmitZipkinBatch_result
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
|
||||
FIELDS = {
|
||||
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class EmitBatch_args
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
BATCH = 1
|
||||
|
||||
FIELDS = {
|
||||
BATCH => {:type => ::Thrift::Types::STRUCT, :name => 'batch', :class => ::Jaeger::Thrift::Batch}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class EmitBatch_result
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
|
||||
FIELDS = {
|
||||
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,118 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'jaeger/thrift/agent/agent_types'
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
module Agent
|
||||
module Agent
|
||||
class Client
|
||||
include ::Thrift::Client
|
||||
|
||||
def emitZipkinBatch(spans)
|
||||
send_emitZipkinBatch(spans)
|
||||
end
|
||||
|
||||
def send_emitZipkinBatch(spans)
|
||||
send_oneway_message('emitZipkinBatch', EmitZipkinBatch_args, :spans => spans)
|
||||
end
|
||||
def emitBatch(batch)
|
||||
send_emitBatch(batch)
|
||||
end
|
||||
|
||||
def send_emitBatch(batch)
|
||||
send_oneway_message('emitBatch', EmitBatch_args, :batch => batch)
|
||||
end
|
||||
end
|
||||
|
||||
class Processor
|
||||
include ::Thrift::Processor
|
||||
|
||||
def process_emitZipkinBatch(seqid, iprot, oprot)
|
||||
args = read_args(iprot, EmitZipkinBatch_args)
|
||||
@handler.emitZipkinBatch(args.spans)
|
||||
return
|
||||
end
|
||||
|
||||
def process_emitBatch(seqid, iprot, oprot)
|
||||
args = read_args(iprot, EmitBatch_args)
|
||||
@handler.emitBatch(args.batch)
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# HELPER FUNCTIONS AND STRUCTURES
|
||||
|
||||
class EmitZipkinBatch_args
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
SPANS = 1
|
||||
|
||||
FIELDS = {
|
||||
SPANS => {:type => ::Thrift::Types::LIST, :name => 'spans', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Zipkin::Span}}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class EmitZipkinBatch_result
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
|
||||
FIELDS = {
|
||||
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class EmitBatch_args
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
BATCH = 1
|
||||
|
||||
FIELDS = {
|
||||
BATCH => {:type => ::Thrift::Types::STRUCT, :name => 'batch', :class => ::Jaeger::Thrift::Batch}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class EmitBatch_result
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
|
||||
FIELDS = {
|
||||
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'jaeger/thrift/agent/agent_types'
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
module Agent
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'jaeger/thrift/jaeger_types'
|
||||
require 'jaeger/thrift/zipkin/zipkincore_types'
|
||||
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
module Agent
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'jaeger/thrift/agent_types'
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'jaeger/thrift/jaeger_types'
|
||||
require 'jaeger/thrift/zipkin/zipkincore_types'
|
||||
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
end
|
||||
end
|
|
@ -1,82 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'jaeger/thrift/jaeger_types'
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
module Collector
|
||||
class Client
|
||||
include ::Thrift::Client
|
||||
|
||||
def submitBatches(batches)
|
||||
send_submitBatches(batches)
|
||||
return recv_submitBatches()
|
||||
end
|
||||
|
||||
def send_submitBatches(batches)
|
||||
send_message('submitBatches', SubmitBatches_args, :batches => batches)
|
||||
end
|
||||
|
||||
def recv_submitBatches()
|
||||
result = receive_message(SubmitBatches_result)
|
||||
return result.success unless result.success.nil?
|
||||
raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'submitBatches failed: unknown result')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Processor
|
||||
include ::Thrift::Processor
|
||||
|
||||
def process_submitBatches(seqid, iprot, oprot)
|
||||
args = read_args(iprot, SubmitBatches_args)
|
||||
result = SubmitBatches_result.new()
|
||||
result.success = @handler.submitBatches(args.batches)
|
||||
write_result(result, oprot, 'submitBatches', seqid)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# HELPER FUNCTIONS AND STRUCTURES
|
||||
|
||||
class SubmitBatches_args
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
BATCHES = 1
|
||||
|
||||
FIELDS = {
|
||||
BATCHES => {:type => ::Thrift::Types::LIST, :name => 'batches', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Batch}}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class SubmitBatches_result
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
SUCCESS = 0
|
||||
|
||||
FIELDS = {
|
||||
SUCCESS => {:type => ::Thrift::Types::LIST, :name => 'success', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::BatchSubmitResponse}}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'jaeger/thrift/jaeger_types'
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
end
|
||||
end
|
|
@ -1,211 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
module TagType
|
||||
STRING = 0
|
||||
DOUBLE = 1
|
||||
BOOL = 2
|
||||
LONG = 3
|
||||
BINARY = 4
|
||||
VALUE_MAP = {0 => "STRING", 1 => "DOUBLE", 2 => "BOOL", 3 => "LONG", 4 => "BINARY"}
|
||||
VALID_VALUES = Set.new([STRING, DOUBLE, BOOL, LONG, BINARY]).freeze
|
||||
end
|
||||
|
||||
module SpanRefType
|
||||
CHILD_OF = 0
|
||||
FOLLOWS_FROM = 1
|
||||
VALUE_MAP = {0 => "CHILD_OF", 1 => "FOLLOWS_FROM"}
|
||||
VALID_VALUES = Set.new([CHILD_OF, FOLLOWS_FROM]).freeze
|
||||
end
|
||||
|
||||
class Tag
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
KEY = 1
|
||||
VTYPE = 2
|
||||
VSTR = 3
|
||||
VDOUBLE = 4
|
||||
VBOOL = 5
|
||||
VLONG = 6
|
||||
VBINARY = 7
|
||||
|
||||
FIELDS = {
|
||||
KEY => {:type => ::Thrift::Types::STRING, :name => 'key'},
|
||||
VTYPE => {:type => ::Thrift::Types::I32, :name => 'vType', :enum_class => ::Jaeger::Thrift::TagType},
|
||||
VSTR => {:type => ::Thrift::Types::STRING, :name => 'vStr', :optional => true},
|
||||
VDOUBLE => {:type => ::Thrift::Types::DOUBLE, :name => 'vDouble', :optional => true},
|
||||
VBOOL => {:type => ::Thrift::Types::BOOL, :name => 'vBool', :optional => true},
|
||||
VLONG => {:type => ::Thrift::Types::I64, :name => 'vLong', :optional => true},
|
||||
VBINARY => {:type => ::Thrift::Types::STRING, :name => 'vBinary', :binary => true, :optional => true}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field key is unset!') unless @key
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field vType is unset!') unless @vType
|
||||
unless @vType.nil? || ::Jaeger::Thrift::TagType::VALID_VALUES.include?(@vType)
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field vType!')
|
||||
end
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class Log
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
TIMESTAMP = 1
|
||||
LOG_FIELDS = 2
|
||||
|
||||
FIELDS = {
|
||||
TIMESTAMP => {:type => ::Thrift::Types::I64, :name => 'timestamp'},
|
||||
LOG_FIELDS => {:type => ::Thrift::Types::LIST, :name => 'fields', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Tag}}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field timestamp is unset!') unless @timestamp
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field fields is unset!') unless @fields
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class SpanRef
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
REFTYPE = 1
|
||||
TRACEIDLOW = 2
|
||||
TRACEIDHIGH = 3
|
||||
SPANID = 4
|
||||
|
||||
FIELDS = {
|
||||
REFTYPE => {:type => ::Thrift::Types::I32, :name => 'refType', :enum_class => ::Jaeger::Thrift::SpanRefType},
|
||||
TRACEIDLOW => {:type => ::Thrift::Types::I64, :name => 'traceIdLow'},
|
||||
TRACEIDHIGH => {:type => ::Thrift::Types::I64, :name => 'traceIdHigh'},
|
||||
SPANID => {:type => ::Thrift::Types::I64, :name => 'spanId'}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field refType is unset!') unless @refType
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field traceIdLow is unset!') unless @traceIdLow
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field traceIdHigh is unset!') unless @traceIdHigh
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field spanId is unset!') unless @spanId
|
||||
unless @refType.nil? || ::Jaeger::Thrift::SpanRefType::VALID_VALUES.include?(@refType)
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field refType!')
|
||||
end
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class Span
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
TRACEIDLOW = 1
|
||||
TRACEIDHIGH = 2
|
||||
SPANID = 3
|
||||
PARENTSPANID = 4
|
||||
OPERATIONNAME = 5
|
||||
REFERENCES = 6
|
||||
FLAGS = 7
|
||||
STARTTIME = 8
|
||||
DURATION = 9
|
||||
TAGS = 10
|
||||
LOGS = 11
|
||||
|
||||
FIELDS = {
|
||||
TRACEIDLOW => {:type => ::Thrift::Types::I64, :name => 'traceIdLow'},
|
||||
TRACEIDHIGH => {:type => ::Thrift::Types::I64, :name => 'traceIdHigh'},
|
||||
SPANID => {:type => ::Thrift::Types::I64, :name => 'spanId'},
|
||||
PARENTSPANID => {:type => ::Thrift::Types::I64, :name => 'parentSpanId'},
|
||||
OPERATIONNAME => {:type => ::Thrift::Types::STRING, :name => 'operationName'},
|
||||
REFERENCES => {:type => ::Thrift::Types::LIST, :name => 'references', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::SpanRef}, :optional => true},
|
||||
FLAGS => {:type => ::Thrift::Types::I32, :name => 'flags'},
|
||||
STARTTIME => {:type => ::Thrift::Types::I64, :name => 'startTime'},
|
||||
DURATION => {:type => ::Thrift::Types::I64, :name => 'duration'},
|
||||
TAGS => {:type => ::Thrift::Types::LIST, :name => 'tags', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Tag}, :optional => true},
|
||||
LOGS => {:type => ::Thrift::Types::LIST, :name => 'logs', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Log}, :optional => true}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field traceIdLow is unset!') unless @traceIdLow
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field traceIdHigh is unset!') unless @traceIdHigh
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field spanId is unset!') unless @spanId
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field parentSpanId is unset!') unless @parentSpanId
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field operationName is unset!') unless @operationName
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field flags is unset!') unless @flags
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field startTime is unset!') unless @startTime
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field duration is unset!') unless @duration
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class Process
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
SERVICENAME = 1
|
||||
TAGS = 2
|
||||
|
||||
FIELDS = {
|
||||
SERVICENAME => {:type => ::Thrift::Types::STRING, :name => 'serviceName'},
|
||||
TAGS => {:type => ::Thrift::Types::LIST, :name => 'tags', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Tag}, :optional => true}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field serviceName is unset!') unless @serviceName
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class Batch
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
PROCESS = 1
|
||||
SPANS = 2
|
||||
|
||||
FIELDS = {
|
||||
PROCESS => {:type => ::Thrift::Types::STRUCT, :name => 'process', :class => ::Jaeger::Thrift::Process},
|
||||
SPANS => {:type => ::Thrift::Types::LIST, :name => 'spans', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Span}}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field process is unset!') unless @process
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field spans is unset!') unless @spans
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class BatchSubmitResponse
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
OK = 1
|
||||
|
||||
FIELDS = {
|
||||
OK => {:type => ::Thrift::Types::BOOL, :name => 'ok'}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field ok is unset!') if @ok.nil?
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,84 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'jaeger/thrift/zipkin/zipkincore_types'
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
module Zipkin
|
||||
module ZipkinCollector
|
||||
class Client
|
||||
include ::Thrift::Client
|
||||
|
||||
def submitZipkinBatch(spans)
|
||||
send_submitZipkinBatch(spans)
|
||||
return recv_submitZipkinBatch()
|
||||
end
|
||||
|
||||
def send_submitZipkinBatch(spans)
|
||||
send_message('submitZipkinBatch', SubmitZipkinBatch_args, :spans => spans)
|
||||
end
|
||||
|
||||
def recv_submitZipkinBatch()
|
||||
result = receive_message(SubmitZipkinBatch_result)
|
||||
return result.success unless result.success.nil?
|
||||
raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'submitZipkinBatch failed: unknown result')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Processor
|
||||
include ::Thrift::Processor
|
||||
|
||||
def process_submitZipkinBatch(seqid, iprot, oprot)
|
||||
args = read_args(iprot, SubmitZipkinBatch_args)
|
||||
result = SubmitZipkinBatch_result.new()
|
||||
result.success = @handler.submitZipkinBatch(args.spans)
|
||||
write_result(result, oprot, 'submitZipkinBatch', seqid)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# HELPER FUNCTIONS AND STRUCTURES
|
||||
|
||||
class SubmitZipkinBatch_args
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
SPANS = 1
|
||||
|
||||
FIELDS = {
|
||||
SPANS => {:type => ::Thrift::Types::LIST, :name => 'spans', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Zipkin::Span}}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class SubmitZipkinBatch_result
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
SUCCESS = 0
|
||||
|
||||
FIELDS = {
|
||||
SUCCESS => {:type => ::Thrift::Types::LIST, :name => 'success', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Zipkin::Response}}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,41 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'jaeger/thrift/zipkin/zipkincore_types'
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
module Zipkin
|
||||
CLIENT_SEND = %q"cs"
|
||||
|
||||
CLIENT_RECV = %q"cr"
|
||||
|
||||
SERVER_SEND = %q"ss"
|
||||
|
||||
SERVER_RECV = %q"sr"
|
||||
|
||||
WIRE_SEND = %q"ws"
|
||||
|
||||
WIRE_RECV = %q"wr"
|
||||
|
||||
CLIENT_SEND_FRAGMENT = %q"csf"
|
||||
|
||||
CLIENT_RECV_FRAGMENT = %q"crf"
|
||||
|
||||
SERVER_SEND_FRAGMENT = %q"ssf"
|
||||
|
||||
SERVER_RECV_FRAGMENT = %q"srf"
|
||||
|
||||
LOCAL_COMPONENT = %q"lc"
|
||||
|
||||
CLIENT_ADDR = %q"ca"
|
||||
|
||||
SERVER_ADDR = %q"sa"
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,220 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.10.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
|
||||
module Jaeger
|
||||
module Thrift
|
||||
module Zipkin
|
||||
module AnnotationType
|
||||
BOOL = 0
|
||||
BYTES = 1
|
||||
I16 = 2
|
||||
I32 = 3
|
||||
I64 = 4
|
||||
DOUBLE = 5
|
||||
STRING = 6
|
||||
VALUE_MAP = {0 => "BOOL", 1 => "BYTES", 2 => "I16", 3 => "I32", 4 => "I64", 5 => "DOUBLE", 6 => "STRING"}
|
||||
VALID_VALUES = Set.new([BOOL, BYTES, I16, I32, I64, DOUBLE, STRING]).freeze
|
||||
end
|
||||
|
||||
# Indicates the network context of a service recording an annotation with two
|
||||
# exceptions.
|
||||
#
|
||||
# When a BinaryAnnotation, and key is CLIENT_ADDR or SERVER_ADDR,
|
||||
# the endpoint indicates the source or destination of an RPC. This exception
|
||||
# allows zipkin to display network context of uninstrumented services, or
|
||||
# clients such as web browsers.
|
||||
class Endpoint
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
IPV4 = 1
|
||||
PORT = 2
|
||||
SERVICE_NAME = 3
|
||||
|
||||
FIELDS = {
|
||||
# IPv4 host address packed into 4 bytes.
|
||||
#
|
||||
# Ex for the ip 1.2.3.4, it would be (1 << 24) | (2 << 16) | (3 << 8) | 4
|
||||
IPV4 => {:type => ::Thrift::Types::I32, :name => 'ipv4'},
|
||||
# IPv4 port
|
||||
#
|
||||
# Note: this is to be treated as an unsigned integer, so watch for negatives.
|
||||
#
|
||||
# Conventionally, when the port isn't known, port = 0.
|
||||
PORT => {:type => ::Thrift::Types::I16, :name => 'port'},
|
||||
# Service name in lowercase, such as "memcache" or "zipkin-web"
|
||||
#
|
||||
# Conventionally, when the service name isn't known, service_name = "unknown".
|
||||
SERVICE_NAME => {:type => ::Thrift::Types::STRING, :name => 'service_name'}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
# An annotation is similar to a log statement. It includes a host field which
|
||||
# allows these events to be attributed properly, and also aggregatable.
|
||||
class Annotation
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
TIMESTAMP = 1
|
||||
VALUE = 2
|
||||
HOST = 3
|
||||
|
||||
FIELDS = {
|
||||
# Microseconds from epoch.
|
||||
#
|
||||
# This value should use the most precise value possible. For example,
|
||||
# gettimeofday or syncing nanoTime against a tick of currentTimeMillis.
|
||||
TIMESTAMP => {:type => ::Thrift::Types::I64, :name => 'timestamp'},
|
||||
VALUE => {:type => ::Thrift::Types::STRING, :name => 'value'},
|
||||
# Always the host that recorded the event. By specifying the host you allow
|
||||
# rollup of all events (such as client requests to a service) by IP address.
|
||||
HOST => {:type => ::Thrift::Types::STRUCT, :name => 'host', :class => ::Jaeger::Thrift::Zipkin::Endpoint, :optional => true}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
# Binary annotations are tags applied to a Span to give it context. For
|
||||
# example, a binary annotation of "http.uri" could the path to a resource in a
|
||||
# RPC call.
|
||||
#
|
||||
# Binary annotations of type STRING are always queryable, though more a
|
||||
# historical implementation detail than a structural concern.
|
||||
#
|
||||
# Binary annotations can repeat, and vary on the host. Similar to Annotation,
|
||||
# the host indicates who logged the event. This allows you to tell the
|
||||
# difference between the client and server side of the same key. For example,
|
||||
# the key "http.uri" might be different on the client and server side due to
|
||||
# rewriting, like "/api/v1/myresource" vs "/myresource. Via the host field,
|
||||
# you can see the different points of view, which often help in debugging.
|
||||
class BinaryAnnotation
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
KEY = 1
|
||||
VALUE = 2
|
||||
ANNOTATION_TYPE = 3
|
||||
HOST = 4
|
||||
|
||||
FIELDS = {
|
||||
KEY => {:type => ::Thrift::Types::STRING, :name => 'key'},
|
||||
VALUE => {:type => ::Thrift::Types::STRING, :name => 'value', :binary => true},
|
||||
ANNOTATION_TYPE => {:type => ::Thrift::Types::I32, :name => 'annotation_type', :enum_class => ::Jaeger::Thrift::Zipkin::AnnotationType},
|
||||
# The host that recorded tag, which allows you to differentiate between
|
||||
# multiple tags with the same key. There are two exceptions to this.
|
||||
#
|
||||
# When the key is CLIENT_ADDR or SERVER_ADDR, host indicates the source or
|
||||
# destination of an RPC. This exception allows zipkin to display network
|
||||
# context of uninstrumented services, or clients such as web browsers.
|
||||
HOST => {:type => ::Thrift::Types::STRUCT, :name => 'host', :class => ::Jaeger::Thrift::Zipkin::Endpoint, :optional => true}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
unless @annotation_type.nil? || ::Jaeger::Thrift::Zipkin::AnnotationType::VALID_VALUES.include?(@annotation_type)
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field annotation_type!')
|
||||
end
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
# A trace is a series of spans (often RPC calls) which form a latency tree.
|
||||
#
|
||||
# The root span is where trace_id = id and parent_id = Nil. The root span is
|
||||
# usually the longest interval in the trace, starting with a SERVER_RECV
|
||||
# annotation and ending with a SERVER_SEND.
|
||||
class Span
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
TRACE_ID = 1
|
||||
NAME = 3
|
||||
ID = 4
|
||||
PARENT_ID = 5
|
||||
ANNOTATIONS = 6
|
||||
BINARY_ANNOTATIONS = 8
|
||||
DEBUG = 9
|
||||
TIMESTAMP = 10
|
||||
DURATION = 11
|
||||
|
||||
FIELDS = {
|
||||
TRACE_ID => {:type => ::Thrift::Types::I64, :name => 'trace_id'},
|
||||
# Span name in lowercase, rpc method for example
|
||||
#
|
||||
# Conventionally, when the span name isn't known, name = "unknown".
|
||||
NAME => {:type => ::Thrift::Types::STRING, :name => 'name'},
|
||||
ID => {:type => ::Thrift::Types::I64, :name => 'id'},
|
||||
PARENT_ID => {:type => ::Thrift::Types::I64, :name => 'parent_id', :optional => true},
|
||||
ANNOTATIONS => {:type => ::Thrift::Types::LIST, :name => 'annotations', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Zipkin::Annotation}},
|
||||
BINARY_ANNOTATIONS => {:type => ::Thrift::Types::LIST, :name => 'binary_annotations', :element => {:type => ::Thrift::Types::STRUCT, :class => ::Jaeger::Thrift::Zipkin::BinaryAnnotation}},
|
||||
DEBUG => {:type => ::Thrift::Types::BOOL, :name => 'debug', :default => false, :optional => true},
|
||||
# Microseconds from epoch of the creation of this span.
|
||||
#
|
||||
# This value should be set directly by instrumentation, using the most
|
||||
# precise value possible. For example, gettimeofday or syncing nanoTime
|
||||
# against a tick of currentTimeMillis.
|
||||
#
|
||||
# For compatibilty with instrumentation that precede this field, collectors
|
||||
# or span stores can derive this via Annotation.timestamp.
|
||||
# For example, SERVER_RECV.timestamp or CLIENT_SEND.timestamp.
|
||||
#
|
||||
# This field is optional for compatibility with old data: first-party span
|
||||
# stores are expected to support this at time of introduction.
|
||||
TIMESTAMP => {:type => ::Thrift::Types::I64, :name => 'timestamp', :optional => true},
|
||||
# Measurement of duration in microseconds, used to support queries.
|
||||
#
|
||||
# This value should be set directly, where possible. Doing so encourages
|
||||
# precise measurement decoupled from problems of clocks, such as skew or NTP
|
||||
# updates causing time to move backwards.
|
||||
#
|
||||
# For compatibilty with instrumentation that precede this field, collectors
|
||||
# or span stores can derive this by subtracting Annotation.timestamp.
|
||||
# For example, SERVER_SEND.timestamp - SERVER_RECV.timestamp.
|
||||
#
|
||||
# If this field is persisted as unset, zipkin will continue to work, except
|
||||
# duration query support will be implementation-specific. Similarly, setting
|
||||
# this field non-atomically is implementation-specific.
|
||||
#
|
||||
# This field is i64 vs i32 to support spans longer than 35 minutes.
|
||||
DURATION => {:type => ::Thrift::Types::I64, :name => 'duration', :optional => true}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class Response
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
OK = 1
|
||||
|
||||
FIELDS = {
|
||||
OK => {:type => ::Thrift::Types::BOOL, :name => 'ok'}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field ok is unset!') if @ok.nil?
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,88 +0,0 @@
|
|||
# Copyright (c) 2016 Uber Technologies, Inc.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
namespace java com.uber.jaeger.thriftjava
|
||||
namespace rb Jaeger.Thrift
|
||||
|
||||
# TagType denotes the type of a Tag's value.
|
||||
enum TagType { STRING, DOUBLE, BOOL, LONG, BINARY }
|
||||
|
||||
# Tag is a basic strongly typed key/value pair. It has been flattened to reduce the use of pointers in golang
|
||||
struct Tag {
|
||||
1: required string key
|
||||
2: required TagType vType
|
||||
3: optional string vStr
|
||||
4: optional double vDouble
|
||||
5: optional bool vBool
|
||||
6: optional i64 vLong
|
||||
7: optional binary vBinary
|
||||
}
|
||||
|
||||
# Log is a timed even with an arbitrary set of tags.
|
||||
struct Log {
|
||||
1: required i64 timestamp
|
||||
2: required list<Tag> fields
|
||||
}
|
||||
|
||||
enum SpanRefType { CHILD_OF, FOLLOWS_FROM }
|
||||
|
||||
# SpanRef describes causal relationship of the current span to another span (e.g. 'child-of')
|
||||
struct SpanRef {
|
||||
1: required SpanRefType refType
|
||||
2: required i64 traceIdLow
|
||||
3: required i64 traceIdHigh
|
||||
4: required i64 spanId
|
||||
}
|
||||
|
||||
# Span represents a named unit of work performed by a service.
|
||||
struct Span {
|
||||
1: required i64 traceIdLow # the least significant 64 bits of a traceID
|
||||
2: required i64 traceIdHigh # the most significant 64 bits of a traceID; 0 when only 64bit IDs are used
|
||||
3: required i64 spanId # unique span id (only unique within a given trace)
|
||||
4: required i64 parentSpanId # since nearly all spans will have parents spans, CHILD_OF refs do not have to be explicit
|
||||
5: required string operationName
|
||||
6: optional list<SpanRef> references # causal references to other spans
|
||||
7: required i32 flags # tbd
|
||||
8: required i64 startTime
|
||||
9: required i64 duration
|
||||
10: optional list<Tag> tags
|
||||
11: optional list<Log> logs
|
||||
}
|
||||
|
||||
# Process describes the traced process/service that emits spans.
|
||||
struct Process {
|
||||
1: required string serviceName
|
||||
2: optional list<Tag> tags
|
||||
}
|
||||
|
||||
# Batch is a collection of spans reported out of process.
|
||||
struct Batch {
|
||||
1: required Process process
|
||||
2: required list<Span> spans
|
||||
}
|
||||
|
||||
# BatchSubmitResponse is the response on submitting a batch.
|
||||
struct BatchSubmitResponse {
|
||||
1: required bool ok # The Collector's client is expected to only log (or emit a counter) when not ok equals false
|
||||
}
|
||||
|
||||
service Collector {
|
||||
list<BatchSubmitResponse> submitBatches(1: list<Batch> batches)
|
||||
}
|
|
@ -1,300 +0,0 @@
|
|||
# Copyright 2012 Twitter 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.
|
||||
namespace java com.twitter.zipkin.thriftjava
|
||||
#@namespace scala com.twitter.zipkin.thriftscala
|
||||
namespace rb Jaeger.Thrift.Zipkin
|
||||
|
||||
#************** Annotation.value **************
|
||||
/**
|
||||
* The client sent ("cs") a request to a server. There is only one send per
|
||||
* span. For example, if there's a transport error, each attempt can be logged
|
||||
* as a WIRE_SEND annotation.
|
||||
*
|
||||
* If chunking is involved, each chunk could be logged as a separate
|
||||
* CLIENT_SEND_FRAGMENT in the same span.
|
||||
*
|
||||
* Annotation.host is not the server. It is the host which logged the send
|
||||
* event, almost always the client. When logging CLIENT_SEND, instrumentation
|
||||
* should also log the SERVER_ADDR.
|
||||
*/
|
||||
const string CLIENT_SEND = "cs"
|
||||
/**
|
||||
* The client received ("cr") a response from a server. There is only one
|
||||
* receive per span. For example, if duplicate responses were received, each
|
||||
* can be logged as a WIRE_RECV annotation.
|
||||
*
|
||||
* If chunking is involved, each chunk could be logged as a separate
|
||||
* CLIENT_RECV_FRAGMENT in the same span.
|
||||
*
|
||||
* Annotation.host is not the server. It is the host which logged the receive
|
||||
* event, almost always the client. The actual endpoint of the server is
|
||||
* recorded separately as SERVER_ADDR when CLIENT_SEND is logged.
|
||||
*/
|
||||
const string CLIENT_RECV = "cr"
|
||||
/**
|
||||
* The server sent ("ss") a response to a client. There is only one response
|
||||
* per span. If there's a transport error, each attempt can be logged as a
|
||||
* WIRE_SEND annotation.
|
||||
*
|
||||
* Typically, a trace ends with a server send, so the last timestamp of a trace
|
||||
* is often the timestamp of the root span's server send.
|
||||
*
|
||||
* If chunking is involved, each chunk could be logged as a separate
|
||||
* SERVER_SEND_FRAGMENT in the same span.
|
||||
*
|
||||
* Annotation.host is not the client. It is the host which logged the send
|
||||
* event, almost always the server. The actual endpoint of the client is
|
||||
* recorded separately as CLIENT_ADDR when SERVER_RECV is logged.
|
||||
*/
|
||||
const string SERVER_SEND = "ss"
|
||||
/**
|
||||
* The server received ("sr") a request from a client. There is only one
|
||||
* request per span. For example, if duplicate responses were received, each
|
||||
* can be logged as a WIRE_RECV annotation.
|
||||
*
|
||||
* Typically, a trace starts with a server receive, so the first timestamp of a
|
||||
* trace is often the timestamp of the root span's server receive.
|
||||
*
|
||||
* If chunking is involved, each chunk could be logged as a separate
|
||||
* SERVER_RECV_FRAGMENT in the same span.
|
||||
*
|
||||
* Annotation.host is not the client. It is the host which logged the receive
|
||||
* event, almost always the server. When logging SERVER_RECV, instrumentation
|
||||
* should also log the CLIENT_ADDR.
|
||||
*/
|
||||
const string SERVER_RECV = "sr"
|
||||
/**
|
||||
* Optionally logs an attempt to send a message on the wire. Multiple wire send
|
||||
* events could indicate network retries. A lag between client or server send
|
||||
* and wire send might indicate queuing or processing delay.
|
||||
*/
|
||||
const string WIRE_SEND = "ws"
|
||||
/**
|
||||
* Optionally logs an attempt to receive a message from the wire. Multiple wire
|
||||
* receive events could indicate network retries. A lag between wire receive
|
||||
* and client or server receive might indicate queuing or processing delay.
|
||||
*/
|
||||
const string WIRE_RECV = "wr"
|
||||
/**
|
||||
* Optionally logs progress of a (CLIENT_SEND, WIRE_SEND). For example, this
|
||||
* could be one chunk in a chunked request.
|
||||
*/
|
||||
const string CLIENT_SEND_FRAGMENT = "csf"
|
||||
/**
|
||||
* Optionally logs progress of a (CLIENT_RECV, WIRE_RECV). For example, this
|
||||
* could be one chunk in a chunked response.
|
||||
*/
|
||||
const string CLIENT_RECV_FRAGMENT = "crf"
|
||||
/**
|
||||
* Optionally logs progress of a (SERVER_SEND, WIRE_SEND). For example, this
|
||||
* could be one chunk in a chunked response.
|
||||
*/
|
||||
const string SERVER_SEND_FRAGMENT = "ssf"
|
||||
/**
|
||||
* Optionally logs progress of a (SERVER_RECV, WIRE_RECV). For example, this
|
||||
* could be one chunk in a chunked request.
|
||||
*/
|
||||
const string SERVER_RECV_FRAGMENT = "srf"
|
||||
|
||||
#***** BinaryAnnotation.key ******
|
||||
/**
|
||||
* The value of "lc" is the component or namespace of a local span.
|
||||
*
|
||||
* BinaryAnnotation.host adds service context needed to support queries.
|
||||
*
|
||||
* Local Component("lc") supports three key features: flagging, query by
|
||||
* service and filtering Span.name by namespace.
|
||||
*
|
||||
* While structurally the same, local spans are fundamentally different than
|
||||
* RPC spans in how they should be interpreted. For example, zipkin v1 tools
|
||||
* center on RPC latency and service graphs. Root local-spans are neither
|
||||
* indicative of critical path RPC latency, nor have impact on the shape of a
|
||||
* service graph. By flagging with "lc", tools can special-case local spans.
|
||||
*
|
||||
* Zipkin v1 Spans are unqueryable unless they can be indexed by service name.
|
||||
* The only path to a service name is by (Binary)?Annotation.host.serviceName.
|
||||
* By logging "lc", a local span can be queried even if no other annotations
|
||||
* are logged.
|
||||
*
|
||||
* The value of "lc" is the namespace of Span.name. For example, it might be
|
||||
* "finatra2", for a span named "bootstrap". "lc" allows you to resolves
|
||||
* conflicts for the same Span.name, for example "finatra/bootstrap" vs
|
||||
* "finch/bootstrap". Using local component, you'd search for spans named
|
||||
* "bootstrap" where "lc=finch"
|
||||
*/
|
||||
const string LOCAL_COMPONENT = "lc"
|
||||
|
||||
#***** BinaryAnnotation.key where value = [1] and annotation_type = BOOL ******
|
||||
/**
|
||||
* Indicates a client address ("ca") in a span. Most likely, there's only one.
|
||||
* Multiple addresses are possible when a client changes its ip or port within
|
||||
* a span.
|
||||
*/
|
||||
const string CLIENT_ADDR = "ca"
|
||||
/**
|
||||
* Indicates a server address ("sa") in a span. Most likely, there's only one.
|
||||
* Multiple addresses are possible when a client is redirected, or fails to a
|
||||
* different server ip or port.
|
||||
*/
|
||||
const string SERVER_ADDR = "sa"
|
||||
|
||||
/**
|
||||
* Indicates the network context of a service recording an annotation with two
|
||||
* exceptions.
|
||||
*
|
||||
* When a BinaryAnnotation, and key is CLIENT_ADDR or SERVER_ADDR,
|
||||
* the endpoint indicates the source or destination of an RPC. This exception
|
||||
* allows zipkin to display network context of uninstrumented services, or
|
||||
* clients such as web browsers.
|
||||
*/
|
||||
struct Endpoint {
|
||||
/**
|
||||
* IPv4 host address packed into 4 bytes.
|
||||
*
|
||||
* Ex for the ip 1.2.3.4, it would be (1 << 24) | (2 << 16) | (3 << 8) | 4
|
||||
*/
|
||||
1: i32 ipv4
|
||||
/**
|
||||
* IPv4 port
|
||||
*
|
||||
* Note: this is to be treated as an unsigned integer, so watch for negatives.
|
||||
*
|
||||
* Conventionally, when the port isn't known, port = 0.
|
||||
*/
|
||||
2: i16 port
|
||||
/**
|
||||
* Service name in lowercase, such as "memcache" or "zipkin-web"
|
||||
*
|
||||
* Conventionally, when the service name isn't known, service_name = "unknown".
|
||||
*/
|
||||
3: string service_name
|
||||
}
|
||||
|
||||
/**
|
||||
* An annotation is similar to a log statement. It includes a host field which
|
||||
* allows these events to be attributed properly, and also aggregatable.
|
||||
*/
|
||||
struct Annotation {
|
||||
/**
|
||||
* Microseconds from epoch.
|
||||
*
|
||||
* This value should use the most precise value possible. For example,
|
||||
* gettimeofday or syncing nanoTime against a tick of currentTimeMillis.
|
||||
*/
|
||||
1: i64 timestamp
|
||||
2: string value // what happened at the timestamp?
|
||||
/**
|
||||
* Always the host that recorded the event. By specifying the host you allow
|
||||
* rollup of all events (such as client requests to a service) by IP address.
|
||||
*/
|
||||
3: optional Endpoint host
|
||||
// don't reuse 4: optional i32 OBSOLETE_duration // how long did the operation take? microseconds
|
||||
}
|
||||
|
||||
enum AnnotationType { BOOL, BYTES, I16, I32, I64, DOUBLE, STRING }
|
||||
|
||||
/**
|
||||
* Binary annotations are tags applied to a Span to give it context. For
|
||||
* example, a binary annotation of "http.uri" could the path to a resource in a
|
||||
* RPC call.
|
||||
*
|
||||
* Binary annotations of type STRING are always queryable, though more a
|
||||
* historical implementation detail than a structural concern.
|
||||
*
|
||||
* Binary annotations can repeat, and vary on the host. Similar to Annotation,
|
||||
* the host indicates who logged the event. This allows you to tell the
|
||||
* difference between the client and server side of the same key. For example,
|
||||
* the key "http.uri" might be different on the client and server side due to
|
||||
* rewriting, like "/api/v1/myresource" vs "/myresource. Via the host field,
|
||||
* you can see the different points of view, which often help in debugging.
|
||||
*/
|
||||
struct BinaryAnnotation {
|
||||
1: string key,
|
||||
2: binary value,
|
||||
3: AnnotationType annotation_type,
|
||||
/**
|
||||
* The host that recorded tag, which allows you to differentiate between
|
||||
* multiple tags with the same key. There are two exceptions to this.
|
||||
*
|
||||
* When the key is CLIENT_ADDR or SERVER_ADDR, host indicates the source or
|
||||
* destination of an RPC. This exception allows zipkin to display network
|
||||
* context of uninstrumented services, or clients such as web browsers.
|
||||
*/
|
||||
4: optional Endpoint host
|
||||
}
|
||||
|
||||
/**
|
||||
* A trace is a series of spans (often RPC calls) which form a latency tree.
|
||||
*
|
||||
* The root span is where trace_id = id and parent_id = Nil. The root span is
|
||||
* usually the longest interval in the trace, starting with a SERVER_RECV
|
||||
* annotation and ending with a SERVER_SEND.
|
||||
*/
|
||||
struct Span {
|
||||
1: i64 trace_id # unique trace id, use for all spans in trace
|
||||
/**
|
||||
* Span name in lowercase, rpc method for example
|
||||
*
|
||||
* Conventionally, when the span name isn't known, name = "unknown".
|
||||
*/
|
||||
3: string name,
|
||||
4: i64 id, # unique span id, only used for this span
|
||||
5: optional i64 parent_id, # parent span id
|
||||
6: list<Annotation> annotations, # all annotations/events that occured, sorted by timestamp
|
||||
8: list<BinaryAnnotation> binary_annotations # any binary annotations
|
||||
9: optional bool debug = 0 # if true, we DEMAND that this span passes all samplers
|
||||
/**
|
||||
* Microseconds from epoch of the creation of this span.
|
||||
*
|
||||
* This value should be set directly by instrumentation, using the most
|
||||
* precise value possible. For example, gettimeofday or syncing nanoTime
|
||||
* against a tick of currentTimeMillis.
|
||||
*
|
||||
* For compatibilty with instrumentation that precede this field, collectors
|
||||
* or span stores can derive this via Annotation.timestamp.
|
||||
* For example, SERVER_RECV.timestamp or CLIENT_SEND.timestamp.
|
||||
*
|
||||
* This field is optional for compatibility with old data: first-party span
|
||||
* stores are expected to support this at time of introduction.
|
||||
*/
|
||||
10: optional i64 timestamp,
|
||||
/**
|
||||
* Measurement of duration in microseconds, used to support queries.
|
||||
*
|
||||
* This value should be set directly, where possible. Doing so encourages
|
||||
* precise measurement decoupled from problems of clocks, such as skew or NTP
|
||||
* updates causing time to move backwards.
|
||||
*
|
||||
* For compatibilty with instrumentation that precede this field, collectors
|
||||
* or span stores can derive this by subtracting Annotation.timestamp.
|
||||
* For example, SERVER_SEND.timestamp - SERVER_RECV.timestamp.
|
||||
*
|
||||
* If this field is persisted as unset, zipkin will continue to work, except
|
||||
* duration query support will be implementation-specific. Similarly, setting
|
||||
* this field non-atomically is implementation-specific.
|
||||
*
|
||||
* This field is i64 vs i32 to support spans longer than 35 minutes.
|
||||
*/
|
||||
11: optional i64 duration
|
||||
}
|
||||
|
||||
# define TChannel service
|
||||
|
||||
struct Response {
|
||||
1: required bool ok
|
||||
}
|
||||
|
||||
service ZipkinCollector {
|
||||
list<Response> submitZipkinBatch(1: list<Span> spans)
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
engines:
|
||||
duplication:
|
||||
enabled: true
|
||||
config:
|
||||
languages:
|
||||
- ruby
|
||||
fixme:
|
||||
enabled: true
|
||||
rubocop:
|
||||
enabled: true
|
||||
ratings:
|
||||
paths:
|
||||
- "**.rb"
|
||||
exclude_paths:
|
||||
- test/
|
50
debian/gems-compat/opentracing-0.4.3/.gitignore
vendored
50
debian/gems-compat/opentracing-0.4.3/.gitignore
vendored
|
@ -1,50 +0,0 @@
|
|||
*.gem
|
||||
*.rbc
|
||||
/.config
|
||||
/coverage/
|
||||
/InstalledFiles
|
||||
/pkg/
|
||||
/spec/reports/
|
||||
/spec/examples.txt
|
||||
/test/tmp/
|
||||
/test/version_tmp/
|
||||
/tmp/
|
||||
|
||||
# Used by dotenv library to load environment variables.
|
||||
# .env
|
||||
|
||||
## Specific to RubyMotion:
|
||||
.dat*
|
||||
.repl_history
|
||||
build/
|
||||
*.bridgesupport
|
||||
build-iPhoneOS/
|
||||
build-iPhoneSimulator/
|
||||
|
||||
## Specific to RubyMotion (use of CocoaPods):
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
# vendor/Pods/
|
||||
|
||||
## Documentation cache and generated files:
|
||||
/.yardoc/
|
||||
/_yardoc/
|
||||
/doc/
|
||||
/rdoc/
|
||||
|
||||
## Environment normalization:
|
||||
/.bundle/
|
||||
/vendor/bundle
|
||||
/lib/bundler/man/
|
||||
|
||||
# for a library or gem, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
Gemfile.lock
|
||||
# .ruby-version
|
||||
# .ruby-gemset
|
||||
|
||||
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
||||
.rvmrc
|
|
@ -1,8 +0,0 @@
|
|||
Lint/UnusedMethodArgument:
|
||||
Enabled: no
|
||||
|
||||
Metrics/LineLength:
|
||||
Max: 120
|
||||
|
||||
Metrics/ParameterLists:
|
||||
Enabled: no
|
|
@ -1,8 +0,0 @@
|
|||
sudo: false
|
||||
language: ruby
|
||||
rvm:
|
||||
- 2.3.4
|
||||
- 2.4.1
|
||||
- jruby-9.1.8.0
|
||||
before_install: gem install bundler -v 1.13.6
|
||||
script: JRUBY_OPTS="--debug" bundle exec rake
|
|
@ -1,30 +0,0 @@
|
|||
# Changelog
|
||||
|
||||
## 0.4.3
|
||||
|
||||
* Specify versions for development dependencies ([#40](https://github.com/opentracing/opentracing-ruby/pull/40))
|
||||
|
||||
## 0.4.2
|
||||
|
||||
* Update opentracing.io links and scheme on README ([#38](https://github.com/opentracing/opentracing-ruby/pull/38))
|
||||
|
||||
* Add active_span method to Tracer ([#34](https://github.com/opentracing/opentracing-ruby/pull/34))
|
||||
|
||||
## 0.4.1
|
||||
|
||||
* Add active_span convenience method to OpenTracing module ([#30](https://github.com/opentracing/opentracing-ruby/pull/30))
|
||||
* Fix global tracer delegators ([#28](https://github.com/opentracing/opentracing-ruby/pull/28))
|
||||
* Add Rubocop ([#29](https://github.com/opentracing/opentracing-ruby/pull/27))
|
||||
* Update license from MIT => Apache 2.0 ([#26](https://github.com/opentracing/opentracing-ruby/pull/26))
|
||||
|
||||
## 0.4.0
|
||||
|
||||
* The tracer now implements the OpenTracing Scope API for in-process scope propagation([#21](https://github.com/opentracing/opentracing-ruby/pull/21))
|
||||
* Adds a `log_kv` method and deprecates `log` for consistency with other language implementations. See [#22](https://github.com/opentracing/opentracing-ruby/pull/23).
|
||||
|
||||
## 0.3.2
|
||||
|
||||
* Addressing Ruby style issues ([#14](https://github.com/opentracing/opentracing-ruby/pull/14))
|
||||
* Default to the no-op tracer ([#17](https://github.com/opentracing/opentracing-ruby/pull/17))
|
||||
* Fixing serialization example in README ([#18](https://github.com/opentracing/opentracing-ruby/pull/18))
|
||||
* Removing bundler development version requirement
|
4
debian/gems-compat/opentracing-0.4.3/Gemfile
vendored
4
debian/gems-compat/opentracing-0.4.3/Gemfile
vendored
|
@ -1,4 +0,0 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in opentracing.gemspec
|
||||
gemspec
|
201
debian/gems-compat/opentracing-0.4.3/LICENSE
vendored
201
debian/gems-compat/opentracing-0.4.3/LICENSE
vendored
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright The OpenTracing Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
198
debian/gems-compat/opentracing-0.4.3/README.md
vendored
198
debian/gems-compat/opentracing-0.4.3/README.md
vendored
|
@ -1,198 +0,0 @@
|
|||
# OpenTracing API for Ruby
|
||||
|
||||
[![Build Status](https://travis-ci.org/ngauthier/opentracing-ruby.svg?branch=master)](https://travis-ci.org/ngauthier/opentracing-ruby) [![Code Climate](https://codeclimate.com/github/ngauthier/opentracing-ruby/badges/gpa.svg)](https://codeclimate.com/github/ngauthier/opentracing-ruby) [![Test Coverage](https://codeclimate.com/github/ngauthier/opentracing-ruby/badges/coverage.svg)](https://codeclimate.com/github/ngauthier/opentracing-ruby/coverage)
|
||||
|
||||
This package is a Ruby platform API for OpenTracing.
|
||||
|
||||
## Required Reading
|
||||
|
||||
In order to understand the Ruby platform API, one must first be familiar with the
|
||||
[OpenTracing project](https://opentracing.io) and
|
||||
[terminology](https://opentracing.io/docs/overview/) more specifically.
|
||||
|
||||
## Installation
|
||||
|
||||
Add this line to your application's Gemfile:
|
||||
|
||||
```ruby
|
||||
gem 'opentracing'
|
||||
```
|
||||
|
||||
And then execute:
|
||||
|
||||
$ bundle
|
||||
|
||||
Or install it yourself as:
|
||||
|
||||
$ gem install opentracing
|
||||
|
||||
`opentracing` supports Ruby 2.0+.
|
||||
|
||||
## Usage
|
||||
|
||||
Everyday consumers of this `opentracing` gem really only need to worry
|
||||
about a couple of key abstractions: the `start_active_span` and `start_span`
|
||||
methods, the `Span` and `ScopeManager` interfaces, and binding a `Tracer`
|
||||
at runtime. Here are code snippets demonstrating some important use cases.
|
||||
|
||||
### Singleton initialization
|
||||
|
||||
As early as possible, call
|
||||
|
||||
```ruby
|
||||
require 'opentracing'
|
||||
OpenTracing.global_tracer = MyTracerImplementation.new(...)
|
||||
```
|
||||
|
||||
Where `MyTracerImplementation` is your tracer. For testing, you can use
|
||||
the provided `OpenTracing::Tracer`
|
||||
|
||||
### Non-Singleton initialization
|
||||
|
||||
If you prefer direct control to singletons, manage ownership of the
|
||||
`Tracer` implementation explicitly.
|
||||
|
||||
### Scopes and within-process propagation
|
||||
|
||||
For any thread, at most one `Span` may be "active". Of course there may be many
|
||||
other `Spans` involved with the thread which are (a) started, (b) not finished,
|
||||
and yet (c) not "active": perhaps they are waiting for I/O, blocked on a child
|
||||
`Span`, or otherwise off of the critical path.
|
||||
|
||||
It's inconvenient to pass an active `Span` from function to function manually,
|
||||
so OpenTracing requires that every `Tracer` contains a `ScopeManager` that
|
||||
grants access to the active `Span` through a `Scope`. Any `Span` may be
|
||||
transferred to another callback or thread, but not `Scope`.
|
||||
|
||||
#### Accessing the active Span through Scope
|
||||
|
||||
```ruby
|
||||
# Access to the active span is straightforward.
|
||||
|
||||
span = OpenTracing.active_span
|
||||
if span
|
||||
span.set_tag('...', '...')
|
||||
end
|
||||
|
||||
# or
|
||||
|
||||
scope = OpenTracing.scope_manager.active
|
||||
if scope
|
||||
scope.span.set_tag('...', '...')
|
||||
end
|
||||
```
|
||||
|
||||
### Starting a new Span
|
||||
|
||||
The common case starts a `Scope` that's automatically registered for
|
||||
intra-process propagation via `ScopeManager`.
|
||||
|
||||
Note that `start_active_span('...')` automatically finishes the span on
|
||||
`Scope#close` (`start_active_span('...', finish_on_close: false)` does not
|
||||
finish it, in contrast).
|
||||
|
||||
```ruby
|
||||
# Automatic activation of the Span.
|
||||
# By default the active span will be finished when the returned scope is closed.
|
||||
# This can be controlled by passing finish_on_close parameter to
|
||||
# start_active_span
|
||||
scope = OpenTracing.start_active_span('operation_name')
|
||||
# Do things.
|
||||
|
||||
# Block form of start_active_span
|
||||
# start_active_span optionally accepts a block. If a block is passed to
|
||||
# start_active_span it will yield the newly created scope. The scope will
|
||||
# be closed and its associated span will be finished unless
|
||||
# finish_on_close: false is passed to start_active_span.
|
||||
OpenTracing.start_active_span('operation_name') do |scope|
|
||||
# Do things.
|
||||
end
|
||||
|
||||
# Manual activation of the Span.
|
||||
# Spans can be managed manually. This is equivalent to the more concise examples
|
||||
# above.
|
||||
span = OpenTracing.start_span('operation_name')
|
||||
OpenTracing.scope_manager.activate(span)
|
||||
scope = OpenTracing.scope_manager.active
|
||||
# Do things.
|
||||
|
||||
# If there is an active Scope, it will act as the parent to any newly started
|
||||
# Span unless ignore_active_scope: true is passed to start_span or
|
||||
# start_active_span.
|
||||
|
||||
# create a root span, ignoring the currently active scope (if it's set)
|
||||
scope = OpenTracing.start_active_span('operation_name', ignore_active_scope: true)
|
||||
|
||||
# or
|
||||
span = OpenTracing.start_span('operation_name', ignore_active_scope: true)
|
||||
|
||||
# It's possible to create a child Span given an existing parent Span by
|
||||
# using the child_of option.
|
||||
|
||||
parent_scope = OpenTracing.start_active_span('parent_operation, ignore_active_scope: true)
|
||||
child_scope = OpenTracing.start_active_span('child_operation', child_of: parent_scope.span)
|
||||
|
||||
# or
|
||||
parent_span = OpenTracing.start_span('parent_operation', ignore_active_scope: true)
|
||||
child_span = OpenTracing.start_span('child_operation', child_of: parent_span)
|
||||
|
||||
```
|
||||
|
||||
### Serializing to the wire
|
||||
|
||||
Using `Net::HTTP`:
|
||||
```ruby
|
||||
client = Net::HTTP.new("myservice.com")
|
||||
req = Net::HTTP::Post.new("/")
|
||||
|
||||
span = OpenTracing.start_span("my_span")
|
||||
OpenTracing.inject(span.context, OpenTracing::FORMAT_RACK, req)
|
||||
res = client.request(req)
|
||||
#...
|
||||
```
|
||||
|
||||
Using Faraday middleware:
|
||||
```ruby
|
||||
class TraceMiddleware < Faraday::Middleware
|
||||
def call(env)
|
||||
span = OpenTracing.start_span("my_span")
|
||||
OpenTracing.inject(span.context, OpenTracing::FORMAT_RACK, env)
|
||||
@app.call(env).on_complete do
|
||||
span.finish
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Deserializing from the wire
|
||||
|
||||
The OpenTracing Ruby gem provides a specific Rack header extraction format,
|
||||
since most Ruby web servers get their HTTP Headers from Rack. Keep in mind that
|
||||
Rack automatically uppercases all headers and replaces dashes with underscores.
|
||||
This means that if you use dashes and underscores and case-sensitive baggage,
|
||||
it will not be possible to discern once Rack has processed it.
|
||||
|
||||
```ruby
|
||||
class MyRackApp
|
||||
def call(env)
|
||||
extracted_ctx = @tracer.extract(OpenTracing::FORMAT_RACK, env)
|
||||
span = @tracer.start_span("my_app", child_of: extracted_ctx)
|
||||
span.finish
|
||||
[200, {}, ["hello"]]
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
||||
|
||||
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
||||
|
||||
## Contributing
|
||||
|
||||
Bug reports and pull requests are welcome on GitHub at https://github.com/opentracing/opentracing-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
||||
|
||||
## Licensing
|
||||
|
||||
[Apache 2.0 License](./LICENSE).
|
17
debian/gems-compat/opentracing-0.4.3/Rakefile
vendored
17
debian/gems-compat/opentracing-0.4.3/Rakefile
vendored
|
@ -1,17 +0,0 @@
|
|||
require 'bundler/gem_tasks'
|
||||
require 'rake/testtask'
|
||||
require 'rubocop/rake_task'
|
||||
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'test'
|
||||
t.libs << 'lib'
|
||||
t.test_files = FileList['test/**/*_test.rb']
|
||||
end
|
||||
|
||||
RuboCop::RakeTask.new(:rubocop)
|
||||
|
||||
if RUBY_PLATFORM == 'java'
|
||||
task default: :test
|
||||
else
|
||||
task default: %i[rubocop test]
|
||||
end
|
|
@ -1,6 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'bundler/setup'
|
||||
require 'opentracing'
|
||||
require 'irb'
|
||||
IRB.start
|
|
@ -1,6 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
set -vx
|
||||
|
||||
bundle install
|
|
@ -1,45 +0,0 @@
|
|||
require 'forwardable'
|
||||
require 'opentracing/version'
|
||||
require 'opentracing/span_context'
|
||||
require 'opentracing/span'
|
||||
require 'opentracing/reference'
|
||||
require 'opentracing/tracer'
|
||||
require 'opentracing/scope'
|
||||
require 'opentracing/scope_manager'
|
||||
|
||||
#:nodoc:
|
||||
module OpenTracing
|
||||
# Text format for Tracer#inject and Tracer#extract.
|
||||
#
|
||||
# The carrier for FORMAT_TEXT_MAP should be a Hash with string values.
|
||||
FORMAT_TEXT_MAP = 1
|
||||
|
||||
# Binary format for #inject and #extract
|
||||
#
|
||||
# The carrier for FORMAT_BINARY should be a string, treated as a raw sequence
|
||||
# of bytes.
|
||||
FORMAT_BINARY = 2
|
||||
|
||||
# Due to Rack's popularity within the Ruby community, OpenTracing-Ruby
|
||||
# provides a Rack-specific format for injection into and extraction from HTTP
|
||||
# headers specifically, though there are some strings attached.
|
||||
#
|
||||
# The carrier for FORMAT_RACK should be `env` or equivalent. It behaves like
|
||||
# FORMAT_TEXT_MAP, but with all keys transformed per Rack's treatment of HTTP
|
||||
# headers. Keep in mind that Rack automatically uppercases all headers and
|
||||
# replaces dashes with underscores. This means that if you use dashes and
|
||||
# underscores and case-sensitive baggage keys, they may collide or become
|
||||
# unrecognizable.
|
||||
FORMAT_RACK = 3
|
||||
|
||||
class << self
|
||||
extend Forwardable
|
||||
# Global tracer to be used when OpenTracing.start_span, inject or extract is called
|
||||
attr_accessor :global_tracer
|
||||
def_delegators :global_tracer, :scope_manager, :start_active_span,
|
||||
:start_span, :inject, :extract, :active_span
|
||||
end
|
||||
end
|
||||
|
||||
# Default to the no-op tracer
|
||||
OpenTracing.global_tracer = OpenTracing::Tracer.new
|
|
@ -1,22 +0,0 @@
|
|||
module OpenTracing
|
||||
# Carriers are used for inject and extract operations. A carrier should be a
|
||||
# Hash or hash-like object. At a minimum, it should implement `[]`, `[]=`, and
|
||||
# `each` shown here.
|
||||
class Carrier
|
||||
# [] retrieves a value by the given key
|
||||
# @param key [String] key to retrieve the value
|
||||
# @return [String] the desired value
|
||||
def [](key); end
|
||||
|
||||
# []= sets the value for the given key
|
||||
# @param key [String] key to set
|
||||
# @param value [String] value to set
|
||||
def []=(key, value); end
|
||||
|
||||
# each iterates over every key-value pair in the carrier
|
||||
# @yield [key, value]
|
||||
# @yieldparam key [String] the key of the tuple
|
||||
# @yieldparam value [String] the value of the tuple
|
||||
def each(&block); end
|
||||
end
|
||||
end
|
|
@ -1,79 +0,0 @@
|
|||
module OpenTracing
|
||||
#:nodoc:
|
||||
class Reference
|
||||
CHILD_OF = 'child_of'.freeze
|
||||
FOLLOWS_FROM = 'follows_from'.freeze
|
||||
|
||||
# @param context [SpanContext, Span] child_of context refers to a
|
||||
# parent Span that caused *and* somehow depends upon the new child Span.
|
||||
# Often (but not always), the parent Span cannot finish until the child
|
||||
# Span does.
|
||||
#
|
||||
# An timing diagram for a child Span that is blocked on the new Span:
|
||||
#
|
||||
# [-Parent Span----------]
|
||||
# [-Child Span----]
|
||||
#
|
||||
# See http://opentracing.io/documentation/pages/spec
|
||||
#
|
||||
# @return [Reference] a ChildOf reference
|
||||
#
|
||||
# @example
|
||||
# root_span = OpenTracing.start_span('root operation')
|
||||
# child_span = OpenTracing.start_span('child operation', references: [
|
||||
# OpenTracing::Reference.child_of(root_span)
|
||||
# ])
|
||||
#
|
||||
def self.child_of(context)
|
||||
context = context.context if context.is_a?(Span)
|
||||
Reference.new(CHILD_OF, context)
|
||||
end
|
||||
|
||||
# @param context [SpanContext, Span] follows_from context refers to a
|
||||
# parent Span that does not depend in any way on the result of the new
|
||||
# child Span. For instance, one might use FollowsFrom Span to describe
|
||||
# pipeline stages separated by queues, or a fire-and-forget cache insert
|
||||
# at the tail end of a web request.
|
||||
#
|
||||
# A FollowsFrom Span is part of the same logical trace as the new Span:
|
||||
# i.e., the new Span is somehow caused by the work of its FollowsFrom
|
||||
# Span.
|
||||
#
|
||||
# All of the following could be valid timing diagrams for children that
|
||||
# "FollowFrom" a parent:
|
||||
#
|
||||
# [-Parent Span--] [-Child Span-]
|
||||
#
|
||||
# [-Parent Span--]
|
||||
# [-Child Span-]
|
||||
#
|
||||
# [-Parent Span-]
|
||||
# [-Child Span-]
|
||||
#
|
||||
# See http://opentracing.io/documentation/pages/spec
|
||||
#
|
||||
# @return [Reference] a FollowsFrom reference
|
||||
#
|
||||
# @example
|
||||
# context = OpenTracing.extract(OpenTracing::FORMAT_RACK, rack_env)
|
||||
# span = OpenTracing.start_span('following operation', references: [
|
||||
# OpenTracing::Reference.follows_from(context)
|
||||
# ])
|
||||
#
|
||||
def self.follows_from(context)
|
||||
context = context.context if context.is_a?(Span)
|
||||
Reference.new(FOLLOWS_FROM, context)
|
||||
end
|
||||
|
||||
def initialize(type, context)
|
||||
@type = type
|
||||
@context = context
|
||||
end
|
||||
|
||||
# @return [String] reference type
|
||||
attr_reader :type
|
||||
|
||||
# @return [SpanContext] the context of a span this reference is referencing
|
||||
attr_reader :context
|
||||
end
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
module OpenTracing
|
||||
# Scope represents an OpenTracing Scope
|
||||
#
|
||||
# See http://www.opentracing.io for more information.
|
||||
class Scope
|
||||
NOOP_INSTANCE = Scope.new.freeze
|
||||
|
||||
# Return the Span scoped by this Scope
|
||||
#
|
||||
# @return [Span]
|
||||
def span
|
||||
Span::NOOP_INSTANCE
|
||||
end
|
||||
|
||||
# Mark the end of the active period for the current thread and Scope,
|
||||
# updating the ScopeManager#active in the process.
|
||||
#
|
||||
# NOTE: Calling close more than once on a single Scope instance leads to
|
||||
# undefined behavior.
|
||||
def close; end
|
||||
end
|
||||
end
|
|
@ -1,35 +0,0 @@
|
|||
module OpenTracing
|
||||
# ScopeManager represents an OpenTracing ScopeManager
|
||||
#
|
||||
# See http://www.opentracing.io for more information.
|
||||
#
|
||||
# The ScopeManager interface abstracts both the activation of Span instances
|
||||
# via ScopeManager#activate and access to an active Span/Scope via
|
||||
# ScopeManager#active
|
||||
#
|
||||
class ScopeManager
|
||||
NOOP_INSTANCE = ScopeManager.new.freeze
|
||||
|
||||
# Make a span instance active.
|
||||
#
|
||||
# @param span [Span] the Span that should become active
|
||||
# @param finish_on_close [Boolean] whether the Span should automatically be
|
||||
# finished when Scope#close is called
|
||||
# @return [Scope] instance to control the end of the active period for the
|
||||
# Span. It is a programming error to neglect to call Scope#close on the
|
||||
# returned instance.
|
||||
def activate(span, finish_on_close: true)
|
||||
Scope::NOOP_INSTANCE
|
||||
end
|
||||
|
||||
# @return [Scope] the currently active Scope which can be used to access the
|
||||
# currently active Span.
|
||||
#
|
||||
# If there is a non-null Scope, its wrapped Span becomes an implicit parent
|
||||
# (as Reference#CHILD_OF) of any newly-created Span at Tracer#start_active_span
|
||||
# or Tracer#start_span time.
|
||||
def active
|
||||
Scope::NOOP_INSTANCE
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,68 +0,0 @@
|
|||
module OpenTracing
|
||||
# Span represents an OpenTracing Span
|
||||
#
|
||||
# See http://www.opentracing.io for more information.
|
||||
class Span
|
||||
NOOP_INSTANCE = Span.new.freeze
|
||||
|
||||
# Set the name of the operation
|
||||
#
|
||||
# @param [String] name
|
||||
def operation_name=(name); end
|
||||
|
||||
# Span Context
|
||||
#
|
||||
# @return [SpanContext]
|
||||
def context
|
||||
SpanContext::NOOP_INSTANCE
|
||||
end
|
||||
|
||||
# Set a tag value on this span
|
||||
# @param key [String] the key of the tag
|
||||
# @param value [String, Numeric, Boolean] the value of the tag. If it's not
|
||||
# a String, Numeric, or Boolean it will be encoded with to_s
|
||||
def set_tag(key, value)
|
||||
self
|
||||
end
|
||||
|
||||
# Set a baggage item on the span
|
||||
# @param key [String] the key of the baggage item
|
||||
# @param value [String] the value of the baggage item
|
||||
def set_baggage_item(key, value)
|
||||
self
|
||||
end
|
||||
|
||||
# Get a baggage item
|
||||
# @param key [String] the key of the baggage item
|
||||
# @return [String] value of the baggage item
|
||||
def get_baggage_item(key)
|
||||
nil
|
||||
end
|
||||
|
||||
# @deprecated Use {#log_kv} instead.
|
||||
# Reason: event is an optional standard log field defined in spec and not required. Also,
|
||||
# method name {#log_kv} is more consistent with other language implementations such as Python and Go.
|
||||
#
|
||||
# Add a log entry to this span
|
||||
# @param event [String] event name for the log
|
||||
# @param timestamp [Time] time of the log
|
||||
# @param fields [Hash] Additional information to log
|
||||
def log(event: nil, timestamp: Time.now, **fields)
|
||||
warn 'Span#log is deprecated. Please use Span#log_kv instead.'
|
||||
nil
|
||||
end
|
||||
|
||||
# Add a log entry to this span
|
||||
# @param timestamp [Time] time of the log
|
||||
# @param fields [Hash] Additional information to log
|
||||
def log_kv(timestamp: Time.now, **fields)
|
||||
nil
|
||||
end
|
||||
|
||||
# Finish the {Span}
|
||||
# @param end_time [Time] custom end time, if not now
|
||||
def finish(end_time: Time.now)
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
module OpenTracing
|
||||
# SpanContext holds the data for a span that gets inherited to child spans
|
||||
class SpanContext
|
||||
NOOP_INSTANCE = SpanContext.new.freeze
|
||||
|
||||
attr_reader :baggage
|
||||
|
||||
# Create a new SpanContext
|
||||
# @param id the ID of the Context
|
||||
# @param trace_id the ID of the current trace
|
||||
# @param baggage baggage
|
||||
def initialize(baggage: {}); end
|
||||
end
|
||||
end
|
|
@ -1,117 +0,0 @@
|
|||
module OpenTracing
|
||||
# Tracer is the entry point API between instrumentation code and the tracing
|
||||
# implementation.
|
||||
#
|
||||
# This implementation both defines the public Tracer API, and provides a
|
||||
# default no-op behavior.
|
||||
#
|
||||
class Tracer
|
||||
# @return [ScopeManager] the current ScopeManager, which may be a no-op but
|
||||
# may not be nil.
|
||||
def scope_manager
|
||||
ScopeManager::NOOP_INSTANCE
|
||||
end
|
||||
|
||||
# @return [Span, nil] the active span. This is a shorthand for
|
||||
# `scope_manager.active.span`, and nil will be returned if
|
||||
# Scope#active is nil.
|
||||
def active_span
|
||||
scope = scope_manager.active
|
||||
scope.span if scope
|
||||
end
|
||||
|
||||
# Returns a newly started and activated Scope.
|
||||
#
|
||||
# If the Tracer's ScopeManager#active is not nil, no explicit references
|
||||
# are provided, and `ignore_active_scope` is false, then an inferred
|
||||
# References#CHILD_OF reference is created to the ScopeManager#active's
|
||||
# SpanContext when start_active is invoked.
|
||||
#
|
||||
# @param operation_name [String] The operation name for the Span
|
||||
# @param child_of [SpanContext, Span] SpanContext that acts as a parent to
|
||||
# the newly-started Span. If a Span instance is provided, its
|
||||
# context is automatically substituted. See [Reference] for more
|
||||
# information.
|
||||
#
|
||||
# If specified, the `references` parameter must be omitted.
|
||||
# @param references [Array<Reference>] An array of reference
|
||||
# objects that identify one or more parent SpanContexts.
|
||||
# @param start_time [Time] When the Span started, if not now
|
||||
# @param tags [Hash] Tags to assign to the Span at start time
|
||||
# @param ignore_active_scope [Boolean] whether to create an implicit
|
||||
# References#CHILD_OF reference to the ScopeManager#active.
|
||||
# @param finish_on_close [Boolean] whether span should automatically be
|
||||
# finished when Scope#close is called
|
||||
# @yield [Scope] If an optional block is passed to start_active it will
|
||||
# yield the newly-started Scope. If `finish_on_close` is true then the
|
||||
# Span will be finished automatically after the block is executed.
|
||||
# @return [Scope] The newly-started and activated Scope
|
||||
def start_active_span(operation_name,
|
||||
child_of: nil,
|
||||
references: nil,
|
||||
start_time: Time.now,
|
||||
tags: nil,
|
||||
ignore_active_scope: false,
|
||||
finish_on_close: true)
|
||||
Scope::NOOP_INSTANCE.tap do |scope|
|
||||
yield scope if block_given?
|
||||
end
|
||||
end
|
||||
|
||||
# Like #start_active_span, but the returned Span has not been registered via the
|
||||
# ScopeManager.
|
||||
#
|
||||
# @param operation_name [String] The operation name for the Span
|
||||
# @param child_of [SpanContext, Span] SpanContext that acts as a parent to
|
||||
# the newly-started Span. If a Span instance is provided, its
|
||||
# context is automatically substituted. See [Reference] for more
|
||||
# information.
|
||||
#
|
||||
# If specified, the `references` parameter must be omitted.
|
||||
# @param references [Array<Reference>] An array of reference
|
||||
# objects that identify one or more parent SpanContexts.
|
||||
# @param start_time [Time] When the Span started, if not now
|
||||
# @param tags [Hash] Tags to assign to the Span at start time
|
||||
# @param ignore_active_scope [Boolean] whether to create an implicit
|
||||
# References#CHILD_OF reference to the ScopeManager#active.
|
||||
# @return [Span] the newly-started Span instance, which has not been
|
||||
# automatically registered via the ScopeManager
|
||||
def start_span(operation_name,
|
||||
child_of: nil,
|
||||
references: nil,
|
||||
start_time: Time.now,
|
||||
tags: nil,
|
||||
ignore_active_scope: false)
|
||||
Span::NOOP_INSTANCE
|
||||
end
|
||||
|
||||
# Inject a SpanContext into the given carrier
|
||||
#
|
||||
# @param span_context [SpanContext]
|
||||
# @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
|
||||
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
||||
def inject(span_context, format, carrier)
|
||||
case format
|
||||
when OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK
|
||||
return nil
|
||||
else
|
||||
warn 'Unknown inject format'
|
||||
end
|
||||
end
|
||||
|
||||
# Extract a SpanContext in the given format from the given carrier.
|
||||
#
|
||||
# @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
|
||||
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
||||
# @return [SpanContext, nil] the extracted SpanContext or nil if none could be found
|
||||
def extract(format, carrier)
|
||||
case format
|
||||
when OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK
|
||||
return SpanContext::NOOP_INSTANCE
|
||||
else
|
||||
warn 'Unknown extract format'
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
module OpenTracing
|
||||
VERSION = '0.4.3'.freeze
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
lib = File.expand_path('lib', __dir__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'opentracing/version'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = 'opentracing'
|
||||
spec.version = OpenTracing::VERSION
|
||||
spec.authors = %w[ngauthier bcronin bensigelman]
|
||||
spec.email = ['info@opentracing.io']
|
||||
|
||||
spec.summary = 'OpenTracing Ruby Platform API'
|
||||
spec.homepage = 'https://github.com/opentracing/opentracing-ruby'
|
||||
spec.license = 'Apache-2.0'
|
||||
|
||||
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
||||
f.match(%r{^(test|spec|features)/})
|
||||
end
|
||||
spec.bindir = 'exe'
|
||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||
spec.require_paths = ['lib']
|
||||
|
||||
spec.add_development_dependency 'minitest', '~> 5.0'
|
||||
spec.add_development_dependency 'rake', '~> 10.0'
|
||||
spec.add_development_dependency 'rubocop', '~> 0.54.0'
|
||||
spec.add_development_dependency 'simplecov', '~> 0.16.0'
|
||||
spec.add_development_dependency 'simplecov-console', '~> 0.4.0'
|
||||
end
|
43
debian/gems-compat/thrift-0.11.0.0/README.md
vendored
43
debian/gems-compat/thrift-0.11.0.0/README.md
vendored
|
@ -1,43 +0,0 @@
|
|||
Thrift Ruby Software Library
|
||||
http://thrift.apache.org
|
||||
|
||||
== LICENSE:
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
|
||||
== DESCRIPTION:
|
||||
|
||||
Thrift is a strongly-typed language-agnostic RPC system.
|
||||
This library is the ruby implementation for both clients and servers.
|
||||
|
||||
== INSTALL:
|
||||
|
||||
$ gem install thrift
|
||||
|
||||
== CAVEATS:
|
||||
|
||||
This library provides the client and server implementations of thrift.
|
||||
It does <em>not</em> provide the compiler for the .thrift files. To compile
|
||||
.thrift files into language-specific implementations, please download the full
|
||||
thrift software package.
|
||||
|
||||
== USAGE:
|
||||
|
||||
This section should get written by someone with the time and inclination.
|
||||
In the meantime, look at existing code, such as the benchmark or the tutorial
|
||||
in the full thrift distribution.
|
|
@ -1,24 +0,0 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
|
||||
namespace rb ThriftBenchmark
|
||||
|
||||
service BenchmarkService {
|
||||
i32 fibonacci(1:byte n)
|
||||
}
|
|
@ -1,271 +0,0 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
|
||||
require 'rubygems'
|
||||
$:.unshift File.dirname(__FILE__) + '/../lib'
|
||||
require 'thrift'
|
||||
require 'stringio'
|
||||
|
||||
HOST = '127.0.0.1'
|
||||
PORT = 42587
|
||||
|
||||
###############
|
||||
## Server
|
||||
###############
|
||||
|
||||
class Server
|
||||
attr_accessor :serverclass
|
||||
attr_accessor :interpreter
|
||||
attr_accessor :host
|
||||
attr_accessor :port
|
||||
|
||||
def initialize(opts)
|
||||
@serverclass = opts.fetch(:class, Thrift::NonblockingServer)
|
||||
@interpreter = opts.fetch(:interpreter, "ruby")
|
||||
@host = opts.fetch(:host, ::HOST)
|
||||
@port = opts.fetch(:port, ::PORT)
|
||||
end
|
||||
|
||||
def start
|
||||
return if @serverclass == Object
|
||||
args = (File.basename(@interpreter) == "jruby" ? "-J-server" : "")
|
||||
@pipe = IO.popen("#{@interpreter} #{args} #{File.dirname(__FILE__)}/server.rb #{@host} #{@port} #{@serverclass.name}", "r+")
|
||||
Marshal.load(@pipe) # wait until the server has started
|
||||
sleep 0.4 # give the server time to actually start spawning sockets
|
||||
end
|
||||
|
||||
def shutdown
|
||||
return unless @pipe
|
||||
Marshal.dump(:shutdown, @pipe)
|
||||
begin
|
||||
@pipe.read(10) # block until the server shuts down
|
||||
rescue EOFError
|
||||
end
|
||||
@pipe.close
|
||||
@pipe = nil
|
||||
end
|
||||
end
|
||||
|
||||
class BenchmarkManager
|
||||
def initialize(opts, server)
|
||||
@socket = opts.fetch(:socket) do
|
||||
@host = opts.fetch(:host, 'localhost')
|
||||
@port = opts.fetch(:port)
|
||||
nil
|
||||
end
|
||||
@num_processes = opts.fetch(:num_processes, 40)
|
||||
@clients_per_process = opts.fetch(:clients_per_process, 10)
|
||||
@calls_per_client = opts.fetch(:calls_per_client, 50)
|
||||
@interpreter = opts.fetch(:interpreter, "ruby")
|
||||
@server = server
|
||||
@log_exceptions = opts.fetch(:log_exceptions, false)
|
||||
end
|
||||
|
||||
def run
|
||||
@pool = []
|
||||
@benchmark_start = Time.now
|
||||
puts "Spawning benchmark processes..."
|
||||
@num_processes.times do
|
||||
spawn
|
||||
sleep 0.02 # space out spawns
|
||||
end
|
||||
collect_output
|
||||
@benchmark_end = Time.now # we know the procs are done here
|
||||
translate_output
|
||||
analyze_output
|
||||
report_output
|
||||
end
|
||||
|
||||
def spawn
|
||||
pipe = IO.popen("#{@interpreter} #{File.dirname(__FILE__)}/client.rb #{"-log-exceptions" if @log_exceptions} #{@host} #{@port} #{@clients_per_process} #{@calls_per_client}")
|
||||
@pool << pipe
|
||||
end
|
||||
|
||||
def socket_class
|
||||
if @socket
|
||||
Thrift::UNIXSocket
|
||||
else
|
||||
Thrift::Socket
|
||||
end
|
||||
end
|
||||
|
||||
def collect_output
|
||||
puts "Collecting output..."
|
||||
# read from @pool until all sockets are closed
|
||||
@buffers = Hash.new { |h,k| h[k] = '' }
|
||||
until @pool.empty?
|
||||
rd, = select(@pool)
|
||||
next if rd.nil?
|
||||
rd.each do |fd|
|
||||
begin
|
||||
@buffers[fd] << fd.readpartial(4096)
|
||||
rescue EOFError
|
||||
@pool.delete fd
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def translate_output
|
||||
puts "Translating output..."
|
||||
@output = []
|
||||
@buffers.each do |fd, buffer|
|
||||
strio = StringIO.new(buffer)
|
||||
logs = []
|
||||
begin
|
||||
loop do
|
||||
logs << Marshal.load(strio)
|
||||
end
|
||||
rescue EOFError
|
||||
@output << logs
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def analyze_output
|
||||
puts "Analyzing output..."
|
||||
call_times = []
|
||||
client_times = []
|
||||
connection_failures = []
|
||||
connection_errors = []
|
||||
shortest_call = 0
|
||||
shortest_client = 0
|
||||
longest_call = 0
|
||||
longest_client = 0
|
||||
@output.each do |logs|
|
||||
cur_call, cur_client = nil
|
||||
logs.each do |tok, time|
|
||||
case tok
|
||||
when :start
|
||||
cur_client = time
|
||||
when :call_start
|
||||
cur_call = time
|
||||
when :call_end
|
||||
delta = time - cur_call
|
||||
call_times << delta
|
||||
longest_call = delta unless longest_call > delta
|
||||
shortest_call = delta if shortest_call == 0 or delta < shortest_call
|
||||
cur_call = nil
|
||||
when :end
|
||||
delta = time - cur_client
|
||||
client_times << delta
|
||||
longest_client = delta unless longest_client > delta
|
||||
shortest_client = delta if shortest_client == 0 or delta < shortest_client
|
||||
cur_client = nil
|
||||
when :connection_failure
|
||||
connection_failures << time
|
||||
when :connection_error
|
||||
connection_errors << time
|
||||
end
|
||||
end
|
||||
end
|
||||
@report = {}
|
||||
@report[:total_calls] = call_times.inject(0.0) { |a,t| a += t }
|
||||
@report[:avg_calls] = @report[:total_calls] / call_times.size
|
||||
@report[:total_clients] = client_times.inject(0.0) { |a,t| a += t }
|
||||
@report[:avg_clients] = @report[:total_clients] / client_times.size
|
||||
@report[:connection_failures] = connection_failures.size
|
||||
@report[:connection_errors] = connection_errors.size
|
||||
@report[:shortest_call] = shortest_call
|
||||
@report[:shortest_client] = shortest_client
|
||||
@report[:longest_call] = longest_call
|
||||
@report[:longest_client] = longest_client
|
||||
@report[:total_benchmark_time] = @benchmark_end - @benchmark_start
|
||||
@report[:fastthread] = $".include?('fastthread.bundle')
|
||||
end
|
||||
|
||||
def report_output
|
||||
fmt = "%.4f seconds"
|
||||
puts
|
||||
tabulate "%d",
|
||||
[["Server class", "%s"], @server.serverclass == Object ? "" : @server.serverclass],
|
||||
[["Server interpreter", "%s"], @server.interpreter],
|
||||
[["Client interpreter", "%s"], @interpreter],
|
||||
[["Socket class", "%s"], socket_class],
|
||||
["Number of processes", @num_processes],
|
||||
["Clients per process", @clients_per_process],
|
||||
["Calls per client", @calls_per_client],
|
||||
[["Using fastthread", "%s"], @report[:fastthread] ? "yes" : "no"]
|
||||
puts
|
||||
failures = (@report[:connection_failures] > 0)
|
||||
tabulate fmt,
|
||||
[["Connection failures", "%d", [:red, :bold]], @report[:connection_failures]],
|
||||
[["Connection errors", "%d", [:red, :bold]], @report[:connection_errors]],
|
||||
["Average time per call", @report[:avg_calls]],
|
||||
["Average time per client (%d calls)" % @calls_per_client, @report[:avg_clients]],
|
||||
["Total time for all calls", @report[:total_calls]],
|
||||
["Real time for benchmarking", @report[:total_benchmark_time]],
|
||||
["Shortest call time", @report[:shortest_call]],
|
||||
["Longest call time", @report[:longest_call]],
|
||||
["Shortest client time (%d calls)" % @calls_per_client, @report[:shortest_client]],
|
||||
["Longest client time (%d calls)" % @calls_per_client, @report[:longest_client]]
|
||||
end
|
||||
|
||||
ANSI = {
|
||||
:reset => 0,
|
||||
:bold => 1,
|
||||
:black => 30,
|
||||
:red => 31,
|
||||
:green => 32,
|
||||
:yellow => 33,
|
||||
:blue => 34,
|
||||
:magenta => 35,
|
||||
:cyan => 36,
|
||||
:white => 37
|
||||
}
|
||||
|
||||
def tabulate(fmt, *labels_and_values)
|
||||
labels = labels_and_values.map { |l| Array === l ? l.first : l }
|
||||
label_width = labels.inject(0) { |w,l| l.size > w ? l.size : w }
|
||||
labels_and_values.each do |(l,v)|
|
||||
f = fmt
|
||||
l, f, c = l if Array === l
|
||||
fmtstr = "%-#{label_width+1}s #{f}"
|
||||
if STDOUT.tty? and c and v.to_i > 0
|
||||
fmtstr = "\e[#{[*c].map { |x| ANSI[x] } * ";"}m" + fmtstr + "\e[#{ANSI[:reset]}m"
|
||||
end
|
||||
puts fmtstr % [l+":", v]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_const(const)
|
||||
const and const.split('::').inject(Object) { |k,c| k.const_get(c) }
|
||||
end
|
||||
|
||||
puts "Starting server..."
|
||||
args = {}
|
||||
args[:interpreter] = ENV['THRIFT_SERVER_INTERPRETER'] || ENV['THRIFT_INTERPRETER'] || "ruby"
|
||||
args[:class] = resolve_const(ENV['THRIFT_SERVER']) || Thrift::NonblockingServer
|
||||
args[:host] = ENV['THRIFT_HOST'] || HOST
|
||||
args[:port] = (ENV['THRIFT_PORT'] || PORT).to_i
|
||||
server = Server.new(args)
|
||||
server.start
|
||||
|
||||
args = {}
|
||||
args[:host] = ENV['THRIFT_HOST'] || HOST
|
||||
args[:port] = (ENV['THRIFT_PORT'] || PORT).to_i
|
||||
args[:num_processes] = (ENV['THRIFT_NUM_PROCESSES'] || 40).to_i
|
||||
args[:clients_per_process] = (ENV['THRIFT_NUM_CLIENTS'] || 5).to_i
|
||||
args[:calls_per_client] = (ENV['THRIFT_NUM_CALLS'] || 50).to_i
|
||||
args[:interpreter] = ENV['THRIFT_CLIENT_INTERPRETER'] || ENV['THRIFT_INTERPRETER'] || "ruby"
|
||||
args[:log_exceptions] = !!ENV['THRIFT_LOG_EXCEPTIONS']
|
||||
BenchmarkManager.new(args, server).run
|
||||
|
||||
server.shutdown
|
|
@ -1,74 +0,0 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
|
||||
$:.unshift File.dirname(__FILE__) + '/../lib'
|
||||
require 'thrift'
|
||||
$:.unshift File.dirname(__FILE__) + "/gen-rb"
|
||||
require 'benchmark_service'
|
||||
|
||||
class Client
|
||||
def initialize(host, port, clients_per_process, calls_per_client, log_exceptions)
|
||||
@host = host
|
||||
@port = port
|
||||
@clients_per_process = clients_per_process
|
||||
@calls_per_client = calls_per_client
|
||||
@log_exceptions = log_exceptions
|
||||
end
|
||||
|
||||
def run
|
||||
@clients_per_process.times do
|
||||
socket = Thrift::Socket.new(@host, @port)
|
||||
transport = Thrift::FramedTransport.new(socket)
|
||||
protocol = Thrift::BinaryProtocol.new(transport)
|
||||
client = ThriftBenchmark::BenchmarkService::Client.new(protocol)
|
||||
begin
|
||||
start = Time.now
|
||||
transport.open
|
||||
Marshal.dump [:start, start], STDOUT
|
||||
rescue => e
|
||||
Marshal.dump [:connection_failure, Time.now], STDOUT
|
||||
print_exception e if @log_exceptions
|
||||
else
|
||||
begin
|
||||
@calls_per_client.times do
|
||||
Marshal.dump [:call_start, Time.now], STDOUT
|
||||
client.fibonacci(15)
|
||||
Marshal.dump [:call_end, Time.now], STDOUT
|
||||
end
|
||||
transport.close
|
||||
Marshal.dump [:end, Time.now], STDOUT
|
||||
rescue Thrift::TransportException => e
|
||||
Marshal.dump [:connection_error, Time.now], STDOUT
|
||||
print_exception e if @log_exceptions
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def print_exception(e)
|
||||
STDERR.puts "ERROR: #{e.message}"
|
||||
STDERR.puts "\t#{e.backtrace * "\n\t"}"
|
||||
end
|
||||
end
|
||||
|
||||
log_exceptions = true if ARGV[0] == '-log-exceptions' and ARGV.shift
|
||||
|
||||
host, port, clients_per_process, calls_per_client = ARGV
|
||||
|
||||
Client.new(host, port.to_i, clients_per_process.to_i, calls_per_client.to_i, log_exceptions).run
|
|
@ -1,11 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.11.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'benchmark_types'
|
||||
|
||||
module ThriftBenchmark
|
||||
end
|
|
@ -1,80 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.11.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
require 'benchmark_types'
|
||||
|
||||
module ThriftBenchmark
|
||||
module BenchmarkService
|
||||
class Client
|
||||
include ::Thrift::Client
|
||||
|
||||
def fibonacci(n)
|
||||
send_fibonacci(n)
|
||||
return recv_fibonacci()
|
||||
end
|
||||
|
||||
def send_fibonacci(n)
|
||||
send_message('fibonacci', Fibonacci_args, :n => n)
|
||||
end
|
||||
|
||||
def recv_fibonacci()
|
||||
result = receive_message(Fibonacci_result)
|
||||
return result.success unless result.success.nil?
|
||||
raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'fibonacci failed: unknown result')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Processor
|
||||
include ::Thrift::Processor
|
||||
|
||||
def process_fibonacci(seqid, iprot, oprot)
|
||||
args = read_args(iprot, Fibonacci_args)
|
||||
result = Fibonacci_result.new()
|
||||
result.success = @handler.fibonacci(args.n)
|
||||
write_result(result, oprot, 'fibonacci', seqid)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# HELPER FUNCTIONS AND STRUCTURES
|
||||
|
||||
class Fibonacci_args
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
N = 1
|
||||
|
||||
FIELDS = {
|
||||
N => {:type => ::Thrift::Types::BYTE, :name => 'n'}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
class Fibonacci_result
|
||||
include ::Thrift::Struct, ::Thrift::Struct_Union
|
||||
SUCCESS = 0
|
||||
|
||||
FIELDS = {
|
||||
SUCCESS => {:type => ::Thrift::Types::I32, :name => 'success'}
|
||||
}
|
||||
|
||||
def struct_fields; FIELDS; end
|
||||
|
||||
def validate
|
||||
end
|
||||
|
||||
::Thrift::Struct.generate_accessors self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
#
|
||||
# Autogenerated by Thrift Compiler (0.11.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
|
||||
require 'thrift'
|
||||
|
||||
module ThriftBenchmark
|
||||
end
|
|
@ -1,82 +0,0 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
|
||||
$:.unshift File.dirname(__FILE__) + '/../lib'
|
||||
require 'thrift'
|
||||
$:.unshift File.dirname(__FILE__) + "/gen-rb"
|
||||
require 'benchmark_service'
|
||||
|
||||
module Server
|
||||
include Thrift
|
||||
|
||||
class BenchmarkHandler
|
||||
# 1-based index into the fibonacci sequence
|
||||
def fibonacci(n)
|
||||
seq = [1, 1]
|
||||
3.upto(n) do
|
||||
seq << seq[-1] + seq[-2]
|
||||
end
|
||||
seq[n-1] # n is 1-based
|
||||
end
|
||||
end
|
||||
|
||||
def self.start_server(host, port, serverClass)
|
||||
handler = BenchmarkHandler.new
|
||||
processor = ThriftBenchmark::BenchmarkService::Processor.new(handler)
|
||||
transport = ServerSocket.new(host, port)
|
||||
transport_factory = FramedTransportFactory.new
|
||||
args = [processor, transport, transport_factory, nil, 20]
|
||||
if serverClass == NonblockingServer
|
||||
logger = Logger.new(STDERR)
|
||||
logger.level = Logger::WARN
|
||||
args << logger
|
||||
end
|
||||
server = serverClass.new(*args)
|
||||
@server_thread = Thread.new do
|
||||
server.serve
|
||||
end
|
||||
@server = server
|
||||
end
|
||||
|
||||
def self.shutdown
|
||||
return if @server.nil?
|
||||
if @server.respond_to? :shutdown
|
||||
@server.shutdown
|
||||
else
|
||||
@server_thread.kill
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_const(const)
|
||||
const and const.split('::').inject(Object) { |k,c| k.const_get(c) }
|
||||
end
|
||||
|
||||
host, port, serverklass = ARGV
|
||||
|
||||
Server.start_server(host, port.to_i, resolve_const(serverklass))
|
||||
|
||||
# let our host know that the interpreter has started
|
||||
# ideally we'd wait until the server was serving, but we don't have a hook for that
|
||||
Marshal.dump(:started, STDOUT)
|
||||
STDOUT.flush
|
||||
|
||||
Marshal.load(STDIN) # wait until we're instructed to shut down
|
||||
|
||||
Server.shutdown
|
|
@ -1,44 +0,0 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
|
||||
$:.unshift File.dirname(__FILE__) + '/../lib'
|
||||
require 'thrift'
|
||||
$:.unshift File.dirname(__FILE__) + "/gen-rb"
|
||||
require 'benchmark_service'
|
||||
HOST = 'localhost'
|
||||
PORT = 42587
|
||||
|
||||
class BenchmarkHandler
|
||||
# 1-based index into the fibonacci sequence
|
||||
def fibonacci(n)
|
||||
seq = [1, 1]
|
||||
3.upto(n) do
|
||||
seq << seq[-1] + seq[-2]
|
||||
end
|
||||
seq[n-1] # n is 1-based
|
||||
end
|
||||
end
|
||||
|
||||
handler = BenchmarkHandler.new
|
||||
processor = ThriftBenchmark::BenchmarkService::Processor.new(handler)
|
||||
transport = Thrift::ServerSocket.new(HOST, PORT)
|
||||
transport_factory = Thrift::FramedTransportFactory.new
|
||||
logger = Logger.new(STDERR)
|
||||
logger.level = Logger::WARN
|
||||
Thrift::NonblockingServer.new(processor, transport, transport_factory, nil, 20, logger).serve
|
|
@ -1,460 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
#include <ruby.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <constants.h>
|
||||
#include <struct.h>
|
||||
#include <macros.h>
|
||||
#include <bytes.h>
|
||||
|
||||
VALUE rb_thrift_binary_proto_native_qmark(VALUE self) {
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int VERSION_1;
|
||||
static int VERSION_MASK;
|
||||
static int TYPE_MASK;
|
||||
static int BAD_VERSION;
|
||||
static ID rbuf_ivar_id;
|
||||
|
||||
static void write_byte_direct(VALUE trans, int8_t b) {
|
||||
WRITE(trans, (char*)&b, 1);
|
||||
}
|
||||
|
||||
static void write_i16_direct(VALUE trans, int16_t value) {
|
||||
char data[2];
|
||||
|
||||
data[1] = value;
|
||||
data[0] = (value >> 8);
|
||||
|
||||
WRITE(trans, data, 2);
|
||||
}
|
||||
|
||||
static void write_i32_direct(VALUE trans, int32_t value) {
|
||||
char data[4];
|
||||
|
||||
data[3] = value;
|
||||
data[2] = (value >> 8);
|
||||
data[1] = (value >> 16);
|
||||
data[0] = (value >> 24);
|
||||
|
||||
WRITE(trans, data, 4);
|
||||
}
|
||||
|
||||
|
||||
static void write_i64_direct(VALUE trans, int64_t value) {
|
||||
char data[8];
|
||||
|
||||
data[7] = value;
|
||||
data[6] = (value >> 8);
|
||||
data[5] = (value >> 16);
|
||||
data[4] = (value >> 24);
|
||||
data[3] = (value >> 32);
|
||||
data[2] = (value >> 40);
|
||||
data[1] = (value >> 48);
|
||||
data[0] = (value >> 56);
|
||||
|
||||
WRITE(trans, data, 8);
|
||||
}
|
||||
|
||||
static void write_string_direct(VALUE trans, VALUE str) {
|
||||
if (TYPE(str) != T_STRING) {
|
||||
rb_raise(rb_eStandardError, "Value should be a string");
|
||||
}
|
||||
str = convert_to_utf8_byte_buffer(str);
|
||||
write_i32_direct(trans, RSTRING_LEN(str));
|
||||
rb_funcall(trans, write_method_id, 1, str);
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
// interface writing methods
|
||||
//--------------------------------
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_message_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_struct_begin(VALUE self, VALUE name) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_struct_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_field_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_map_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_list_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_set_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_message_begin(VALUE self, VALUE name, VALUE type, VALUE seqid) {
|
||||
VALUE trans = GET_TRANSPORT(self);
|
||||
VALUE strict_write = GET_STRICT_WRITE(self);
|
||||
|
||||
if (strict_write == Qtrue) {
|
||||
write_i32_direct(trans, VERSION_1 | FIX2INT(type));
|
||||
write_string_direct(trans, name);
|
||||
write_i32_direct(trans, FIX2INT(seqid));
|
||||
} else {
|
||||
write_string_direct(trans, name);
|
||||
write_byte_direct(trans, FIX2INT(type));
|
||||
write_i32_direct(trans, FIX2INT(seqid));
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_field_begin(VALUE self, VALUE name, VALUE type, VALUE id) {
|
||||
VALUE trans = GET_TRANSPORT(self);
|
||||
write_byte_direct(trans, FIX2INT(type));
|
||||
write_i16_direct(trans, FIX2INT(id));
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_field_stop(VALUE self) {
|
||||
write_byte_direct(GET_TRANSPORT(self), TTYPE_STOP);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_map_begin(VALUE self, VALUE ktype, VALUE vtype, VALUE size) {
|
||||
VALUE trans = GET_TRANSPORT(self);
|
||||
write_byte_direct(trans, FIX2INT(ktype));
|
||||
write_byte_direct(trans, FIX2INT(vtype));
|
||||
write_i32_direct(trans, FIX2INT(size));
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_list_begin(VALUE self, VALUE etype, VALUE size) {
|
||||
VALUE trans = GET_TRANSPORT(self);
|
||||
write_byte_direct(trans, FIX2INT(etype));
|
||||
write_i32_direct(trans, FIX2INT(size));
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_set_begin(VALUE self, VALUE etype, VALUE size) {
|
||||
rb_thrift_binary_proto_write_list_begin(self, etype, size);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_bool(VALUE self, VALUE b) {
|
||||
write_byte_direct(GET_TRANSPORT(self), RTEST(b) ? 1 : 0);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_byte(VALUE self, VALUE byte) {
|
||||
CHECK_NIL(byte);
|
||||
write_byte_direct(GET_TRANSPORT(self), NUM2INT(byte));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_i16(VALUE self, VALUE i16) {
|
||||
CHECK_NIL(i16);
|
||||
write_i16_direct(GET_TRANSPORT(self), FIX2INT(i16));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_i32(VALUE self, VALUE i32) {
|
||||
CHECK_NIL(i32);
|
||||
write_i32_direct(GET_TRANSPORT(self), NUM2INT(i32));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_i64(VALUE self, VALUE i64) {
|
||||
CHECK_NIL(i64);
|
||||
write_i64_direct(GET_TRANSPORT(self), NUM2LL(i64));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_double(VALUE self, VALUE dub) {
|
||||
CHECK_NIL(dub);
|
||||
// Unfortunately, bitwise_cast doesn't work in C. Bad C!
|
||||
union {
|
||||
double f;
|
||||
int64_t t;
|
||||
} transfer;
|
||||
transfer.f = RFLOAT_VALUE(rb_Float(dub));
|
||||
write_i64_direct(GET_TRANSPORT(self), transfer.t);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_string(VALUE self, VALUE str) {
|
||||
CHECK_NIL(str);
|
||||
VALUE trans = GET_TRANSPORT(self);
|
||||
write_string_direct(trans, str);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_write_binary(VALUE self, VALUE buf) {
|
||||
CHECK_NIL(buf);
|
||||
VALUE trans = GET_TRANSPORT(self);
|
||||
buf = force_binary_encoding(buf);
|
||||
write_i32_direct(trans, RSTRING_LEN(buf));
|
||||
rb_funcall(trans, write_method_id, 1, buf);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
// interface reading methods
|
||||
//---------------------------------------
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_string(VALUE self);
|
||||
VALUE rb_thrift_binary_proto_read_binary(VALUE self);
|
||||
VALUE rb_thrift_binary_proto_read_byte(VALUE self);
|
||||
VALUE rb_thrift_binary_proto_read_i32(VALUE self);
|
||||
VALUE rb_thrift_binary_proto_read_i16(VALUE self);
|
||||
|
||||
static char read_byte_direct(VALUE self) {
|
||||
VALUE byte = rb_funcall(GET_TRANSPORT(self), read_byte_method_id, 0);
|
||||
return (char)(FIX2INT(byte));
|
||||
}
|
||||
|
||||
static int16_t read_i16_direct(VALUE self) {
|
||||
VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id);
|
||||
rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(2));
|
||||
return (int16_t)(((uint8_t)(RSTRING_PTR(rbuf)[1])) | ((uint16_t)((RSTRING_PTR(rbuf)[0]) << 8)));
|
||||
}
|
||||
|
||||
static int32_t read_i32_direct(VALUE self) {
|
||||
VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id);
|
||||
rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(4));
|
||||
return ((uint8_t)(RSTRING_PTR(rbuf)[3])) |
|
||||
(((uint8_t)(RSTRING_PTR(rbuf)[2])) << 8) |
|
||||
(((uint8_t)(RSTRING_PTR(rbuf)[1])) << 16) |
|
||||
(((uint8_t)(RSTRING_PTR(rbuf)[0])) << 24);
|
||||
}
|
||||
|
||||
static int64_t read_i64_direct(VALUE self) {
|
||||
VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id);
|
||||
rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(8));
|
||||
uint64_t hi = ((uint8_t)(RSTRING_PTR(rbuf)[3])) |
|
||||
(((uint8_t)(RSTRING_PTR(rbuf)[2])) << 8) |
|
||||
(((uint8_t)(RSTRING_PTR(rbuf)[1])) << 16) |
|
||||
(((uint8_t)(RSTRING_PTR(rbuf)[0])) << 24);
|
||||
uint32_t lo = ((uint8_t)(RSTRING_PTR(rbuf)[7])) |
|
||||
(((uint8_t)(RSTRING_PTR(rbuf)[6])) << 8) |
|
||||
(((uint8_t)(RSTRING_PTR(rbuf)[5])) << 16) |
|
||||
(((uint8_t)(RSTRING_PTR(rbuf)[4])) << 24);
|
||||
return (hi << 32) | lo;
|
||||
}
|
||||
|
||||
static VALUE get_protocol_exception(VALUE code, VALUE message) {
|
||||
VALUE args[2];
|
||||
args[0] = code;
|
||||
args[1] = message;
|
||||
return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class);
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_message_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_struct_begin(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_struct_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_field_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_map_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_list_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_set_end(VALUE self) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_message_begin(VALUE self) {
|
||||
VALUE strict_read = GET_STRICT_READ(self);
|
||||
VALUE name, seqid;
|
||||
int type;
|
||||
|
||||
int version = read_i32_direct(self);
|
||||
|
||||
if (version < 0) {
|
||||
if ((version & VERSION_MASK) != VERSION_1) {
|
||||
rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("Missing version identifier")));
|
||||
}
|
||||
type = version & TYPE_MASK;
|
||||
name = rb_thrift_binary_proto_read_string(self);
|
||||
seqid = rb_thrift_binary_proto_read_i32(self);
|
||||
} else {
|
||||
if (strict_read == Qtrue) {
|
||||
rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("No version identifier, old protocol client?")));
|
||||
}
|
||||
name = READ(self, version);
|
||||
type = read_byte_direct(self);
|
||||
seqid = rb_thrift_binary_proto_read_i32(self);
|
||||
}
|
||||
|
||||
return rb_ary_new3(3, name, INT2FIX(type), seqid);
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_field_begin(VALUE self) {
|
||||
int type = read_byte_direct(self);
|
||||
if (type == TTYPE_STOP) {
|
||||
return rb_ary_new3(3, Qnil, INT2FIX(type), INT2FIX(0));
|
||||
} else {
|
||||
VALUE id = rb_thrift_binary_proto_read_i16(self);
|
||||
return rb_ary_new3(3, Qnil, INT2FIX(type), id);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_map_begin(VALUE self) {
|
||||
VALUE ktype = rb_thrift_binary_proto_read_byte(self);
|
||||
VALUE vtype = rb_thrift_binary_proto_read_byte(self);
|
||||
VALUE size = rb_thrift_binary_proto_read_i32(self);
|
||||
return rb_ary_new3(3, ktype, vtype, size);
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_list_begin(VALUE self) {
|
||||
VALUE etype = rb_thrift_binary_proto_read_byte(self);
|
||||
VALUE size = rb_thrift_binary_proto_read_i32(self);
|
||||
return rb_ary_new3(2, etype, size);
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_set_begin(VALUE self) {
|
||||
return rb_thrift_binary_proto_read_list_begin(self);
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_bool(VALUE self) {
|
||||
char byte = read_byte_direct(self);
|
||||
return byte != 0 ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_byte(VALUE self) {
|
||||
return INT2FIX(read_byte_direct(self));
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_i16(VALUE self) {
|
||||
return INT2FIX(read_i16_direct(self));
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_i32(VALUE self) {
|
||||
return INT2NUM(read_i32_direct(self));
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_i64(VALUE self) {
|
||||
return LL2NUM(read_i64_direct(self));
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_double(VALUE self) {
|
||||
union {
|
||||
double f;
|
||||
int64_t t;
|
||||
} transfer;
|
||||
transfer.t = read_i64_direct(self);
|
||||
return rb_float_new(transfer.f);
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_string(VALUE self) {
|
||||
VALUE buffer = rb_thrift_binary_proto_read_binary(self);
|
||||
return convert_to_string(buffer);
|
||||
}
|
||||
|
||||
VALUE rb_thrift_binary_proto_read_binary(VALUE self) {
|
||||
int size = read_i32_direct(self);
|
||||
return READ(self, size);
|
||||
}
|
||||
|
||||
void Init_binary_protocol_accelerated() {
|
||||
VALUE thrift_binary_protocol_class = rb_const_get(thrift_module, rb_intern("BinaryProtocol"));
|
||||
|
||||
VERSION_1 = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("VERSION_1")));
|
||||
VERSION_MASK = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("VERSION_MASK")));
|
||||
TYPE_MASK = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("TYPE_MASK")));
|
||||
|
||||
VALUE bpa_class = rb_define_class_under(thrift_module, "BinaryProtocolAccelerated", thrift_binary_protocol_class);
|
||||
|
||||
rb_define_method(bpa_class, "native?", rb_thrift_binary_proto_native_qmark, 0);
|
||||
|
||||
rb_define_method(bpa_class, "write_message_begin", rb_thrift_binary_proto_write_message_begin, 3);
|
||||
rb_define_method(bpa_class, "write_field_begin", rb_thrift_binary_proto_write_field_begin, 3);
|
||||
rb_define_method(bpa_class, "write_field_stop", rb_thrift_binary_proto_write_field_stop, 0);
|
||||
rb_define_method(bpa_class, "write_map_begin", rb_thrift_binary_proto_write_map_begin, 3);
|
||||
rb_define_method(bpa_class, "write_list_begin", rb_thrift_binary_proto_write_list_begin, 2);
|
||||
rb_define_method(bpa_class, "write_set_begin", rb_thrift_binary_proto_write_set_begin, 2);
|
||||
rb_define_method(bpa_class, "write_byte", rb_thrift_binary_proto_write_byte, 1);
|
||||
rb_define_method(bpa_class, "write_bool", rb_thrift_binary_proto_write_bool, 1);
|
||||
rb_define_method(bpa_class, "write_i16", rb_thrift_binary_proto_write_i16, 1);
|
||||
rb_define_method(bpa_class, "write_i32", rb_thrift_binary_proto_write_i32, 1);
|
||||
rb_define_method(bpa_class, "write_i64", rb_thrift_binary_proto_write_i64, 1);
|
||||
rb_define_method(bpa_class, "write_double", rb_thrift_binary_proto_write_double, 1);
|
||||
rb_define_method(bpa_class, "write_string", rb_thrift_binary_proto_write_string, 1);
|
||||
rb_define_method(bpa_class, "write_binary", rb_thrift_binary_proto_write_binary, 1);
|
||||
// unused methods
|
||||
rb_define_method(bpa_class, "write_message_end", rb_thrift_binary_proto_write_message_end, 0);
|
||||
rb_define_method(bpa_class, "write_struct_begin", rb_thrift_binary_proto_write_struct_begin, 1);
|
||||
rb_define_method(bpa_class, "write_struct_end", rb_thrift_binary_proto_write_struct_end, 0);
|
||||
rb_define_method(bpa_class, "write_field_end", rb_thrift_binary_proto_write_field_end, 0);
|
||||
rb_define_method(bpa_class, "write_map_end", rb_thrift_binary_proto_write_map_end, 0);
|
||||
rb_define_method(bpa_class, "write_list_end", rb_thrift_binary_proto_write_list_end, 0);
|
||||
rb_define_method(bpa_class, "write_set_end", rb_thrift_binary_proto_write_set_end, 0);
|
||||
|
||||
rb_define_method(bpa_class, "read_message_begin", rb_thrift_binary_proto_read_message_begin, 0);
|
||||
rb_define_method(bpa_class, "read_field_begin", rb_thrift_binary_proto_read_field_begin, 0);
|
||||
rb_define_method(bpa_class, "read_map_begin", rb_thrift_binary_proto_read_map_begin, 0);
|
||||
rb_define_method(bpa_class, "read_list_begin", rb_thrift_binary_proto_read_list_begin, 0);
|
||||
rb_define_method(bpa_class, "read_set_begin", rb_thrift_binary_proto_read_set_begin, 0);
|
||||
rb_define_method(bpa_class, "read_byte", rb_thrift_binary_proto_read_byte, 0);
|
||||
rb_define_method(bpa_class, "read_bool", rb_thrift_binary_proto_read_bool, 0);
|
||||
rb_define_method(bpa_class, "read_i16", rb_thrift_binary_proto_read_i16, 0);
|
||||
rb_define_method(bpa_class, "read_i32", rb_thrift_binary_proto_read_i32, 0);
|
||||
rb_define_method(bpa_class, "read_i64", rb_thrift_binary_proto_read_i64, 0);
|
||||
rb_define_method(bpa_class, "read_double", rb_thrift_binary_proto_read_double, 0);
|
||||
rb_define_method(bpa_class, "read_string", rb_thrift_binary_proto_read_string, 0);
|
||||
rb_define_method(bpa_class, "read_binary", rb_thrift_binary_proto_read_binary, 0);
|
||||
// unused methods
|
||||
rb_define_method(bpa_class, "read_message_end", rb_thrift_binary_proto_read_message_end, 0);
|
||||
rb_define_method(bpa_class, "read_struct_begin", rb_thrift_binary_proto_read_struct_begin, 0);
|
||||
rb_define_method(bpa_class, "read_struct_end", rb_thrift_binary_proto_read_struct_end, 0);
|
||||
rb_define_method(bpa_class, "read_field_end", rb_thrift_binary_proto_read_field_end, 0);
|
||||
rb_define_method(bpa_class, "read_map_end", rb_thrift_binary_proto_read_map_end, 0);
|
||||
rb_define_method(bpa_class, "read_list_end", rb_thrift_binary_proto_read_list_end, 0);
|
||||
rb_define_method(bpa_class, "read_set_end", rb_thrift_binary_proto_read_set_end, 0);
|
||||
|
||||
rbuf_ivar_id = rb_intern("@rbuf");
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue