Yodeler
A generic instrumentation library thats supports reporting to multiple endpoints via pluggable backend adapters.
Spoutin' off noise to whoever is listening.
Installation
Add this line to your application's Gemfile:
gem 'yodeler', '~>0.1.2'
And then execute:
$ bundle
Or install it yourself as:
$ gem install yodeler
Usage
Configuration
Single endpoint
In config/initializers/yodeler.rb
Yodeler.configure do |client|
# if no endpoint name is given, it defaults to :default
client.adapter(:http) do |http|
http.path = '/events'
http.host = 'example.com'
# http.port = 80
# http.use_ssl = false
# http.default_params = {}
end
# if no timestamp_format is set, defaults to UTC ISO8601
client.timestamp_format = :iso8601
#client.timestamp_format = :epoch
#client.timestamp_format = -> { Time.now.whatever.you_feel_like! }
end
Multiple Endpoints
In config/initializers/yodeler.rb
Yodeler.configure do |client|
client.endpoint(:sales_reporting).adapter(:http) do |http|
http.path = '/events'
http.host = 'sales.example.com'
end
client.endpoint(:devops_reporting).adapter(:http) do |http|
http.path = '/events'
http.host = 'devops.example.com'
end
# by default, the client dispatches to the first registered endpoint
# you can change it to a different one
# Alternatively you can dispatch to a set of endpoints when dispatching a metric
# Yodeler.gauge('users.count', 35, to: [:sales_reporting, :devops_reporting])
client.default_endpoint_name = :devops_reporting
end
Full Configuration Example
In config/yodeler.yml
development:
auth_token: SOSECUREZ
sales_reporting:
host: localhost
port: 3030
devops_reporting:
host: localhost
port: 3031
In config/initializers/yodeler.rb
config = YAML.load(File.read("./config/yodeler.yml"))[Rails.env]
Yodeler.configure do |client|
client.endpoint(:sales_reporting).adapter(:http) do |http|
http.path = '/events'
http.host = config[:sales_reporting][:host]
http.port = config[:sales_reporting][:port]
http.default_params = {
auth_token: config[:auth_token]
}
end
client.endpoint(:devops_reporting).adapter(:http) do |http|
http.path = '/events'
http.host = config[:devops_reporting][:host]
http.port = config[:devops_reporting][:port]
http.default_params = {
auth_token: config[:auth_token]
}
# Overwrite the default http dispatcher or overwrite an individual metric dispatcher
# http.handle(:gauge){ |url, metric, default_params| ... something cool ... }
http.handle(:default) do |url, metric, default_params|
# This is the default handler definition, but you could change it
HTTP.post(url, json: default_params.merge(metric.to_hash))
end
end
client.default_endpoint_name = :devops_reporting
end
Yodeler.configure do |client|
client.endpoint(:karma_widget).adapter(:http) do |http|
http.path = '/widgets/karma'
http.host = 'localhost'
http.default_params = {
auth_token: config[:auth_token]
}
end
client.endpoint(:user_count_widget).adapter(:http) do |http|
http.path = '/widgets/user_count'
http.host = 'localhost'
http.default_params = {
auth_token: config[:auth_token]
}
end
end
Publishing Metrics and Events
All instrumentation methods support an options hash
- :prefix - [~String] :prefix your metric/event names
- :tags - [Array<String,Symbol>, String, Symbol] :tags ([]) array of tags to apply to metric/event
- :sample_rate - [Float] :sample_rate (1.0) The sample rate to use
- :to - [Array, Symbol] :to array of endpoint names to send the metric/event to. If not set will send to Yodeler::Client#default_endpoint_name
- :meta - [Hash] :meta additional meta data to send with metric/event. Meta data like :tags, :hostname and :timestamp are merged into this hash
Gauge
Yodeler.gauge 'user.count', 35
Yodeler.gauge 'user.count', 35, prefix: 'test'
Yodeler.gauge 'user.count', 35, sample_rate: 0.5
Yodeler.gauge 'user.count', 35, prefix: 'test', tags: ['cool']
Yodeler.gauge 'user.count', 35, to: [:devops_reporting, :sales_reporting]
Increment
Yodeler.increment 'users.count'
Yodeler.increment 'users.count', to: [:devops_reporting, :sales_reporting]
Yodeler.increment 'revenue', 10_000
Yodeler.increment 'revenue', 10_000, to: [:devops_reporting, :sales_reporting]
Yodeler.increment 'revenue', 10_000, to: [:devops_reporting, :sales_reporting], meta: {ip: request.remote_ip}
Timing
Yodeler.timing('eat.sandwich', {prefix: :test}) do
user.eat(sandwich)
end #=> returns result of block
Yodeler.timing 'eat.sandwich', 250 #in ms
Yodeler.timing 'eat.sandwich', 250, to: [:devops_reporting, :sales_reporting]
Event
wizz_bang = {name: 'Wizz Bang 3000', image_url: 'http://example.com/wizzbang.jpg'}
Yodeler.publish 'product.sold', wizz_bang
Yodeler.publish 'product.sold', wizz_bang, prefix: 'ecommerce'
Yodeler.publish 'product.sold', wizz_bang, sample_rate: 0.25
Yodeler.publish 'product.sold', wizz_bang, to: [:devops_reporting, :sales_reporting]
Yodeler.publish 'product.sold', wizz_bang, to: [:devops_reporting, :sales_reporting], meta: {ip: request.remote_ip}
Yodeler.publish 'product.sold' do |msg|
msg[:name] = "Wizz Bang 3000"
msg[:image_url] = "http://example.com/wizzbang.jpg"
end
Yodeler.publish 'product.sold', tags: [:wizzbang] do |msg|
msg[:name] = "Wizz Bang 3000"
msg[:image_url] = "http://example.com/wizzbang.jpg"
end
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.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/coryodaniel/yodeler.
TODOs
- Yodeler#publish receive block
- Add a configuration proxy to use instead of initializing adapters and endpoints on #config
- Custom adapter documentation
- Client#format_options -> Metric.format_options
- Client#default_endpoint_name accept array of names
- Dispatch to any object or proc, if adapter not registered
- client.endpoint(:dashboard).use(:something_that_responds_to_dispatch)
- client.endpoint(:dashboard).use{ |metric| MyWorker.perform_later(metric) }
- more yard docs