newrelic_rpm 3.9.1.236 → 3.9.2.239

Sign up to get free protection for your applications and to get access to all the features.
Files changed (220) hide show
  1. data.tar.gz.sig +2 -4
  2. data/CHANGELOG +96 -2
  3. data/lib/new_relic/agent.rb +47 -4
  4. data/lib/new_relic/agent/agent.rb +51 -26
  5. data/lib/new_relic/agent/agent_logger.rb +4 -0
  6. data/lib/new_relic/agent/configuration.rb +2 -32
  7. data/lib/new_relic/agent/configuration/default_source.rb +153 -118
  8. data/lib/new_relic/agent/configuration/dotted_hash.rb +52 -0
  9. data/lib/new_relic/agent/configuration/environment_source.rb +1 -1
  10. data/lib/new_relic/agent/configuration/manager.rb +101 -2
  11. data/lib/new_relic/agent/configuration/manual_source.rb +17 -0
  12. data/lib/new_relic/agent/configuration/server_source.rb +12 -4
  13. data/lib/new_relic/agent/configuration/yaml_source.rb +46 -22
  14. data/lib/new_relic/agent/cross_app_monitor.rb +1 -1
  15. data/lib/new_relic/agent/cross_app_tracing.rb +1 -1
  16. data/lib/new_relic/agent/database/obfuscation_helpers.rb +55 -14
  17. data/lib/new_relic/agent/database/obfuscator.rb +22 -7
  18. data/lib/new_relic/agent/database/postgres_explain_obfuscator.rb +6 -8
  19. data/lib/new_relic/agent/error_collector.rb +24 -16
  20. data/lib/new_relic/agent/event_loop.rb +189 -0
  21. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +8 -17
  22. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -1
  23. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +1 -1
  24. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +17 -16
  25. data/lib/new_relic/agent/instrumentation/ignore_actions.rb +41 -0
  26. data/lib/new_relic/agent/instrumentation/merb/controller.rb +0 -11
  27. data/lib/new_relic/agent/instrumentation/middleware_tracing.rb +1 -1
  28. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +0 -8
  29. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +1 -9
  30. data/lib/new_relic/agent/instrumentation/rails4/action_controller.rb +0 -18
  31. data/lib/new_relic/agent/instrumentation/rubyprof.rb +1 -1
  32. data/lib/new_relic/agent/instrumentation/sidekiq.rb +1 -1
  33. data/lib/new_relic/agent/instrumentation/sinatra.rb +12 -1
  34. data/lib/new_relic/agent/instrumentation/sinatra/transaction_namer.rb +1 -1
  35. data/lib/new_relic/agent/method_tracer.rb +33 -39
  36. data/lib/new_relic/agent/new_relic_service.rb +35 -156
  37. data/lib/new_relic/agent/new_relic_service/encoders.rb +34 -0
  38. data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +50 -0
  39. data/lib/new_relic/agent/new_relic_service/marshaller.rb +52 -0
  40. data/lib/new_relic/agent/new_relic_service/pruby_marshaller.rb +52 -0
  41. data/lib/new_relic/agent/threading/backtrace_node.rb +1 -1
  42. data/lib/new_relic/agent/traced_method_stack.rb +16 -2
  43. data/lib/new_relic/agent/transaction.rb +0 -4
  44. data/lib/new_relic/collection_helper.rb +2 -2
  45. data/lib/new_relic/control/frameworks/rails.rb +3 -0
  46. data/lib/new_relic/control/instrumentation.rb +6 -2
  47. data/lib/new_relic/json_wrapper.rb +47 -25
  48. data/lib/new_relic/language_support.rb +0 -4
  49. data/lib/new_relic/latest_changes.rb +2 -2
  50. data/lib/new_relic/rack/developer_mode.rb +4 -3
  51. data/lib/new_relic/recipes/capistrano3.rb +2 -2
  52. data/lib/new_relic/recipes/capistrano_legacy.rb +1 -1
  53. data/lib/new_relic/timer_lib.rb +1 -1
  54. data/lib/new_relic/version.rb +2 -2
  55. data/lib/tasks/config.html.erb +28 -0
  56. data/lib/tasks/config.rake +134 -0
  57. data/lib/tasks/config.text.erb +7 -0
  58. data/lib/tasks/install.rake +0 -63
  59. data/newrelic.yml +7 -0
  60. data/test/active_record_fixtures.rb +4 -4
  61. data/test/agent_helper.rb +58 -18
  62. data/test/environments/lib/environments/runner.rb +1 -1
  63. data/test/environments/rails21/Gemfile +1 -1
  64. data/test/environments/rails21/config/boot.rb +1 -1
  65. data/test/environments/rails22/Gemfile +1 -1
  66. data/test/environments/rails22/config/boot.rb +1 -1
  67. data/test/environments/rails23/config/boot.rb +2 -2
  68. data/test/environments/rails30/Gemfile +1 -1
  69. data/test/environments/rails31/Gemfile +1 -1
  70. data/test/environments/rails32/Gemfile +1 -1
  71. data/test/environments/rails40/Gemfile +1 -1
  72. data/test/environments/rails41/Gemfile +1 -1
  73. data/test/fixtures/cross_agent_tests/labels.json +104 -0
  74. data/test/fixtures/cross_agent_tests/sql_obfuscation/README.md +23 -0
  75. data/test/fixtures/cross_agent_tests/sql_obfuscation/back_quoted_identifiers.mysql.obfuscated +1 -0
  76. data/test/fixtures/cross_agent_tests/sql_obfuscation/back_quoted_identifiers.mysql.sql +1 -0
  77. data/test/fixtures/cross_agent_tests/sql_obfuscation/comment_delimiters_in_strings.obfuscated +1 -0
  78. data/test/fixtures/cross_agent_tests/sql_obfuscation/comment_delimiters_in_strings.sql +1 -0
  79. data/test/fixtures/cross_agent_tests/sql_obfuscation/double_quoted_identifiers.postgres.obfuscated +1 -0
  80. data/test/fixtures/cross_agent_tests/sql_obfuscation/double_quoted_identifiers.postgres.sql +1 -0
  81. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comment_in_string.obfuscated +2 -0
  82. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comment_in_string.sql +2 -0
  83. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comments_with_quotes.obfuscated +1 -0
  84. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comments_with_quotes.sql +2 -0
  85. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_cstyle.obfuscated +1 -0
  86. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_cstyle.sql +1 -0
  87. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_doubledash.obfuscated +2 -0
  88. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_doubledash.sql +2 -0
  89. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_hash.obfuscated +1 -0
  90. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_hash.sql +1 -0
  91. data/test/fixtures/cross_agent_tests/sql_obfuscation/escape_string_constants.postgres.obfuscated +1 -0
  92. data/test/fixtures/cross_agent_tests/sql_obfuscation/escape_string_constants.postgres.sql +4 -0
  93. data/test/fixtures/cross_agent_tests/sql_obfuscation/malformed/unterminated_double_quoted_string.mysql.sql +1 -0
  94. data/test/fixtures/cross_agent_tests/sql_obfuscation/malformed/unterminated_single_quoted_string.sql +1 -0
  95. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_comments_and_quotes.obfuscated +1 -0
  96. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_comments_and_quotes.sql +2 -0
  97. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_quotes_comments_and_newlines.obfuscated +1 -0
  98. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_quotes_comments_and_newlines.sql +4 -0
  99. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_quotes_end_of_line_comments.obfuscated +1 -0
  100. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_quotes_end_of_line_comments.sql +3 -0
  101. data/test/fixtures/cross_agent_tests/sql_obfuscation/multiple_literal_types.mysql.obfuscated +1 -0
  102. data/test/fixtures/cross_agent_tests/sql_obfuscation/multiple_literal_types.mysql.sql +1 -0
  103. data/test/fixtures/cross_agent_tests/sql_obfuscation/numbers_in_identifiers.obfuscated +1 -0
  104. data/test/fixtures/cross_agent_tests/sql_obfuscation/numbers_in_identifiers.sql +1 -0
  105. data/test/fixtures/cross_agent_tests/sql_obfuscation/numeric_literals.obfuscated +1 -0
  106. data/test/fixtures/cross_agent_tests/sql_obfuscation/numeric_literals.sql +1 -0
  107. data/test/fixtures/cross_agent_tests/sql_obfuscation/quote_delimiters_in_comments.obfuscated +1 -0
  108. data/test/fixtures/cross_agent_tests/sql_obfuscation/quote_delimiters_in_comments.sql +1 -0
  109. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_double_quoted.mysql.obfuscated +1 -0
  110. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_double_quoted.mysql.sql +1 -0
  111. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_single_quoted.obfuscated +1 -0
  112. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_single_quoted.sql +1 -0
  113. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_backslash_and_twin_single_quotes.obfuscated +1 -0
  114. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_backslash_and_twin_single_quotes.sql +4 -0
  115. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_double_quote.obfuscated +1 -0
  116. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_double_quote.sql +1 -0
  117. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_newline.obfuscated +1 -0
  118. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_newline.sql +2 -0
  119. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_single_quote.mysql.obfuscated +1 -0
  120. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_single_quote.mysql.sql +1 -0
  121. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_escaped_quotes.mysql.obfuscated +1 -0
  122. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_escaped_quotes.mysql.sql +1 -0
  123. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_backslash.obfuscated +1 -0
  124. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_backslash.sql +4 -0
  125. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash.mysql.obfuscated +1 -0
  126. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash.mysql.sql +1 -0
  127. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash_single_quoted.obfuscated +1 -0
  128. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash_single_quoted.sql +1 -0
  129. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_quote.obfuscated +1 -0
  130. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_quote.sql +1 -0
  131. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_twin_single_quotes.obfuscated +1 -0
  132. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_twin_single_quotes.sql +1 -0
  133. data/test/multiverse/lib/multiverse/output_collector.rb +1 -1
  134. data/test/multiverse/lib/multiverse/runner.rb +1 -1
  135. data/test/multiverse/lib/multiverse/suite.rb +19 -4
  136. data/test/multiverse/suites/agent_only/audit_log_test.rb +1 -38
  137. data/test/multiverse/suites/agent_only/collector_exception_handling_test.rb +25 -35
  138. data/test/multiverse/suites/agent_only/config/newrelic.yml +2 -0
  139. data/test/multiverse/suites/agent_only/encoding_handling_test.rb +1 -0
  140. data/test/multiverse/suites/agent_only/harvest_timestamps_test.rb +1 -1
  141. data/test/multiverse/suites/agent_only/keepalive_test.rb +29 -0
  142. data/test/multiverse/suites/agent_only/labels_test.rb +89 -0
  143. data/test/multiverse/suites/agent_only/marshaling_test.rb +1 -3
  144. data/test/multiverse/suites/agent_only/service_timeout_test.rb +1 -1
  145. data/test/multiverse/suites/agent_only/start_up_test.rb +9 -1
  146. data/test/multiverse/suites/capistrano/config/deploy.rb +6 -2
  147. data/test/multiverse/suites/capistrano/deployment_test.rb +12 -4
  148. data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +29 -1
  149. data/test/multiverse/suites/curb/Envfile +6 -2
  150. data/test/multiverse/suites/datamapper/Envfile +0 -4
  151. data/test/multiverse/suites/deferred_instrumentation/Envfile +0 -4
  152. data/test/multiverse/suites/deferred_instrumentation/sinatra_test.rb +1 -1
  153. data/test/multiverse/suites/excon/Envfile +5 -4
  154. data/test/multiverse/suites/excon/excon_test.rb +1 -1
  155. data/test/multiverse/suites/httpclient/Envfile +0 -4
  156. data/test/multiverse/suites/marshalling/Envfile +12 -0
  157. data/test/multiverse/suites/marshalling/config/newrelic.yml +20 -0
  158. data/test/multiverse/suites/marshalling/marshalling_test.rb +60 -0
  159. data/test/multiverse/suites/mongo/helpers/mongo_operation_tests.rb +1 -1
  160. data/test/multiverse/suites/mongo/helpers/mongo_replica_set.rb +1 -1
  161. data/test/multiverse/suites/mongo/helpers/mongo_server.rb +4 -4
  162. data/test/multiverse/suites/padrino/Envfile +0 -5
  163. data/test/multiverse/suites/padrino/padrino_test.rb +1 -1
  164. data/test/multiverse/suites/rack/rack_auto_instrumentation_test.rb +1 -1
  165. data/test/multiverse/suites/rails/gc_instrumentation_test.rb +2 -1
  166. data/test/multiverse/suites/rails/ignore_test.rb +22 -0
  167. data/test/multiverse/suites/rails/rails2_app/config/boot.rb +2 -2
  168. data/test/multiverse/suites/rails/rails2_app/config/routes.rb +1 -0
  169. data/test/multiverse/suites/resque/Envfile +0 -4
  170. data/test/multiverse/suites/sequel/Envfile +0 -5
  171. data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +1 -1
  172. data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +1 -1
  173. data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +22 -0
  174. data/test/multiverse/suites/typhoeus/Envfile +1 -4
  175. data/test/new_relic/agent/agent/start_worker_thread_test.rb +1 -13
  176. data/test/new_relic/agent/agent_logger_test.rb +11 -0
  177. data/test/new_relic/agent/agent_test.rb +43 -20
  178. data/test/new_relic/agent/audit_logger_test.rb +7 -3
  179. data/test/new_relic/agent/commands/thread_profiler_session_test.rb +0 -1
  180. data/test/new_relic/agent/commands/xray_session_collection_test.rb +1 -1
  181. data/test/new_relic/agent/configuration/dotted_hash_test.rb +53 -0
  182. data/test/new_relic/agent/configuration/manager_test.rb +99 -6
  183. data/test/new_relic/agent/configuration/manual_source_test.rb +18 -0
  184. data/test/new_relic/agent/configuration/orphan_configuration_test.rb +1 -1
  185. data/test/new_relic/agent/configuration/yaml_source_test.rb +8 -4
  186. data/test/new_relic/agent/database/sql_obfuscation_test.rb +76 -0
  187. data/test/new_relic/agent/database_test.rb +2 -38
  188. data/test/new_relic/agent/error_collector/notice_error_test.rb +21 -3
  189. data/test/new_relic/agent/error_collector_test.rb +15 -2
  190. data/test/new_relic/agent/event_loop_test.rb +202 -0
  191. data/test/new_relic/agent/instrumentation/active_record_helper_test.rb +4 -0
  192. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +283 -182
  193. data/test/new_relic/agent/method_tracer_test.rb +1 -2
  194. data/test/new_relic/agent/new_relic_service_test.rb +83 -27
  195. data/test/new_relic/agent/pipe_channel_manager_test.rb +6 -6
  196. data/test/new_relic/agent/rpm_agent_test.rb +1 -8
  197. data/test/new_relic/agent/sql_sampler_test.rb +10 -8
  198. data/test/new_relic/agent/threading/backtrace_service_test.rb +1 -1
  199. data/test/new_relic/agent/traced_method_stack_test.rb +45 -13
  200. data/test/new_relic/agent/transaction_sample_builder_test.rb +1 -2
  201. data/test/new_relic/agent/transaction_test.rb +3 -3
  202. data/test/new_relic/agent_test.rb +47 -8
  203. data/test/new_relic/collection_helper_test.rb +5 -5
  204. data/test/new_relic/control/instrumentation_test.rb +56 -0
  205. data/test/new_relic/control_test.rb +4 -3
  206. data/test/new_relic/fake_collector.rb +7 -2
  207. data/test/new_relic/http_client_test_cases.rb +4 -4
  208. data/test/new_relic/latest_changes_test.rb +3 -3
  209. data/test/new_relic/transaction_sample/segment_test.rb +0 -1
  210. data/test/new_relic/transaction_sample_test.rb +19 -2
  211. data/test/performance/lib/performance/runner.rb +4 -4
  212. data/test/performance/suites/marshalling.rb +46 -30
  213. data/test/performance/suites/sql_obfuscation.rb +30 -0
  214. data/test/test_helper.rb +1 -1
  215. data/ui/helpers/developer_mode_helper.rb +2 -2
  216. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/java.rb +1 -1
  217. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/view.rb +1 -1
  218. metadata +84 -3
  219. metadata.gz.sig +0 -0
  220. data/test/environments/rails23/config/environments/development.rb +0 -11
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require 'new_relic/agent/configuration'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module Configuration
10
+ class DottedHash < ::Hash
11
+ def initialize(hash, keep_nesting=false)
12
+ # Add the hash keys to our collection explicitly so they survive the
13
+ # dot flattening. This is typical for full config source instances,
14
+ # but not for uses of DottedHash serializing for transmission.
15
+ self.merge!(hash) if keep_nesting
16
+
17
+ self.merge!(dot_flattened(hash))
18
+ DottedHash.symbolize(self)
19
+ end
20
+
21
+ def inspect
22
+ "#<#{self.class.name}:#{object_id} #{super}>"
23
+ end
24
+
25
+ def to_hash
26
+ {}.replace(self)
27
+ end
28
+
29
+ def self.symbolize(hash)
30
+ hash.keys.each do |key|
31
+ hash[key.to_sym] = hash.delete(key)
32
+ end
33
+ end
34
+
35
+ protected
36
+ # turns {'a' => {'b' => 'c'}} into {'a.b' => 'c'}
37
+ def dot_flattened(nested_hash, names=[], result={})
38
+ nested_hash.each do |key, val|
39
+ next if val == nil
40
+ if val.respond_to?(:has_key?)
41
+ dot_flattened(val, names + [key], result)
42
+ else
43
+ result[(names + [key]).join('.')] = val
44
+ end
45
+ end
46
+ result
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -6,7 +6,7 @@ module NewRelic
6
6
  module Agent
7
7
  module Configuration
8
8
  class EnvironmentSource < DottedHash
9
- SUPPORTED_PREFIXES = /^new_relic_|newrelic_/i
9
+ SUPPORTED_PREFIXES = /^new_relic_|^newrelic_/i
10
10
 
11
11
  attr_accessor :alias_map, :type_map
12
12
 
@@ -189,6 +189,101 @@ module NewRelic
189
189
  end
190
190
  end
191
191
 
192
+ MALFORMED_LABELS_WARNING = "Skipping malformed labels configuration"
193
+ PARSING_LABELS_FAILURE = "Failure during parsing labels. Ignoring and carrying on with connect."
194
+
195
+ MAX_LABEL_COUNT = 64
196
+ MAX_LABEL_LENGTH = 255
197
+
198
+ def parsed_labels
199
+ case NewRelic::Agent.config[:labels]
200
+ when String
201
+ parse_labels_from_string
202
+ else
203
+ parse_labels_from_dictionary
204
+ end
205
+ rescue => e
206
+ NewRelic::Agent.logger.error(PARSING_LABELS_FAILURE, e)
207
+ []
208
+ end
209
+
210
+ def parse_labels_from_string
211
+ labels = NewRelic::Agent.config[:labels]
212
+ label_pairs = break_label_string_into_pairs(labels)
213
+ make_label_hash(label_pairs, labels)
214
+ end
215
+
216
+ def break_label_string_into_pairs(labels)
217
+ # Strip whitespaces immediately before and after colons or semicolons
218
+ stripped_labels = labels.gsub(/\s*(:|;)\s*/, '\1')
219
+ stripped_labels.split(';').map do |pair|
220
+ pair.split(':')
221
+ end
222
+ end
223
+
224
+ def valid_label_pairs?(label_pairs)
225
+ label_pairs.all? do |pair|
226
+ pair.length == 2 &&
227
+ valid_label_item?(pair.first) &&
228
+ valid_label_item?(pair.last)
229
+ end
230
+ end
231
+
232
+ def valid_label_item?(item)
233
+ case item
234
+ when String then !item.empty?
235
+ when Numeric then true
236
+ when true then true
237
+ when false then true
238
+ else false
239
+ end
240
+ end
241
+
242
+ def make_label_hash(pairs, labels = nil)
243
+ # This can accept a hash, so force it down to an array of pairs first
244
+ pairs = Array(pairs)
245
+
246
+ unless valid_label_pairs?(pairs)
247
+ NewRelic::Agent.logger.warn("#{MALFORMED_LABELS_WARNING}: #{labels||pairs}")
248
+ return []
249
+ end
250
+
251
+ pairs = limit_number_of_labels(pairs)
252
+ pairs.map do |key, value|
253
+ {
254
+ 'label_type' => truncate(key),
255
+ 'label_value' => truncate(value.to_s, key)
256
+ }
257
+ end
258
+ end
259
+
260
+ def truncate(text, key=nil)
261
+ if text.length > MAX_LABEL_LENGTH
262
+ if key
263
+ msg = "The value for the label '#{key}' is longer than the allowed #{MAX_LABEL_LENGTH} and will be truncated. Value = '#{text}'"
264
+ else
265
+ msg = "Label name longer than the allowed #{MAX_LABEL_LENGTH} will be truncated. Name = '#{text}'"
266
+ end
267
+ NewRelic::Agent.logger.warn(msg)
268
+ text[0..MAX_LABEL_LENGTH-1]
269
+ else
270
+ text
271
+ end
272
+ end
273
+
274
+ def limit_number_of_labels(pairs)
275
+ if pairs.length > MAX_LABEL_COUNT
276
+ NewRelic::Agent.logger.warn("Too many labels defined. Only taking first #{MAX_LABEL_COUNT}")
277
+ pairs[0...64]
278
+ else
279
+ pairs
280
+ end
281
+ end
282
+
283
+ def parse_labels_from_dictionary
284
+ make_label_hash(NewRelic::Agent.config[:labels])
285
+ end
286
+
192
287
  # Generally only useful during initial construction and tests
193
288
  def reset_to_defaults
194
289
  @high_security_source = nil
@@ -247,8 +342,12 @@ module NewRelic
247
342
 
248
343
  stack.compact!
249
344
 
250
- @configs_for_testing.each do |config, index|
251
- stack.insert(index, config)
345
+ @configs_for_testing.each do |config, at_start|
346
+ if at_start
347
+ stack.insert(0, config)
348
+ else
349
+ stack.push(config)
350
+ end
252
351
  end
253
352
 
254
353
  stack
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require 'new_relic/agent/configuration/dotted_hash'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module Configuration
10
+ class ManualSource < DottedHash
11
+ def initialize(hash)
12
+ super(hash, true)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -12,7 +12,8 @@ module NewRelic
12
12
  # when value is "apdex_f" remove the config and defer to default
13
13
  hash['agent_config'].delete('transaction_tracer.transaction_threshold')
14
14
  end
15
- super(hash.delete('agent_config'))
15
+
16
+ hoist_agent_config(hash)
16
17
  end
17
18
 
18
19
  if hash['web_transactions_apdex']
@@ -38,15 +39,22 @@ module NewRelic
38
39
  gated_features.each do |feature, gate_key|
39
40
  if server_config.has_key?(gate_key)
40
41
  allowed_by_server = server_config[gate_key]
41
- requested_value = ungated_value(feature, existing_config)
42
+ requested_value = ungated_value(feature, server_config, existing_config)
42
43
  effective_value = (allowed_by_server && requested_value)
43
44
  server_config[feature] = effective_value
44
45
  end
45
46
  end
46
47
  end
47
48
 
48
- def ungated_value(key, existing_config)
49
- self.has_key?(key) ? self[key] : existing_config[key]
49
+ def ungated_value(key, server_config, existing_config)
50
+ server_config.has_key?(key) ? server_config[key] : existing_config[key]
51
+ end
52
+
53
+ # Move agent_config subkey to top level of hash, symbolizing it too
54
+ def hoist_agent_config(hash)
55
+ agent_config = hash.delete('agent_config')
56
+ DottedHash.symbolize(agent_config)
57
+ hash.merge!(agent_config)
50
58
  end
51
59
  end
52
60
  end
@@ -17,33 +17,18 @@ module NewRelic
17
17
  @file_path = validate_config_file_path(path)
18
18
  return unless @file_path
19
19
 
20
- ::NewRelic::Agent.logger.info("Reading configuration from #{path}")
21
- file = File.read(@file_path)
22
-
23
- # Next two are for populating the newrelic.yml via erb binding, necessary
24
- # when using the default newrelic.yml file
25
- generated_for_user = ''
26
- license_key = ''
27
-
28
- erb = ERB.new(file).result(binding)
29
- confighash = with_yaml_engine { YAML.load(erb) }
30
- ::NewRelic::Agent.logger.error("Config (#{path}) doesn't include a '#{env}' environment!") unless
31
- confighash.key?(env)
32
-
33
- config = merge!(confighash[env] || {})
20
+ ::NewRelic::Agent.logger.info("Reading configuration from #{path} (#{Dir.pwd})")
21
+ raw_file = File.read(@file_path)
22
+ erb_file = process_erb(raw_file)
23
+ config = process_yaml(erb_file, env, config)
34
24
  rescue ScriptError, StandardError => e
35
- ::NewRelic::Agent.logger.error("Failed to read or parse configuration file at #{path}: #{e}")
36
- end
37
-
38
- if config['transaction_tracer'] &&
39
- config['transaction_tracer']['transaction_threshold'] =~ /apdex_f/i
40
- # when value is "apdex_f" remove the config and defer to default
41
- config['transaction_tracer'].delete('transaction_threshold')
25
+ ::NewRelic::Agent.logger.error("Failed to read or parse configuration file at #{path}", e)
42
26
  end
43
27
 
28
+ substitute_transaction_threshold(config)
44
29
  booleanify_values(config, 'agent_enabled', 'enabled', 'monitor_daemons')
45
30
 
46
- super(config)
31
+ super(config, true)
47
32
  end
48
33
 
49
34
  protected
@@ -82,6 +67,44 @@ module NewRelic
82
67
  )
83
68
  end
84
69
 
70
+ def process_erb(file)
71
+ begin
72
+ # Exclude lines that are commented out so failing Ruby code in an
73
+ # ERB template commented at the YML level is fine. Leave the line,
74
+ # though, so ERB line numbers remain correct.
75
+ file.gsub!(/^\s*#.*$/, '#')
76
+
77
+ # Next two are for populating the newrelic.yml via erb binding, necessary
78
+ # when using the default newrelic.yml file
79
+ generated_for_user = ''
80
+ license_key = ''
81
+
82
+ ERB.new(file).result(binding)
83
+ rescue ScriptError, StandardError => e
84
+ ::NewRelic::Agent.logger.error("Failed ERB processing configuration file. This is typically caused by a Ruby error in <% %> templating blocks in your newrelic.yml file.", e)
85
+ nil
86
+ end
87
+ end
88
+
89
+ def process_yaml(file, env, config)
90
+ if file
91
+ confighash = with_yaml_engine { YAML.load(file) }
92
+ ::NewRelic::Agent.logger.error("Config (#{path}) doesn't include a '#{env}' environment!") unless confighash.key?(env)
93
+
94
+ config = confighash[env] || {}
95
+ end
96
+
97
+ config
98
+ end
99
+
100
+ def substitute_transaction_threshold(config)
101
+ if config['transaction_tracer'] &&
102
+ config['transaction_tracer']['transaction_threshold'] =~ /apdex_f/i
103
+ # when value is "apdex_f" remove the config and defer to default
104
+ config['transaction_tracer'].delete('transaction_threshold')
105
+ end
106
+ end
107
+
85
108
  def with_yaml_engine
86
109
  return yield unless NewRelic::LanguageSupport.needs_syck?
87
110
 
@@ -92,6 +115,7 @@ module NewRelic
92
115
  result
93
116
  end
94
117
 
118
+
95
119
  def booleanify_values(config, *keys)
96
120
  # auto means defer ro default
97
121
  keys.each do |option|
@@ -59,7 +59,7 @@ module NewRelic
59
59
  end
60
60
  end
61
61
 
62
- events.subscribe(:after_call) do |env, (status_code, headers, body)| #THREAD_LOCAL_ACCESS
62
+ events.subscribe(:after_call) do |env, (_status_code, headers, _body)| #THREAD_LOCAL_ACCESS
63
63
  state = NewRelic::Agent::TransactionState.tl_get
64
64
 
65
65
  insert_response_header(state, env, headers)
@@ -249,7 +249,7 @@ module NewRelic
249
249
  # Return the set of metric objects appropriate for the given cross app
250
250
  # +response+.
251
251
  def metrics_for_crossapp_response( request, response )
252
- xp_id, txn_name, q_time, r_time, req_len, _ = extract_appdata( response )
252
+ xp_id, txn_name, _q_time, _r_time, _req_len, _ = extract_appdata( response )
253
253
 
254
254
  check_crossapp_id( xp_id )
255
255
  check_transaction_name( txn_name )
@@ -6,30 +6,71 @@ module NewRelic
6
6
  module Agent
7
7
  module Database
8
8
  module ObfuscationHelpers
9
- NUMERICS = /\b\d+\b/
10
- SINGLE_QUOTES = /'(?:[^']|'')*'/
11
- DOUBLE_QUOTES = /"(?:[^"]|"")*"/
9
+ # Note that the following two regexes are applied to a reversed version
10
+ # of the query. This is why the backslash escape sequences (\' and \")
11
+ # appear reversed within them.
12
+ #
13
+ # Note that some database adapters (notably, PostgreSQL with
14
+ # standard_conforming_strings on and MySQL with NO_BACKSLASH_ESCAPES on)
15
+ # do not apply special treatment to backslashes within quoted string
16
+ # literals. We don't have an easy way of determining whether the
17
+ # database connection from which a query was captured was operating in
18
+ # one of these modes, but the obfuscation is done in such a way that it
19
+ # should not matter.
20
+ #
21
+ # Reversing the query string before obfuscation allows us to get around
22
+ # the fact that a \' appearing within a string may or may not terminate
23
+ # the string, because we know that a string cannot *start* with a \'.
24
+ REVERSE_SINGLE_QUOTES_REGEX = /'(?:''|'\\|[^'])*'/
25
+ REVERSE_ANY_QUOTES_REGEX = /'(?:''|'\\|[^'])*'|"(?:""|"\\|[^"])*"/
12
26
 
13
- def remove_escaped_quotes(sql)
14
- sql.gsub(/\\"/, '').gsub(/\\'/, '')
15
- end
27
+ NUMERICS_REGEX = /\b\d+\b/
28
+
29
+ # We take a conservative, overly-aggressive approach to obfuscating
30
+ # comments, and drop everything from the query after encountering any
31
+ # character sequence that could be a comment initiator. We do this after
32
+ # removal of string literals to avoid accidentally over-obfuscating when
33
+ # a string literal contains a comment initiator.
34
+ SQL_COMMENT_REGEX = Regexp.new('(?:/\*|--|#).*', Regexp::MULTILINE).freeze
35
+
36
+ # We use these to check whether the query contains any quote characters
37
+ # after obfuscation. If so, that's a good indication that the original
38
+ # query was malformed, and so our obfuscation can't reliabily find
39
+ # literals. In such a case, we'll replace the entire query with a
40
+ # placeholder.
41
+ LITERAL_SINGLE_QUOTE = "'".freeze
42
+ LITERAL_DOUBLE_QUOTE = '"'.freeze
43
+
44
+ PLACEHOLDER = '?'.freeze
16
45
 
17
46
  def obfuscate_single_quote_literals(sql)
18
- sql.gsub(SINGLE_QUOTES, '?')
47
+ obfuscated = sql.reverse
48
+ obfuscated.gsub!(REVERSE_SINGLE_QUOTES_REGEX, PLACEHOLDER)
49
+ obfuscated.reverse!
50
+ obfuscated
19
51
  end
20
52
 
21
- def obfuscate_double_quote_literals(sql)
22
- sql.gsub(DOUBLE_QUOTES, '?')
53
+ def obfuscate_quoted_literals(sql)
54
+ obfuscated = sql.reverse
55
+ obfuscated.gsub!(REVERSE_ANY_QUOTES_REGEX, PLACEHOLDER)
56
+ obfuscated.reverse!
57
+ obfuscated
23
58
  end
24
59
 
25
60
  def obfuscate_numeric_literals(sql)
26
- sql.gsub(NUMERICS, "?")
61
+ sql.gsub(NUMERICS_REGEX, PLACEHOLDER)
62
+ end
63
+
64
+ def remove_comments(sql)
65
+ sql.gsub(SQL_COMMENT_REGEX, PLACEHOLDER)
66
+ end
67
+
68
+ def contains_single_quotes?(str)
69
+ str.include?(LITERAL_SINGLE_QUOTE)
27
70
  end
28
71
 
29
- def find_literals(sql)
30
- literals = sql.scan(NUMERICS)
31
- literals << sql.scan(SINGLE_QUOTES)
32
- literals.flatten
72
+ def contains_quotes?(str)
73
+ str.include?(LITERAL_SINGLE_QUOTE) || str.include?(LITERAL_DOUBLE_QUOTE)
33
74
  end
34
75
  end
35
76
  end
@@ -13,6 +13,9 @@ module NewRelic
13
13
 
14
14
  attr_reader :obfuscator
15
15
 
16
+ QUERY_TOO_LARGE_MESSAGE = "Query too large (over 16k characters) to safely obfuscate"
17
+ FAILED_TO_OBFUSCATE_MESSAGE = "Failed to obfuscate SQL query - quote characters remained after obfuscation"
18
+
16
19
  def initialize
17
20
  reset
18
21
  end
@@ -46,17 +49,29 @@ module NewRelic
46
49
 
47
50
  def default_sql_obfuscator(sql)
48
51
  if sql[-3,3] == '...'
49
- return "Query too large (over 16k characters) to safely obfuscate"
52
+ return QUERY_TOO_LARGE_MESSAGE
50
53
  end
51
54
 
52
55
  stmt = sql.kind_of?(Statement) ? sql : Statement.new(sql)
53
- adapter = stmt.adapter
54
- obfuscated = remove_escaped_quotes(stmt)
55
- obfuscated = obfuscate_single_quote_literals(obfuscated)
56
- if !(adapter.to_s =~ /postgres/ || adapter.to_s =~ /sqlite/)
57
- obfuscated = obfuscate_double_quote_literals(obfuscated)
56
+ obfuscate_double_quotes = stmt.adapter.to_s !~ /postgres|sqlite/
57
+
58
+ obfuscated = obfuscate_numeric_literals(stmt)
59
+
60
+ if obfuscate_double_quotes
61
+ obfuscated = obfuscate_quoted_literals(obfuscated)
62
+ obfuscated = remove_comments(obfuscated)
63
+ if contains_quotes?(obfuscated)
64
+ obfuscated = FAILED_TO_OBFUSCATE_MESSAGE
65
+ end
66
+ else
67
+ obfuscated = obfuscate_single_quote_literals(obfuscated)
68
+ obfuscated = remove_comments(obfuscated)
69
+ if contains_single_quotes?(obfuscated)
70
+ obfuscated = FAILED_TO_OBFUSCATE_MESSAGE
71
+ end
58
72
  end
59
- obfuscated = obfuscate_numeric_literals(obfuscated)
73
+
74
+
60
75
  obfuscated.to_s # return back to a regular String
61
76
  end
62
77
  end