regrapher 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0c6c54892db698ad0b8d1befa73224f9f6c115c2
4
+ data.tar.gz: 9cb429ea5c0c2660a5ee5107265b238d83e656ed
5
+ SHA512:
6
+ metadata.gz: c367ec86a1f35b7a0d2e1624dd99faa07ff1ed2a37e7a86c117242d89b4ff33244b0928e03e24bb3a64d49c186996d7a46bcc48cd62ec893666f02e869b7f956
7
+ data.tar.gz: 71f591c3db855bfa594e693e8248df7ed18939fcfec637f8d8bed2bd4f7f6dac68de51389c76a1a59e2b49a77781d895074344e02bd12837764ffb121fe7eb8b
data/README.md ADDED
@@ -0,0 +1,5 @@
1
+ Regrapher Ruby Logger
2
+ ======================
3
+
4
+ Provides convenience logger to print events and metric values in the Regrapher format.
5
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,111 @@
1
+ require 'json'
2
+ require 'securerandom'
3
+
4
+ module Regrapher
5
+ # Examples:
6
+ # client.increment 'page.views'
7
+ # client.gauge 'users.online', 100.43
8
+ # client.event 'clients.sign_ups', :title=>'Premium Package Sold', :text=>'Hurray !'
9
+ class Client
10
+ # A namespace to prepend to all statsd calls. Defaults to no namespace.
11
+ attr_reader :namespace
12
+
13
+ # Global tags to be added to every statsd call. Defaults to no tags.
14
+ attr_reader :tags
15
+
16
+ # Output stream used to log metrics and event data. Defaults to STDOUT.
17
+ attr_reader :output_stream
18
+
19
+ # @param [Hash] opts
20
+ # @option opts [String] :namespace set a namespace to be prepended to every metric name
21
+ # @option opts [Array<String>] :tags tags to be added to every metric
22
+ # @option opts :output_stream an object with a puts method that takes accepts a string parameter
23
+ def initialize(opts = {})
24
+ @namespace = opts[:namespace]
25
+ @tags = opts.fetch(:tags, []).uniq
26
+ @output_stream = opts.fetch(:output_stream, STDOUT)
27
+ end
28
+
29
+ # Sends an increment (count = 1) for the given metric.
30
+ #
31
+ # @param [String] name metric name
32
+ # @param [Hash] opts the options to create the metric with
33
+ # @option opts [Numeric] :sample_rate sample rate, 1 for always
34
+ # @option opts [Array<String>] :tags An array of tags
35
+ # @see #count
36
+ def increment(name, opts={})
37
+ count(name, 1, opts)
38
+ end
39
+
40
+ # Sends a decrement (count = -1) for the given metric.
41
+ #
42
+ # @param [String] name metric name
43
+ # @param [Hash] opts the options to create the metric with
44
+ # @option opts [Numeric] :sample_rate sample rate, 1 for always
45
+ # @option opts [Array<String>] :tags An array of tags
46
+ # @see #count
47
+ def decrement(name, opts={})
48
+ count(name, -1, opts)
49
+ end
50
+
51
+ # Sends an arbitrary count for the given metric.
52
+ #
53
+ # @param [String] name metric name
54
+ # @param [Integer] count count
55
+ # @param [Hash] opts the options to create the metric with
56
+ # @option opts [Numeric] :sample_rate sample rate, 1 for always
57
+ # @option opts [Array<String>] :tags An array of tags
58
+ def count(name, count, opts={})
59
+ send_metric('c', name, count, opts)
60
+ end
61
+
62
+ # Sends an arbitrary gauge value for the given metric.
63
+ #
64
+ # This is useful for recording things like available disk space,
65
+ # memory usage, and the like, which have different semantics than
66
+ # counters.
67
+ #
68
+ # @param [String] name metric name.
69
+ # @param [Numeric] value gauge value.
70
+ # @param [Hash] opts the options to create the metric with
71
+ # @option opts [Numeric] :sample_rate sample rate, 1 for always
72
+ # @option opts [Array<String>] :tags An array of tags
73
+ # @example Report the current user count:
74
+ # client.gauge('user.count', User.count)
75
+ def gauge(name, value, opts={})
76
+ send_metric('g', name, value, opts)
77
+ end
78
+
79
+ # Sends events to the stream of events.
80
+ #
81
+ # @param [String] name metric name.
82
+ # @param [Hash] value the event value. Should contain a title and text. Could contain any other custom data.
83
+ # @option value[String] :title Event title.
84
+ # @option value [String, nil] :text Event text. Supports +\n+.
85
+ # @param [Hash] opts the additional data about the event
86
+ # @option opts [Array<String>] :tags tags to be added to every metric
87
+ # @example Report an event:
88
+ # client.event('clients.sign_ups', {:title=>'New VIP Client', text=>'Hurray !',
89
+ # :data=>{:name=>'Doe',:photo=>'http://example.com/12.jpg'}}, :tags=>['region:US_CAL','payment:paypal'])
90
+ def event(name, value, opts={})
91
+ send_metric('e', name, value, opts)
92
+ end
93
+
94
+ private
95
+
96
+ def send_metric(type, name, value, opts={})
97
+ sample_rate = opts.fetch(:sample_rate, 1)
98
+ return unless sample_rate >= 1 || rand < sample_rate
99
+ name = "#{namespace}.#{name}" if namespace
100
+ obj = opts.merge(:type => type,
101
+ :name => name,
102
+ :value => value,
103
+ :ts => Time.now.to_i,
104
+ :id => SecureRandom.uuid)
105
+ tags = (opts[:tags] || []) | self.tags
106
+ obj.merge!(:tags => tags) unless tags.empty?
107
+ obj_json = JSON::generate(obj)
108
+ output_stream.puts "[regrapher][#{obj_json.length}]#{obj_json}"
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,16 @@
1
+ module Regrapher
2
+ class Parser
3
+ LINE_REGEX = /^\[regrapher\]\[(\d+)\](.+)$/
4
+
5
+ def parse(line)
6
+ _, length, rest = line.match(LINE_REGEX).to_a
7
+ if length && rest && rest.length >= 2 && (length=length.to_i) <= rest.length
8
+ begin
9
+ JSON.parse rest[0, length], symbolize_names: true
10
+ rescue JSON::ParserError
11
+ # mute exception
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module Regrapher
2
+ VERSION = '0.1.0'
3
+ end
data/lib/regrapher.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'regrapher/client'
2
+
3
+ module Regrapher
4
+
5
+ class << self
6
+
7
+ def client=(client)
8
+ @client = client
9
+ end
10
+
11
+ def client
12
+ @client ||= Client.new(options)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Regrapher::Client do
4
+
5
+ LINE_REGEX = /^\[regrapher\]\[(\d+)\](.*)$/
6
+
7
+ let(:output_stream) { StringIO.new }
8
+
9
+ let(:client) { Regrapher::Client.new(output_stream: output_stream) }
10
+
11
+ let(:string) { output_stream.string }
12
+
13
+ {
14
+ gauge: ['basket.value', 34.2],
15
+ increment: ['users.count'],
16
+ decrement: ['users.count'],
17
+ count: ['users.count', -55],
18
+ event: ['users.sign_up', { name: 'John', company: 'Acme Corp' }]
19
+ }.each do |method, params|
20
+ context "##{method}" do
21
+
22
+ it 'has a "[regrapher][<length>]" prefix' do
23
+ client.send method, *params
24
+ expect(string).to match(LINE_REGEX)
25
+ _, length, json = string.match(LINE_REGEX).to_a
26
+ expect(json.length).to eq(length.to_i)
27
+ end
28
+
29
+ it '<length> equals the json length' do
30
+ client.send method, *params
31
+ _, length, json = string.match(LINE_REGEX).to_a
32
+ expect(json.length).to eq(length.to_i)
33
+ end
34
+ end
35
+ end
36
+ end
data/spec/examples.txt ADDED
@@ -0,0 +1,12 @@
1
+ example_id | status | run_time |
2
+ ---------------------------- | ------ | --------------- |
3
+ ./spec/client_spec.rb[1:1:1] | passed | 0.00011 seconds |
4
+ ./spec/client_spec.rb[1:1:2] | passed | 0.00013 seconds |
5
+ ./spec/client_spec.rb[1:2:1] | passed | 0.00013 seconds |
6
+ ./spec/client_spec.rb[1:2:2] | passed | 0.00015 seconds |
7
+ ./spec/client_spec.rb[1:3:1] | passed | 0.00254 seconds |
8
+ ./spec/client_spec.rb[1:3:2] | passed | 0.00019 seconds |
9
+ ./spec/client_spec.rb[1:4:1] | passed | 0.0002 seconds |
10
+ ./spec/client_spec.rb[1:4:2] | passed | 0.00017 seconds |
11
+ ./spec/client_spec.rb[1:5:1] | passed | 0.00017 seconds |
12
+ ./spec/client_spec.rb[1:5:2] | passed | 0.00018 seconds |
@@ -0,0 +1,77 @@
1
+ require 'regrapher'
2
+ RSpec.configure do |config|
3
+ # rspec-expectations config goes here. You can use an alternate
4
+ # assertion/expectation library such as wrong or the stdlib/minitest
5
+ # assertions if you prefer.
6
+ config.expect_with :rspec do |expectations|
7
+ # This option will default to `true` in RSpec 4. It makes the `description`
8
+ # and `failure_message` of custom matchers include text for helper methods
9
+ # defined using `chain`, e.g.:
10
+ # be_bigger_than(2).and_smaller_than(4).description
11
+ # # => "be bigger than 2 and smaller than 4"
12
+ # ...rather than:
13
+ # # => "be bigger than 2"
14
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
15
+ end
16
+
17
+ # rspec-mocks config goes here. You can use an alternate test double
18
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
19
+ config.mock_with :rspec do |mocks|
20
+ # Prevents you from mocking or stubbing a method that does not exist on
21
+ # a real object. This is generally recommended, and will default to
22
+ # `true` in RSpec 4.
23
+ mocks.verify_partial_doubles = true
24
+ end
25
+
26
+ # The settings below are suggested to provide a good initial experience
27
+ # with RSpec, but feel free to customize to your heart's content.
28
+ # These two settings work together to allow you to limit a spec run
29
+ # to individual examples or groups you care about by tagging them with
30
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
31
+ # get run.
32
+ config.filter_run :focus
33
+ config.run_all_when_everything_filtered = true
34
+
35
+ # Allows RSpec to persist some state between runs in order to support
36
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
37
+ # you configure your source control system to ignore this file.
38
+ config.example_status_persistence_file_path = 'spec/examples.txt'
39
+
40
+ # Limits the available syntax to the non-monkey patched syntax that is
41
+ # recommended. For more details, see:
42
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
43
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
44
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
45
+ config.disable_monkey_patching!
46
+
47
+ # This setting enables warnings. It's recommended, but in some cases may
48
+ # be too noisy due to issues in dependencies.
49
+ config.warnings = true
50
+
51
+ # Many RSpec users commonly either run the entire suite or an individual
52
+ # file, and it's useful to allow more verbose output when running an
53
+ # individual spec file.
54
+ if config.files_to_run.one?
55
+ # Use the documentation formatter for detailed output,
56
+ # unless a formatter has already been configured
57
+ # (e.g. via a command-line flag).
58
+ config.default_formatter = 'doc'
59
+ end
60
+
61
+ # Print the 10 slowest examples and example groups at the
62
+ # end of the spec run, to help surface which specs are running
63
+ # particularly slow.
64
+ config.profile_examples = 10
65
+
66
+ # Run specs in random order to surface order dependencies. If you find an
67
+ # order dependency and want to debug it, you can fix the order by providing
68
+ # the seed, which is printed after each run.
69
+ # --seed 1234
70
+ config.order = :random
71
+
72
+ # Seed global randomization in this process using the `--seed` CLI option.
73
+ # Setting this allows you to use `--seed` to deterministically reproduce
74
+ # test failures related to randomization by passing the same `--seed` value
75
+ # as the one that triggered the failure.
76
+ Kernel.srand config.seed
77
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: regrapher
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ramzi Ben Salah
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '11.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '11.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.4'
41
+ description: Provides convenience logger to format events and metric values in the
42
+ regrapher format
43
+ email:
44
+ - ramzi.salah@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - README.md
50
+ - Rakefile
51
+ - lib/regrapher.rb
52
+ - lib/regrapher/client.rb
53
+ - lib/regrapher/parser.rb
54
+ - lib/regrapher/version.rb
55
+ - spec/client_spec.rb
56
+ - spec/examples.txt
57
+ - spec/spec_helper.rb
58
+ homepage: http://github.com/regrapher/regrapher
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options:
64
+ - "--charset=UTF-8"
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: 1.9.3
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.4.8
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Regrapher logger for ruby
83
+ test_files:
84
+ - spec/client_spec.rb
85
+ - spec/examples.txt
86
+ - spec/spec_helper.rb
87
+ has_rdoc: