appsignal 5.0.2-java → 5.0.3-java
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/CHANGELOG.md +8 -0
- data/lib/appsignal/opentelemetry/process_resource.rb +137 -0
- data/lib/appsignal/opentelemetry.rb +5 -1
- data/lib/appsignal/version.rb +1 -1
- data/sig/appsignal.rbi +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f511b69fdbdeb226062bbaf05e00fe52eb3bd20854c3eeb202edba0b815b1db5
|
|
4
|
+
data.tar.gz: e1261b245afbc044c149b030ba2b4f4656c7d56f56e37223006ed21a68d1a8be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a18f025051286fc68ff81d27cdc6d4d2fd91b71f79e3d439a9d957e39c98350c9dd46fc7626738c8dfddd13908f13884f9be13155475dedfc8e2844e10f44021
|
|
7
|
+
data.tar.gz: eb8047d550aaa8afd456483ef40db0d188ba492215e582b6f7ddc5c73b6d7e1d957c39bf0183e2b2d5fa1dbd5531a5064d66ac874a1112193feddf9d90f1cd94
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# AppSignal for Ruby gem Changelog
|
|
2
2
|
|
|
3
|
+
## 5.0.3
|
|
4
|
+
|
|
5
|
+
_Published on 2026-10-08._
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- In collector mode, report counter metrics correctly from processes forked after AppSignal starts, such as Puma workers when using `preload_app!`. Before this change, applications running several forked processes would lose data points or report incorrect values for them. (patch [4e5a3e78](https://github.com/appsignal/appsignal-ruby/commit/4e5a3e781b4ce2b2620b172a15198a2a59e0ebee))
|
|
10
|
+
|
|
3
11
|
## 5.0.2
|
|
4
12
|
|
|
5
13
|
_Published on 2026-10-06._
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
module Appsignal
|
|
6
|
+
module OpenTelemetry
|
|
7
|
+
# @!visibility private
|
|
8
|
+
#
|
|
9
|
+
# The resource attributes that identify the current process:
|
|
10
|
+
# `service.instance.id` and `process.pid`. The OpenTelemetry providers are
|
|
11
|
+
# built once, so a process forked after that inherits its parent's values
|
|
12
|
+
# until {.attach_fork_hook} refreshes them in the child.
|
|
13
|
+
module ProcessResource
|
|
14
|
+
SERVICE_INSTANCE_ID = "service.instance.id"
|
|
15
|
+
PROCESS_PID = "process.pid"
|
|
16
|
+
REFRESH_FAILED = "Could not refresh the OpenTelemetry resource after fork"
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# A random UUIDv4, generated again when the process ID changes.
|
|
20
|
+
def service_instance_id
|
|
21
|
+
pid = Process.pid
|
|
22
|
+
unless @service_instance_id_pid == pid
|
|
23
|
+
@service_instance_id = SecureRandom.uuid
|
|
24
|
+
@service_instance_id_pid = pid
|
|
25
|
+
end
|
|
26
|
+
@service_instance_id
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def resource
|
|
30
|
+
::OpenTelemetry::SDK::Resources::Resource.create(
|
|
31
|
+
SERVICE_INSTANCE_ID => service_instance_id,
|
|
32
|
+
PROCESS_PID => Process.pid
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def attach_fork_hook
|
|
37
|
+
return if @fork_hook_attached
|
|
38
|
+
|
|
39
|
+
Process.singleton_class.prepend(ForkHook)
|
|
40
|
+
@fork_hook_attached = true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def before_fork
|
|
44
|
+
return unless Appsignal::OpenTelemetry.started?
|
|
45
|
+
|
|
46
|
+
providers.transform_values do |provider|
|
|
47
|
+
current = current_resource(provider)
|
|
48
|
+
current && attribute(current, SERVICE_INSTANCE_ID)
|
|
49
|
+
end
|
|
50
|
+
rescue => e
|
|
51
|
+
log_failure("#{e.class}: #{e.message}")
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def after_fork(instance_ids_before_fork)
|
|
56
|
+
return unless instance_ids_before_fork
|
|
57
|
+
|
|
58
|
+
update = resource
|
|
59
|
+
providers.each do |name, provider|
|
|
60
|
+
refresh(name, provider, update, instance_ids_before_fork[name])
|
|
61
|
+
end
|
|
62
|
+
rescue => e
|
|
63
|
+
log_failure("#{e.class}: #{e.message}")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def providers
|
|
69
|
+
{
|
|
70
|
+
"tracer" => ::OpenTelemetry.tracer_provider,
|
|
71
|
+
"meter" => ::OpenTelemetry.meter_provider,
|
|
72
|
+
"logger" => ::OpenTelemetry.logger_provider
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def refresh(name, provider, update, instance_id_before_fork)
|
|
77
|
+
current = current_resource(provider)
|
|
78
|
+
unless current
|
|
79
|
+
log_failure("the #{name} provider's resource could not be read")
|
|
80
|
+
return
|
|
81
|
+
end
|
|
82
|
+
return unless attribute(current, SERVICE_INSTANCE_ID) == instance_id_before_fork
|
|
83
|
+
|
|
84
|
+
refreshed = current.merge(update)
|
|
85
|
+
write_resource(provider, refreshed)
|
|
86
|
+
return if current_resource(provider).equal?(refreshed)
|
|
87
|
+
|
|
88
|
+
log_failure("the #{name} provider did not keep the new resource")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# The SDK providers take their resource only in their constructors, and
|
|
92
|
+
# read it from `@resource` when they export.
|
|
93
|
+
def current_resource(provider)
|
|
94
|
+
if provider.respond_to?(:resource)
|
|
95
|
+
resource = provider.resource
|
|
96
|
+
unless provider.respond_to?(:resource=)
|
|
97
|
+
# Without a setter, only `@resource` can be written, and it isn't there.
|
|
98
|
+
return unless provider.instance_variable_defined?(:@resource)
|
|
99
|
+
# The reader returns something else, so writing `@resource` would change nothing.
|
|
100
|
+
return unless provider.instance_variable_get(:@resource).equal?(resource)
|
|
101
|
+
end
|
|
102
|
+
elsif provider.instance_variable_defined?(:@resource)
|
|
103
|
+
resource = provider.instance_variable_get(:@resource)
|
|
104
|
+
end
|
|
105
|
+
# If it's not a resource, it isn't what the provider exports.
|
|
106
|
+
resource if resource.is_a?(::OpenTelemetry::SDK::Resources::Resource)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def write_resource(provider, resource)
|
|
110
|
+
if provider.respond_to?(:resource=)
|
|
111
|
+
provider.resource = resource
|
|
112
|
+
else
|
|
113
|
+
provider.instance_variable_set(:@resource, resource)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def attribute(resource, key)
|
|
118
|
+
resource.attribute_enumerator.each { |k, v| return v if k == key }
|
|
119
|
+
nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def log_failure(reason)
|
|
123
|
+
Appsignal.internal_logger.warn("#{REFRESH_FAILED}: #{reason}")
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
module ForkHook
|
|
128
|
+
def _fork
|
|
129
|
+
instance_ids = ProcessResource.before_fork
|
|
130
|
+
pid = super
|
|
131
|
+
ProcessResource.after_fork(instance_ids) if pid.zero?
|
|
132
|
+
pid
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -8,6 +8,7 @@ require "appsignal/opentelemetry/http_method"
|
|
|
8
8
|
require "appsignal/opentelemetry/http_response"
|
|
9
9
|
require "appsignal/opentelemetry/http_server_request"
|
|
10
10
|
require "appsignal/opentelemetry/messaging"
|
|
11
|
+
require "appsignal/opentelemetry/process_resource"
|
|
11
12
|
require "appsignal/opentelemetry/proxied_exporter"
|
|
12
13
|
require "appsignal/opentelemetry/rendering"
|
|
13
14
|
require "appsignal/opentelemetry/sql_db_system"
|
|
@@ -59,7 +60,9 @@ module Appsignal
|
|
|
59
60
|
# `LoggerProvider` take a `resource:` kwarg that replaces (not
|
|
60
61
|
# merges), so we do the merge ourselves and use the same merged
|
|
61
62
|
# resource for the tracer provider to keep all three in sync.
|
|
62
|
-
resource =
|
|
63
|
+
resource = ProcessResource.resource
|
|
64
|
+
.merge(::OpenTelemetry::SDK::Resources::Resource.default)
|
|
65
|
+
.merge(build_resource(config))
|
|
63
66
|
|
|
64
67
|
span_exporter = build_exporter(
|
|
65
68
|
::OpenTelemetry::Exporter::OTLP::Exporter,
|
|
@@ -103,6 +106,7 @@ module Appsignal
|
|
|
103
106
|
)
|
|
104
107
|
|
|
105
108
|
@started = true
|
|
109
|
+
ProcessResource.attach_fork_hook
|
|
106
110
|
rescue LoadError => e
|
|
107
111
|
@started = false
|
|
108
112
|
Appsignal::Utils::StdoutAndLoggerMessage.error(
|
data/lib/appsignal/version.rb
CHANGED
data/sig/appsignal.rbi
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: appsignal
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.0.
|
|
4
|
+
version: 5.0.3
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Beekman
|
|
@@ -306,6 +306,7 @@ files:
|
|
|
306
306
|
- lib/appsignal/opentelemetry/http_response.rb
|
|
307
307
|
- lib/appsignal/opentelemetry/http_server_request.rb
|
|
308
308
|
- lib/appsignal/opentelemetry/messaging.rb
|
|
309
|
+
- lib/appsignal/opentelemetry/process_resource.rb
|
|
309
310
|
- lib/appsignal/opentelemetry/proxied_exporter.rb
|
|
310
311
|
- lib/appsignal/opentelemetry/rendering.rb
|
|
311
312
|
- lib/appsignal/opentelemetry/sql_db_system.rb
|