app_profiler 0.2.8 → 0.3.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/lib/app_profiler/base_profile.rb +10 -2
- data/lib/app_profiler/middleware.rb +29 -0
- data/lib/app_profiler/profile_id.rb +24 -4
- data/lib/app_profiler/railtie.rb +2 -0
- data/lib/app_profiler/request_parameters.rb +1 -1
- data/lib/app_profiler/stackprof_profile.rb +11 -0
- data/lib/app_profiler/vernier_profile.rb +13 -0
- data/lib/app_profiler/version.rb +1 -1
- data/lib/app_profiler.rb +17 -2
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e78035c478029d4ad4de636efab44240957c2bd05ea761dc9fe28b753b4fa1d3
|
4
|
+
data.tar.gz: c4d6659a31eaa7440c6c8a2550c9cf41fbadb567426cae7c6bd0cd4442e8039a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45610912af0b6952b2c104d27bfc3bf2b37b92f91d2c873bdf9e2bfc43498529decf9568af63b9ee47d84794dd921dbf6312de11aac272be296f99416d5f2b31
|
7
|
+
data.tar.gz: 29ee1a661cc8c81274fbdb7f6123ce90d7dbeaa351ca3b16a8a6bfe933ec3f68385bfe0f2d0afb2ae6c49ba59fa318d733bd23d6cf7724a3d03f1246e36b65ca
|
@@ -8,7 +8,7 @@ module AppProfiler
|
|
8
8
|
private_constant :INTERNAL_METADATA_KEYS
|
9
9
|
class UnsafeFilename < StandardError; end
|
10
10
|
|
11
|
-
attr_reader :
|
11
|
+
attr_reader :context
|
12
12
|
|
13
13
|
delegate :[], to: :@data
|
14
14
|
|
@@ -34,9 +34,17 @@ module AppProfiler
|
|
34
34
|
# `data` is assumed to be a Hash for Stackprof,
|
35
35
|
# a vernier "result" object for vernier
|
36
36
|
def initialize(data, id: nil, context: nil)
|
37
|
-
|
37
|
+
ProfileId.current = id if id.present?
|
38
|
+
|
38
39
|
@context = context
|
39
40
|
@data = data
|
41
|
+
|
42
|
+
metadata[PROFILE_BACKEND_METADATA_KEY] = self.class.backend_name
|
43
|
+
metadata[PROFILE_ID_METADATA_KEY] = ProfileId.current
|
44
|
+
end
|
45
|
+
|
46
|
+
def id
|
47
|
+
metadata[PROFILE_ID_METADATA_KEY]
|
40
48
|
end
|
41
49
|
|
42
50
|
def upload
|
@@ -7,6 +7,11 @@ require "app_profiler/middleware/view_action"
|
|
7
7
|
|
8
8
|
module AppProfiler
|
9
9
|
class Middleware
|
10
|
+
OTEL_PROFILE_ID = "profile.id"
|
11
|
+
OTEL_PROFILE_BACKEND = "profile.profiler"
|
12
|
+
OTEL_PROFILE_MODE = "profile.mode"
|
13
|
+
OTEL_PROFILE_CONTEXT = "profile.context"
|
14
|
+
|
10
15
|
class_attribute :action, default: UploadAction
|
11
16
|
class_attribute :disabled, default: false
|
12
17
|
|
@@ -29,8 +34,11 @@ module AppProfiler
|
|
29
34
|
return yield unless app_profiler_params
|
30
35
|
|
31
36
|
params_hash = app_profiler_params.to_h
|
37
|
+
|
32
38
|
return yield unless before_profile(env, params_hash)
|
33
39
|
|
40
|
+
add_otel_instrumentation(env, params_hash) if AppProfiler.otel_instrumentation_enabled
|
41
|
+
|
34
42
|
profile = AppProfiler.run(**params_hash) do
|
35
43
|
response = yield
|
36
44
|
end
|
@@ -47,6 +55,27 @@ module AppProfiler
|
|
47
55
|
response
|
48
56
|
end
|
49
57
|
|
58
|
+
def add_otel_instrumentation(env, params)
|
59
|
+
rack_span = OpenTelemetry::Instrumentation::Rack.current_span
|
60
|
+
return unless rack_span.recording?
|
61
|
+
|
62
|
+
metadata = params[:metadata]
|
63
|
+
profile_id = if metadata[:id].present?
|
64
|
+
metadata[:id]
|
65
|
+
else
|
66
|
+
AppProfiler::ProfileId.current
|
67
|
+
end
|
68
|
+
|
69
|
+
attributes = {
|
70
|
+
OTEL_PROFILE_ID => profile_id,
|
71
|
+
OTEL_PROFILE_BACKEND => params[:backend].to_s,
|
72
|
+
OTEL_PROFILE_MODE => params[:mode].to_s,
|
73
|
+
OTEL_PROFILE_CONTEXT => AppProfiler.context,
|
74
|
+
}
|
75
|
+
|
76
|
+
rack_span.add_attributes(attributes)
|
77
|
+
end
|
78
|
+
|
50
79
|
def profile_params(params)
|
51
80
|
return params if params.valid?
|
52
81
|
return unless AppProfiler.profile_sampler_enabled
|
@@ -1,19 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/current_attributes"
|
4
3
|
require "securerandom"
|
5
4
|
|
6
5
|
module AppProfiler
|
7
6
|
class ProfileId
|
8
|
-
class Current
|
9
|
-
|
7
|
+
class Current
|
8
|
+
PROFILE_ID_KEY = :__app_profiler_profile_id__
|
9
|
+
class << self
|
10
|
+
# This is a thread local variable which gets reset by the middleware at the end of the request.
|
11
|
+
# Need to be mindful of the middleware order. If we try to access ProfileId after the middleware has finished,
|
12
|
+
# lets say in a middleware which runs before Profiling middleware, it will return a different value,
|
13
|
+
# as the middleware has already reset.
|
14
|
+
|
15
|
+
def id
|
16
|
+
Thread.current[PROFILE_ID_KEY] ||= SecureRandom.hex
|
17
|
+
end
|
18
|
+
|
19
|
+
def id=(id)
|
20
|
+
Thread.current[PROFILE_ID_KEY] = id
|
21
|
+
end
|
22
|
+
|
23
|
+
def reset
|
24
|
+
Thread.current[PROFILE_ID_KEY] = nil
|
25
|
+
end
|
26
|
+
end
|
10
27
|
end
|
11
28
|
|
12
29
|
class << self
|
13
30
|
def current
|
14
|
-
Current.id ||= SecureRandom.hex
|
15
31
|
Current.id
|
16
32
|
end
|
33
|
+
|
34
|
+
def current=(id)
|
35
|
+
Current.id = id
|
36
|
+
end
|
17
37
|
end
|
18
38
|
end
|
19
39
|
end
|
data/lib/app_profiler/railtie.rb
CHANGED
@@ -51,6 +51,8 @@ module AppProfiler
|
|
51
51
|
AppProfiler.profile_sampler_enabled = app.config.app_profiler.profile_sampler_enabled || false
|
52
52
|
AppProfiler.profile_sampler_config = app.config.app_profiler.profile_sampler_config ||
|
53
53
|
AppProfiler::Sampler::Config.new
|
54
|
+
|
55
|
+
AppProfiler.otel_instrumentation_enabled = app.config.app_profiler.otel_instrumentation_enabled || false
|
54
56
|
end
|
55
57
|
|
56
58
|
initializer "app_profiler.add_middleware" do |app|
|
@@ -33,7 +33,7 @@ module AppProfiler
|
|
33
33
|
|
34
34
|
return false if backend != AppProfiler::Backend::StackprofBackend.name && !AppProfiler.vernier_supported?
|
35
35
|
|
36
|
-
if AppProfiler.vernier_supported? && backend == AppProfiler::
|
36
|
+
if AppProfiler.vernier_supported? && backend == AppProfiler::VernierProfile::BACKEND_NAME &&
|
37
37
|
!AppProfiler::Backend::VernierBackend::AVAILABLE_MODES.include?(mode.to_sym)
|
38
38
|
AppProfiler.logger.info("[AppProfiler] unsupported profiling mode=#{mode} for backend #{backend}")
|
39
39
|
return false
|
@@ -4,6 +4,17 @@ module AppProfiler
|
|
4
4
|
class StackprofProfile < BaseProfile
|
5
5
|
FILE_EXTENSION = ".stackprof.json"
|
6
6
|
|
7
|
+
class << self
|
8
|
+
def backend_name
|
9
|
+
Backend::StackprofBackend.name.to_s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(data, id: nil, context: nil)
|
14
|
+
data[:metadata] ||= {}
|
15
|
+
super(data, id: id, context: context)
|
16
|
+
end
|
17
|
+
|
7
18
|
def mode
|
8
19
|
@data[:mode]
|
9
20
|
end
|
@@ -3,6 +3,19 @@
|
|
3
3
|
module AppProfiler
|
4
4
|
class VernierProfile < BaseProfile
|
5
5
|
FILE_EXTENSION = ".vernier.json"
|
6
|
+
BACKEND_NAME = :vernier
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def backend_name
|
10
|
+
# cannot reference Backend::VernierBackend because of different ruby versions we have to support
|
11
|
+
BACKEND_NAME.to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(data, id: nil, context: nil)
|
16
|
+
data[:meta] ||= {}
|
17
|
+
super(data, id: id, context: context)
|
18
|
+
end
|
6
19
|
|
7
20
|
def mode
|
8
21
|
@data[:meta][:mode]
|
data/lib/app_profiler/version.rb
CHANGED
data/lib/app_profiler.rb
CHANGED
@@ -7,6 +7,9 @@ require "logger"
|
|
7
7
|
require "app_profiler/version"
|
8
8
|
|
9
9
|
module AppProfiler
|
10
|
+
PROFILE_ID_METADATA_KEY = :profile_id
|
11
|
+
PROFILE_BACKEND_METADATA_KEY = :profiler
|
12
|
+
|
10
13
|
class ConfigurationError < StandardError
|
11
14
|
end
|
12
15
|
|
@@ -73,6 +76,8 @@ module AppProfiler
|
|
73
76
|
mattr_reader :profile_file_name
|
74
77
|
|
75
78
|
class << self
|
79
|
+
attr_reader :otel_instrumentation_enabled
|
80
|
+
|
76
81
|
def deprecator # :nodoc:
|
77
82
|
@deprecator ||= ActiveSupport::Deprecation.new("in future releases", "app_profiler")
|
78
83
|
end
|
@@ -90,6 +95,7 @@ module AppProfiler
|
|
90
95
|
yield
|
91
96
|
ensure
|
92
97
|
self.backend = original_backend if backend
|
98
|
+
ProfileId::Current.reset
|
93
99
|
end
|
94
100
|
|
95
101
|
def start(*args, backend: nil, **kwargs)
|
@@ -158,9 +164,18 @@ module AppProfiler
|
|
158
164
|
false
|
159
165
|
end
|
160
166
|
|
167
|
+
def otel_instrumentation_enabled=(value)
|
168
|
+
if value
|
169
|
+
gem("opentelemetry-instrumentation-rack")
|
170
|
+
require("opentelemetry/instrumentation/rack")
|
171
|
+
end
|
172
|
+
|
173
|
+
@otel_instrumentation_enabled = value
|
174
|
+
end
|
175
|
+
|
161
176
|
def backend_for(backend_name)
|
162
177
|
if vernier_supported? &&
|
163
|
-
backend_name&.to_sym == AppProfiler::
|
178
|
+
backend_name&.to_sym == AppProfiler::VernierProfile::BACKEND_NAME
|
164
179
|
AppProfiler::Backend::VernierBackend
|
165
180
|
elsif backend_name&.to_sym == AppProfiler::Backend::StackprofBackend.name
|
166
181
|
AppProfiler::Backend::StackprofBackend
|
@@ -174,7 +189,7 @@ module AppProfiler
|
|
174
189
|
end
|
175
190
|
|
176
191
|
def vernier_supported?
|
177
|
-
RUBY_VERSION >= "3.2.1" && defined?(AppProfiler::
|
192
|
+
RUBY_VERSION >= "3.2.1" && defined?(AppProfiler::VernierProfile::BACKEND_NAME)
|
178
193
|
end
|
179
194
|
|
180
195
|
def profile_header=(profile_header)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: app_profiler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gannon McGibbon
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
- Scott Francis
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2025-02-
|
15
|
+
date: 2025-02-24 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: activesupport
|
@@ -112,6 +112,20 @@ dependencies:
|
|
112
112
|
- - ">="
|
113
113
|
- !ruby/object:Gem::Version
|
114
114
|
version: '0'
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: opentelemetry-instrumentation-rack
|
117
|
+
requirement: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
type: :development
|
123
|
+
prerelease: false
|
124
|
+
version_requirements: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
115
129
|
- !ruby/object:Gem::Dependency
|
116
130
|
name: rake
|
117
131
|
requirement: !ruby/object:Gem::Requirement
|