yeller_ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 69148c3deef072819ef088784bbab18ba78499ff
4
+ data.tar.gz: dcb6d17d8c297cc968ea8915f562200498af1003
5
+ SHA512:
6
+ metadata.gz: 1a5e13ea29a5fb9b3385f50201fe2776d8ca105b5f75ce4b0a589e176a24e339c21caa0015330bf7215e1a1ef9f4618a5ee39749efc3308cc5efd45b1aa1cd90
7
+ data.tar.gz: a63d64093d5e56edc5b773829e1024edc835fac1341bd213991c78b393323e9f65e8bb92e08cad52198b548b6b9d907f4c2cb7acd2bb1ecdd6462e69ef9bd63e
@@ -0,0 +1,43 @@
1
+ module Yeller
2
+ class Client
3
+ def initialize(servers, token, startup_params, error_handler)
4
+ @servers = servers
5
+ @last_server = rand(servers.size)
6
+ @startup_params = startup_params
7
+ @token = token
8
+ @error_handler = error_handler
9
+ end
10
+
11
+ def report(exception, options={})
12
+ hash = ExceptionFormatter.format(exception, options)
13
+ serialized = JSON.dump(@startup_params.merge(hash))
14
+ report_with_roundtrip(serialized, 0)
15
+ end
16
+
17
+ def report_with_roundtrip(serialized, error_count)
18
+ next_server.client.post("/#{@token}", serialized, {"Content-Type" => "application/json"})
19
+ rescue StandardError => e
20
+ if error_count <= (@servers.size * 2)
21
+ report_with_roundtrip(serialized, error_count + 1)
22
+ else
23
+ @error_handler.handle(e)
24
+ end
25
+ end
26
+
27
+ def record_deploy(revision, user, environment)
28
+ post = Net::HTTP::Post.new("/#{@token}/deploys")
29
+ post.set_form_data('revision' => revision,
30
+ 'user' => user,
31
+ 'environment' => environment)
32
+ next_server.client.request(post)
33
+ end
34
+
35
+ private
36
+
37
+ def next_server
38
+ index = @last_server
39
+ @last_server = (index + 1) % @servers.size
40
+ @servers[index]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,65 @@
1
+ require_relative 'server'
2
+
3
+ module Yeller
4
+ class Configuration
5
+ DEFAULT_SERVERS = [
6
+ Yeller::SecureServer.new("collector1.yellerapp.com", 443),
7
+ Yeller::SecureServer.new("collector2.yellerapp.com", 443),
8
+ Yeller::SecureServer.new("collector3.yellerapp.com", 443),
9
+ Yeller::SecureServer.new("collector4.yellerapp.com", 443),
10
+ Yeller::SecureServer.new("collector5.yellerapp.com", 443),
11
+ ]
12
+
13
+ def initialize
14
+ @servers = DEFAULT_SERVERS
15
+ @startup_params = {}
16
+ @error_handler = Yeller::LogErrorHandler.new
17
+ end
18
+
19
+ def remove_default_servers
20
+ @servers = []
21
+ self
22
+ end
23
+
24
+ def add_server(host, port=443)
25
+ @servers << Yeller::SecureServer.new(host, port)
26
+ self
27
+ end
28
+
29
+ def add_insecure_server(host, port=80)
30
+ @servers << Yeller::Server.new(host, port)
31
+ end
32
+
33
+ def environment=(new_environment)
34
+ @startup_params[:"application-environment"] = new_environment
35
+ end
36
+
37
+ def host=(new_host)
38
+ @startup_params[:host] = new_host
39
+ end
40
+
41
+ def token=(token)
42
+ @token = token
43
+ end
44
+
45
+ def token
46
+ @token
47
+ end
48
+
49
+ def servers
50
+ @servers
51
+ end
52
+
53
+ def startup_params
54
+ @startup_params
55
+ end
56
+
57
+ def error_handler
58
+ @error_handler
59
+ end
60
+
61
+ def error_handler=(new_error_handler)
62
+ @error_handler = new_error_handler
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,44 @@
1
+ module Yeller
2
+ class ExceptionFormatter
3
+ BACKTRACE_FORMAT = %r{^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$}.freeze
4
+
5
+ def self.format(exception, options={})
6
+ new(exception, options).to_hash
7
+ end
8
+
9
+ attr_reader :type, :options
10
+
11
+ def initialize(exception, options)
12
+ @type = exception.class.name
13
+ @message = exception.message
14
+ @backtrace = exception.backtrace
15
+ @options = options
16
+ end
17
+
18
+ def message
19
+ # If a message is not given, rubby will set message to the class name
20
+ @message == type ? nil : @message
21
+ end
22
+
23
+ def formatted_backtrace
24
+ return [] unless @backtrace
25
+
26
+ @backtrace.map do |line|
27
+ _, file, number, method = line.match(BACKTRACE_FORMAT).to_a
28
+ [file, number, method]
29
+ end
30
+ end
31
+
32
+ def to_hash
33
+ result = {
34
+ message: message,
35
+ stacktrace: formatted_backtrace,
36
+ type: type,
37
+ :"custom-data" => options.fetch(:custom_data, {})
38
+ }
39
+ result[:url] = options[:url] if options.key?(:url)
40
+ result[:location] = options[:location] if options.key?(:location)
41
+ result
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,12 @@
1
+ require 'logger'
2
+ module Yeller
3
+ class LogErrorHandler
4
+ def initialize(logger=Logger.new(STDERR))
5
+ @logger = logger
6
+ end
7
+
8
+ def handle(e)
9
+ @logger.warn(e)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,40 @@
1
+ require 'rack/request'
2
+ require_relative '../yeller'
3
+
4
+ module Yeller
5
+ class Rack
6
+ def self.configure(&block)
7
+ @client = Yeller.client(&block)
8
+ end
9
+
10
+ def self.report(exception, options={})
11
+ @client.report(exception, options)
12
+ end
13
+
14
+ def initialize(app)
15
+ @app = app
16
+ end
17
+
18
+ def call(env)
19
+ begin
20
+ @app.call(env)
21
+ rescue Exception => exception
22
+ Yeller::Rack.rescue_rack_exception(exception, env)
23
+ raise exception
24
+ end
25
+ end
26
+
27
+ def self.rescue_rack_exception(exception, env)
28
+ ::Rails.logger.info("sending exception to yeller")
29
+ request = ::Rack::Request.new(env)
30
+ Yeller::Rack.report(
31
+ exception,
32
+ :url => request.url,
33
+ :custom_data => {
34
+ :params => request.params,
35
+ :session => env.fetch('rack.session', {}),
36
+ })
37
+ ::Rails.logger.info("sent exception to yeller")
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,49 @@
1
+ require 'rails'
2
+ require 'yeller'
3
+ require 'yeller/rack'
4
+
5
+ module Yeller
6
+ class Rails
7
+ def self.configure(&block)
8
+ Yeller::Rack.configure do |config|
9
+ config.error_handler = Yeller::LogErrorHandler.new(::Rails.logger)
10
+ block.call(config)
11
+ end
12
+ end
13
+
14
+ module ActionControllerCatchingHooks
15
+ def self.included(base)
16
+ base.send(:alias_method, :render_exception_without_yeller, :render_exception)
17
+ base.send(:alias_method, :render_exception, :render_exception_with_yeller)
18
+ end
19
+
20
+ protected
21
+ def render_exception_with_yeller(env, exception)
22
+ ::Rails.logger.info("yeller: caught exception")
23
+ Yeller::Rack.rescue_rack_exception(exception, env)
24
+ render_exception_without_yeller(env, exception)
25
+ rescue Exception => e
26
+ ::Rails.logger.info("exception whilst handling exception: #{e} #{e.class} #{e.backtrace.join("\n")}")
27
+ end
28
+ end
29
+
30
+ class Railtie < ::Rails::Railtie
31
+ initializer "yeller.use_rack_middleware" do |app|
32
+ app.config.middleware.insert 0, "Yeller::Rack"
33
+ end
34
+
35
+ initializer "yeller.action_controller" do
36
+ ActiveSupport.on_load :action_controller do
37
+ end
38
+ end
39
+
40
+ config.after_initialize do
41
+ if defined?(::ActionDispatch::DebugExceptions)
42
+ ::ActionDispatch::DebugExceptions.send(:include, Yeller::Rails::ActionControllerCatchingHooks)
43
+ elsif defined(::ActionDispatch::ShowExceptions)
44
+ ::ActionDispatch::ShowExceptions.send(:include, Yeller::Rails::ActionControllerCatchingHooks)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,22 @@
1
+ require 'openssl'
2
+ module Yeller
3
+ Server = Struct.new(:host, :port) do
4
+ def client
5
+ @client ||= Net::HTTP.new(host, port)
6
+ end
7
+ end
8
+
9
+ SecureServer = Struct.new(:host, :port) do
10
+ def client
11
+ @client ||= setup_client
12
+ end
13
+
14
+ def setup_client
15
+ http = Net::HTTP.new(host, port)
16
+ http.use_ssl = true
17
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
18
+ http.ciphers = "DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2"
19
+ http
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'version'
2
+
3
+ module Yeller
4
+ class StartupParams
5
+ PRODUCTION = 'production'.freeze
6
+ VERSION = "yeller_rubby: #{Yeller::VERSION}"
7
+
8
+ def self.defaults(options={})
9
+ {
10
+ :host => Socket.gethostname,
11
+ :"application-environment" => application_environment(options),
12
+ :"client-version" => VERSION,
13
+ }
14
+ end
15
+
16
+ def self.application_environment(options)
17
+ options[:"application-environment"] ||
18
+ ENV['RAILS_ENV'] ||
19
+ ENV['RACK_ENV'] ||
20
+ PRODUCTION
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module Yeller
2
+ VERSION = "0.0.1"
3
+ end
data/lib/yeller.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'net/http'
2
+ require 'yajl/json_gem'
3
+
4
+ require_relative 'yeller/client'
5
+ require_relative 'yeller/configuration'
6
+ require_relative 'yeller/exception_formatter'
7
+ require_relative 'yeller/server'
8
+ require_relative 'yeller/version'
9
+ require_relative 'yeller/startup_params'
10
+ require_relative 'yeller/log_error_handler'
11
+
12
+ module Yeller
13
+ def self.client(&block)
14
+ config = Yeller::Configuration.new
15
+ block.call(config)
16
+ build_client(config)
17
+ end
18
+
19
+ def self.build_client(config)
20
+ Yeller::Client.new(
21
+ config.servers,
22
+ config.token,
23
+ Yeller::StartupParams.defaults(config.startup_params),
24
+ config.error_handler
25
+ )
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yeller_ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tom Crayford
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yajl-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.2.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.2.0
55
+ description: A Ruby/Rack/Rails client for yellerapp.com
56
+ email:
57
+ - tcrayford@googlemail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - lib/yeller.rb
63
+ - lib/yeller/client.rb
64
+ - lib/yeller/configuration.rb
65
+ - lib/yeller/exception_formatter.rb
66
+ - lib/yeller/log_error_handler.rb
67
+ - lib/yeller/rack.rb
68
+ - lib/yeller/rails.rb
69
+ - lib/yeller/server.rb
70
+ - lib/yeller/startup_params.rb
71
+ - lib/yeller/version.rb
72
+ homepage: https://github.com/tcrayford/yeller_rubby
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.2.0
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: A Ruby/Rack/Rails client for yellerapp.com
96
+ test_files: []