scout_apm 3.0.0.pre13 → 3.0.0.pre14
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.
- checksums.yaml +4 -4
- data/lib/scout_apm.rb +20 -10
- data/lib/scout_apm/agent.rb +114 -319
- data/lib/scout_apm/agent/exit_handler.rb +66 -0
- data/lib/scout_apm/agent/preconditions.rb +69 -0
- data/lib/scout_apm/agent_context.rb +234 -0
- data/lib/scout_apm/app_server_load.rb +24 -14
- data/lib/scout_apm/background_job_integrations/resque.rb +7 -8
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -2
- data/lib/scout_apm/background_recorder.rb +8 -3
- data/lib/scout_apm/background_worker.rb +14 -7
- data/lib/scout_apm/config.rb +35 -26
- data/lib/scout_apm/context.rb +11 -4
- data/lib/scout_apm/db_query_metric_set.rb +17 -5
- data/lib/scout_apm/debug.rb +1 -1
- data/lib/scout_apm/environment.rb +10 -14
- data/lib/scout_apm/framework_integrations/sinatra.rb +1 -1
- data/lib/scout_apm/git_revision.rb +13 -8
- data/lib/scout_apm/histogram.rb +1 -1
- data/lib/scout_apm/instant/middleware.rb +7 -7
- data/lib/scout_apm/instant_reporting.rb +7 -7
- data/lib/scout_apm/instrument_manager.rb +87 -0
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +12 -7
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +17 -12
- data/lib/scout_apm/instruments/action_view.rb +11 -7
- data/lib/scout_apm/instruments/active_record.rb +25 -11
- data/lib/scout_apm/instruments/elasticsearch.rb +10 -6
- data/lib/scout_apm/instruments/grape.rb +12 -8
- data/lib/scout_apm/instruments/http_client.rb +10 -6
- data/lib/scout_apm/instruments/influxdb.rb +10 -6
- data/lib/scout_apm/instruments/middleware_detailed.rb +11 -5
- data/lib/scout_apm/instruments/middleware_summary.rb +11 -5
- data/lib/scout_apm/instruments/mongoid.rb +10 -5
- data/lib/scout_apm/instruments/moped.rb +11 -6
- data/lib/scout_apm/instruments/net_http.rb +10 -6
- data/lib/scout_apm/instruments/percentile_sampler.rb +8 -6
- data/lib/scout_apm/instruments/process/process_cpu.rb +8 -4
- data/lib/scout_apm/instruments/process/process_memory.rb +15 -10
- data/lib/scout_apm/instruments/rails_router.rb +12 -6
- data/lib/scout_apm/instruments/redis.rb +10 -6
- data/lib/scout_apm/instruments/samplers.rb +11 -0
- data/lib/scout_apm/instruments/sinatra.rb +5 -4
- data/lib/scout_apm/layaway.rb +21 -20
- data/lib/scout_apm/layaway_file.rb +8 -3
- data/lib/scout_apm/layer.rb +3 -3
- data/lib/scout_apm/layer_converters/converter_base.rb +6 -7
- data/lib/scout_apm/layer_converters/database_converter.rb +1 -1
- data/lib/scout_apm/layer_converters/histograms.rb +2 -2
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +4 -3
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +5 -4
- data/lib/scout_apm/logger.rb +143 -0
- data/lib/scout_apm/middleware.rb +7 -9
- data/lib/scout_apm/periodic_work.rb +28 -0
- data/lib/scout_apm/reporter.rb +14 -8
- data/lib/scout_apm/reporting.rb +135 -0
- data/lib/scout_apm/request_manager.rb +4 -6
- data/lib/scout_apm/serializers/payload_serializer.rb +1 -1
- data/lib/scout_apm/slow_job_policy.rb +6 -2
- data/lib/scout_apm/slow_job_record.rb +5 -5
- data/lib/scout_apm/slow_request_policy.rb +6 -2
- data/lib/scout_apm/slow_transaction.rb +5 -5
- data/lib/scout_apm/store.rb +22 -16
- data/lib/scout_apm/synchronous_recorder.rb +7 -3
- data/lib/scout_apm/tasks/doctor.rb +75 -0
- data/lib/scout_apm/tasks/support.rb +22 -0
- data/lib/scout_apm/tracer.rb +5 -5
- data/lib/scout_apm/tracked_request.rb +43 -19
- data/lib/scout_apm/utils/active_record_metric_name.rb +66 -8
- data/lib/scout_apm/utils/backtrace_parser.rb +1 -1
- data/lib/scout_apm/utils/installed_gems.rb +7 -3
- data/lib/scout_apm/utils/klass_helper.rb +8 -2
- data/lib/scout_apm/utils/scm.rb +1 -1
- data/lib/scout_apm/utils/sql_sanitizer.rb +3 -3
- data/lib/scout_apm/version.rb +1 -1
- data/lib/tasks/doctor.rake +11 -0
- data/scout_apm.gemspec +1 -0
- data/test/test_helper.rb +17 -2
- data/test/unit/agent_test.rb +1 -54
- data/test/unit/config_test.rb +9 -5
- data/test/unit/context_test.rb +4 -4
- data/test/unit/db_query_metric_set_test.rb +11 -4
- data/test/unit/fake_store_test.rb +1 -1
- data/test/unit/git_revision_test.rb +3 -3
- data/test/unit/instruments/net_http_test.rb +2 -1
- data/test/unit/instruments/percentile_sampler_test.rb +5 -9
- data/test/unit/layaway_test.rb +10 -5
- data/test/unit/layer_converters/metric_converter_test.rb +2 -2
- data/test/unit/slow_request_policy_test.rb +7 -3
- data/test/unit/sql_sanitizer_test.rb +0 -6
- data/test/unit/store_test.rb +11 -8
- data/test/unit/utils/active_record_metric_name_test.rb +45 -7
- metadata +27 -5
- data/lib/scout_apm/agent/logging.rb +0 -74
- data/lib/scout_apm/agent/reporting.rb +0 -129
- data/lib/scout_apm/utils/null_logger.rb +0 -13
data/test/unit/store_test.rb
CHANGED
|
@@ -3,15 +3,17 @@ require 'test_helper'
|
|
|
3
3
|
require 'scout_apm/store'
|
|
4
4
|
|
|
5
5
|
class FakeFailingLayaway
|
|
6
|
+
attr_reader :rps_written
|
|
6
7
|
def write_reporting_period(rp)
|
|
7
|
-
|
|
8
|
+
@rps_written ||= []
|
|
9
|
+
@rps_written << rp
|
|
8
10
|
end
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
class StoreTest < Minitest::Test
|
|
12
14
|
# TODO: Introduce a clock object to avoid having to use 'force'
|
|
13
15
|
def test_writing_layaway_removes_timestamps
|
|
14
|
-
s = ScoutApm::Store.new
|
|
16
|
+
s = ScoutApm::Store.new(ScoutApm::AgentContext.new)
|
|
15
17
|
s.track_one!("Controller", "user/show", 10)
|
|
16
18
|
|
|
17
19
|
assert_equal(1, s.instance_variable_get('@reporting_periods').size)
|
|
@@ -22,13 +24,14 @@ class StoreTest < Minitest::Test
|
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
def test_writing_layaway_removes_stale_timestamps
|
|
27
|
+
context = ScoutApm::AgentContext.new
|
|
25
28
|
current_time = Time.now.utc
|
|
26
|
-
current_rp = ScoutApm::StoreReportingPeriod.new(current_time)
|
|
27
|
-
stale_rp = ScoutApm::StoreReportingPeriod.new(current_time - current_time.sec - 120)
|
|
29
|
+
current_rp = ScoutApm::StoreReportingPeriod.new(current_time, context)
|
|
30
|
+
stale_rp = ScoutApm::StoreReportingPeriod.new(current_time - current_time.sec - 120, context)
|
|
28
31
|
|
|
29
|
-
s = ScoutApm::Store.new
|
|
30
|
-
ScoutApm::Instruments::Process::ProcessMemory.new(
|
|
31
|
-
ScoutApm::Instruments::Process::ProcessMemory.new(
|
|
32
|
+
s = ScoutApm::Store.new(context)
|
|
33
|
+
ScoutApm::Instruments::Process::ProcessMemory.new(context).metrics(stale_rp.timestamp, s)
|
|
34
|
+
ScoutApm::Instruments::Process::ProcessMemory.new(context).metrics(current_rp.timestamp, s)
|
|
32
35
|
assert_equal 2, s.instance_variable_get('@reporting_periods').size
|
|
33
36
|
|
|
34
37
|
s.write_to_layaway(FakeFailingLayaway.new, true)
|
|
@@ -43,7 +46,7 @@ class StoreReportingPeriodTest < Minitest::Test
|
|
|
43
46
|
attr_reader :subject
|
|
44
47
|
|
|
45
48
|
def setup
|
|
46
|
-
@subject = ScoutApm::StoreReportingPeriod.new(ScoutApm::StoreReportingPeriodTimestamp.new)
|
|
49
|
+
@subject = ScoutApm::StoreReportingPeriod.new(ScoutApm::StoreReportingPeriodTimestamp.new(Time.now), ScoutApm::AgentContext.new)
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
# Check default values at creation time
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'test_helper'
|
|
2
2
|
require 'scout_apm/utils/active_record_metric_name'
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
class ActiveRecordMetricNameTest < Minitest::Test
|
|
5
6
|
# This is a bug report from Андрей Филиппов <tmn.sun@gmail.com>
|
|
6
7
|
# The code that triggered the bug was: ActiveRecord::Base.connection.execute("%some sql%", :skip_logging)
|
|
@@ -9,7 +10,7 @@ class ActiveRecordMetricNameTest < Minitest::Test
|
|
|
9
10
|
name = :skip_logging
|
|
10
11
|
|
|
11
12
|
mn = ScoutApm::Utils::ActiveRecordMetricName.new(sql, name)
|
|
12
|
-
assert_equal "
|
|
13
|
+
assert_equal "User/find", mn.to_s
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def test_postgres_column_lookup
|
|
@@ -27,7 +28,7 @@ class ActiveRecordMetricNameTest < Minitest::Test
|
|
|
27
28
|
name = "SCHEMA"
|
|
28
29
|
|
|
29
30
|
mn = ScoutApm::Utils::ActiveRecordMetricName.new(sql, name)
|
|
30
|
-
assert_equal "SQL/
|
|
31
|
+
assert_equal "SQL/other", mn.to_s
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
|
|
@@ -44,23 +45,60 @@ class ActiveRecordMetricNameTest < Minitest::Test
|
|
|
44
45
|
name = nil
|
|
45
46
|
|
|
46
47
|
mn = ScoutApm::Utils::ActiveRecordMetricName.new(sql, name)
|
|
47
|
-
assert_equal "
|
|
48
|
+
assert_equal "User/find", mn.to_s
|
|
48
49
|
end
|
|
49
50
|
|
|
50
51
|
def test_with_sql_name
|
|
51
|
-
sql = %q|INSERT INTO "users"
|
|
52
|
+
sql = %q|INSERT INTO "users" VALUES (1,2,3)|
|
|
52
53
|
name = "SQL"
|
|
53
54
|
|
|
54
55
|
mn = ScoutApm::Utils::ActiveRecordMetricName.new(sql, name)
|
|
55
|
-
assert_equal "
|
|
56
|
+
assert_equal "User/create", mn.to_s
|
|
56
57
|
end
|
|
57
58
|
|
|
58
|
-
# TODO: Determine if there should be a distinction between Unknown and Other.
|
|
59
59
|
def test_with_custom_name
|
|
60
60
|
sql = %q|SELECT "users".* FROM "users" /*application:Testapp,controller:public,action:index*/|
|
|
61
61
|
name = "A whole sentance describing what's what"
|
|
62
62
|
|
|
63
63
|
mn = ScoutApm::Utils::ActiveRecordMetricName.new(sql, name)
|
|
64
|
-
assert_equal "
|
|
64
|
+
assert_equal "User/find", mn.to_s
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# Regex test cases, pass these in w/ "SQL" as the AR provided name field
|
|
69
|
+
[
|
|
70
|
+
["LoginRecord/save", 'UPDATE "login_record" SET "updated_at" = ? WHERE "login_record"."login_record_id" = ?'],
|
|
71
|
+
["UserAccount/save", 'UPDATE "user_account" SET "last_activity" = ? WHERE "user_account"."user_account_id" = ?'],
|
|
72
|
+
["Membership/save", 'UPDATE "membership" SET "updated_at" = ? WHERE "membership"."membership_id" = ?'],
|
|
73
|
+
["Membership/save", 'UPDATE "membership" SET "updated_by" = ? WHERE "membership"."membership_id" = ?'],
|
|
74
|
+
["Project/find", 'SELECT "project".project_id FROM "project" INNER JOIN "membership" ON "project"."project_id" = "membership"."project_id" WHERE "membership"."user_account_id" = ?'],
|
|
75
|
+
["Entity/count", 'SELECT COUNT(*) FROM "entity" WHERE "entity"."entity_id" IN (?)'],
|
|
76
|
+
["EntityEventStep/find", 'SELECT entity_event_step.entity_id, entity_event_step.event_step_id, event_step.event_id FROM entity_event_step INNER JOIN event_step ON event_step.event_step_id = entity_event_step.event_step_id WHERE event_step.event_id in (?) AND entity_event_step.entity_id in (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'],
|
|
77
|
+
["CustomField/count", 'SELECT COUNT(*) FROM "custom_field" WHERE "custom_field"."project_id" = ? AND "custom_field"."enabled" = ?'],
|
|
78
|
+
["Event/find", 'SELECT MAX("events"."updated_at") AS max_id FROM "events" LEFT OUTER JOIN "configurations" ON "configurations"."event_id" = "events"."id" WHERE (configurations.date >= ?)'],
|
|
79
|
+
["Sponsorship/find", ' SELECT "sponsorships"."id" AS t0_r0, "sponsorships"."event_id" AS t0_r1, "sponsorships"."name" AS t0_r2, "sponsorships"."position" AS t0_r3, "sponsorships"."created_at" AS t0_r4, "sponsorships"."updated_at" AS t0_r5, "sponsorships"."display_name" AS t0_r6, "sponsorships"."home_page_id" AS t0_r7, "sponsors"."id" AS t1_r0, "sponsors"."name" AS t1_r1, "sponsors"."url" AS t1_r2, "sponsors"."created_at" AS t1_r3, "sponsors"."updated_at" AS t1_r4, "assets"."id" AS t2_r0, "assets"."type" AS t2_r1, "assets"."assetable_id" AS t2_r2, "assets"."assetable_type" AS t2_r3, "assets"."attachment_file_name" AS t2_r4, "assets"."attachment_content_type" AS t2_r5, "assets"."attachment_file_size" AS t2_r6, "assets"."attachment_updated_at" AS t2_r7, "assets"."created_at" AS t2_r8, "assets"."updated_at" AS t2_r9 FROM "sponsorships" LEFT OUTER JOIN "ranks" ON "ranks"."sponsorship_id" = "sponsorships"."id" LEFT OUTER JOIN "sponsors" ON "sponsors"."id" = "ranks"."sponsor_id" LEFT OUTER JOIN "assets" ON "assets".'],
|
|
80
|
+
["MaxmindGeoliteCountry/find", 'SELECT country, country_code FROM maxmind_geolite_country WHERE start_ip_num <= ? AND ? <= end_ip_num'],
|
|
81
|
+
["Activity/find", 'SELECT `activities`.`id` FROM `activities` INNER JOIN `activity_attendees` ON `activity_attendees`.`activity_id` = `activities`.`id` AND `activity_attendees`.`deleted` = ? LEFT JOIN activity_recurrence_periods arp ON arp.activity_id = activities.id WHERE (activities.updated_at >= ?) AND ((activities.start_date between ? and ? and activities.all_day = ?) or (CAST(activities.start_date as Date) between ? and ? and activities.all_day = ?)) AND (activity_attendees.user_id IN (?)) AND (arp.id IS NULL)'],
|
|
82
|
+
|
|
83
|
+
# Lower Case.
|
|
84
|
+
# ["MaxmindGeoliteCountry#Select", 'select country, country_code from maxmind_geolite_country where start_ip_num <= ? and ? <= end_ip_num'],
|
|
85
|
+
|
|
86
|
+
# No FROM clause (was clipped off)
|
|
87
|
+
["SQL/other", 'SELECT "events"."id" AS t0_r0, "events"."name" AS t0_r1, "events"."subdomain" AS t0_r2, "events"."created_at" AS t0_r3, "events"."updated_at" AS t0_r4, "events"."slug" AS t0_r5, "events"."domain" AS t0_r6, "events"."published" AS t0_r7, "events"."category" AS t0_r8, "events"."venue_id" AS t0_r9, "events"."bitly_url" AS t0_r10, "events"."shown_in_events_list" AS t0_r11, "venues"."id" AS t1_r0, "venues"."name" AS t1_r1, "venues"."capacity" AS t1_r2, "venues"."address" AS t1_r3, "venues"."parking_info" AS t1_r4, "venues"."manual_coordinates" AS t1_r5, "venues"."latitude" AS t1_r6, "venues"."longitude" AS t1_r7, "venues"."description" AS t1_r8, "venues"."created_at" AS t1_r9, "venues"."updated_at" AS t1_r10, "venue_translations"."id" AS t2_r0, "venue_translations"."venue_id" AS t2_r1, "venue_translations"."locale" AS t2_r2, "venue_translations"."created_at" AS t2_r3, "venue_translations"."updated_at" AS t2_r4, "venue_translations"."name" AS t2_r5, "venue_translations"."description" AS t2_r6'],
|
|
88
|
+
|
|
89
|
+
# Stuff we don't care about in SQL
|
|
90
|
+
["SQL/other", 'SET SESSION statement_timeout = ?'],
|
|
91
|
+
["SQL/other", 'SHOW TIME ZONE'],
|
|
92
|
+
["SQL/other", 'BEGIN'],
|
|
93
|
+
["SQL/other", 'COMMIT'],
|
|
94
|
+
|
|
95
|
+
# Empty strings, or invalid SQL
|
|
96
|
+
["SQL/other", ''],
|
|
97
|
+
["SQL/other", 'not sql at all!'],
|
|
98
|
+
].each_with_index do |(expected, sql), i|
|
|
99
|
+
define_method :"test_regex_naming_#{i}" do
|
|
100
|
+
actual = ScoutApm::Utils::ActiveRecordMetricName.new(sql, "SQL").to_s
|
|
101
|
+
assert_equal expected, actual
|
|
102
|
+
end
|
|
65
103
|
end
|
|
66
104
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: scout_apm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.0.
|
|
4
|
+
version: 3.0.0.pre14
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Derek Haynes
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2017-
|
|
12
|
+
date: 2017-12-18 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: minitest
|
|
@@ -137,6 +137,20 @@ dependencies:
|
|
|
137
137
|
- - ">="
|
|
138
138
|
- !ruby/object:Gem::Version
|
|
139
139
|
version: '0'
|
|
140
|
+
- !ruby/object:Gem::Dependency
|
|
141
|
+
name: activesupport
|
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
|
143
|
+
requirements:
|
|
144
|
+
- - ">="
|
|
145
|
+
- !ruby/object:Gem::Version
|
|
146
|
+
version: '0'
|
|
147
|
+
type: :development
|
|
148
|
+
prerelease: false
|
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
150
|
+
requirements:
|
|
151
|
+
- - ">="
|
|
152
|
+
- !ruby/object:Gem::Version
|
|
153
|
+
version: '0'
|
|
140
154
|
description: Monitors Ruby apps and reports detailed metrics on performance to Scout.
|
|
141
155
|
email:
|
|
142
156
|
- support@scoutapp.com
|
|
@@ -166,8 +180,9 @@ files:
|
|
|
166
180
|
- ext/stacks/stacks.c
|
|
167
181
|
- lib/scout_apm.rb
|
|
168
182
|
- lib/scout_apm/agent.rb
|
|
169
|
-
- lib/scout_apm/agent/
|
|
170
|
-
- lib/scout_apm/agent/
|
|
183
|
+
- lib/scout_apm/agent/exit_handler.rb
|
|
184
|
+
- lib/scout_apm/agent/preconditions.rb
|
|
185
|
+
- lib/scout_apm/agent_context.rb
|
|
171
186
|
- lib/scout_apm/app_server_load.rb
|
|
172
187
|
- lib/scout_apm/attribute_arranger.rb
|
|
173
188
|
- lib/scout_apm/background_job_integrations/delayed_job.rb
|
|
@@ -194,6 +209,7 @@ files:
|
|
|
194
209
|
- lib/scout_apm/instant/assets/xmlhttp_instrumentation.html
|
|
195
210
|
- lib/scout_apm/instant/middleware.rb
|
|
196
211
|
- lib/scout_apm/instant_reporting.rb
|
|
212
|
+
- lib/scout_apm/instrument_manager.rb
|
|
197
213
|
- lib/scout_apm/instruments/.DS_Store
|
|
198
214
|
- lib/scout_apm/instruments/action_controller_rails_2.rb
|
|
199
215
|
- lib/scout_apm/instruments/action_controller_rails_3_rails4.rb
|
|
@@ -214,6 +230,7 @@ files:
|
|
|
214
230
|
- lib/scout_apm/instruments/rails_router.rb
|
|
215
231
|
- lib/scout_apm/instruments/redis.rb
|
|
216
232
|
- lib/scout_apm/instruments/resque.rb
|
|
233
|
+
- lib/scout_apm/instruments/samplers.rb
|
|
217
234
|
- lib/scout_apm/instruments/sinatra.rb
|
|
218
235
|
- lib/scout_apm/job_record.rb
|
|
219
236
|
- lib/scout_apm/layaway.rb
|
|
@@ -233,10 +250,12 @@ files:
|
|
|
233
250
|
- lib/scout_apm/layer_converters/slow_job_converter.rb
|
|
234
251
|
- lib/scout_apm/layer_converters/slow_request_converter.rb
|
|
235
252
|
- lib/scout_apm/limited_layer.rb
|
|
253
|
+
- lib/scout_apm/logger.rb
|
|
236
254
|
- lib/scout_apm/metric_meta.rb
|
|
237
255
|
- lib/scout_apm/metric_set.rb
|
|
238
256
|
- lib/scout_apm/metric_stats.rb
|
|
239
257
|
- lib/scout_apm/middleware.rb
|
|
258
|
+
- lib/scout_apm/periodic_work.rb
|
|
240
259
|
- lib/scout_apm/platform_integrations/cloud_foundry.rb
|
|
241
260
|
- lib/scout_apm/platform_integrations/heroku.rb
|
|
242
261
|
- lib/scout_apm/platform_integrations/server.rb
|
|
@@ -246,6 +265,7 @@ files:
|
|
|
246
265
|
- lib/scout_apm/remote/router.rb
|
|
247
266
|
- lib/scout_apm/remote/server.rb
|
|
248
267
|
- lib/scout_apm/reporter.rb
|
|
268
|
+
- lib/scout_apm/reporting.rb
|
|
249
269
|
- lib/scout_apm/request_histograms.rb
|
|
250
270
|
- lib/scout_apm/request_manager.rb
|
|
251
271
|
- lib/scout_apm/scored_item_set.rb
|
|
@@ -272,6 +292,8 @@ files:
|
|
|
272
292
|
- lib/scout_apm/stack_item.rb
|
|
273
293
|
- lib/scout_apm/store.rb
|
|
274
294
|
- lib/scout_apm/synchronous_recorder.rb
|
|
295
|
+
- lib/scout_apm/tasks/doctor.rb
|
|
296
|
+
- lib/scout_apm/tasks/support.rb
|
|
275
297
|
- lib/scout_apm/trace_compactor.rb
|
|
276
298
|
- lib/scout_apm/tracer.rb
|
|
277
299
|
- lib/scout_apm/tracked_request.rb
|
|
@@ -281,7 +303,6 @@ files:
|
|
|
281
303
|
- lib/scout_apm/utils/gzip_helper.rb
|
|
282
304
|
- lib/scout_apm/utils/installed_gems.rb
|
|
283
305
|
- lib/scout_apm/utils/klass_helper.rb
|
|
284
|
-
- lib/scout_apm/utils/null_logger.rb
|
|
285
306
|
- lib/scout_apm/utils/numbers.rb
|
|
286
307
|
- lib/scout_apm/utils/scm.rb
|
|
287
308
|
- lib/scout_apm/utils/sql_sanitizer.rb
|
|
@@ -290,6 +311,7 @@ files:
|
|
|
290
311
|
- lib/scout_apm/utils/time.rb
|
|
291
312
|
- lib/scout_apm/utils/unique_id.rb
|
|
292
313
|
- lib/scout_apm/version.rb
|
|
314
|
+
- lib/tasks/doctor.rake
|
|
293
315
|
- scout_apm.gemspec
|
|
294
316
|
- test/data/config_test_1.yml
|
|
295
317
|
- test/test_helper.rb
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Contains methods specific to logging (initializing the log file, applying the log level, applying the log format, etc.)
|
|
2
|
-
module ScoutApm
|
|
3
|
-
class Agent
|
|
4
|
-
module Logging
|
|
5
|
-
def default_log_path
|
|
6
|
-
"#{environment.root}/log"
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def init_logger(opts={})
|
|
10
|
-
if opts[:force]
|
|
11
|
-
@log_file = nil
|
|
12
|
-
@logger = nil
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
begin
|
|
16
|
-
@log_file ||= determine_log_destination
|
|
17
|
-
rescue => e
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
begin
|
|
21
|
-
@logger ||= Logger.new(@log_file)
|
|
22
|
-
@logger.level = log_level
|
|
23
|
-
apply_log_format
|
|
24
|
-
rescue Exception => e
|
|
25
|
-
@logger = Logger.new(STDOUT)
|
|
26
|
-
apply_log_format
|
|
27
|
-
@logger.error "Unable to open log file for writing: #{e.message}. Falling back to STDOUT"
|
|
28
|
-
end
|
|
29
|
-
@logger
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def apply_log_format
|
|
33
|
-
def logger.format_message(severity, timestamp, progname, msg)
|
|
34
|
-
# since STDOUT isn't exclusive like the scout_apm.log file, apply a prefix.
|
|
35
|
-
prefix = @logdev.dev == STDOUT ? "[Scout] " : ''
|
|
36
|
-
prefix + "[#{Utils::Time.to_s(timestamp)} #{ScoutApm::Agent.instance.environment.hostname} (#{$$})] #{severity} : #{msg}\n"
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def log_level
|
|
41
|
-
case config.value('log_level').downcase
|
|
42
|
-
when "debug" then Logger::DEBUG
|
|
43
|
-
when "info" then Logger::INFO
|
|
44
|
-
when "warn" then Logger::WARN
|
|
45
|
-
when "error" then Logger::ERROR
|
|
46
|
-
when "fatal" then Logger::FATAL
|
|
47
|
-
else Logger::INFO
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def determine_log_destination
|
|
52
|
-
case true
|
|
53
|
-
when wants_stdout? then STDOUT
|
|
54
|
-
when wants_stderr? then STDERR
|
|
55
|
-
else "#{log_file_path}/scout_apm.log"
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def wants_stdout?
|
|
60
|
-
config.value('log_file_path').to_s.upcase == 'STDOUT' || environment.platform_integration.log_to_stdout?
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def wants_stderr?
|
|
64
|
-
config.value('log_file_path').to_s.upcase == 'STDERR'
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def log_file_path
|
|
68
|
-
config.value('log_file_path') || default_log_path
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
include Logging
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
# Methods related to sending metrics to scoutapp.com.
|
|
2
|
-
module ScoutApm
|
|
3
|
-
class Agent
|
|
4
|
-
module Reporting
|
|
5
|
-
def reporter
|
|
6
|
-
@reporter ||= ScoutApm::Reporter.new(:checkin, config, logger)
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
# The data moves through a treadmill of reporting, coordinating several Rails processes by using an external file.
|
|
10
|
-
# * During the minute it is being recorded by the instruments, it gets
|
|
11
|
-
# recorded into the ram of each process (in the Store class).
|
|
12
|
-
# * The minute after, each process writes its own metrics to a shared LayawayFile
|
|
13
|
-
# * The minute after that, the first process to wake up pushes the combined
|
|
14
|
-
# data to the server, and wipes it. Next processes don't have anything to do.
|
|
15
|
-
#
|
|
16
|
-
# At any given point, there is data in each of those steps, moving its way through the process
|
|
17
|
-
def process_metrics
|
|
18
|
-
# Write the previous minute's data to the shared-across-process layaway file.
|
|
19
|
-
store.write_to_layaway(layaway)
|
|
20
|
-
|
|
21
|
-
# Attempt to send 2 minutes ago's data up to the server. This
|
|
22
|
-
# only acctually occurs if this process is the first to wake up this
|
|
23
|
-
# minute.
|
|
24
|
-
report_to_server
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# In a running app, one process will get the period ready for delivery, the others will see 0.
|
|
28
|
-
def report_to_server
|
|
29
|
-
period_to_report = ScoutApm::StoreReportingPeriodTimestamp.minutes_ago(2)
|
|
30
|
-
|
|
31
|
-
logger.debug("Attempting to claim #{period_to_report.to_s}")
|
|
32
|
-
|
|
33
|
-
did_write = layaway.with_claim(period_to_report) do |rps|
|
|
34
|
-
logger.debug("Succeeded claiming #{period_to_report.to_s}")
|
|
35
|
-
|
|
36
|
-
begin
|
|
37
|
-
merged = rps.inject { |memo, rp| memo.merge(rp) }
|
|
38
|
-
logger.debug("Merged #{rps.length} reporting periods, delivering")
|
|
39
|
-
deliver_period(merged)
|
|
40
|
-
true
|
|
41
|
-
rescue => e
|
|
42
|
-
logger.debug("Error merging reporting periods #{e.message}")
|
|
43
|
-
logger.debug("Error merging reporting periods #{e.backtrace}")
|
|
44
|
-
false
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
if !did_write
|
|
50
|
-
logger.debug("Failed to obtain claim for #{period_to_report.to_s}")
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def deliver_period(reporting_period)
|
|
57
|
-
metrics = reporting_period.metrics_payload
|
|
58
|
-
slow_transactions = reporting_period.slow_transactions_payload
|
|
59
|
-
jobs = reporting_period.jobs
|
|
60
|
-
slow_jobs = reporting_period.slow_jobs_payload
|
|
61
|
-
histograms = reporting_period.histograms
|
|
62
|
-
db_query_metrics = reporting_period.db_query_metrics_payload
|
|
63
|
-
|
|
64
|
-
metadata = {
|
|
65
|
-
:app_root => ScoutApm::Environment.instance.root.to_s,
|
|
66
|
-
:unique_id => ScoutApm::Utils::UniqueId.simple,
|
|
67
|
-
:agent_version => ScoutApm::VERSION,
|
|
68
|
-
:agent_time => reporting_period.timestamp.to_s,
|
|
69
|
-
:agent_pid => Process.pid,
|
|
70
|
-
:platform => "ruby",
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
log_deliver(metrics, slow_transactions, metadata, slow_jobs, histograms)
|
|
74
|
-
|
|
75
|
-
payload = ScoutApm::Serializers::PayloadSerializer.serialize(metadata, metrics, slow_transactions, jobs, slow_jobs, histograms, db_query_metrics)
|
|
76
|
-
logger.debug("Sending payload w/ Headers: #{headers.inspect}")
|
|
77
|
-
|
|
78
|
-
reporter.report(payload, headers)
|
|
79
|
-
rescue => e
|
|
80
|
-
logger.warn "Error on checkin"
|
|
81
|
-
logger.info e.message
|
|
82
|
-
logger.debug e.backtrace
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def log_deliver(metrics, slow_transactions, metadata, jobs_traces, histograms)
|
|
86
|
-
total_request_count = metrics.
|
|
87
|
-
select { |meta,stats| meta.metric_name =~ /\AController/ }.
|
|
88
|
-
inject(0) {|sum, (_, stat)| sum + stat.call_count }
|
|
89
|
-
|
|
90
|
-
memory = metrics.
|
|
91
|
-
find {|meta,stats| meta.metric_name =~ /\AMemory/ }
|
|
92
|
-
process_log_str = if memory
|
|
93
|
-
"Recorded from #{memory.last.call_count} processes"
|
|
94
|
-
else
|
|
95
|
-
"Recorded across (unknown) processes"
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
time_clause = "[#{Time.parse(metadata[:agent_time]).strftime("%H:%M")}]"
|
|
99
|
-
metrics_clause = "#{metrics.length} Metrics for #{total_request_count} requests"
|
|
100
|
-
slow_trans_clause = "#{slow_transactions.length} Slow Transaction Traces"
|
|
101
|
-
job_clause = "#{jobs_traces.length} Job Traces"
|
|
102
|
-
histogram_clause = "#{histograms.length} Histograms"
|
|
103
|
-
|
|
104
|
-
logger.info "#{time_clause} Delivering #{metrics_clause} and #{slow_trans_clause} and #{job_clause}, #{process_log_str}."
|
|
105
|
-
# logger.debug("\n\nMetrics: #{metrics.pretty_inspect}\nSlowTrans: #{slow_transactions.pretty_inspect}\nMetadata: #{metadata.inspect.pretty_inspect}\n\n")
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# TODO: Move this into PayloadSerializer?
|
|
109
|
-
def headers
|
|
110
|
-
if ScoutApm::Agent.instance.config.value("report_format") == 'json'
|
|
111
|
-
headers = {'Content-Type' => 'application/json'}
|
|
112
|
-
else
|
|
113
|
-
headers = {}
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# Before reporting, lookup metric_id for each MetricMeta. This speeds up
|
|
118
|
-
# reporting on the server-side.
|
|
119
|
-
def add_metric_ids(metrics)
|
|
120
|
-
metrics.each do |meta,stats|
|
|
121
|
-
if metric_id = metric_lookup[meta]
|
|
122
|
-
meta.metric_id = metric_id
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
include Reporting
|
|
128
|
-
end
|
|
129
|
-
end
|