inst_statsd 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe InstStatsd::BlockStat do
4
+ it "track exclusives correctly" do
5
+ stat = InstStatsd::BlockStat.new("key")
6
+ stat.stats['total'] = 5.0
7
+ stat.subtract_exclusives("total" => 1.5)
8
+ stat.subtract_exclusives("total" => 2.1)
9
+ expect(stat.exclusive_stats).to eql("total" => 1.4)
10
+ end
11
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe InstStatsd::BlockTracking do
4
+ before(:all) do
5
+ InstStatsd::DefaultTracking.track_sql
6
+ end
7
+
8
+ it "works" do
9
+ statsd = double()
10
+ allow(statsd).to receive(:timing).with('mykey.total', anything)
11
+ expect(statsd).to receive(:timing).with("mykey.sql.read", 1)
12
+
13
+ InstStatsd::BlockTracking.track("mykey", statsd: statsd, only: 'sql.read') do
14
+ ActiveSupport::Notifications.instrument('sql.active_record', name: "LOAD", sql: "SELECT * FROM users") {}
15
+ end
16
+ end
17
+
18
+ it "keeps track of exclusive stats too" do
19
+ statsd = double()
20
+ expect(statsd).to receive(:timing).with("mykey.sql.read", 2).ordered
21
+ expect(statsd).to receive(:timing).with('mykey.total', anything).ordered
22
+ expect(statsd).to receive(:timing).with("mykey.exclusive.sql.read", 2).ordered
23
+ expect(statsd).to receive(:timing).with('mykey.exclusive.total', anything).ordered
24
+ expect(statsd).to receive(:timing).with("mykey.sql.read", 2).ordered
25
+ expect(statsd).to receive(:timing).with('mykey.total', anything).ordered
26
+ expect(statsd).to receive(:timing).with("mykey.exclusive.sql.read", 2).ordered
27
+ expect(statsd).to receive(:timing).with('mykey.exclusive.total', anything).ordered
28
+ expect(statsd).to receive(:timing).with("mykey.sql.read", 5).ordered
29
+ expect(statsd).to receive(:timing).with('mykey.total', anything).ordered
30
+ expect(statsd).to receive(:timing).with("mykey.exclusive.sql.read", 1).ordered
31
+ expect(statsd).to receive(:timing).with('mykey.exclusive.total', anything).ordered
32
+
33
+ InstStatsd::BlockTracking.track("mykey", category: :nested, statsd: statsd, only: 'sql.read') do
34
+ ActiveSupport::Notifications.instrument('sql.active_record', name: "LOAD", sql: "SELECT * FROM users") {}
35
+ InstStatsd::BlockTracking.track("mykey", category: :nested, statsd: statsd, only: 'sql.read') do
36
+ ActiveSupport::Notifications.instrument('sql.active_record', name: "LOAD", sql: "SELECT * FROM users") {}
37
+ ActiveSupport::Notifications.instrument('sql.active_record', name: "LOAD", sql: "SELECT * FROM users") {}
38
+ end
39
+ InstStatsd::BlockTracking.track("mykey", category: :nested, statsd: statsd, only: 'sql.read') do
40
+ ActiveSupport::Notifications.instrument('sql.active_record', name: "LOAD", sql: "SELECT * FROM users") {}
41
+ ActiveSupport::Notifications.instrument('sql.active_record', name: "LOAD", sql: "SELECT * FROM users") {}
42
+ end
43
+ end
44
+ end
45
+
46
+ context "mask" do
47
+ after do
48
+ InstStatsd::BlockTracking.mask = nil
49
+ InstStatsd::BlockTracking.negative_mask = nil
50
+ end
51
+
52
+ it "only tracks keys that match the mask" do
53
+ InstStatsd::BlockTracking.mask = /mykey/
54
+ statsd = double()
55
+ allow(statsd).to receive(:timing).with('mykey.total', anything)
56
+ expect(statsd).to receive(:timing).with("mykey.sql.read", 1)
57
+
58
+ InstStatsd::BlockTracking.track("mykey", statsd: statsd, only: 'sql.read') do
59
+ InstStatsd::BlockTracking.track("ignoreme", statsd: statsd, only: 'sql.read') do
60
+ ActiveSupport::Notifications.instrument('sql.active_record', name: "LOAD", sql: "SELECT * FROM users") {}
61
+ end
62
+ end
63
+ end
64
+
65
+ it "doesn't track keys that match the negative mask" do
66
+ InstStatsd::BlockTracking.negative_mask = /ignoreme/
67
+ statsd = double()
68
+ allow(statsd).to receive(:timing).with('mykey.total', anything)
69
+ expect(statsd).to receive(:timing).with("mykey.sql.read", 1)
70
+
71
+ InstStatsd::BlockTracking.track("mykey", statsd: statsd, only: 'sql.read') do
72
+ InstStatsd::BlockTracking.track("ignoreme", statsd: statsd, only: 'sql.read') do
73
+ ActiveSupport::Notifications.instrument('sql.active_record', name: "LOAD", sql: "SELECT * FROM users") {}
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe InstStatsd::Counter do
4
+
5
+ let(:subject) { InstStatsd::Counter.new('test', ['foo']) }
6
+
7
+ describe "#accepted_name?" do
8
+ it 'should return true for names not in blocked_names' do
9
+ expect(subject.accepted_name?('bar')).to eq true
10
+ end
11
+
12
+ it 'should return false for names in blocked_names' do
13
+ expect(subject.accepted_name?('foo')).to eq false
14
+ end
15
+
16
+ it 'should return true for empty string names' do
17
+ expect(subject.accepted_name?('')).to eq true
18
+ end
19
+
20
+ it 'should return true for empty nil names' do
21
+ expect(subject.accepted_name?(nil)).to eq true
22
+ end
23
+ end
24
+
25
+ describe "#track" do
26
+ it 'should increment when given allowed names' do
27
+ cookie = subject.start
28
+ subject.track('bar')
29
+ subject.track('baz')
30
+ expect(subject.finalize_count(cookie)).to eq 2
31
+ end
32
+
33
+ it 'should not increment when given a blocked name' do
34
+ cookie = subject.start
35
+ subject.track('foo') #shouldn't count as foo is a blocked name
36
+ subject.track('name')
37
+ expect(subject.finalize_count(cookie)).to eq 1
38
+ end
39
+ end
40
+
41
+ describe "#finalize_count" do
42
+ it 'should return the current count' do
43
+ cookie = subject.start
44
+ subject.track('bar')
45
+ expect(subject.finalize_count(cookie)).to eq 1
46
+ end
47
+
48
+ it 'should not interfere with multiple people using the object' do
49
+ cookie1 = subject.start
50
+ subject.track('bar')
51
+ cookie2 = subject.start
52
+ subject.track('bar')
53
+ expect(subject.finalize_count(cookie1)).to eq 2
54
+ expect(subject.finalize_count(cookie2)).to eq 1
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,187 @@
1
+ require 'spec_helper'
2
+
3
+ describe InstStatsd do
4
+ before(:each) do
5
+ InstStatsd.settings = nil
6
+ end
7
+
8
+ after(:each) do
9
+ [
10
+ 'INST_STATSD_HOST',
11
+ 'INST_STATSD_NAMESPACE',
12
+ 'INST_STATSD_PORT',
13
+ 'INST_STATSD_APPEND_HOST_NAME',
14
+ ].each {|k| ENV.delete k}
15
+ end
16
+
17
+ describe ".settings" do
18
+ it "have default settings" do
19
+ expect(InstStatsd.settings).to eq({})
20
+ end
21
+
22
+ it "can be assigned a new value" do
23
+ settings = { host: 'bar', port: 1234 }
24
+ InstStatsd.settings = settings
25
+
26
+ expect(InstStatsd.settings).to eq settings
27
+ end
28
+
29
+ it 'pulls from ENV if not already set' do
30
+ ENV['INST_STATSD_HOST'] = 'statsd.example.org'
31
+ ENV['INST_STATSD_NAMESPACE'] = 'canvas'
32
+
33
+ expected = {
34
+ host: 'statsd.example.org',
35
+ namespace: 'canvas',
36
+ }
37
+ expect(InstStatsd.settings).to eq(expected)
38
+ end
39
+
40
+ it 'configured settings are merged into and take precedence over any existing ENV settings' do
41
+ ENV['INST_STATSD_HOST'] = 'statsd.example.org'
42
+ ENV['INST_STATSD_NAMESPACE'] = 'canvas'
43
+
44
+ settings = { host: 'statsd.example-override.org' }
45
+ InstStatsd.settings = settings
46
+
47
+ expect(InstStatsd.settings).to eq(InstStatsd.env_settings.merge(settings))
48
+ expect(InstStatsd.settings[:host]).to eq(settings[:host])
49
+ end
50
+
51
+ it 'validates settings' do
52
+ settings = { foo: 'blah' }
53
+ expect { InstStatsd.settings = settings }.to raise_error(InstStatsd::ConfigurationError)
54
+ end
55
+
56
+ it 'converts string keys to symbols' do
57
+ settings = { 'host' => 'bar', 'port' => 1234 }
58
+ InstStatsd.settings = settings
59
+ expect(InstStatsd.settings).to eq({ host: 'bar', port: 1234 })
60
+ end
61
+ end
62
+
63
+ describe ".convert_bool" do
64
+ it 'sets string true values to boolean true' do
65
+ config = {potential_string_bool: 'true'}
66
+ InstStatsd.convert_bool(config, :potential_string_bool)
67
+ expect(config[:potential_string_bool]).to be(true)
68
+ end
69
+ it 'sets string True values to boolean true' do
70
+ config = {potential_string_bool: 'True'}
71
+ InstStatsd.convert_bool(config, :potential_string_bool)
72
+ expect(config[:potential_string_bool]).to be(true)
73
+ end
74
+ it 'sets boolean true values to boolean true' do
75
+ config = {potential_string_bool: true}
76
+ InstStatsd.convert_bool(config, :potential_string_bool)
77
+ expect(config[:potential_string_bool]).to be(true)
78
+ end
79
+ it 'sets false strings to boolean false' do
80
+ config = {potential_string_bool: 'false'}
81
+ InstStatsd.convert_bool(config, :potential_string_bool)
82
+ expect(config[:potential_string_bool]).to be(false)
83
+ end
84
+ it 'sets False strings to boolean false' do
85
+ config = {potential_string_bool: 'False'}
86
+ InstStatsd.convert_bool(config, :potential_string_bool)
87
+ expect(config[:potential_string_bool]).to be(false)
88
+ end
89
+ it 'sets false booleans to boolean false' do
90
+ config = {potential_string_bool: false}
91
+ InstStatsd.convert_bool(config, :potential_string_bool)
92
+ expect(config[:potential_string_bool]).to be(false)
93
+ end
94
+ it 'makes no change for nil values' do
95
+ config = {foo: 'bar'}
96
+ InstStatsd.convert_bool(config, :potential_string_bool)
97
+ expect(config).to eq({foo: 'bar'})
98
+ end
99
+ it 'raises error for non true or false strings or booleans' do
100
+ config = {potential_string_bool: 'trrruuue'}
101
+ expect{InstStatsd.convert_bool(config, :potential_string_bool)}.to raise_error(InstStatsd::ConfigurationError)
102
+ end
103
+
104
+ end
105
+
106
+ describe ".env_settings" do
107
+ it 'returns empty hash when no INST_STATSD_HOST found' do
108
+ env = {
109
+ 'INST_STATSD_NAMESPACE' => 'canvas'
110
+ }
111
+ expect(InstStatsd.env_settings(env)).to eq({})
112
+ end
113
+
114
+ it 'builds settings hash from environment vars' do
115
+ env = {
116
+ 'INST_STATSD_HOST' => 'statsd.example.org',
117
+ 'INST_STATSD_NAMESPACE' => 'canvas',
118
+ }
119
+ expected = {
120
+ host: 'statsd.example.org',
121
+ namespace: 'canvas',
122
+ }
123
+ expect(InstStatsd.env_settings(env)).to eq(expected)
124
+ end
125
+
126
+ it 'uses ENV if env argument hash not passed' do
127
+ ENV['INST_STATSD_HOST'] = 'statsd.example.org'
128
+ ENV['INST_STATSD_NAMESPACE'] = 'canvas'
129
+
130
+ expected = {
131
+ host: 'statsd.example.org',
132
+ namespace: 'canvas',
133
+ }
134
+ expect(InstStatsd.env_settings).to eq(expected)
135
+ end
136
+
137
+ it 'converts env append_hostname "false" to boolean' do
138
+ env = {
139
+ 'INST_STATSD_HOST' => 'statsd.example.org',
140
+ 'INST_STATSD_APPEND_HOSTNAME' => 'false',
141
+ }
142
+ expected = {
143
+ host: 'statsd.example.org',
144
+ append_hostname: false,
145
+ }
146
+ expect(InstStatsd.env_settings(env)).to eq(expected)
147
+ end
148
+
149
+ it 'converts env append_hostname "true" to boolean' do
150
+ env = {
151
+ 'INST_STATSD_HOST' => 'statsd.example.org',
152
+ 'INST_STATSD_APPEND_HOSTNAME' => 'true',
153
+ }
154
+ expected = {
155
+ host: 'statsd.example.org',
156
+ append_hostname: true,
157
+ }
158
+ expect(InstStatsd.env_settings(env)).to eq(expected)
159
+ end
160
+
161
+ it 'keeps boolean false values for append_hostname' do
162
+ env = {
163
+ 'INST_STATSD_HOST' => 'statsd.example.org',
164
+ 'INST_STATSD_APPEND_HOSTNAME' => false,
165
+ }
166
+ expected = {
167
+ host: 'statsd.example.org',
168
+ append_hostname: false,
169
+ }
170
+ expect(InstStatsd.env_settings(env)).to eq(expected)
171
+ end
172
+
173
+ it 'keeps boolean true values for append_hostname' do
174
+ env = {
175
+ 'INST_STATSD_HOST' => 'statsd.example.org',
176
+ 'INST_STATSD_APPEND_HOSTNAME' => true,
177
+ }
178
+ expected = {
179
+ host: 'statsd.example.org',
180
+ append_hostname: true,
181
+ }
182
+ expect(InstStatsd.env_settings(env)).to eq(expected)
183
+ end
184
+
185
+ end
186
+
187
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe InstStatsd::NullLogger do
4
+
5
+ describe 'initialize' do
6
+ it 'takes any arguments' do
7
+ expect{InstStatsd::NullLogger.new}.to_not raise_error
8
+ expect{InstStatsd::NullLogger.new(1, 2, 3)}.to_not raise_error
9
+ end
10
+ end
11
+
12
+ describe 'debug, info, warn, fatal, and unknown' do
13
+ it 'should all no-op instead of logging' do
14
+ log_path = 'spec/support/test.log'
15
+ File.open(log_path, 'w') { |f| f.write('') } # empty log file
16
+ logger = InstStatsd::NullLogger.new(log_path)
17
+ %w[debug info warn error fatal unknown].each { |m| logger.send(m, 'foo') }
18
+ log_contents = File.read(log_path)
19
+ expect(log_contents).to eq ''
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+ require 'logger'
3
+
4
+ describe InstStatsd::RequestLogger do
5
+
6
+ describe '#build_log_message' do
7
+ before :all do
8
+ @logger = InstStatsd::RequestLogger.new(Logger.new(STDOUT))
9
+ end
10
+ it 'includes the supplied header' do
11
+ request_stat = double('request_stat')
12
+ allow(request_stat).to receive(:exclusive_stats).and_return(nil)
13
+ allow(request_stat).to receive(:stats).and_return({})
14
+ results = @logger.build_log_message(request_stat, 'FOO_STATS')
15
+ expect(results).to eq("[FOO_STATS]")
16
+ end
17
+ it 'falls back to the default header' do
18
+ request_stat = double('request_stat')
19
+ allow(request_stat).to receive(:exclusive_stats).and_return(nil)
20
+ allow(request_stat).to receive(:stats).and_return({})
21
+ results = @logger.build_log_message(request_stat)
22
+ expect(results).to eq("[STATSD]")
23
+ end
24
+ it 'includes stats that are available' do
25
+ request_stat = double('request_stat')
26
+ allow(request_stat).to receive(:exclusive_stats).and_return(nil)
27
+ allow(request_stat).to receive(:stats).and_return(
28
+ "total" => 100.21,
29
+ "active.record" => 24)
30
+ results = @logger.build_log_message(request_stat)
31
+ expect(results).to eq("[STATSD] (total: 100.21) (active_record: 24.00)")
32
+ end
33
+
34
+ it 'includes exclusive_stats if there are any' do
35
+ request_stat = double('request_stat')
36
+ allow(request_stat).to receive(:stats).and_return(
37
+ "total" => 100.21,
38
+ "active.record" => 24)
39
+ allow(request_stat).to receive(:exclusive_stats).and_return(
40
+ "total" => 54.32,
41
+ "active.record" => 1)
42
+ results = @logger.build_log_message(request_stat)
43
+ expect(results).to eq("[STATSD] (total: 100.21) (active_record: 24.00) (exclusive_total: 54.32) (exclusive_active_record: 1.00)")
44
+ end
45
+
46
+ describe 'decimal precision' do
47
+ it 'forces 2 decimal precision' do
48
+ request_stat = double('request_stat')
49
+ allow(request_stat).to receive(:stats).and_return(total: 72.1)
50
+ allow(request_stat).to receive(:exclusive_stats).and_return(nil)
51
+ results = @logger.build_log_message(request_stat)
52
+ expect(results).to eq("[STATSD] (total: 72.10)")
53
+ end
54
+ it 'rounds values to 2 decimals' do
55
+ request_stat = double('request_stat')
56
+ allow(request_stat).to receive(:stats).and_return(total: 72.1382928)
57
+ allow(request_stat).to receive(:exclusive_stats).and_return(nil)
58
+ results = @logger.build_log_message(request_stat)
59
+ expect(results).to eq("[STATSD] (total: 72.14)")
60
+ allow(request_stat).to receive(:stats).and_return(total: 72.1348209)
61
+ results = @logger.build_log_message(request_stat)
62
+ expect(results).to eq("[STATSD] (total: 72.13)")
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ describe '#log' do
69
+ it 'sends info method to logger if logger exists' do
70
+ std_out_logger = Logger.new(STDOUT)
71
+ logger = InstStatsd::RequestLogger.new(std_out_logger)
72
+ expect(std_out_logger).to receive(:info)
73
+ request_stat = double('request_stat')
74
+ allow(request_stat).to receive(:stats).and_return({})
75
+ allow(request_stat).to receive(:exclusive_stats).and_return(nil)
76
+ logger.log(request_stat)
77
+ end
78
+ it 'sends info method with build_log_message output if logger exists' do
79
+ std_out_logger = Logger.new(STDOUT)
80
+ logger = InstStatsd::RequestLogger.new(std_out_logger)
81
+ expect(std_out_logger).to receive(:info).with("[DEFAULT_METRICS] (total: 100.20)")
82
+ request_stat = double('request_stat')
83
+ allow(request_stat).to receive(:stats).and_return(total: 100.2)
84
+ allow(request_stat).to receive(:exclusive_stats).and_return(nil)
85
+ logger.log(request_stat, "DEFAULT_METRICS")
86
+ end
87
+ end
88
+
89
+ end