appsignal 0.6.7 → 0.7.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +3 -2
  3. data/.travis.yml +11 -11
  4. data/CHANGELOG.md +6 -0
  5. data/README.md +26 -0
  6. data/Rakefile +32 -3
  7. data/appsignal.gemspec +25 -16
  8. data/gemfiles/no_dependencies.gemfile +3 -0
  9. data/gemfiles/{3.0.gemfile → rails-3.0.gemfile} +2 -1
  10. data/gemfiles/{3.1.gemfile → rails-3.1.gemfile} +2 -1
  11. data/gemfiles/{3.2.gemfile → rails-3.2.gemfile} +2 -1
  12. data/gemfiles/{4.0.gemfile → rails-4.0.gemfile} +2 -1
  13. data/gemfiles/sinatra.gemfile +5 -0
  14. data/lib/appsignal.rb +30 -25
  15. data/lib/appsignal/agent.rb +37 -17
  16. data/lib/appsignal/aggregator.rb +2 -4
  17. data/lib/appsignal/aggregator/middleware.rb +4 -0
  18. data/lib/appsignal/aggregator/middleware/action_view_sanitizer.rb +23 -0
  19. data/lib/appsignal/aggregator/middleware/active_record_sanitizer.rb +64 -0
  20. data/lib/appsignal/aggregator/middleware/chain.rb +101 -0
  21. data/lib/appsignal/aggregator/middleware/delete_blanks.rb +16 -0
  22. data/lib/appsignal/aggregator/post_processor.rb +21 -18
  23. data/lib/appsignal/auth_check.rb +7 -21
  24. data/lib/appsignal/capistrano.rb +1 -36
  25. data/lib/appsignal/cli.rb +30 -46
  26. data/lib/appsignal/config.rb +46 -61
  27. data/lib/appsignal/integrations/capistrano.rb +44 -0
  28. data/lib/appsignal/{careful_logger.rb → integrations/capistrano/careful_logger.rb} +2 -0
  29. data/lib/appsignal/integrations/passenger.rb +6 -6
  30. data/lib/appsignal/integrations/rails.rb +33 -0
  31. data/lib/appsignal/integrations/sinatra.rb +20 -0
  32. data/lib/appsignal/marker.rb +9 -10
  33. data/lib/appsignal/rack/instrumentation.rb +28 -0
  34. data/lib/appsignal/rack/listener.rb +33 -0
  35. data/lib/appsignal/transaction.rb +18 -12
  36. data/lib/appsignal/transaction/formatter.rb +96 -0
  37. data/lib/appsignal/transaction/params_sanitizer.rb +80 -78
  38. data/lib/appsignal/transmitter.rb +10 -9
  39. data/lib/appsignal/version.rb +1 -1
  40. data/lib/generators/appsignal/appsignal_generator.rb +20 -21
  41. data/lib/generators/appsignal/templates/appsignal.yml +15 -21
  42. data/spec/{appsignal → lib/appsignal}/agent_spec.rb +69 -1
  43. data/spec/lib/appsignal/aggregator/middleware/action_view_sanitizer_spec.rb +32 -0
  44. data/spec/lib/appsignal/aggregator/middleware/active_record_sanitizer_spec.rb +215 -0
  45. data/spec/{appsignal → lib/appsignal/aggregator}/middleware/chain_spec.rb +5 -5
  46. data/spec/{appsignal → lib/appsignal/aggregator}/middleware/delete_blanks_spec.rb +2 -2
  47. data/spec/{appsignal → lib/appsignal}/aggregator/post_processor_spec.rb +15 -6
  48. data/spec/{appsignal → lib/appsignal}/aggregator_spec.rb +4 -1
  49. data/spec/{appsignal → lib/appsignal}/auth_check_spec.rb +8 -23
  50. data/spec/{appsignal → lib/appsignal}/cli_spec.rb +65 -66
  51. data/spec/lib/appsignal/config_spec.rb +132 -0
  52. data/spec/lib/appsignal/integrations/capistrano_spec.rb +123 -0
  53. data/spec/{appsignal → lib/appsignal}/integrations/passenger_spec.rb +0 -1
  54. data/spec/lib/appsignal/integrations/rails_spec.rb +38 -0
  55. data/spec/lib/appsignal/integrations/sinatra_spec.rb +43 -0
  56. data/spec/{appsignal → lib/appsignal}/marker_spec.rb +20 -23
  57. data/spec/lib/appsignal/rack/instrumentation_spec.rb +49 -0
  58. data/spec/{appsignal → lib/appsignal/rack}/listener_spec.rb +39 -6
  59. data/spec/{appsignal/transaction/transaction_formatter_spec.rb → lib/appsignal/transaction/formatter_spec.rb} +29 -6
  60. data/spec/{appsignal → lib/appsignal}/transaction/params_sanitizer_spec.rb +13 -12
  61. data/spec/{appsignal → lib/appsignal}/transaction_spec.rb +52 -7
  62. data/spec/{appsignal → lib/appsignal}/transmitter_spec.rb +27 -20
  63. data/spec/lib/appsignal_spec.rb +230 -0
  64. data/spec/lib/generators/appsignal/appsignal_generator_spec.rb +166 -0
  65. data/spec/lib/tmp/config/appsignal.yml +2 -0
  66. data/spec/spec_helper.rb +29 -20
  67. data/spec/support/delegate_matcher.rb +0 -1
  68. data/spec/support/fixtures/generated_config.yml +20 -0
  69. data/{log/.gitkeep → spec/support/fixtures/uploaded_file.txt} +0 -0
  70. data/spec/support/helpers/config_helpers.rb +24 -0
  71. data/spec/support/helpers/notification_helpers.rb +0 -2
  72. data/spec/support/helpers/transaction_helpers.rb +17 -2
  73. data/spec/support/project_fixture/config/appsignal.yml +18 -0
  74. data/spec/support/project_fixture/log/.gitkeep +0 -0
  75. data/spec/support/rails/my_app.rb +6 -0
  76. metadata +99 -83
  77. data/config/appsignal.yml +0 -10
  78. data/lib/appsignal/listener.rb +0 -21
  79. data/lib/appsignal/middleware.rb +0 -3
  80. data/lib/appsignal/middleware/action_view_sanitizer.rb +0 -21
  81. data/lib/appsignal/middleware/active_record_sanitizer.rb +0 -62
  82. data/lib/appsignal/middleware/chain.rb +0 -99
  83. data/lib/appsignal/middleware/delete_blanks.rb +0 -12
  84. data/lib/appsignal/railtie.rb +0 -37
  85. data/lib/appsignal/to_appsignal_hash.rb +0 -21
  86. data/lib/appsignal/transaction/transaction_formatter.rb +0 -67
  87. data/spec/appsignal/capistrano_spec.rb +0 -81
  88. data/spec/appsignal/config_spec.rb +0 -177
  89. data/spec/appsignal/inactive_railtie_spec.rb +0 -32
  90. data/spec/appsignal/middleware/action_view_sanitizer_spec.rb +0 -27
  91. data/spec/appsignal/middleware/active_record_sanitizer_spec.rb +0 -212
  92. data/spec/appsignal/railtie_spec.rb +0 -74
  93. data/spec/appsignal/to_appsignal_hash_spec.rb +0 -29
  94. data/spec/appsignal_spec.rb +0 -195
  95. data/spec/generators/appsignal/appsignal_generator_spec.rb +0 -181
@@ -1,12 +1,16 @@
1
1
  require 'spec_helper'
2
+ require 'appsignal/cli'
2
3
 
3
4
  describe Appsignal::CLI do
4
5
  let(:out_stream) { StringIO.new }
5
6
  let(:error_stream) { StringIO.new }
6
7
  let(:cli) { Appsignal::CLI }
7
- before :each do
8
+ before do
8
9
  @original_stdout, @original_stderr = $stdout, $stderr
9
10
  $stdout, $stderr = out_stream, error_stream
11
+ ENV['PWD'] = project_fixture_path
12
+ cli.config = nil
13
+ cli.options = {:environment => 'production'}
10
14
  end
11
15
  after :each do
12
16
  $stdout = @original_stdout
@@ -19,13 +23,11 @@ describe Appsignal::CLI do
19
23
  end
20
24
  end
21
25
 
22
- it "should print a message if there is no config file" do
23
- File.stub(:exists? => false)
24
- lambda {
25
- cli.run([])
26
- }.should raise_error(SystemExit)
27
- out_stream.string.should include 'No config file present at config/appsignal.yml'
28
- out_stream.string.should include 'Log in to https://appsignal.com to get instructions on how to generate the config file.'
26
+ describe "#config" do
27
+ subject { cli.config }
28
+
29
+ it { should be_instance_of(Appsignal::Config) }
30
+ its(:loaded?) { should be_true }
29
31
  end
30
32
 
31
33
  it "should print the help with no arguments, -h and --help" do
@@ -60,29 +62,28 @@ describe Appsignal::CLI do
60
62
  end
61
63
 
62
64
  describe "#notify_of_deploy" do
63
- it "should validate that all options have been supplied" do
64
- options = {}
65
+ it "should validate that the config has been loaded and all options have been supplied" do
66
+ cli.should_receive(:validate_config_loaded)
65
67
  cli.should_receive(:validate_required_options).with(
66
- [:revision, :repository, :user, :environment],
67
- options
68
+ [:revision, :repository, :user, :environment]
68
69
  )
69
- Appsignal::Marker.should_receive(:new).
70
- and_return(double(:transmit => true))
71
- cli.notify_of_deploy(options)
70
+ Appsignal::Marker.should_receive(:new).and_return(double(:transmit => true))
71
+
72
+ cli.notify_of_deploy
72
73
  end
73
74
 
74
75
  it "should notify of a deploy" do
75
- transmitter = double
76
- Appsignal::Transmitter.should_receive(:new).with(
77
- 'http://localhost:3000/1',
78
- 'markers',
79
- 'def'
80
- ).and_return(transmitter)
81
- transmitter.should_receive(:transmit).with(
82
- :revision => 'aaaaa',
83
- :repository => 'git@github.com:our/project.git',
84
- :user => 'thijs'
85
- )
76
+ marker = double
77
+ Appsignal::Marker.should_receive(:new).with(
78
+ {
79
+ :revision => 'aaaaa',
80
+ :repository => 'git@github.com:our/project.git',
81
+ :user => 'thijs'
82
+ },
83
+ kind_of(Appsignal::Config),
84
+ kind_of(Logger)
85
+ ).and_return(marker)
86
+ marker.should_receive(:transmit)
86
87
 
87
88
  cli.run([
88
89
  'notify_of_deploy',
@@ -94,72 +95,70 @@ describe Appsignal::CLI do
94
95
  end
95
96
  end
96
97
 
97
- describe "#api_check" do
98
- it "should detect configured environments" do
99
- authcheck = double
100
- Appsignal::AuthCheck.should_receive(:new).with(
101
- :development,
102
- kind_of(Hash)
103
- ).and_return(authcheck)
104
- Appsignal::AuthCheck.should_receive(:new).with(
105
- :production,
106
- kind_of(Hash)
107
- ).and_return(authcheck)
108
- Appsignal::AuthCheck.should_receive(:new).with(
109
- :test,
110
- kind_of(Hash)
111
- ).and_return(authcheck)
112
-
113
- authcheck.should_receive(:perform_with_result).exactly(3).times.
114
- and_return(['200', 'result'])
115
- cli.run([
116
- 'api_check'
117
- ])
118
- out_stream.string.should =~ /\[development\]/
119
- out_stream.string.should =~ /\[production\]/
120
- out_stream.string.should =~ /\[test\]/
121
- out_stream.string.should =~ /\* result/
122
- end
123
- end
124
-
125
98
  # protected
126
99
 
127
100
  describe "#validate_required_options" do
128
101
  let(:required_options) { [:option_1, :option_2, :option_3] }
129
102
 
130
103
  it "should do nothing with all options supplied" do
131
- cli.send(
132
- :validate_required_options,
133
- required_options,
104
+ cli.options = {
134
105
  :option_1 => 1,
135
106
  :option_2 => 2,
136
107
  :option_3 => 3
108
+ }
109
+ cli.send(
110
+ :validate_required_options,
111
+ required_options
137
112
  )
138
113
  out_stream.string.should be_empty
139
114
  end
140
115
 
141
- it "should print a message with one option missing" do
116
+ it "should print a message with one option missing and exit" do
117
+ cli.options = {
118
+ :option_1 => 1,
119
+ :option_2 => 2
120
+ }
142
121
  lambda {
143
122
  cli.send(
144
123
  :validate_required_options,
145
- required_options,
146
- :option_1 => 1,
147
- :option_2 => 2
124
+ required_options
148
125
  )
149
126
  }.should raise_error(SystemExit)
150
- out_stream.string.should include("Missing options: option_3")
127
+ out_stream.string.should include('Missing options: option_3')
151
128
  end
152
129
 
153
- it "should print a message with multiple options missing" do
130
+ it "should print a message with multiple options missing and exit" do
131
+ cli.options = {
132
+ :option_1 => 1,
133
+ :option_2 => ''
134
+ }
154
135
  lambda {
155
136
  cli.send(
156
137
  :validate_required_options,
157
- required_options,
158
- :option_1 => 1,
159
- :option_2 => ''
138
+ required_options
160
139
  )
161
140
  }.should raise_error(SystemExit)
162
141
  out_stream.string.should include("Missing options: option_2, option_3")
163
142
  end
164
143
  end
144
+
145
+ describe "#validate_config_loaded" do
146
+ context "when config is present" do
147
+ it "should do nothing" do
148
+ cli.send(:validate_config_loaded)
149
+ out_stream.string.should be_empty
150
+ end
151
+ end
152
+
153
+ context "when config is not present" do
154
+ before { cli.options = {:environment => 'nonsense'} }
155
+
156
+ it "should print a message and exit" do
157
+ lambda {
158
+ cli.send(:validate_config_loaded)
159
+ }.should raise_error(SystemExit)
160
+ out_stream.string.should include('Exiting: No config file or push api key env var found')
161
+ end
162
+ end
163
+ end
165
164
  end
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+
3
+ describe Appsignal::Config do
4
+ subject { config }
5
+
6
+ describe "when there is a config file" do
7
+ let(:config) { project_fixture_config('production') }
8
+
9
+ it "should not log an error" do
10
+ Appsignal::Config.any_instance.should_not_receive(:carefully_log_error)
11
+ subject
12
+ end
13
+
14
+ its(:loaded?) { should be_true }
15
+
16
+ it "should merge with the default config and fill the config hash" do
17
+ subject.config_hash.should == {
18
+ :ignore_exceptions => [],
19
+ :endpoint => 'https://push.appsignal.com/1',
20
+ :slow_request_threshold => 200,
21
+ :push_api_key => 'abc',
22
+ :name => 'TestApp',
23
+ :active => true
24
+ }
25
+ end
26
+
27
+ describe "#[]" do
28
+ it "should get the value for an existing key" do
29
+ subject[:push_api_key].should == 'abc'
30
+ end
31
+
32
+ it "should return nil for a non-existing key" do
33
+ subject[:nonsense].should be_nil
34
+ end
35
+ end
36
+
37
+ context "and there's also an env var present" do
38
+ before do
39
+ ENV['APPSIGNAL_PUSH_API_KEY'] = 'push_api_key'
40
+ end
41
+
42
+ it "should ignore the env var" do
43
+ subject[:push_api_key].should == 'abc'
44
+ end
45
+ end
46
+
47
+ context "and there is an old-style api_key defined" do
48
+ let(:config) { project_fixture_config('old_api_key') }
49
+
50
+ it "should fill the push_api_key with the old style key" do
51
+ subject[:push_api_key].should == 'def'
52
+ end
53
+ end
54
+ end
55
+
56
+ context "when there is a config file without the current env" do
57
+ let(:config) { project_fixture_config('nonsense') }
58
+
59
+ it "should log an error" do
60
+ Appsignal::Config.any_instance.should_receive(:carefully_log_error).with(
61
+ "Not loading: config for 'nonsense' not found"
62
+ )
63
+ subject
64
+ end
65
+
66
+ its(:loaded?) { should be_false }
67
+ end
68
+
69
+ context "when there is no config file" do
70
+ let(:config) { Appsignal::Config.new('/nothing', 'production') }
71
+
72
+ it "should log an error" do
73
+ Appsignal::Config.any_instance.should_receive(:carefully_log_error).with(
74
+ "Not loading: No config file found at '/nothing/config/appsignal.yml' " \
75
+ "and no APPSIGNAL_PUSH_API_KEY env var present"
76
+ )
77
+ subject
78
+ end
79
+
80
+ its(:loaded?) { should be_false }
81
+
82
+ describe "#[]" do
83
+ it "should return nil" do
84
+ subject[:endpoint].should be_nil
85
+ end
86
+ end
87
+
88
+ context "and an env var is present" do
89
+ before do
90
+ ENV['APPSIGNAL_PUSH_API_KEY'] = 'push_api_key'
91
+ end
92
+
93
+ it "should not log an error" do
94
+ Appsignal::Config.any_instance.should_not_receive(:carefully_log_error)
95
+ subject
96
+ end
97
+
98
+ its(:loaded?) { should be_true }
99
+
100
+ it "should merge with the default config and fill the config hash" do
101
+ subject.config_hash.should == {
102
+ :push_api_key => 'push_api_key',
103
+ :ignore_exceptions => [],
104
+ :endpoint => 'https://push.appsignal.com/1',
105
+ :slow_request_threshold => 200,
106
+ :active => true
107
+ }
108
+ end
109
+
110
+ context "with only APPSIGNAL_API_KEY" do
111
+ before do
112
+ ENV.delete('APPSIGNAL_PUSH_API_KEY')
113
+ ENV['APPSIGNAL_API_KEY'] = 'old_style_api_key'
114
+ end
115
+
116
+ it "should use the old style api key" do
117
+ subject[:push_api_key].should == 'old_style_api_key'
118
+ end
119
+ end
120
+
121
+ context "with both APPSIGNAL_PUSH_API_KEY and APPSIGNAL_API_KEY" do
122
+ before do
123
+ ENV['APPSIGNAL_API_KEY'] = 'old_style_api_key'
124
+ end
125
+
126
+ it "should use the new style push api key" do
127
+ subject[:push_api_key].should == 'push_api_key'
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,123 @@
1
+ require 'spec_helper'
2
+ require 'appsignal/capistrano'
3
+ require 'capistrano/configuration'
4
+
5
+ describe Appsignal::Integrations::Capistrano do
6
+ let(:config) { project_fixture_config }
7
+
8
+ before :all do
9
+ @capistrano_config = Capistrano::Configuration.new
10
+ Appsignal::Integrations::Capistrano.tasks(@capistrano_config)
11
+ end
12
+
13
+ it "should have a deploy task" do
14
+ @capistrano_config.find_task('appsignal:deploy').should_not be_nil
15
+ end
16
+
17
+ describe "appsignal:deploy task" do
18
+ before do
19
+ @capistrano_config.set(:rails_env, 'production')
20
+ @capistrano_config.set(:repository, 'master')
21
+ @capistrano_config.set(:deploy_to, '/home/username/app')
22
+ @capistrano_config.set(:current_release, '')
23
+ @capistrano_config.set(:current_revision, '503ce0923ed177a3ce000005')
24
+ @capistrano_config.dry_run = false
25
+ ENV['USER'] = 'batman'
26
+ end
27
+
28
+ context "config" do
29
+ before { @capistrano_config.dry_run = true }
30
+
31
+ it "should be instantiated with the right params" do
32
+ Appsignal::Config.should_receive(:new).with(
33
+ ENV['PWD'],
34
+ 'production',
35
+ kind_of(Capistrano::Logger)
36
+ )
37
+ end
38
+
39
+ context "when rack_env is used instead of rails_env" do
40
+ before do
41
+ @capistrano_config.unset(:rails_env)
42
+ @capistrano_config.set(:rack_env, 'rack_production')
43
+ end
44
+
45
+ it "should be instantiated with the right params" do
46
+ Appsignal::Config.should_receive(:new).with(
47
+ ENV['PWD'],
48
+ 'rack_production',
49
+ kind_of(Capistrano::Logger)
50
+ )
51
+ end
52
+ end
53
+
54
+ after { @capistrano_config.find_and_execute_task('appsignal:deploy') }
55
+ end
56
+
57
+ context "send marker" do
58
+ before :all do
59
+ @io = StringIO.new
60
+ @logger = Capistrano::Logger.new(:output => @io)
61
+ @logger.level = Capistrano::Logger::MAX_LEVEL
62
+ @capistrano_config.logger = @logger
63
+ end
64
+
65
+ let(:marker_data) do
66
+ {
67
+ :revision => "503ce0923ed177a3ce000005",
68
+ :repository => "master",
69
+ :user => "batman"
70
+ }
71
+ end
72
+
73
+ before do
74
+ @marker = Appsignal::Marker.new(
75
+ marker_data,
76
+ config,
77
+ @logger
78
+ )
79
+ Appsignal::Marker.should_receive(:new).with(
80
+ marker_data,
81
+ kind_of(Appsignal::Config),
82
+ kind_of(Capistrano::Logger)
83
+ ).and_return(@marker)
84
+ end
85
+
86
+ context "proper setup" do
87
+ before do
88
+ @transmitter = double
89
+ Appsignal::Transmitter.should_receive(:new).and_return(@transmitter)
90
+ end
91
+
92
+ it "should transmit data" do
93
+ @transmitter.should_receive(:transmit).and_return('200')
94
+ @capistrano_config.find_and_execute_task('appsignal:deploy')
95
+ @io.string.should include('** Notifying Appsignal of deploy...')
96
+ @io.string.should include(
97
+ '** Appsignal has been notified of this deploy!'
98
+ )
99
+ end
100
+ end
101
+
102
+ it "should not transmit data" do
103
+ @capistrano_config.find_and_execute_task('appsignal:deploy')
104
+ @io.string.should include('** Notifying Appsignal of deploy...')
105
+ @io.string.should include(
106
+ '** Something went wrong while trying to notify Appsignal:'
107
+ )
108
+ end
109
+
110
+ context "dry run" do
111
+ before { @capistrano_config.dry_run = true }
112
+
113
+ it "should not send deploy marker" do
114
+ @marker.should_not_receive(:transmit)
115
+ @capistrano_config.find_and_execute_task('appsignal:deploy')
116
+ @io.string.should include(
117
+ '** Dry run: Deploy marker not actually sent.'
118
+ )
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end