From ab1c79ea83d46240f284f1aeccf6ccac82e31c07 Mon Sep 17 00:00:00 2001 From: "jiangzhi.xie" Date: Tue, 12 Jul 2016 18:25:30 +0800 Subject: [PATCH 1/5] Better metrics Support multiple metrics Support custom data --- Gemfile.lock | 59 ++++++++++++++++++++++++++ README.md | 75 +++++++-------------------------- Rakefile | 4 +- fluent-plugin-statsd.gemspec | 2 + lib/fluent/plugin/out_statsd.rb | 68 +++++++++++++++++++++--------- test/plugin/out_statsd.rb | 25 ++++++++--- 6 files changed, 146 insertions(+), 87 deletions(-) create mode 100644 Gemfile.lock diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..86ab32f --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,59 @@ +PATH + remote: . + specs: + fluent-plugin-statsd (1.0.2) + fluentd (>= 0.10.8) + +GEM + remote: http://rubygems.org/ + specs: + coderay (1.1.1) + cool.io (1.4.4) + fluentd (0.14.1) + cool.io (>= 1.4.3, < 2.0.0) + http_parser.rb (>= 0.5.1, < 0.7.0) + json (>= 1.4.3) + msgpack (>= 0.7.0) + serverengine (>= 1.6.4) + sigdump (~> 0.2.2) + strptime (>= 0.1.7) + tzinfo (>= 1.0.0) + tzinfo-data (>= 1.0.0) + yajl-ruby (~> 1.0) + http_parser.rb (0.6.0) + json (2.0.1) + method_source (0.8.2) + msgpack (1.0.0) + power_assert (0.3.0) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + rake (11.1.2) + serverengine (1.6.4) + sigdump (~> 0.2.2) + sigdump (0.2.4) + slop (3.6.0) + statsd-ruby (1.3.0) + strptime (0.1.8) + test-unit (3.1.8) + power_assert + thread_safe (0.3.5) + tzinfo (1.2.2) + thread_safe (~> 0.1) + tzinfo-data (1.2016.6) + tzinfo (>= 1.0.0) + yajl-ruby (1.2.1) + +PLATFORMS + ruby + +DEPENDENCIES + fluent-plugin-statsd! + pry + rake (>= 0.9.2) + statsd-ruby + test-unit + +BUNDLED WITH + 1.10.6 diff --git a/README.md b/README.md index 96e2a16..4a1889e 100644 --- a/README.md +++ b/README.md @@ -14,73 +14,28 @@ $ fluent-gem install fluent-plugin-statsd type statsd host localhost # optional - port 8125# optional + port 8125 # optional + namespace a.b.c # optional + + + statsd_type timing + statsd_key my_app.nginx.response_time + statsd_key ${record['response_time']} + + + + statsd_type incrument + statsd_key my_app.nginx.${response_code.to_i / 100}xx # 2xx 4xx 5xx + ``` -```ruby -fluent_logger.post('statsd', - :statsd_type => 'timing', - :statsd_key => 'org.foo.timing', - :statsd_timing => 0.234 -) - -fluent_logger.post('statsd', - :statsd_type => 'gauge', - :statsd_gauge => 10, - :statsd_key => 'org.foo.gauge' -) - -fluent_logger.post('statsd', - :statsd_type => 'count', - :statsd_gauge => 10, - :statsd_key => 'org.foo.gauge' -) - -fluent_logger.post('statsd', - :statsd_type => 'set', - :statsd_gauge => 10, - :statsd_key => 'org.foo.gauge' -) - -fluent_logger.post('statsd', - :statsd_type => 'increment', - :statsd_key => 'org.foo.counter' -) - - -fluent_logger.post('statsd', - :statsd_type => 'decrement', - :statsd_key => 'org.foo.counter' -) -``` - -# td-agent.conf demo - -worked with record_reformer to transform access log request_time into statsd +# Development ``` - - type copy - - type statsd - host 127.0.0.1 - port 8125 - flush_interval 1s - - # other stores... - - - type record_reformer - output_tag ${tag}.reformer - # transform /url1/url2/url3 --> url.urlNN.urlNN - statsd_key ${"url"+request_uri.gsub(/((\/[^\/]+){2}).*/, '\1').gsub(/([^\?]*)\?.*/,'\1').gsub(/[0-9]+/, "NN").gsub(/\//, ".");} - statsd_timing ${request_time} - statsd_type ${"timing"} - +$ rake test ``` - # Copyright Copyright (c) 2014- Chris Song diff --git a/Rakefile b/Rakefile index f8e784a..b311de3 100644 --- a/Rakefile +++ b/Rakefile @@ -4,9 +4,9 @@ Bundler::GemHelper.install_tasks require 'rake/testtask' Rake::TestTask.new(:test) do |test| - test.libs << 'lib' << 'test' + test.libs << 'test' test.test_files = FileList['test/plugin/*.rb'] - test.verbose = true + test.verbose = false end task :coverage do |t| diff --git a/fluent-plugin-statsd.gemspec b/fluent-plugin-statsd.gemspec index 58f3522..d068777 100644 --- a/fluent-plugin-statsd.gemspec +++ b/fluent-plugin-statsd.gemspec @@ -18,5 +18,7 @@ Gem::Specification.new do |gem| gem.add_dependency "fluentd", ">= 0.10.8" gem.add_development_dependency "rake", ">= 0.9.2" + gem.add_development_dependency "test-unit" gem.add_development_dependency "statsd-ruby", ">=1.2.1" + gem.add_development_dependency "pry" end diff --git a/lib/fluent/plugin/out_statsd.rb b/lib/fluent/plugin/out_statsd.rb index c8aac4b..c028ac0 100644 --- a/lib/fluent/plugin/out_statsd.rb +++ b/lib/fluent/plugin/out_statsd.rb @@ -1,4 +1,6 @@ require 'statsd-ruby' +require 'ostruct' +require 'fluent/output' module Fluent class StatsdOutput < BufferedOutput @@ -7,6 +9,13 @@ class StatsdOutput < BufferedOutput config_param :flush_interval, :time, :default => 1 config_param :host, :string, :default => 'localhost' config_param :port, :string, :default => '8125' + config_param :namespace, :string, :default => nil + + config_section :metric do + config_param :statsd_type, :string + config_param :statsd_key, :string + config_param :statsd_val, :string, default: nil + end attr_reader :statsd @@ -16,7 +25,8 @@ def initialize def configure(conf) super - @statsd = Statsd.new(host, port) + @statsd = Statsd.new(host, port) {|sd| std.namespace = namespace if namespace } + @metrics = conf.elements.select {|elem| elem.name == 'metric' } end def start @@ -28,29 +38,49 @@ def shutdown end def format(tag, time, record) - record.to_msgpack + [tag, record].to_msgpack end def write(chunk) - chunk.msgpack_each {|record| - if statsd_type = record['statsd_type'] - case statsd_type - when 'timing' - @statsd.timing record['statsd_key'], record['statsd_timing'].to_f - when 'gauge' - @statsd.gauge record['statsd_key'], record['statsd_gauge'].to_f - when 'count' - @statsd.count record['statsd_key'], record['statsd_count'].to_f - when 'set' - @statsd.set record['statsd_key'], record['statsd_set'] - when 'increment' - @statsd.increment record['statsd_key'] - when 'decrement' - @statsd.decrement record['statsd_key'] - end + chunk.msgpack_each do |tag, record| + parser = RubyStringParser.new(record: record, tag: tag) + + @metrics.each do |metric| + arg_names = %w{statsd_type statsd_key statsd_val} + send_to_statsd(*metric.values_at(*arg_names).map {|str| parser.parse(str) }) end - } + end end + + private + + def send_to_statsd(type, key, val) + case type + when 'timing' + @statsd.timing key, val.to_f + when 'gauge' + @statsd.gauge key, val.to_f + when 'count' + @statsd.count key, val.to_f + when 'set' + @statsd.set key, val + when 'increment' + @statsd.increment key + when 'decrement' + @statsd.decrement key + end + end + + class RubyStringParser + def initialize(vars = {}) + @obj = Struct.new(*vars.keys).new(*vars.values) + end + + def parse(string) + return unless string + string.gsub(/\$\{.+\}/) {|str| @obj.instance_eval str[2..-2] } + end + end end end diff --git a/test/plugin/out_statsd.rb b/test/plugin/out_statsd.rb index e4c8a51..566b77f 100644 --- a/test/plugin/out_statsd.rb +++ b/test/plugin/out_statsd.rb @@ -1,5 +1,6 @@ require 'fluent/plugin/out_statsd' -require 'statsd-ruby' +require 'fluent/test' +require 'test/unit' class StatsdOutputTest < Test::Unit::TestCase def setup @@ -11,9 +12,20 @@ def setup def treedown end - CONFIG = %[ + CONFIG = %{ type statsd - ] + + + statsd_type timing + statsd_key response_time + statsd_val ${record['response_time']} + + + + statsd_type increment + statsd_key response_code_${record['status'].to_i / 100}xx + + } def create_driver(conf = CONFIG) Fluent::Test::BufferedOutputTestDriver.new(Fluent::StatsdOutput) { @@ -23,9 +35,10 @@ def create_driver(conf = CONFIG) def test_write d = create_driver time = Time.at(@now.to_i).utc - d.emit({ :stastd_type => 'timing', :statsd_key => 'test.statsd.t', :statsd_timing => 100 }, time) - d.emit({ :stastd_type => 'guage', :statsd_key => 'test.statsd.g', :statsd_gauge => 102 }, time) - d.emit({ :stastd_type => 'increment', :statsd_key => 'test.statsd.i'}, time) + d.emit({'response_time' => 102, 'status' => '200'}, time) + d.emit({'response_time' => 105, 'status' => '200'}, time) + d.emit({'response_time' => 112, 'status' => '400'}, time) + d.emit({'response_time' => 125, 'status' => '500'}, time) d.run end From 1a2a901e8d0d758d619a4a6ee1a6756e87a17668 Mon Sep 17 00:00:00 2001 From: "jiangzhi.xie" Date: Tue, 12 Jul 2016 19:05:05 +0800 Subject: [PATCH 2/5] Add debug logs --- .gitignore | 2 ++ Gemfile.lock | 2 +- VERSION | 2 +- lib/fluent/plugin/out_statsd.rb | 7 +++++++ 4 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1b1301 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.swp +*.gem diff --git a/Gemfile.lock b/Gemfile.lock index 86ab32f..df9573d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - fluent-plugin-statsd (1.0.2) + fluent-plugin-statsd (1.1.0) fluentd (>= 0.10.8) GEM diff --git a/VERSION b/VERSION index 6d7de6e..9084fa2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.2 +1.1.0 diff --git a/lib/fluent/plugin/out_statsd.rb b/lib/fluent/plugin/out_statsd.rb index c028ac0..6c97c89 100644 --- a/lib/fluent/plugin/out_statsd.rb +++ b/lib/fluent/plugin/out_statsd.rb @@ -26,7 +26,10 @@ def initialize def configure(conf) super @statsd = Statsd.new(host, port) {|sd| std.namespace = namespace if namespace } + log.info(statsd) + @metrics = conf.elements.select {|elem| elem.name == 'metric' } + log.info(@metrics) end def start @@ -56,6 +59,8 @@ def write(chunk) private def send_to_statsd(type, key, val) + log.debug([type, key, val]) + case type when 'timing' @statsd.timing key, val.to_f @@ -69,6 +74,8 @@ def send_to_statsd(type, key, val) @statsd.increment key when 'decrement' @statsd.decrement key + else + raise "Invalid statsd type '#{type}'" end end From cca36f90c484ee34947aa9d58dde7ac3ca6aa1eb Mon Sep 17 00:00:00 2001 From: "jiangzhi.xie" Date: Tue, 12 Jul 2016 19:13:36 +0800 Subject: [PATCH 3/5] Fix statsd namespace --- lib/fluent/plugin/out_statsd.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/fluent/plugin/out_statsd.rb b/lib/fluent/plugin/out_statsd.rb index 6c97c89..a29aa30 100644 --- a/lib/fluent/plugin/out_statsd.rb +++ b/lib/fluent/plugin/out_statsd.rb @@ -25,7 +25,8 @@ def initialize def configure(conf) super - @statsd = Statsd.new(host, port) {|sd| std.namespace = namespace if namespace } + @statsd = Statsd.new(host, port) + @statsd.namespace = namespace if namespace log.info(statsd) @metrics = conf.elements.select {|elem| elem.name == 'metric' } From 67951202042325ad94585f1c4f8f318e338b946f Mon Sep 17 00:00:00 2001 From: "jiangzhi.xie" Date: Tue, 12 Jul 2016 19:38:17 +0800 Subject: [PATCH 4/5] Update test, use RSpec --- .rspec | 2 + Gemfile.lock | 17 +++++- Rakefile | 17 ------ fluent-plugin-statsd.gemspec | 2 +- spec/examples.txt | 3 ++ spec/plugin/out_statsd_spec.rb | 62 +++++++++++++++++++++ spec/spec_helper.rb | 99 ++++++++++++++++++++++++++++++++++ test/plugin/out_statsd.rb | 45 ---------------- 8 files changed, 182 insertions(+), 65 deletions(-) create mode 100644 .rspec delete mode 100644 Rakefile create mode 100644 spec/examples.txt create mode 100644 spec/plugin/out_statsd_spec.rb create mode 100644 spec/spec_helper.rb delete mode 100644 test/plugin/out_statsd.rb diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..83e16f8 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/Gemfile.lock b/Gemfile.lock index df9573d..195539b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,6 +9,7 @@ GEM specs: coderay (1.1.1) cool.io (1.4.4) + diff-lcs (1.2.5) fluentd (0.14.1) cool.io (>= 1.4.3, < 2.0.0) http_parser.rb (>= 0.5.1, < 0.7.0) @@ -29,7 +30,19 @@ GEM coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - rake (11.1.2) + rspec (3.5.0) + rspec-core (~> 3.5.0) + rspec-expectations (~> 3.5.0) + rspec-mocks (~> 3.5.0) + rspec-core (3.5.1) + rspec-support (~> 3.5.0) + rspec-expectations (3.5.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.5.0) + rspec-mocks (3.5.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.5.0) + rspec-support (3.5.0) serverengine (1.6.4) sigdump (~> 0.2.2) sigdump (0.2.4) @@ -51,7 +64,7 @@ PLATFORMS DEPENDENCIES fluent-plugin-statsd! pry - rake (>= 0.9.2) + rspec (~> 3.0) statsd-ruby test-unit diff --git a/Rakefile b/Rakefile deleted file mode 100644 index b311de3..0000000 --- a/Rakefile +++ /dev/null @@ -1,17 +0,0 @@ -require 'bundler' -Bundler::GemHelper.install_tasks - -require 'rake/testtask' - -Rake::TestTask.new(:test) do |test| - test.libs << 'test' - test.test_files = FileList['test/plugin/*.rb'] - test.verbose = false -end - -task :coverage do |t| - ENV['SIMPLE_COV'] = '1' - Rake::Task["test"].invoke -end - -task :default => [:build] diff --git a/fluent-plugin-statsd.gemspec b/fluent-plugin-statsd.gemspec index d068777..20eaa5b 100644 --- a/fluent-plugin-statsd.gemspec +++ b/fluent-plugin-statsd.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |gem| gem.add_dependency "fluentd", ">= 0.10.8" - gem.add_development_dependency "rake", ">= 0.9.2" + gem.add_development_dependency "rspec", '~> 3.0' gem.add_development_dependency "test-unit" gem.add_development_dependency "statsd-ruby", ">=1.2.1" gem.add_development_dependency "pry" diff --git a/spec/examples.txt b/spec/examples.txt new file mode 100644 index 0000000..df82656 --- /dev/null +++ b/spec/examples.txt @@ -0,0 +1,3 @@ +example_id | status | run_time | +------------------------------------- | ------ | --------------- | +./spec/plugin/out_statsd_spec.rb[1:1] | passed | 0.53516 seconds | diff --git a/spec/plugin/out_statsd_spec.rb b/spec/plugin/out_statsd_spec.rb new file mode 100644 index 0000000..e5e678f --- /dev/null +++ b/spec/plugin/out_statsd_spec.rb @@ -0,0 +1,62 @@ +require 'fluent/plugin/out_statsd' +require 'fluent/test' + +RSpec.describe Fluent::StatsdOutput do + let(:config) do + %{ + type statsd + namespace a.b.c + + + statsd_type timing + statsd_key res_time + statsd_val ${record['response_time']} + + + + statsd_type increment + statsd_key res_code_${record['status'].to_i / 100}xx + + } + end + let(:driver) { create_driver(config) } + let(:statsd) { double('statsd', increment: true, timing: true, 'namespace=' => true) } + let(:time) { Time.now.utc } + + before :all do + Fluent::Test.setup + end + + def create_driver(conf) + Fluent::Test::BufferedOutputTestDriver.new(Fluent::StatsdOutput) { + }.configure(conf) + end + + def emit_events(events) + events.each {|e| driver.emit(e, time) } + end + + + it 'should call statsd with events data' do + allow(Statsd).to receive(:new).and_return(statsd) + + expect(statsd).to receive(:namespace=).with('a.b.c') + + expect(statsd).to receive(:increment).with('res_code_2xx').twice.times + expect(statsd).to receive(:increment).with('res_code_4xx').once.times + expect(statsd).to receive(:increment).with('res_code_5xx').once.times + expect(statsd).to receive(:timing).with('res_time', 102).ordered + expect(statsd).to receive(:timing).with('res_time', 105).ordered + expect(statsd).to receive(:timing).with('res_time', 112).ordered + expect(statsd).to receive(:timing).with('res_time', 125).ordered + + emit_events([ + {'response_time' => 102, 'status' => '200'}, + {'response_time' => 105, 'status' => '200'}, + {'response_time' => 112, 'status' => '400'}, + {'response_time' => 125, 'status' => '500'} + ]) + + driver.run + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..3c8a9ab --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,99 @@ +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +end diff --git a/test/plugin/out_statsd.rb b/test/plugin/out_statsd.rb deleted file mode 100644 index 566b77f..0000000 --- a/test/plugin/out_statsd.rb +++ /dev/null @@ -1,45 +0,0 @@ -require 'fluent/plugin/out_statsd' -require 'fluent/test' -require 'test/unit' - -class StatsdOutputTest < Test::Unit::TestCase - def setup - super - Fluent::Test.setup - @now = Time.now - end - - def treedown - end - - CONFIG = %{ - type statsd - - - statsd_type timing - statsd_key response_time - statsd_val ${record['response_time']} - - - - statsd_type increment - statsd_key response_code_${record['status'].to_i / 100}xx - - } - - def create_driver(conf = CONFIG) - Fluent::Test::BufferedOutputTestDriver.new(Fluent::StatsdOutput) { - }.configure(conf) - end - - def test_write - d = create_driver - time = Time.at(@now.to_i).utc - d.emit({'response_time' => 102, 'status' => '200'}, time) - d.emit({'response_time' => 105, 'status' => '200'}, time) - d.emit({'response_time' => 112, 'status' => '400'}, time) - d.emit({'response_time' => 125, 'status' => '500'}, time) - - d.run - end -end From 195b66b31232f4d91433bf28e9a3174a076ec46b Mon Sep 17 00:00:00 2001 From: "jiangzhi.xie" Date: Tue, 12 Jul 2016 19:41:12 +0800 Subject: [PATCH 5/5] Fix README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a1889e..34826f0 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ $ fluent-gem install fluent-plugin-statsd # Development ``` -$ rake test +$ rspec ``` # Copyright