chordate-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ .idea
2
+ .idea/*
3
+ /.bundle
4
+ *.rdb
5
+ Gemfile.lock
6
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ruby-1.9.3-p327@chordate-ruby --create
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Brian Norton
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a
4
+ copy of this software and associated documentation files (the "Software"),
5
+ to deal in the Software without restriction, including without limitation
6
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the
8
+ Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
+
20
+ The above License is for PERSONAL USE ONLY, when used in COMMERCIAL or CORPORATE
21
+ software release (YES EVEN FOR AN INTERNAL BOARDS AS INTENDED),
22
+ the COMM-LICENSE applies to that and all COMMERCIAL scenarios.
@@ -0,0 +1 @@
1
+ Official Ruby Gem for the Chordate Error Reporting Service.
@@ -0,0 +1,22 @@
1
+ require File.expand_path('../lib/chordate-ruby/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = %w(bnorton)
5
+ gem.email = 'brian.nort@gmail.com'
6
+ gem.summary = ''
7
+ gem.description = ''
8
+ gem.homepage = 'http://github.com/chordate/chordate-ruby'
9
+ gem.license = 'MIT'
10
+ gem.require_paths = %w(lib)
11
+
12
+ gem.version = Chordate::Version::STRING
13
+ gem.name = 'chordate-ruby'
14
+
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.test_files = `git ls-files -- spec/*`.split("\n")
17
+
18
+ gem.add_dependency 'typhoeus', '> 0.5.0'
19
+ gem.add_dependency 'celluloid'
20
+ gem.add_development_dependency 'rspec'
21
+ gem.add_development_dependency 'webmock'
22
+ end
@@ -0,0 +1,13 @@
1
+ require 'chordate-ruby/chordate'
2
+
3
+ ['typhoeus',
4
+ 'celluloid',
5
+ 'chordate-ruby/version',
6
+ 'chordate-ruby/http',
7
+ 'chordate-ruby/error',
8
+ 'chordate-ruby/runner',
9
+ ].each do |file|
10
+ require file
11
+ end
12
+
13
+ Celluloid.logger = nil
@@ -0,0 +1,45 @@
1
+ require 'chordate-ruby/config'
2
+ require 'chordate-ruby/runner/event'
3
+ require 'chordate-ruby/error'
4
+
5
+ module Chordate
6
+ class << self
7
+ def configure
8
+ (@config ||= Chordate::Config.new).tap do |config|
9
+ yield config
10
+ end
11
+ end
12
+
13
+ def config
14
+ @config
15
+ end
16
+
17
+ def run!
18
+ unless running?
19
+ (@event_runner ||= Runner::Event.new).tap do |runner|
20
+ runner.start
21
+ end
22
+
23
+ @running = true
24
+ end
25
+ end
26
+
27
+ def running?
28
+ !!@running
29
+ end
30
+
31
+ def error(*args)
32
+ @event_runner.async.push(
33
+ Chordate::Error.new(*args).as_json
34
+ )
35
+ end
36
+
37
+ private
38
+
39
+ def clear
40
+ @event_runner && @event_runner.terminate
41
+
42
+ @running = @event_runner = nil
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,43 @@
1
+ module Chordate
2
+ class Config
3
+ def initialize
4
+ @config = {
5
+ 'env' => rails(:env) || 'default',
6
+ 'proto' => 'https://',
7
+ 'host' => "chordate.io",
8
+ 'server' => {
9
+ :root => rails(:root) || `pwd`.chomp,
10
+ :hostname => `hostname`.chomp,
11
+ :gem_version => Chordate::Version::STRING
12
+ }
13
+ }
14
+ end
15
+
16
+ def [](key)
17
+ @config[key.to_s]
18
+ end
19
+
20
+ def token=(token)
21
+ token = token.split(':')
22
+
23
+ (@config['token'] = token[1]).tap do
24
+ @config['base_url'] ||= "/v1/applications/#{token[0]}"
25
+ end
26
+ end
27
+
28
+ def method_missing(meth, *args)
29
+ case meth
30
+ when /=$/
31
+ @config[meth.to_s[0..-2]] = args.first
32
+ else
33
+ @config[meth.to_s]
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def rails(method)
40
+ defined?(Rails) ? Rails.send(method).to_s : nil
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,30 @@
1
+ module Chordate
2
+ class Error
3
+ def initialize(*args)
4
+ @ex = args.shift
5
+
6
+ @json = {
7
+ :env => Chordate.config.env,
8
+ :generated_at => Time.now,
9
+ :klass => @ex.class.name,
10
+ :message => @ex.message,
11
+ :backtrace => @ex.backtrace,
12
+ :server => Chordate.config.server
13
+ }
14
+
15
+ merge!(args.shift)
16
+ end
17
+
18
+ def merge!(other)
19
+ other.each do |(k, v)|
20
+ v.nil? ? @json.delete(k) : @json[k] = v
21
+ end
22
+
23
+ self
24
+ end
25
+
26
+ def as_json(*)
27
+ @json
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ module Chordate
2
+ class HTTP
3
+ class << self
4
+ def post(path, body = {})
5
+ Typhoeus.post(url_for(path), :body => body.merge(:token => Chordate.config.token))
6
+ end
7
+
8
+ private
9
+
10
+ def url_for(path)
11
+ "#{Chordate.config.proto}#{Chordate.config.host}#{Chordate.config.base_url}/#{path}.json"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ require 'chordate-ruby/runner/event'
@@ -0,0 +1,40 @@
1
+ require 'celluloid'
2
+
3
+ module Chordate
4
+ module Runner
5
+ class Event
6
+ include Celluloid
7
+
8
+ attr_reader :errors
9
+
10
+ def initialize
11
+ @errors = []
12
+ @exit = false
13
+ end
14
+
15
+ def start
16
+ if errors.any?
17
+ HTTP.post(:events, :batch => errors)
18
+
19
+ @errors = []
20
+ end
21
+
22
+ return if exit?
23
+
24
+ after(5) { start }
25
+ end
26
+
27
+ def push(e)
28
+ @errors << e
29
+ end
30
+
31
+ def exit
32
+ @exit = true
33
+ end
34
+
35
+ def exit?
36
+ @exit
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,10 @@
1
+ module Chordate
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 0
6
+ BUILD = nil
7
+
8
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
9
+ end
10
+ end
@@ -0,0 +1,97 @@
1
+ require "spec_helper"
2
+
3
+ describe Chordate do
4
+ describe '.configure' do
5
+ it 'should yield a Config object' do
6
+ Chordate.configure {|c| c.class.should == Chordate::Config }
7
+ end
8
+
9
+ it 'should cache the object' do
10
+ configs = []
11
+ Chordate.configure {|c| configs << c }
12
+ Chordate.configure {|c| configs << c }
13
+
14
+ configs[0].should == configs[1]
15
+ end
16
+ end
17
+
18
+ describe '.config' do
19
+ before do
20
+ Chordate.configure {|c| c.foo = 'bar' }
21
+ end
22
+
23
+ it 'should be the config object' do
24
+ Chordate.config.class.should == Chordate::Config
25
+ end
26
+
27
+ it 'should have the options' do
28
+ Chordate.config.foo.should == 'bar'
29
+ end
30
+ end
31
+
32
+ describe '.run!' do
33
+ before do
34
+ @event_runner = mock(Chordate::Runner::Event, :start => nil, :terminate => nil)
35
+ Chordate::Runner::Event.stub(:new).and_return(@event_runner)
36
+ end
37
+
38
+ after do
39
+ Chordate.send(:clear)
40
+ end
41
+
42
+ it 'should build the runner' do
43
+ Chordate::Runner::Event.should_receive(:new).and_return(@event_runner)
44
+
45
+ Chordate.run!
46
+ end
47
+
48
+ it 'should start the runner' do
49
+ @event_runner.should_receive(:start)
50
+
51
+ Chordate.run!
52
+ end
53
+
54
+ it "should be running" do
55
+ Chordate.run!
56
+
57
+ Chordate.should be_running
58
+ end
59
+ end
60
+
61
+ describe '.error' do
62
+ let(:exception) { make_exception }
63
+ let(:options) { {} }
64
+
65
+ def error
66
+ Chordate.error(exception, options)
67
+ end
68
+
69
+ before do
70
+ @async = mock(Celluloid::ActorProxy, :push => nil)
71
+ @runner = mock(Chordate::Runner::Event, :start => nil, :async => @async, :terminate => nil)
72
+ Chordate::Runner::Event.stub(:new).and_return(@runner)
73
+
74
+ Chordate.run!
75
+
76
+ @json = mock("JSON")
77
+ @error = mock(Chordate::Error, :as_json => @json)
78
+ Chordate::Error.stub(:new).and_return(@error)
79
+ end
80
+
81
+ after do
82
+ Chordate.send(:clear)
83
+ end
84
+
85
+ it 'should init an error' do
86
+ Chordate::Error.should_receive(:new).with(exception, options).and_return(@error)
87
+
88
+ error
89
+ end
90
+
91
+ it 'should push the error to the runner' do
92
+ @async.should_receive(:push).with(@json)
93
+
94
+ error
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chordate::Config do
4
+ [[:a_key, '123:abcdef']].each do |(method, value)|
5
+ describe "##{method}" do
6
+ before do
7
+ subject.send("#{method}=", value)
8
+ end
9
+
10
+ it 'should store the given value' do
11
+ subject[method].should == value
12
+ end
13
+
14
+ it "should have the value at ##{method}" do
15
+ subject.send(method).should == value
16
+ end
17
+ end
18
+ end
19
+
20
+ describe '#token=' do
21
+ before do
22
+ subject.token = '789:the-token'
23
+ end
24
+
25
+ it 'should have the token' do
26
+ subject.token.should == 'the-token'
27
+ end
28
+
29
+ it 'should have the id in the base url' do
30
+ subject.base_url.should match(/applications\/789$/)
31
+ end
32
+ end
33
+
34
+ describe 'defaults' do
35
+ subject { Chordate.config }
36
+
37
+ it 'should have the gem version' do
38
+ subject.server[:gem_version].should == Chordate::Version::STRING
39
+ end
40
+
41
+ it 'should have the hostname' do
42
+ subject.server[:hostname].should == `hostname`.chomp
43
+ end
44
+
45
+ it 'should have the root' do
46
+ subject.server[:root].should == `pwd`.chomp
47
+ end
48
+
49
+ it 'should have the environment' do
50
+ subject.env.should == 'the-environment'
51
+ end
52
+
53
+ it 'should have the base_url' do
54
+ subject.base_url.should == '/v1/applications/123'
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chordate::Error do
4
+ describe '#as_json' do
5
+ let(:options) { {} }
6
+
7
+ describe "for an exception" do
8
+ let(:exception) { make_exception }
9
+
10
+ def json
11
+ Chordate::Error.new(exception, options).as_json
12
+ end
13
+
14
+ it 'should extract the error class' do
15
+ json[:klass].should == 'RuntimeError'
16
+ end
17
+
18
+ it 'should extract the error message' do
19
+ json[:message].should == 'BOOM!'
20
+ end
21
+
22
+ it 'should extract the error backtrace' do
23
+ json[:backtrace].should == exception.backtrace
24
+ end
25
+
26
+ describe 'server' do
27
+ it 'should have the gem version' do
28
+ json[:server][:gem_version].should == Chordate::Version::STRING
29
+ end
30
+
31
+ it 'should have the hostname' do
32
+ json[:server][:hostname].should == Chordate.config.server[:hostname]
33
+ end
34
+
35
+ it 'should have the app root' do
36
+ json[:server][:root].should == Chordate.config.server[:root]
37
+ end
38
+ end
39
+
40
+ describe 'when given options' do
41
+ before do
42
+ options[:extra] = { :data => 'attr' }
43
+ end
44
+
45
+ it 'should have the options' do
46
+ json[:extra][:data].should == 'attr'
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "merge!" do
53
+ let(:options) { { :key => 'value', :other => 3, :env => nil } }
54
+ let(:exception) { make_exception }
55
+
56
+ subject { Chordate::Error.new(exception, {}) }
57
+
58
+ def merge!
59
+ subject.merge!(options)
60
+ end
61
+
62
+ it 'should return itself' do
63
+ merge!.should == subject
64
+ end
65
+
66
+ it 'should add to the keys' do
67
+ merge!.as_json[:key].should == 'value'
68
+ merge!.as_json[:other].should == 3
69
+ end
70
+
71
+ it 'should remove keys with nil values' do
72
+ merge!.as_json.keys.should_not include(:env)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chordate::HTTP do
4
+ describe '.post' do
5
+ let(:body) { { :key => 'value' } }
6
+
7
+ def post
8
+ Chordate::HTTP.post(:something_special, body)
9
+ end
10
+
11
+ before do
12
+ Chordate::HTTP.rspec_reset
13
+ end
14
+
15
+ it 'should post to the given path' do
16
+ Typhoeus.should_receive(:post).with('https://chordate.io/v1/applications/123/something_special.json', anything)
17
+
18
+ post
19
+ end
20
+
21
+ it 'should pass the given body' do
22
+ Typhoeus.should_receive(:post) do |_, options|
23
+ options[:body][:key].should == 'value'
24
+ end
25
+
26
+ post
27
+ end
28
+
29
+ describe 'defaults' do
30
+ it 'should send the token' do
31
+ Typhoeus.should_receive(:post) do |_, options|
32
+ options[:body][:token].should == Chordate.config.token
33
+ end
34
+
35
+ post
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chordate::Runner::Event do
4
+ describe '#start' do
5
+ def start
6
+ subject.exit; subject.start
7
+ end
8
+
9
+ describe 'when there are waiting errors' do
10
+ let(:errors) do
11
+ [
12
+ { :klass => 'RuntimeError' },
13
+ { :klass => 'OtherError' }
14
+ ]
15
+ end
16
+
17
+ before do
18
+ subject.push(errors.first)
19
+ subject.push(errors.last)
20
+ end
21
+
22
+ it 'should have the errors' do
23
+ subject.errors.should == errors
24
+ end
25
+
26
+ it 'should post to events' do
27
+ Chordate::HTTP.should_receive(:post).with(:events, anything)
28
+
29
+ start
30
+ end
31
+
32
+ it 'should process the errors' do
33
+ Chordate::HTTP.should_receive(:post).with(anything, :batch => errors)
34
+
35
+ start
36
+ end
37
+
38
+ it 'should clear the errors' do
39
+ start
40
+
41
+ subject.errors.should == []
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,38 @@
1
+ require 'rspec'
2
+ require 'webmock'
3
+ require 'chordate-ruby'
4
+
5
+ RSpec.configure do |config|
6
+ config.treat_symbols_as_metadata_keys_with_true_values = true
7
+ config.run_all_when_everything_filtered = true
8
+
9
+ config.order = 'random'
10
+
11
+ config.before :all do
12
+ WebMock.disable_net_connect!
13
+ end
14
+
15
+ config.before :each do
16
+ Chordate::HTTP.stub(:post)
17
+ end
18
+ end
19
+
20
+ module Rails
21
+ def self.root
22
+ `pwd`.chomp
23
+ end
24
+
25
+ def self.env
26
+ 'the-environment'
27
+ end
28
+ end
29
+
30
+ Chordate.configure do |config|
31
+ config.token = '123:abcdef'
32
+ end
33
+
34
+ def make_exception(type = RuntimeError, message = 'BOOM!')
35
+ raise type.new message
36
+ rescue => e
37
+ e
38
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chordate-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - bnorton
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: typhoeus
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>'
20
+ - !ruby/object:Gem::Version
21
+ version: 0.5.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>'
28
+ - !ruby/object:Gem::Version
29
+ version: 0.5.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: celluloid
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: webmock
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: ''
79
+ email: brian.nort@gmail.com
80
+ executables: []
81
+ extensions: []
82
+ extra_rdoc_files: []
83
+ files:
84
+ - .gitignore
85
+ - .rspec
86
+ - .rvmrc
87
+ - Gemfile
88
+ - LICENSE.md
89
+ - README.md
90
+ - chordate-ruby.gemspec
91
+ - lib/chordate-ruby.rb
92
+ - lib/chordate-ruby/chordate.rb
93
+ - lib/chordate-ruby/config.rb
94
+ - lib/chordate-ruby/error.rb
95
+ - lib/chordate-ruby/http.rb
96
+ - lib/chordate-ruby/runner.rb
97
+ - lib/chordate-ruby/runner/event.rb
98
+ - lib/chordate-ruby/version.rb
99
+ - spec/lib/chordate_spec.rb
100
+ - spec/lib/config_spec.rb
101
+ - spec/lib/error_spec.rb
102
+ - spec/lib/http_spec.rb
103
+ - spec/lib/runner/event_spec.rb
104
+ - spec/spec_helper.rb
105
+ homepage: http://github.com/chordate/chordate-ruby
106
+ licenses:
107
+ - MIT
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 1.8.25
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: ''
130
+ test_files:
131
+ - spec/lib/chordate_spec.rb
132
+ - spec/lib/config_spec.rb
133
+ - spec/lib/error_spec.rb
134
+ - spec/lib/http_spec.rb
135
+ - spec/lib/runner/event_spec.rb
136
+ - spec/spec_helper.rb