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.
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