scout_apm 3.0.0.pre13 → 3.0.0.pre14

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 +4 -4
  2. data/lib/scout_apm.rb +20 -10
  3. data/lib/scout_apm/agent.rb +114 -319
  4. data/lib/scout_apm/agent/exit_handler.rb +66 -0
  5. data/lib/scout_apm/agent/preconditions.rb +69 -0
  6. data/lib/scout_apm/agent_context.rb +234 -0
  7. data/lib/scout_apm/app_server_load.rb +24 -14
  8. data/lib/scout_apm/background_job_integrations/resque.rb +7 -8
  9. data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -2
  10. data/lib/scout_apm/background_recorder.rb +8 -3
  11. data/lib/scout_apm/background_worker.rb +14 -7
  12. data/lib/scout_apm/config.rb +35 -26
  13. data/lib/scout_apm/context.rb +11 -4
  14. data/lib/scout_apm/db_query_metric_set.rb +17 -5
  15. data/lib/scout_apm/debug.rb +1 -1
  16. data/lib/scout_apm/environment.rb +10 -14
  17. data/lib/scout_apm/framework_integrations/sinatra.rb +1 -1
  18. data/lib/scout_apm/git_revision.rb +13 -8
  19. data/lib/scout_apm/histogram.rb +1 -1
  20. data/lib/scout_apm/instant/middleware.rb +7 -7
  21. data/lib/scout_apm/instant_reporting.rb +7 -7
  22. data/lib/scout_apm/instrument_manager.rb +87 -0
  23. data/lib/scout_apm/instruments/action_controller_rails_2.rb +12 -7
  24. data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +17 -12
  25. data/lib/scout_apm/instruments/action_view.rb +11 -7
  26. data/lib/scout_apm/instruments/active_record.rb +25 -11
  27. data/lib/scout_apm/instruments/elasticsearch.rb +10 -6
  28. data/lib/scout_apm/instruments/grape.rb +12 -8
  29. data/lib/scout_apm/instruments/http_client.rb +10 -6
  30. data/lib/scout_apm/instruments/influxdb.rb +10 -6
  31. data/lib/scout_apm/instruments/middleware_detailed.rb +11 -5
  32. data/lib/scout_apm/instruments/middleware_summary.rb +11 -5
  33. data/lib/scout_apm/instruments/mongoid.rb +10 -5
  34. data/lib/scout_apm/instruments/moped.rb +11 -6
  35. data/lib/scout_apm/instruments/net_http.rb +10 -6
  36. data/lib/scout_apm/instruments/percentile_sampler.rb +8 -6
  37. data/lib/scout_apm/instruments/process/process_cpu.rb +8 -4
  38. data/lib/scout_apm/instruments/process/process_memory.rb +15 -10
  39. data/lib/scout_apm/instruments/rails_router.rb +12 -6
  40. data/lib/scout_apm/instruments/redis.rb +10 -6
  41. data/lib/scout_apm/instruments/samplers.rb +11 -0
  42. data/lib/scout_apm/instruments/sinatra.rb +5 -4
  43. data/lib/scout_apm/layaway.rb +21 -20
  44. data/lib/scout_apm/layaway_file.rb +8 -3
  45. data/lib/scout_apm/layer.rb +3 -3
  46. data/lib/scout_apm/layer_converters/converter_base.rb +6 -7
  47. data/lib/scout_apm/layer_converters/database_converter.rb +1 -1
  48. data/lib/scout_apm/layer_converters/histograms.rb +2 -2
  49. data/lib/scout_apm/layer_converters/slow_job_converter.rb +4 -3
  50. data/lib/scout_apm/layer_converters/slow_request_converter.rb +5 -4
  51. data/lib/scout_apm/logger.rb +143 -0
  52. data/lib/scout_apm/middleware.rb +7 -9
  53. data/lib/scout_apm/periodic_work.rb +28 -0
  54. data/lib/scout_apm/reporter.rb +14 -8
  55. data/lib/scout_apm/reporting.rb +135 -0
  56. data/lib/scout_apm/request_manager.rb +4 -6
  57. data/lib/scout_apm/serializers/payload_serializer.rb +1 -1
  58. data/lib/scout_apm/slow_job_policy.rb +6 -2
  59. data/lib/scout_apm/slow_job_record.rb +5 -5
  60. data/lib/scout_apm/slow_request_policy.rb +6 -2
  61. data/lib/scout_apm/slow_transaction.rb +5 -5
  62. data/lib/scout_apm/store.rb +22 -16
  63. data/lib/scout_apm/synchronous_recorder.rb +7 -3
  64. data/lib/scout_apm/tasks/doctor.rb +75 -0
  65. data/lib/scout_apm/tasks/support.rb +22 -0
  66. data/lib/scout_apm/tracer.rb +5 -5
  67. data/lib/scout_apm/tracked_request.rb +43 -19
  68. data/lib/scout_apm/utils/active_record_metric_name.rb +66 -8
  69. data/lib/scout_apm/utils/backtrace_parser.rb +1 -1
  70. data/lib/scout_apm/utils/installed_gems.rb +7 -3
  71. data/lib/scout_apm/utils/klass_helper.rb +8 -2
  72. data/lib/scout_apm/utils/scm.rb +1 -1
  73. data/lib/scout_apm/utils/sql_sanitizer.rb +3 -3
  74. data/lib/scout_apm/version.rb +1 -1
  75. data/lib/tasks/doctor.rake +11 -0
  76. data/scout_apm.gemspec +1 -0
  77. data/test/test_helper.rb +17 -2
  78. data/test/unit/agent_test.rb +1 -54
  79. data/test/unit/config_test.rb +9 -5
  80. data/test/unit/context_test.rb +4 -4
  81. data/test/unit/db_query_metric_set_test.rb +11 -4
  82. data/test/unit/fake_store_test.rb +1 -1
  83. data/test/unit/git_revision_test.rb +3 -3
  84. data/test/unit/instruments/net_http_test.rb +2 -1
  85. data/test/unit/instruments/percentile_sampler_test.rb +5 -9
  86. data/test/unit/layaway_test.rb +10 -5
  87. data/test/unit/layer_converters/metric_converter_test.rb +2 -2
  88. data/test/unit/slow_request_policy_test.rb +7 -3
  89. data/test/unit/sql_sanitizer_test.rb +0 -6
  90. data/test/unit/store_test.rb +11 -8
  91. data/test/unit/utils/active_record_metric_name_test.rb +45 -7
  92. metadata +27 -5
  93. data/lib/scout_apm/agent/logging.rb +0 -74
  94. data/lib/scout_apm/agent/reporting.rb +0 -129
  95. data/lib/scout_apm/utils/null_logger.rb +0 -13
@@ -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
- raise "Always fails. Sucks."
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(Logger.new(StringIO.new)).metrics(stale_rp.timestamp, s)
31
- ScoutApm::Instruments::Process::ProcessMemory.new(Logger.new(StringIO.new)).metrics(current_rp.timestamp, s)
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 "SQL/Unknown", mn.to_s
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/Unknown", mn.to_s
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 "SQL/Unknown", mn.to_s
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".* VALUES (1,2,3)|
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 "SQL/Unknown", mn.to_s
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 "SQL/other", mn.to_s
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.pre13
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-10-20 00:00:00.000000000 Z
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/logging.rb
170
- - lib/scout_apm/agent/reporting.rb
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