appsignal 0.4.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.
Files changed (59) hide show
  1. data/.gitignore +19 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +30 -0
  4. data/Gemfile +3 -0
  5. data/LICENCE +20 -0
  6. data/README.md +48 -0
  7. data/Rakefile +52 -0
  8. data/appsignal.gemspec +33 -0
  9. data/bin/appsignal +13 -0
  10. data/config/appsignal.yml +8 -0
  11. data/gemfiles/3.0.gemfile +16 -0
  12. data/gemfiles/3.1.gemfile +16 -0
  13. data/gemfiles/3.2.gemfile +16 -0
  14. data/gemfiles/edge.gemfile +16 -0
  15. data/lib/appsignal.rb +45 -0
  16. data/lib/appsignal/agent.rb +104 -0
  17. data/lib/appsignal/auth_check.rb +19 -0
  18. data/lib/appsignal/capistrano.rb +41 -0
  19. data/lib/appsignal/cli.rb +118 -0
  20. data/lib/appsignal/config.rb +30 -0
  21. data/lib/appsignal/exception_notification.rb +25 -0
  22. data/lib/appsignal/marker.rb +35 -0
  23. data/lib/appsignal/middleware.rb +30 -0
  24. data/lib/appsignal/railtie.rb +19 -0
  25. data/lib/appsignal/transaction.rb +77 -0
  26. data/lib/appsignal/transaction/faulty_request_formatter.rb +30 -0
  27. data/lib/appsignal/transaction/params_sanitizer.rb +36 -0
  28. data/lib/appsignal/transaction/regular_request_formatter.rb +11 -0
  29. data/lib/appsignal/transaction/slow_request_formatter.rb +34 -0
  30. data/lib/appsignal/transaction/transaction_formatter.rb +93 -0
  31. data/lib/appsignal/transmitter.rb +53 -0
  32. data/lib/appsignal/version.rb +3 -0
  33. data/lib/generators/appsignal/USAGE +8 -0
  34. data/lib/generators/appsignal/appsignal_generator.rb +70 -0
  35. data/lib/generators/appsignal/templates/appsignal.yml +4 -0
  36. data/log/.gitkeep +0 -0
  37. data/resources/cacert.pem +3849 -0
  38. data/spec/appsignal/agent_spec.rb +259 -0
  39. data/spec/appsignal/auth_check_spec.rb +36 -0
  40. data/spec/appsignal/capistrano_spec.rb +81 -0
  41. data/spec/appsignal/cli_spec.rb +124 -0
  42. data/spec/appsignal/config_spec.rb +40 -0
  43. data/spec/appsignal/exception_notification_spec.rb +12 -0
  44. data/spec/appsignal/inactive_railtie_spec.rb +30 -0
  45. data/spec/appsignal/marker_spec.rb +83 -0
  46. data/spec/appsignal/middleware_spec.rb +73 -0
  47. data/spec/appsignal/railtie_spec.rb +54 -0
  48. data/spec/appsignal/transaction/faulty_request_formatter_spec.rb +49 -0
  49. data/spec/appsignal/transaction/params_sanitizer_spec.rb +68 -0
  50. data/spec/appsignal/transaction/regular_request_formatter_spec.rb +14 -0
  51. data/spec/appsignal/transaction/slow_request_formatter_spec.rb +76 -0
  52. data/spec/appsignal/transaction/transaction_formatter_spec.rb +178 -0
  53. data/spec/appsignal/transaction_spec.rb +191 -0
  54. data/spec/appsignal/transmitter_spec.rb +64 -0
  55. data/spec/appsignal_spec.rb +66 -0
  56. data/spec/generators/appsignal/appsignal_generator_spec.rb +222 -0
  57. data/spec/spec_helper.rb +85 -0
  58. data/spec/support/delegate_matcher.rb +39 -0
  59. metadata +247 -0
@@ -0,0 +1,19 @@
1
+ *.rbc
2
+ *.sassc
3
+ .sass-cache
4
+ capybara-*.html
5
+ .rspec
6
+ /log/*.log
7
+ /.bundle
8
+ /vendor/bundle
9
+ /tmp/*
10
+ /db/*.sqlite3
11
+ /public/system/*
12
+ /coverage/
13
+ /spec/tmp/*
14
+ **.orig
15
+ rerun.txt
16
+ pickle-email-*.html
17
+ *.gem
18
+ Gemfile.lock
19
+ .DS_Store
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3
@@ -0,0 +1,30 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ # - 1.9.2
5
+ - 1.9.3
6
+ - 1.8.7
7
+ - ree
8
+ # - ruby-head
9
+ # - jruby-18mode
10
+ - jruby-19mode
11
+ # - jruby-head
12
+
13
+ gemfile:
14
+ - gemfiles/3.0.gemfile
15
+ - gemfiles/3.1.gemfile
16
+ - gemfiles/3.2.gemfile
17
+ - gemfiles/edge.gemfile
18
+
19
+ matrix:
20
+ exclude:
21
+ - rvm: 1.8.7
22
+ gemfile: gemfiles/edge.gemfile
23
+ allow_failures:
24
+ - gemfile: gemfiles/edge.gemfile
25
+
26
+ script: RAILS_ENV=test bundle exec rspec spec
27
+
28
+ notifications:
29
+ campfire: 80beans:d43f43244263cafb088182aa79e7d96419da0372@188927
30
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENCE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 80beans
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,48 @@
1
+ appsignal
2
+ =================
3
+
4
+
5
+ ## Pull requests / issues
6
+
7
+ New features should be made in an issue or pullrequest. Title format is as follows:
8
+
9
+
10
+ name [request_count]
11
+
12
+ example
13
+
14
+ tagging [2]
15
+
16
+ ## Event payload sanitizer
17
+ Appsignal logs Rails
18
+ [ActiveSupport::Notification](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html)-events
19
+ to appsignal.com over SSL. These events contain basic metadata such as a name
20
+ and timestamps, and additional 'payload' log data. By default,
21
+ appsignal will transmit all payload data. If you want to restrict the amount of
22
+ payload data that gets sent to <https://appsignal.com>, you can define your own
23
+ event payload sanitizer in `config/environment/my_env.rb`. The
24
+ `event_payload_sanitizer` needs to be a callable object that returns a
25
+ JSON-serializable hash.
26
+
27
+ ### Examples
28
+
29
+ #### Pass through the entire payload unmodified (default)
30
+ ```ruby
31
+ Appsignal.event_payload_sanitizer = proc { |event| event.payload }
32
+ ```
33
+
34
+ #### Delete the entire event payload
35
+ ```ruby
36
+ Appsignal.event_payload_sanitizer = proc { {} }
37
+ ```
38
+
39
+ #### Conditional modification of the payload
40
+ ```ruby
41
+ Appsignal.event_payload_sanitizer = proc do |event|
42
+ if event.name == 'interesting'
43
+ event.payload
44
+ else
45
+ {}
46
+ end
47
+ end
48
+ ```
@@ -0,0 +1,52 @@
1
+ task :publish do
2
+ NAME = 'appsignal'
3
+ VERSION_FILE = 'lib/appsignal/version.rb'
4
+
5
+ raise '$EDITOR should be set' unless ENV['EDITOR']
6
+
7
+ def build_and_push_gem
8
+ puts '# Building gem'
9
+ puts `gem build #{NAME}.gemspec`
10
+ puts '# Publishing Gem'
11
+ puts `gem push #{NAME}-#{gem_version}.gem`
12
+ end
13
+
14
+ def create_and_push_tag
15
+ begin
16
+ puts `git commit -am 'Bump to #{version} [ci skip]'`
17
+ puts "# Creating tag #{version}"
18
+ puts `git tag #{version}`
19
+ puts `git push origin #{version}`
20
+ puts `git push origin master`
21
+ rescue
22
+ raise "Tag: '#{version}' already exists"
23
+ end
24
+ end
25
+
26
+ def changes
27
+ git_status_to_array(`git status -s -u `)
28
+ end
29
+
30
+ def gem_version
31
+ Appsignal::VERSION
32
+ end
33
+
34
+ def version
35
+ @version ||= 'v' << gem_version
36
+ end
37
+
38
+ def git_status_to_array(changes)
39
+ changes.split("\n").each { |change| change.gsub!(/^.. /,'') }
40
+ end
41
+
42
+ raise "Branch should hold no uncommitted file change)" unless changes.empty?
43
+
44
+ system("$EDITOR #{VERSION_FILE}")
45
+ if changes.member?(VERSION_FILE)
46
+ load File.expand_path(VERSION_FILE)
47
+ build_and_push_gem
48
+ create_and_push_tag
49
+ else
50
+ raise "Actually change the version in: #{VERSION_FILE}"
51
+ end
52
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/appsignal/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = [
6
+ 'Robert Beekman',
7
+ 'Steven Weller',
8
+ 'Thijs Cadier',
9
+ 'Ron Cadier',
10
+ 'Jacob Vosmaer'
11
+ ]
12
+ gem.email = ['contact@appsignal.com']
13
+ gem.description = 'The official appsignal.com gem'
14
+ gem.summary = 'Logs performance and exception data from your app to'\
15
+ 'appsignal.com'
16
+ gem.homepage = 'http://github.com/80beans/appsignal'
17
+
18
+ gem.files = `git ls-files`.split($\)
19
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
+ gem.name = 'appsignal'
22
+ gem.require_paths = ['lib']
23
+ gem.version = Appsignal::VERSION
24
+
25
+ gem.add_dependency 'rails', '~>3'
26
+ gem.add_dependency 'rake'
27
+ gem.add_dependency 'json'
28
+ gem.add_dependency 'rack'
29
+
30
+ gem.add_development_dependency 'rspec'
31
+ gem.add_development_dependency 'capistrano'
32
+ gem.add_development_dependency 'generator_spec'
33
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..','lib'))
4
+ require 'appsignal/cli'
5
+
6
+ begin
7
+ Appsignal::CLI.run
8
+ rescue => e
9
+ raise e if $DEBUG
10
+ STDERR.puts e.message
11
+ STDERR.puts e.backtrace.join("\n")
12
+ exit 1
13
+ end
@@ -0,0 +1,8 @@
1
+ development: &development
2
+ endpoint: "http://localhost:3000/1"
3
+ api_key: "abc"
4
+ active: true
5
+ production:
6
+ <<: *development
7
+ test:
8
+ <<: *development
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ source :rubygems
3
+
4
+ gem 'rails', '~> 3.0.17'
5
+ gem 'rspec'
6
+ gem 'rake'
7
+ gem 'json'
8
+
9
+ group :development, :test do
10
+ gem 'capistrano'
11
+ gem 'generator_spec'
12
+ end
13
+
14
+ platforms :jruby do
15
+ gem 'jruby-openssl'
16
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ source :rubygems
3
+
4
+ gem 'rails', '~> 3.1.8'
5
+ gem 'rspec'
6
+ gem 'rake'
7
+ gem 'json'
8
+
9
+ group :development, :test do
10
+ gem 'capistrano'
11
+ gem 'generator_spec'
12
+ end
13
+
14
+ platforms :jruby do
15
+ gem 'jruby-openssl'
16
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ source :rubygems
3
+
4
+ gem 'rails', '~> 3.2.8'
5
+ gem 'rspec'
6
+ gem 'rake'
7
+ gem 'json'
8
+
9
+ group :development, :test do
10
+ gem 'capistrano'
11
+ gem 'generator_spec'
12
+ end
13
+
14
+ platforms :jruby do
15
+ gem 'jruby-openssl'
16
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ source :rubygems
3
+
4
+ gem 'rails', :git => 'git://github.com/rails/rails.git'
5
+ gem 'rspec'
6
+ gem 'rake'
7
+ gem 'json'
8
+
9
+ group :development, :test do
10
+ gem 'capistrano'
11
+ gem 'generator_spec'
12
+ end
13
+
14
+ platforms :jruby do
15
+ gem 'jruby-openssl'
16
+ end
@@ -0,0 +1,45 @@
1
+ raise 'This appsignal gem only works with rails' unless defined?(Rails)
2
+
3
+ module Appsignal
4
+ class << self
5
+ attr_accessor :subscriber, :event_payload_sanitizer
6
+
7
+ def active?
8
+ config && config[:active] == true
9
+ end
10
+
11
+ def logger
12
+ @logger ||= Logger.new("#{Rails.root}/log/appsignal.log").tap do |l|
13
+ l.level = Logger::INFO
14
+ end
15
+ end
16
+
17
+ def transactions
18
+ @transactions ||= {}
19
+ end
20
+
21
+ def agent
22
+ @agent ||= Appsignal::Agent.new
23
+ end
24
+
25
+ def config
26
+ @config ||= Appsignal::Config.new(Rails.root, Rails.env).load
27
+ end
28
+
29
+ def event_payload_sanitizer
30
+ @event_payload_sanitizer ||= proc { |event| event.payload }
31
+ end
32
+ end
33
+ end
34
+
35
+ require 'appsignal/cli'
36
+ require 'appsignal/config'
37
+ require 'appsignal/transmitter'
38
+ require 'appsignal/agent'
39
+ require 'appsignal/marker'
40
+ require 'appsignal/middleware'
41
+ require 'appsignal/transaction'
42
+ require 'appsignal/exception_notification'
43
+ require 'appsignal/auth_check'
44
+ require 'appsignal/version'
45
+ require 'appsignal/railtie'
@@ -0,0 +1,104 @@
1
+ module Appsignal
2
+ class Agent
3
+ attr_reader :queue, :active, :sleep_time, :slowest_transactions, :transmitter
4
+ ACTION = 'log_entries'
5
+
6
+ def initialize
7
+ return unless Appsignal.active?
8
+ @sleep_time = 60.0
9
+ @slowest_transactions = {}
10
+ @queue = []
11
+ @retry_request = true
12
+ @thread = Thread.new do
13
+ while true do
14
+ send_queue if @queue.any?
15
+ sleep @sleep_time
16
+ end
17
+ end
18
+ @transmitter = Transmitter.new(
19
+ Appsignal.config[:endpoint],
20
+ ACTION,
21
+ Appsignal.config[:api_key]
22
+ )
23
+ Appsignal.logger.info 'Started the Appsignal agent'
24
+ end
25
+
26
+ def add_to_queue(transaction)
27
+ if !transaction.exception? && transaction.action
28
+ current_slowest_transaction = @slowest_transactions[transaction.action]
29
+ if current_slowest_transaction
30
+ if current_slowest_transaction.process_action_event.duration <
31
+ transaction.process_action_event.duration
32
+ current_slowest_transaction.clear_payload_and_events!
33
+ @slowest_transactions[transaction.action] = transaction
34
+ else
35
+ transaction.clear_payload_and_events!
36
+ end
37
+ else
38
+ @slowest_transactions[transaction.action] = transaction
39
+ end
40
+ end
41
+ @queue << transaction
42
+ end
43
+
44
+ def send_queue
45
+ Appsignal.logger.debug "Sending queue"
46
+ begin
47
+ handle_result transmitter.transmit(queue.map(&:to_hash))
48
+ rescue Exception => ex
49
+ Appsignal.logger.error "Exception while communicating with AppSignal: #{ex}"
50
+ handle_result nil
51
+ end
52
+ end
53
+
54
+ def handle_result(code)
55
+ Appsignal.logger.debug "Queue sent, response code: #{code}"
56
+ case code.to_i
57
+ when 200
58
+ good_response
59
+ when 420 # Enhance Your Calm
60
+ good_response
61
+ @sleep_time = @sleep_time * 1.5
62
+ when 413 # Request Entity Too Large
63
+ good_response
64
+ @sleep_time = @sleep_time / 1.5
65
+ when 429
66
+ Appsignal.logger.error "Too many requests sent, disengaging the agent"
67
+ stop_logging
68
+ when 406
69
+ Appsignal.logger.error "Your appsignal gem cannot communicate with the API anymore, please upgrade. Disengaging the agent"
70
+ stop_logging
71
+ when 402
72
+ Appsignal.logger.error "Payment required, disengaging the agent"
73
+ stop_logging
74
+ when 401
75
+ Appsignal.logger.error "API token cannot be authorized, disengaging the agent"
76
+ stop_logging
77
+ else
78
+ retry_once
79
+ end
80
+ end
81
+
82
+ protected
83
+
84
+ def good_response
85
+ @queue = []
86
+ @slowest_transactions = {}
87
+ @retry_request = true
88
+ end
89
+
90
+ def retry_once
91
+ if @retry_request
92
+ @retry_request = false
93
+ else
94
+ @retry_request = true
95
+ @queue = []
96
+ end
97
+ end
98
+
99
+ def stop_logging
100
+ ActiveSupport::Notifications.unsubscribe(Appsignal.subscriber)
101
+ Thread.kill(@thread)
102
+ end
103
+ end
104
+ end