newrelic_rpm 10.8.0 → 10.9.0
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/.claude/hooks/check_comments.sh +31 -12
- data/.claude/hooks/check_rubocop.sh +3 -1
- data/CHANGELOG.md +31 -0
- data/lib/new_relic/agent/agent.rb +48 -0
- data/lib/new_relic/agent/audit_logger.rb +13 -6
- data/lib/new_relic/agent/commands/agent_command_router.rb +10 -0
- data/lib/new_relic/agent/configuration/default_source.rb +115 -0
- data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
- data/lib/new_relic/agent/continuous_profiling/profile_encoder.rb +350 -0
- data/lib/new_relic/agent/continuous_profiling/proto/common.proto +154 -0
- data/lib/new_relic/agent/continuous_profiling/proto/common_pb.rb +31 -0
- data/lib/new_relic/agent/continuous_profiling/proto/profiles.proto +537 -0
- data/lib/new_relic/agent/continuous_profiling/proto/profiles_pb.rb +42 -0
- data/lib/new_relic/agent/continuous_profiling/proto/profiles_service.proto +82 -0
- data/lib/new_relic/agent/continuous_profiling/proto/profiles_service_pb.rb +30 -0
- data/lib/new_relic/agent/continuous_profiling/proto/resource.proto +45 -0
- data/lib/new_relic/agent/continuous_profiling/proto/resource_pb.rb +28 -0
- data/lib/new_relic/agent/continuous_profiling/session.rb +534 -0
- data/lib/new_relic/agent/continuous_profiling/stack_prof_sampler.rb +77 -0
- data/lib/new_relic/agent/event_listener.rb +13 -2
- data/lib/new_relic/agent/instrumentation/continuous_profiler.rb +23 -0
- data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +6 -2
- data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +5 -1
- data/lib/new_relic/agent/new_relic_service.rb +144 -2
- data/lib/new_relic/agent/pipe_service.rb +4 -0
- data/lib/new_relic/agent/transaction.rb +4 -0
- data/lib/new_relic/version.rb +1 -1
- data/lib/tasks/continuous_profiling_proto.rake +77 -0
- data/newrelic.yml +27 -0
- metadata +14 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fbb51c8f4559d8bb50f88a7e3fcd47d63de49fbe5ec974e9c4ec48b277e28049
|
|
4
|
+
data.tar.gz: 129662fccdead351c98519c957172412b20a917e79350960875b53a5ff2d4dcd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 630af5f3ffd009f852384cae072cb42d6f0b293c5ca4b13d096d442bbc2f51ab52d12af348e72bdbccfee60549a45ad4e449e45c0ee401aabc8efb58342e61ad
|
|
7
|
+
data.tar.gz: 429d5e818a9ec3ece5838b30882fc9ae56dc717916ce423c1bde6e928f4bc672f3eaeb77f26ea608206c203f0db03bec52bc8d9b406822e4646ad0f807a781f3
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Stop hook: judges every comment line added during this session against this repo's
|
|
3
|
-
# CLAUDE.md comment-discipline rule (WHY only, never WHAT, 1-2 lines)
|
|
4
|
-
# ending if a fresh, context-free `claude -p`
|
|
3
|
+
# CLAUDE.md comment-discipline rule (WHY only, never WHAT, 1-2 lines), defaulting to removal
|
|
4
|
+
# rather than rewording. Blocks the turn from ending if a fresh, context-free `claude -p`
|
|
5
|
+
# review finds anything to fix.
|
|
5
6
|
set -euo pipefail
|
|
6
7
|
|
|
7
8
|
# Guard against the nested `claude -p` judge call below re-triggering this same hook.
|
|
@@ -30,17 +31,34 @@ if [ -z "$ADDED_COMMENTS" ]; then
|
|
|
30
31
|
fi
|
|
31
32
|
|
|
32
33
|
PROMPT="Review ONLY the added lines (prefixed with +) in this git diff for Ruby comments.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
|
|
35
|
+
The default verdict is REMOVE. Deletion is the preferred fix; shortening is a distant second
|
|
36
|
+
and is right only for a comment that genuinely must stay but is wordy. Begin from the
|
|
37
|
+
assumption that every added comment should go, and spare one only if deleting it would
|
|
38
|
+
plausibly lead a competent reader of this code to make a mistake.
|
|
39
|
+
|
|
40
|
+
A comment survives only if it states a non-obvious WHY the code cannot state itself: a hidden
|
|
41
|
+
constraint, a cross-file or ordering dependency, a subtle invariant, a workaround for specific
|
|
42
|
+
behavior, or something whose breakage would be silent. \"Useful context\", \"helps the reader
|
|
43
|
+
follow along\", and \"explains the design\" are NOT survival reasons -- those are removals.
|
|
44
|
+
|
|
45
|
+
Report REMOVE (never merely shortening) when the comment:
|
|
46
|
+
- restates WHAT the code does, or narrates the obvious
|
|
47
|
+
- explains or justifies a change, or reads as commit-message, PR, issue, or task-history content
|
|
48
|
+
- repeats what a nearby existing comment, a method name, a constant name, or a test name says
|
|
49
|
+
- explains why code is defensive, redundant, or belt-and-braces
|
|
50
|
+
- labels or introduces the lines beneath it
|
|
51
|
+
- needs more than 2 lines to make its point -- treat the length as evidence it is narrating
|
|
52
|
+
rather than constraining, and remove it instead of compressing it
|
|
53
|
+
|
|
54
|
+
Ignore the standard 2-line license header, the frozen_string_literal comment, and yardoc
|
|
39
55
|
comments for public documentation.
|
|
40
56
|
|
|
41
|
-
For each added comment that
|
|
42
|
-
|
|
43
|
-
|
|
57
|
+
For each added comment that should change, report file, line (from the diff hunk header), the
|
|
58
|
+
comment text, and a one-sentence reason that starts with the action: \"remove -- \" plus why it
|
|
59
|
+
fails, or, for the rare must-stay-but-wordy case, \"shorten -- \" plus what constraint makes it
|
|
60
|
+
load-bearing. When torn between the two, say remove. If every added comment is justified,
|
|
61
|
+
return an empty violations array.
|
|
44
62
|
|
|
45
63
|
Respond with ONLY a JSON object, no markdown fences, no other text, matching exactly:
|
|
46
64
|
{\"violations\": [{\"file\": \"...\", \"line\": ..., \"comment\": \"...\", \"reason\": \"...\"}]}
|
|
@@ -67,5 +85,6 @@ fi
|
|
|
67
85
|
|
|
68
86
|
REASON="$(echo "$RESULT" | jq -r '.violations[] | "- \(.file):\(.line) — \(.comment | tostring) — \(.reason)"' 2>/dev/null || true)"
|
|
69
87
|
|
|
70
|
-
jq -n --arg reason "Comment-discipline check found
|
|
88
|
+
jq -n --arg reason "Comment-discipline check found comments to fix before finishing. Prefer
|
|
89
|
+
deleting a flagged comment over rewording it; only shorten one that is genuinely load-bearing:
|
|
71
90
|
$REASON" '{decision: "block", reason: $reason}'
|
|
@@ -18,7 +18,9 @@ if [ "${#EXISTING_FILES[@]}" -eq 0 ]; then
|
|
|
18
18
|
fi
|
|
19
19
|
|
|
20
20
|
set +e
|
|
21
|
-
|
|
21
|
+
# --force-exclusion: rubocop ignores AllCops/Exclude when given explicit paths, which would
|
|
22
|
+
# otherwise lint generated files (e.g. the vendored *_pb.rb protobuf classes) the project excludes.
|
|
23
|
+
RESULT="$(bundle exec rubocop --format simple --force-exclusion "${EXISTING_FILES[@]}" 2>&1)"
|
|
22
24
|
EXIT_CODE=$?
|
|
23
25
|
set -e
|
|
24
26
|
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# New Relic Ruby Agent Release Notes
|
|
2
2
|
|
|
3
|
+
## v10.9.0
|
|
4
|
+
|
|
5
|
+
- **Feature: Continuous Profiling (preview)**
|
|
6
|
+
|
|
7
|
+
Continuous Profiling is a new feature which is not yet generally available for use. The agent-side component code is now present in the agent but to actually use it ahead of the General Availability release, you will need to contact your New Relic sales representative to join the preview early.
|
|
8
|
+
|
|
9
|
+
Continuous Profiling repeatedly samples the Ruby call stacks of your running application and reports them to New Relic, so you can see which methods are consuming the most CPU time (or allocating the most objects) in production, without adding code to your app.
|
|
10
|
+
|
|
11
|
+
To turn it on, add the [`stackprof`](https://rubygems.org/gems/stackprof) and [`google-protobuf`](https://rubygems.org/gems/google-protobuf) gems to your application's `Gemfile`, then set `profiling.enabled` to `true`:
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
profiling.enabled: true
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
With only `profiling.enabled` set, the agent samples CPU time every 10 milliseconds for the life of the process. These options let you tune that behavior:
|
|
18
|
+
|
|
19
|
+
| Configuration name | Default | Behavior |
|
|
20
|
+
| ------------------ | ------- | -------- |
|
|
21
|
+
| profiling.enabled | `false` | If `true`, the agent collects and reports continuous profiling data. |
|
|
22
|
+
| profiling.include | `cpu` | What to sample: `cpu` for CPU time, or `object` for object allocations. |
|
|
23
|
+
| profiling.sample_period | `0.01` | Seconds between stack samples. Only used when `profiling.include` is `cpu`. Must be between 0.000001 and 0.999999. |
|
|
24
|
+
| profiling.object_allocation_interval | `10000` | Object allocations between stack samples. Only used when `profiling.include` is `object`. Must be between 1000 and 999999. |
|
|
25
|
+
| profiling.delay | `0` | Milliseconds to wait before profiling starts. `0` starts immediately. |
|
|
26
|
+
| profiling.duration | `0` | Milliseconds to profile before stopping automatically. `0` profiles until the process exits. |
|
|
27
|
+
|
|
28
|
+
[PR#3617](https://github.com/newrelic/newrelic-ruby-agent/pull/3617)
|
|
29
|
+
|
|
30
|
+
- **Feature: Add support for Dalli 5.1.1**
|
|
31
|
+
|
|
32
|
+
Dalli 5.1.1 added arguments to some of the methods the agent instruments, which could raise an `ArgumentError` on multi-key operations or cause request options to be silently dropped. Now, the agent accepts and forwards a variable number of positional and keyword arguments for these methods. [PR#3683](https://github.com/newrelic/newrelic-ruby-agent/pull/3683)
|
|
33
|
+
|
|
3
34
|
## v10.8.0
|
|
4
35
|
|
|
5
36
|
- **Feature: Report a unique hostname for Google Cloud Run Worker Pools and Jobs**
|
|
@@ -28,6 +28,7 @@ require 'new_relic/agent/transaction_event_recorder'
|
|
|
28
28
|
require 'new_relic/agent/custom_event_aggregator'
|
|
29
29
|
require 'new_relic/agent/span_event_aggregator'
|
|
30
30
|
require 'new_relic/agent/log_event_aggregator'
|
|
31
|
+
require 'new_relic/agent/continuous_profiling/session'
|
|
31
32
|
require 'new_relic/agent/sampler_collection'
|
|
32
33
|
require 'new_relic/agent/javascript_instrumentor'
|
|
33
34
|
require 'new_relic/agent/vm/monotonic_gc_profiler'
|
|
@@ -87,6 +88,8 @@ module NewRelic
|
|
|
87
88
|
@wait_on_connect_mutex = Mutex.new
|
|
88
89
|
@after_fork_lock = Mutex.new
|
|
89
90
|
@wait_on_connect_condition = ConditionVariable.new
|
|
91
|
+
@profiles_forwarder_lock = Mutex.new
|
|
92
|
+
@profiles_forwarder_count = 0
|
|
90
93
|
end
|
|
91
94
|
|
|
92
95
|
def init_components
|
|
@@ -121,6 +124,7 @@ module NewRelic
|
|
|
121
124
|
@custom_event_aggregator = CustomEventAggregator.new(@events)
|
|
122
125
|
@span_event_aggregator = SpanEventAggregator.new(@events)
|
|
123
126
|
@log_event_aggregator = LogEventAggregator.new(@events)
|
|
127
|
+
@continuous_profiling_session = ContinuousProfiling::Session.new(@events)
|
|
124
128
|
end
|
|
125
129
|
|
|
126
130
|
def setup_attribute_filter
|
|
@@ -149,6 +153,8 @@ module NewRelic
|
|
|
149
153
|
# Holds all the methods defined on NewRelic::Agent::Agent
|
|
150
154
|
# instances
|
|
151
155
|
module InstanceMethods
|
|
156
|
+
MAX_CONCURRENT_PROFILES_FORWARDERS = 4
|
|
157
|
+
|
|
152
158
|
# the agent control health check file generator
|
|
153
159
|
attr_reader :health_check
|
|
154
160
|
# the statistics engine that holds all the timeslice data
|
|
@@ -181,6 +187,7 @@ module NewRelic
|
|
|
181
187
|
attr_reader :custom_event_aggregator
|
|
182
188
|
attr_reader :span_event_aggregator
|
|
183
189
|
attr_reader :log_event_aggregator
|
|
190
|
+
attr_reader :continuous_profiling_session
|
|
184
191
|
attr_reader :transaction_event_recorder
|
|
185
192
|
attr_reader :attribute_filter
|
|
186
193
|
attr_reader :adaptive_sampler
|
|
@@ -231,6 +238,10 @@ module NewRelic
|
|
|
231
238
|
reset_objects_with_locks
|
|
232
239
|
drop_buffered_data
|
|
233
240
|
|
|
241
|
+
# Ahead of setup_and_start_agent: a connect on the worker thread it spawns applies
|
|
242
|
+
# server-side config, which can start a session this call would then tear down.
|
|
243
|
+
@continuous_profiling_session.after_fork
|
|
244
|
+
|
|
234
245
|
setup_and_start_agent(options)
|
|
235
246
|
end
|
|
236
247
|
|
|
@@ -319,6 +330,9 @@ module NewRelic
|
|
|
319
330
|
# might be holding locks for background thread that aren't there anymore.
|
|
320
331
|
def reset_objects_with_locks
|
|
321
332
|
@stats_engine = StatsEngine.new
|
|
333
|
+
@continuous_profiling_session.reset_after_fork_from_parent_thread
|
|
334
|
+
@profiles_forwarder_lock = Mutex.new
|
|
335
|
+
@profiles_forwarder_count = 0
|
|
322
336
|
end
|
|
323
337
|
|
|
324
338
|
def flush_pipe_data # used only by resque
|
|
@@ -348,7 +362,41 @@ module NewRelic
|
|
|
348
362
|
end
|
|
349
363
|
end
|
|
350
364
|
|
|
365
|
+
# Forwarded off-thread so a slow export doesn't block other children's data; capped
|
|
366
|
+
# since forwarders serialize on NewRelicService's profiles request lock anyway.
|
|
367
|
+
def forward_profiles_data(data)
|
|
368
|
+
@profiles_forwarder_lock.synchronize do
|
|
369
|
+
if @profiles_forwarder_count >= MAX_CONCURRENT_PROFILES_FORWARDERS
|
|
370
|
+
NewRelic::Agent.increment_metric('Supportability/Ruby/Profiling/Forward/Dropped')
|
|
371
|
+
NewRelic::Agent.logger.debug(
|
|
372
|
+
'Dropping a forwarded continuous profiling payload: too many exports already in flight'
|
|
373
|
+
)
|
|
374
|
+
return nil
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
@profiles_forwarder_count += 1
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
begin
|
|
381
|
+
Threading::AgentThread.create('Continuous Profiling Forwarder') do
|
|
382
|
+
@service.profiles_data(data)
|
|
383
|
+
ensure
|
|
384
|
+
@profiles_forwarder_lock.synchronize { @profiles_forwarder_count -= 1 }
|
|
385
|
+
end
|
|
386
|
+
rescue => e
|
|
387
|
+
# The block's ensure never runs if the thread was never created, and a count that
|
|
388
|
+
# can't come back down drops every later payload for the life of the process.
|
|
389
|
+
@profiles_forwarder_lock.synchronize { @profiles_forwarder_count -= 1 }
|
|
390
|
+
NewRelic::Agent.logger.error('Failed to start a continuous profiling forwarder thread', e)
|
|
391
|
+
nil
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
351
395
|
def merge_data_for_endpoint(endpoint, data)
|
|
396
|
+
if endpoint == :profiles_data && data && !data.empty?
|
|
397
|
+
return forward_profiles_data(data)
|
|
398
|
+
end
|
|
399
|
+
|
|
352
400
|
if data && !data.empty?
|
|
353
401
|
container = container_for_endpoint(endpoint)
|
|
354
402
|
if container.respond_to?(:has_metadata?) && container.has_metadata?
|
|
@@ -39,16 +39,23 @@ module NewRelic
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def log_request(uri, data, marshaller)
|
|
42
|
+
log_request_body(uri) do
|
|
43
|
+
if marshaller.class.human_readable?
|
|
44
|
+
marshaller.dump(data, :encoder => @encoder)
|
|
45
|
+
else
|
|
46
|
+
marshaller.prepare(data, :encoder => @encoder).inspect
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Yielded, not passed: rendering a body eagerly would cost a marshal or protobuf decode on
|
|
52
|
+
# every request even when audit logging is off or the endpoint is filtered out.
|
|
53
|
+
def log_request_body(uri)
|
|
42
54
|
return unless enabled? && allowed_endpoint?(uri)
|
|
43
55
|
|
|
44
56
|
setup_logger unless setup?
|
|
45
|
-
request_body = if marshaller.class.human_readable?
|
|
46
|
-
marshaller.dump(data, :encoder => @encoder)
|
|
47
|
-
else
|
|
48
|
-
marshaller.prepare(data, :encoder => @encoder).inspect
|
|
49
|
-
end
|
|
50
57
|
@log.info("REQUEST: #{uri}")
|
|
51
|
-
@log.info("REQUEST BODY: #{
|
|
58
|
+
@log.info("REQUEST BODY: #{yield}")
|
|
52
59
|
rescue StandardError, SystemStackError, SystemCallError => e
|
|
53
60
|
::NewRelic::Agent.logger.warn('Failed writing to audit log', e)
|
|
54
61
|
rescue Exception => e
|
|
@@ -15,6 +15,9 @@ module NewRelic
|
|
|
15
15
|
module Agent
|
|
16
16
|
module Commands
|
|
17
17
|
class AgentCommandRouter
|
|
18
|
+
START_CONTINUOUS_PROFILING_COMMAND = 'start_continuous_profiling'
|
|
19
|
+
STOP_CONTINUOUS_PROFILING_COMMAND = 'stop_continuous_profiling'
|
|
20
|
+
|
|
18
21
|
attr_reader :handlers
|
|
19
22
|
|
|
20
23
|
attr_accessor :thread_profiler_session, :backtrace_service
|
|
@@ -28,6 +31,8 @@ module NewRelic
|
|
|
28
31
|
|
|
29
32
|
@handlers['start_profiler'] = proc { |cmd| thread_profiler_session.handle_start_command(cmd) }
|
|
30
33
|
@handlers['stop_profiler'] = proc { |cmd| thread_profiler_session.handle_stop_command(cmd) }
|
|
34
|
+
@handlers[START_CONTINUOUS_PROFILING_COMMAND] = proc { |cmd| continuous_profiling_session.handle_start_command(cmd) }
|
|
35
|
+
@handlers[STOP_CONTINUOUS_PROFILING_COMMAND] = proc { |cmd| continuous_profiling_session.handle_stop_command(cmd) }
|
|
31
36
|
|
|
32
37
|
event_listener&.subscribe(:before_shutdown, &method(:on_before_shutdown))
|
|
33
38
|
end
|
|
@@ -36,6 +41,11 @@ module NewRelic
|
|
|
36
41
|
NewRelic::Agent.instance.service
|
|
37
42
|
end
|
|
38
43
|
|
|
44
|
+
def continuous_profiling_session
|
|
45
|
+
NewRelic::Agent.agent&.continuous_profiling_session ||
|
|
46
|
+
raise(AgentCommandError, 'Continuous profiling session unavailable; agent not fully started')
|
|
47
|
+
end
|
|
48
|
+
|
|
39
49
|
def check_for_and_handle_agent_commands
|
|
40
50
|
commands = get_agent_commands
|
|
41
51
|
|
|
@@ -216,6 +216,58 @@ module NewRelic
|
|
|
216
216
|
constants.compact!
|
|
217
217
|
constants
|
|
218
218
|
end
|
|
219
|
+
|
|
220
|
+
OBJECT_ALLOCATION_INTERVAL_MINIMUM = 1000
|
|
221
|
+
|
|
222
|
+
# StackProf's C extension rejects any interval outside 1..999_999 (stackprof_start in
|
|
223
|
+
# stackprof.c), whether it's microseconds or a raw allocation count.
|
|
224
|
+
STACKPROF_INTERVAL_MAXIMUM = 999_999
|
|
225
|
+
SAMPLE_PERIOD_MINIMUM_SECONDS = 1 / 1_000_000.0
|
|
226
|
+
SAMPLE_PERIOD_MAXIMUM_SECONDS = STACKPROF_INTERVAL_MAXIMUM / 1_000_000.0
|
|
227
|
+
|
|
228
|
+
def self.enforce_object_allocation_interval_range(value)
|
|
229
|
+
return value if value.nil?
|
|
230
|
+
|
|
231
|
+
if value < OBJECT_ALLOCATION_INTERVAL_MINIMUM
|
|
232
|
+
NewRelic::Agent.logger.debug(
|
|
233
|
+
"profiling.object_allocation_interval is set to #{value.inspect}, which is below the minimum " \
|
|
234
|
+
"of #{OBJECT_ALLOCATION_INTERVAL_MINIMUM}. Using #{OBJECT_ALLOCATION_INTERVAL_MINIMUM} instead."
|
|
235
|
+
)
|
|
236
|
+
return OBJECT_ALLOCATION_INTERVAL_MINIMUM
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
if value > STACKPROF_INTERVAL_MAXIMUM
|
|
240
|
+
NewRelic::Agent.logger.debug(
|
|
241
|
+
"profiling.object_allocation_interval is set to #{value.inspect}, which is above the maximum " \
|
|
242
|
+
"of #{STACKPROF_INTERVAL_MAXIMUM}. Using #{STACKPROF_INTERVAL_MAXIMUM} instead."
|
|
243
|
+
)
|
|
244
|
+
return STACKPROF_INTERVAL_MAXIMUM
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
value
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def self.enforce_sample_period_range(value)
|
|
251
|
+
return value if value.nil?
|
|
252
|
+
|
|
253
|
+
if value < SAMPLE_PERIOD_MINIMUM_SECONDS
|
|
254
|
+
NewRelic::Agent.logger.debug(
|
|
255
|
+
"profiling.sample_period is set to #{value.inspect}, which is below the minimum of " \
|
|
256
|
+
"#{SAMPLE_PERIOD_MINIMUM_SECONDS} seconds. Using #{SAMPLE_PERIOD_MINIMUM_SECONDS} instead."
|
|
257
|
+
)
|
|
258
|
+
return SAMPLE_PERIOD_MINIMUM_SECONDS
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
if value > SAMPLE_PERIOD_MAXIMUM_SECONDS
|
|
262
|
+
NewRelic::Agent.logger.debug(
|
|
263
|
+
"profiling.sample_period is set to #{value.inspect}, which is above the maximum of " \
|
|
264
|
+
"#{SAMPLE_PERIOD_MAXIMUM_SECONDS} seconds. Using #{SAMPLE_PERIOD_MAXIMUM_SECONDS} instead."
|
|
265
|
+
)
|
|
266
|
+
return SAMPLE_PERIOD_MAXIMUM_SECONDS
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
value
|
|
270
|
+
end
|
|
219
271
|
end
|
|
220
272
|
|
|
221
273
|
AUTOSTART_DENYLISTED_RAKE_TASKS = [
|
|
@@ -1054,6 +1106,69 @@ module NewRelic
|
|
|
1054
1106
|
:description => "If `true`, the agent will report source code level metrics for traced methods.\n\tSee: " \
|
|
1055
1107
|
'https://docs.newrelic.com/docs/apm/agents/ruby-agent/features/ruby-codestream-integration/'
|
|
1056
1108
|
},
|
|
1109
|
+
# Continuous profiler
|
|
1110
|
+
:'profiling.enabled' => {
|
|
1111
|
+
:default => false,
|
|
1112
|
+
:public => true,
|
|
1113
|
+
:type => Boolean,
|
|
1114
|
+
:allowed_from_server => true,
|
|
1115
|
+
:description => 'If `true`, enables continuous profiling. Requires the `stackprof` and `google-protobuf` ' \
|
|
1116
|
+
'gems to be present in the application. Not supported on JRuby. Automatically disabled when high ' \
|
|
1117
|
+
'security mode is enabled.'
|
|
1118
|
+
},
|
|
1119
|
+
:'profiling.delay' => {
|
|
1120
|
+
:default => 0,
|
|
1121
|
+
:public => true,
|
|
1122
|
+
:type => Integer,
|
|
1123
|
+
:allowed_from_server => true,
|
|
1124
|
+
:description => 'The delay, in milliseconds, before continuous profiling starts after being enabled. ' \
|
|
1125
|
+
'Defaults to `0`, meaning profiling starts immediately.'
|
|
1126
|
+
},
|
|
1127
|
+
:'profiling.duration' => {
|
|
1128
|
+
:default => 0,
|
|
1129
|
+
:public => true,
|
|
1130
|
+
:type => Integer,
|
|
1131
|
+
:allowed_from_server => true,
|
|
1132
|
+
:description => 'The duration, in milliseconds, that continuous profiling runs before automatically ' \
|
|
1133
|
+
'stopping. Defaults to `0`, meaning profiling runs indefinitely until explicitly stopped.'
|
|
1134
|
+
},
|
|
1135
|
+
:'profiling.include' => {
|
|
1136
|
+
:default => 'cpu',
|
|
1137
|
+
:public => true,
|
|
1138
|
+
:type => String,
|
|
1139
|
+
:allowed_from_server => true,
|
|
1140
|
+
:allowlist => %w[cpu object],
|
|
1141
|
+
:description => 'The `stackprof` sampling mode to use for continuous profiling: `cpu` or `object`.'
|
|
1142
|
+
},
|
|
1143
|
+
:'profiling.sample_period' => {
|
|
1144
|
+
:default => 0.01,
|
|
1145
|
+
:public => true,
|
|
1146
|
+
:type => Float,
|
|
1147
|
+
:allowed_from_server => true,
|
|
1148
|
+
:transform => DefaultSource.method(:enforce_sample_period_range),
|
|
1149
|
+
:description => 'The interval, in seconds, between stack samples taken by the continuous profiler. ' \
|
|
1150
|
+
'Only used when `profiling.include` is `cpu`. Must be between ' \
|
|
1151
|
+
"#{format('%.6f', DefaultSource::SAMPLE_PERIOD_MINIMUM_SECONDS)} and " \
|
|
1152
|
+
"#{format('%.6f', DefaultSource::SAMPLE_PERIOD_MAXIMUM_SECONDS)}."
|
|
1153
|
+
},
|
|
1154
|
+
:'profiling.object_allocation_interval' => {
|
|
1155
|
+
:default => 10000,
|
|
1156
|
+
:public => true,
|
|
1157
|
+
:type => Integer,
|
|
1158
|
+
:allowed_from_server => true,
|
|
1159
|
+
:transform => DefaultSource.method(:enforce_object_allocation_interval_range),
|
|
1160
|
+
:description => 'The number of object allocations between stack samples taken by the continuous ' \
|
|
1161
|
+
'profiler. Only used when `profiling.include` is `object`. Must be between ' \
|
|
1162
|
+
"#{DefaultSource::OBJECT_ALLOCATION_INTERVAL_MINIMUM} and #{DefaultSource::STACKPROF_INTERVAL_MAXIMUM}."
|
|
1163
|
+
},
|
|
1164
|
+
:'profiling.harvest_period' => {
|
|
1165
|
+
:default => 10,
|
|
1166
|
+
:public => false,
|
|
1167
|
+
:type => Integer,
|
|
1168
|
+
:allowed_from_server => true,
|
|
1169
|
+
:description => 'The interval, in seconds, at which the continuous profiler converts and reports its ' \
|
|
1170
|
+
'collected samples.'
|
|
1171
|
+
},
|
|
1057
1172
|
# Custom attributes
|
|
1058
1173
|
:'custom_attributes.enabled' => {
|
|
1059
1174
|
:default => true,
|