diff --git a/README.md b/README.md index 63c72f7279f..5a80d4e972e 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,17 @@ The UI is a standard Rails 3 app. bundle exec rails server. ``` +#### zipkin-tracer gem +The `zipkin-tracer` gem adds tracing to a Rails application through the use of a Rack Handler. +In `config.ru`: + +``` + use ZipkinTracer::RackHandler + run +``` + +If the application's static assets are served through Rails, those requests will be traced. + ## Running a Hadoop job It's possible to setup Scribe to log into Hadoop. If you do this you can generate various reports from the data that is not easy to do on the fly in Zipkin itself. diff --git a/zipkin-gems/zipkin-tracer/Rakefile b/zipkin-gems/zipkin-tracer/Rakefile new file mode 100644 index 00000000000..1850eee0356 --- /dev/null +++ b/zipkin-gems/zipkin-tracer/Rakefile @@ -0,0 +1,19 @@ +# 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. +require 'rubygems' + +desc 'Build the gem' +task :build do + system "gem build zipkin-tracer.gemspec" +end diff --git a/zipkin-gems/zipkin-tracer/lib/zipkin-tracer.rb b/zipkin-gems/zipkin-tracer/lib/zipkin-tracer.rb new file mode 100644 index 00000000000..08f8a341abe --- /dev/null +++ b/zipkin-gems/zipkin-tracer/lib/zipkin-tracer.rb @@ -0,0 +1,79 @@ +# 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. +require 'finagle-thrift' +require 'finagle-thrift/trace' +require 'scribe' + +require 'zipkin-tracer/careless_scribe' + +module ZipkinTracer extend self + + class RackHandler + def initialize(app) + @app = app + @lock = Mutex.new + + config = app.config.zipkin_tracer + @service_name = config[:service_name] + @service_port = config[:service_port] + + scribe = + if config[:scribe_server] then + Scribe.new(config[:scribe_server]) + else + Scribe.new() + end + + scribe_max_buffer = + if config[:scribe_max_buffer] then + config[:scribe_max_buffer] + else + 10 + end + + @sample_rate = + if config[:sample_rate] then + config[:sample_rate] + else + 0.1 + end + + ::Trace.tracer = ::Trace::ZipkinTracer.new(CarelessScribe.new(scribe), scribe_max_buffer) + end + + def call(env) + id = ::Trace::TraceId.new(::Trace.generate_id, nil, ::Trace.generate_id, true) + ::Trace.default_endpoint = ::Trace.default_endpoint.with_service_name(@service_name).with_port(@service_port) + ::Trace.sample_rate=(@sample_rate) + tracing_filter(id, env) { @app.call(env) } + end + + private + def tracing_filter(trace_id, env) + @lock.synchronize do + ::Trace.push(trace_id) + ::Trace.set_rpc_name(env["REQUEST_METHOD"]) # get/post and all that jazz + ::Trace.record(::Trace::BinaryAnnotation.new("http.uri", env["PATH_INFO"], "STRING", ::Trace.default_endpoint)) + ::Trace.record(::Trace::Annotation.new(::Trace::Annotation::SERVER_RECV, ::Trace.default_endpoint)) + end + yield if block_given? + ensure + @lock.synchronize do + ::Trace.record(::Trace::Annotation.new(::Trace::Annotation::SERVER_SEND, ::Trace.default_endpoint)) + ::Trace.pop + end + end + end + +end diff --git a/zipkin-web/lib/careless_scribe.rb b/zipkin-gems/zipkin-tracer/lib/zipkin-tracer/careless_scribe.rb similarity index 100% rename from zipkin-web/lib/careless_scribe.rb rename to zipkin-gems/zipkin-tracer/lib/zipkin-tracer/careless_scribe.rb diff --git a/zipkin-gems/zipkin-tracer/lib/zipkin-tracer/version.rb b/zipkin-gems/zipkin-tracer/lib/zipkin-tracer/version.rb new file mode 100644 index 00000000000..3fddafa0558 --- /dev/null +++ b/zipkin-gems/zipkin-tracer/lib/zipkin-tracer/version.rb @@ -0,0 +1,17 @@ +# 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. +module ZipkinTracer + VERSION = "0.0.1" +end + diff --git a/zipkin-gems/zipkin-tracer/zipkin-tracer.gemspec b/zipkin-gems/zipkin-tracer/zipkin-tracer.gemspec new file mode 100644 index 00000000000..8d76b9548ba --- /dev/null +++ b/zipkin-gems/zipkin-tracer/zipkin-tracer.gemspec @@ -0,0 +1,36 @@ +# -*- encoding: utf-8 -*- +# 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. +lib = File.expand_path('../lib/', __FILE__) +$:.unshift lib unless $:.include?(lib) + +require 'zipkin-tracer/version' + +Gem::Specification.new do |s| + s.name = "zipkin-tracer" + s.version = ZipkinTracer::VERSION + s.authors = ["Franklin Hu"] + s.email = ["franklin@twitter.com"] + s.homepage = "https://github.com/twitter/zipkin" + s.summary = "Ruby tracing via Zipkin" + s.description = "Adds tracing instrumentation for ruby applications" + + s.required_rubygems_version = ">= 1.3.5" + + s.files = Dir.glob("{bin,lib}/**/*") + s.require_path = 'lib' + + s.add_dependency "finagle-thrift", "~> 1.2.0" + s.add_dependency "scribe", "~> 0.2.4" +end diff --git a/zipkin-web/Gemfile b/zipkin-web/Gemfile index 11524c1fe46..e085cb63408 100644 --- a/zipkin-web/Gemfile +++ b/zipkin-web/Gemfile @@ -6,4 +6,5 @@ gem 'thrift_client', "0.6.3" gem 'zookeeper', "1.2.4" gem 'finagle-thrift', '1.2.0' gem 'scribe', '0.2.4' +gem 'zipkin-tracer', '0.0.1' diff --git a/zipkin-web/Gemfile.lock b/zipkin-web/Gemfile.lock index 203e37b9532..b7f97c45133 100644 --- a/zipkin-web/Gemfile.lock +++ b/zipkin-web/Gemfile.lock @@ -88,6 +88,9 @@ GEM polyglot polyglot (>= 0.3.1) tzinfo (0.3.33) + zipkin-tracer (0.0.1) + finagle-thrift (~> 1.2.0) + scribe (~> 0.2.4) zookeeper (1.2.4) backports (~> 2.5.1) logging (~> 1.7.2) @@ -101,4 +104,5 @@ DEPENDENCIES scribe (= 0.2.4) thrift (= 0.6.0) thrift_client (= 0.6.3) + zipkin-tracer (= 0.0.1) zookeeper (= 1.2.4) diff --git a/zipkin-web/config.ru b/zipkin-web/config.ru index 43ab285cde3..ed15f6ed894 100644 --- a/zipkin-web/config.ru +++ b/zipkin-web/config.ru @@ -1,11 +1,11 @@ # 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. @@ -15,5 +15,5 @@ # This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) -use ZipkinRackHandler +use ZipkinTracer::RackHandler run Zipkin::Application diff --git a/zipkin-web/config/application.rb b/zipkin-web/config/application.rb index 5042fb80495..169bdc7fd76 100644 --- a/zipkin-web/config/application.rb +++ b/zipkin-web/config/application.rb @@ -21,7 +21,6 @@ require "action_mailer/railtie" require "active_resource/railtie" require "rails/test_unit/railtie" -require 'lib/careless_scribe' require 'sprockets/railtie' # If you have a Gemfile, require the gems listed there, including any gems @@ -88,43 +87,17 @@ class Application < Rails::Application # :skip_zookeeper => true #} - end -end + config.zipkin_tracer = { + # Scribe settings that can be overwritten + #:scribe_server => "HOST:PORT", + #:scribe_max_buff => 10 -class ZipkinRackHandler - def initialize(app) - @app = app - @lock = Mutex.new - Trace.tracer = Trace::ZipkinTracer.new(CarelessScribe.new(Scribe.new()), 10) - end + # Required settings + :service_name => "ZipkinUI", + :service_port => 80, - def call(env) - # TODO HERE BE HACK. Chad made me do it! - # this is due to our setup where statics are served through the ruby app, but we don't want to trace that. - rp = env["REQUEST_PATH"] - if !rp.blank? && (rp.starts_with?("/stylesheets") || rp.starts_with?("/javascripts") || rp.starts_with?("/images")) - return @app.call(env) - end - - id = Trace::TraceId.new(Trace.generate_id, nil, Trace.generate_id, true) - Trace.default_endpoint = Trace.default_endpoint.with_service_name("zipkinui").with_port(0) #TODO any way to get the port? - Trace.sample_rate=(1) - tracing_filter(id, env) { @app.call(env) } - end + :sample_rate => 1 + } - private - def tracing_filter(trace_id, env) - @lock.synchronize do - Trace.push(trace_id) - Trace.set_rpc_name(env["REQUEST_METHOD"]) # get/post and all that jazz - Trace.record(Trace::BinaryAnnotation.new("http.uri", env["PATH_INFO"], "STRING", Trace.default_endpoint)) - Trace.record(Trace::Annotation.new(Trace::Annotation::SERVER_RECV, Trace.default_endpoint)) - end - yield if block_given? - ensure - @lock.synchronize do - Trace.record(Trace::Annotation.new(Trace::Annotation::SERVER_SEND, Trace.default_endpoint)) - Trace.pop - end end end