nurse_andrea 0.2.1 → 0.2.3
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/nurse_andrea/configuration.rb +1 -0
- data/lib/nurse_andrea/deploy.rb +35 -0
- data/lib/nurse_andrea/instrumentation_subscriber.rb +20 -4
- data/lib/nurse_andrea/managed_service_scanner.rb +8 -2
- data/lib/nurse_andrea/platform_detector.rb +1 -1
- data/lib/nurse_andrea/self_filter.rb +39 -0
- data/lib/nurse_andrea/version.rb +1 -1
- data/lib/nurse_andrea.rb +2 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ae308e57dd4f7a8bf6182f34e49a8223cc695448e9a0ef0146b37396e6deea19
|
|
4
|
+
data.tar.gz: 7323b870d40f057ac56130b11061ca84bb9d9db9f97f61697c1234d392df296b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4848f27cff94597a94a21b6fe366da00c547831aad652717e59a41255d25005142bf6a1b8fb9181f37a7358ee88e08e4e597b5e1c83cdff8da052ea716c2b583
|
|
7
|
+
data.tar.gz: f01a8a679ddcd4be389125c43ca2cfeca6703acc5dcf29f53a392896406f6384e87aaba578d24fd86d4a8e474400779c47dd2e02b02e3b751131458a604c7ee2
|
|
@@ -43,6 +43,7 @@ module NurseAndrea
|
|
|
43
43
|
def metrics_url = "#{normalised_host}/api/v1/metrics"
|
|
44
44
|
def traces_url = "#{normalised_host}/api/v1/traces"
|
|
45
45
|
def handshake_url = "#{normalised_host}/api/v1/handshake"
|
|
46
|
+
def deploy_url = "#{normalised_host}/api/v1/deploy"
|
|
46
47
|
|
|
47
48
|
def enabled?
|
|
48
49
|
@enabled
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module NurseAndrea
|
|
2
|
+
# Public: ship a deploy event to the NurseAndrea backend so the
|
|
3
|
+
# dashboard can render it as a vertical marker on time-series charts
|
|
4
|
+
# and as a chip in the recent-deploys strip.
|
|
5
|
+
#
|
|
6
|
+
# Fire-and-forget: any failure (no token, network error, non-2xx) is
|
|
7
|
+
# logged in debug mode and swallowed so the host application never
|
|
8
|
+
# crashes from a deploy notification.
|
|
9
|
+
module Deploy
|
|
10
|
+
DESCRIPTION_LIMIT = 500
|
|
11
|
+
|
|
12
|
+
def self.call(version:, deployer: nil, environment: "production", description: nil)
|
|
13
|
+
return false unless NurseAndrea.config.valid?
|
|
14
|
+
return false if version.to_s.strip.empty?
|
|
15
|
+
|
|
16
|
+
payload = {
|
|
17
|
+
version: version.to_s,
|
|
18
|
+
deployer: deployer,
|
|
19
|
+
environment: environment,
|
|
20
|
+
description: description.is_a?(String) ? description[0, DESCRIPTION_LIMIT] : description,
|
|
21
|
+
deployed_at: Time.now.utc.iso8601
|
|
22
|
+
}.compact
|
|
23
|
+
|
|
24
|
+
HttpClient.new.post(NurseAndrea.config.deploy_url, payload)
|
|
25
|
+
rescue => e
|
|
26
|
+
NurseAndrea.debug("[NurseAndrea] deploy() error: #{e.class}: #{e.message}")
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Convenience top-level: NurseAndrea.deploy(version: "1.4.2")
|
|
32
|
+
def self.deploy(**kwargs)
|
|
33
|
+
Deploy.call(**kwargs)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -14,7 +14,7 @@ module NurseAndrea
|
|
|
14
14
|
"cache_delete.active_support" => :on_cache_delete,
|
|
15
15
|
"perform.active_job" => :on_job_perform,
|
|
16
16
|
"enqueue.active_job" => :on_job_enqueue,
|
|
17
|
-
"deliver.action_mailer" => :on_mailer
|
|
17
|
+
"deliver.action_mailer" => :on_mailer
|
|
18
18
|
}.freeze
|
|
19
19
|
|
|
20
20
|
attr_reader :telemetry, :discovered_components
|
|
@@ -48,13 +48,14 @@ module NurseAndrea
|
|
|
48
48
|
return if event.payload[:name] == "SCHEMA"
|
|
49
49
|
return if event.payload[:name]&.start_with?("EXPLAIN")
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
conn = event.payload[:connection]
|
|
52
|
+
adapter = conn&.adapter_name rescue nil
|
|
52
53
|
|
|
53
54
|
# Skip platform's own ClickHouse queries — not the customer's infrastructure
|
|
54
55
|
return if adapter&.downcase&.include?("clickhouse")
|
|
55
56
|
|
|
56
57
|
tech = adapter_to_tech(adapter)
|
|
57
|
-
register_discovery("database", tech) if tech
|
|
58
|
+
register_discovery("database", tech, connection: conn) if tech
|
|
58
59
|
|
|
59
60
|
table = extract_table(event.payload[:sql])
|
|
60
61
|
@telemetry.record_query(duration_ms: event.duration, table: table)
|
|
@@ -100,8 +101,9 @@ module NurseAndrea
|
|
|
100
101
|
register_discovery("external", "email")
|
|
101
102
|
end
|
|
102
103
|
|
|
103
|
-
def register_discovery(type, tech)
|
|
104
|
+
def register_discovery(type, tech, connection: nil)
|
|
104
105
|
return if tech.nil? || tech.empty? || tech == "unknown"
|
|
106
|
+
return if self_referential?(connection)
|
|
105
107
|
|
|
106
108
|
key = "#{type}:#{tech}"
|
|
107
109
|
return if @discovered_components.include?(key)
|
|
@@ -113,6 +115,20 @@ module NurseAndrea
|
|
|
113
115
|
)
|
|
114
116
|
end
|
|
115
117
|
|
|
118
|
+
# True when the SDK is running inside NurseAndrea itself, OR when
|
|
119
|
+
# the SQL event's connection points at NurseAndrea's own infra.
|
|
120
|
+
# Either way the discovery would be a self-reference, not a
|
|
121
|
+
# customer component. Process-level + connection-level checks are
|
|
122
|
+
# both consulted; the same module powers the env-scanner filter.
|
|
123
|
+
def self_referential?(connection)
|
|
124
|
+
return true if NurseAndrea::SelfFilter.platform_self?
|
|
125
|
+
return false unless connection
|
|
126
|
+
|
|
127
|
+
db_name = connection.current_database.to_s rescue ""
|
|
128
|
+
host = connection.pool&.db_config&.host.to_s rescue ""
|
|
129
|
+
NurseAndrea::SelfFilter.host_matches?(db_name, host)
|
|
130
|
+
end
|
|
131
|
+
|
|
116
132
|
def adapter_to_tech(adapter_name)
|
|
117
133
|
case adapter_name&.downcase
|
|
118
134
|
when "postgresql", "postgis" then "postgresql"
|
|
@@ -15,15 +15,21 @@ module NurseAndrea
|
|
|
15
15
|
"MONGODB_URI" => "database",
|
|
16
16
|
"MONGO_URL" => "database",
|
|
17
17
|
"ELASTICSEARCH_URL" => "search",
|
|
18
|
-
"KAFKA_BROKERS" => "queue"
|
|
18
|
+
"KAFKA_BROKERS" => "queue"
|
|
19
19
|
}.freeze
|
|
20
20
|
|
|
21
21
|
def self.scan
|
|
22
|
+
# Skip env-based discovery entirely when the SDK is loaded inside
|
|
23
|
+
# NurseAndrea itself — every URL we'd find belongs to the platform's
|
|
24
|
+
# own infrastructure, not a customer component.
|
|
25
|
+
return [] if NurseAndrea::SelfFilter.platform_self?
|
|
26
|
+
|
|
22
27
|
discoveries = []
|
|
23
28
|
|
|
24
29
|
SCAN_MAP.each do |var_name, component_type|
|
|
25
30
|
url = ENV[var_name]
|
|
26
31
|
next if url.nil? || url.strip.empty?
|
|
32
|
+
next if NurseAndrea::SelfFilter.host_matches?(url)
|
|
27
33
|
|
|
28
34
|
tech = Sanitizer.extract_tech(url)
|
|
29
35
|
provider = Sanitizer.extract_provider(url)
|
|
@@ -39,7 +45,7 @@ module NurseAndrea
|
|
|
39
45
|
discoveries << Sanitizer.sanitize_discovery(raw)
|
|
40
46
|
end
|
|
41
47
|
|
|
42
|
-
discoveries.uniq { |d| [d[:type], d[:tech], d[:provider]] }
|
|
48
|
+
discoveries.uniq { |d| [ d[:type], d[:tech], d[:provider] ] }
|
|
43
49
|
end
|
|
44
50
|
end
|
|
45
51
|
end
|
|
@@ -10,7 +10,7 @@ module NurseAndrea
|
|
|
10
10
|
fly: -> { ENV.key?("FLY_APP_NAME") },
|
|
11
11
|
heroku: -> { ENV.key?("DYNO") },
|
|
12
12
|
digitalocean: -> { ENV.key?("DIGITALOCEAN_APP_PLATFORM_COMPONENT_NAME") },
|
|
13
|
-
vercel: -> { ENV.key?("VERCEL") }
|
|
13
|
+
vercel: -> { ENV.key?("VERCEL") }
|
|
14
14
|
}.freeze
|
|
15
15
|
|
|
16
16
|
def self.detect
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Suppresses discovery emission when the SDK is loaded inside
|
|
2
|
+
# NurseAndrea itself. Both the InstrumentationSubscriber (hook-based)
|
|
3
|
+
# and the ManagedServiceScanner (env-based) must consult this filter
|
|
4
|
+
# before adding to NurseAndrea.component_discoveries — otherwise the
|
|
5
|
+
# platform's own infrastructure shows up as proposed components on
|
|
6
|
+
# every workspace dashboard.
|
|
7
|
+
|
|
8
|
+
module NurseAndrea
|
|
9
|
+
module SelfFilter
|
|
10
|
+
SELF_INDICATORS = %w[nurseandrea nurse-andrea nurse_andrea].freeze
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def platform_self?
|
|
14
|
+
return @platform_self if defined?(@platform_self)
|
|
15
|
+
@platform_self = compute_platform_self
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def reset!
|
|
19
|
+
remove_instance_variable(:@platform_self) if defined?(@platform_self)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def host_matches?(*candidates)
|
|
23
|
+
candidates.compact.map(&:to_s).map(&:downcase).any? do |s|
|
|
24
|
+
SELF_INDICATORS.any? { |i| s.include?(i) }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def compute_platform_self
|
|
31
|
+
return false unless defined?(Rails) && Rails.application
|
|
32
|
+
app_name = Rails.application.class.module_parent_name.to_s.downcase
|
|
33
|
+
SELF_INDICATORS.any? { |i| app_name.include?(i) }
|
|
34
|
+
rescue
|
|
35
|
+
false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/nurse_andrea/version.rb
CHANGED
data/lib/nurse_andrea.rb
CHANGED
|
@@ -15,6 +15,8 @@ require "nurse_andrea/managed_service_scanner"
|
|
|
15
15
|
require "nurse_andrea/component_telemetry"
|
|
16
16
|
require "nurse_andrea/instrumentation_subscriber"
|
|
17
17
|
require "nurse_andrea/memory_sampler"
|
|
18
|
+
require "nurse_andrea/deploy"
|
|
19
|
+
require "nurse_andrea/self_filter"
|
|
18
20
|
|
|
19
21
|
require "nurse_andrea/railtie" if defined?(Rails::Railtie)
|
|
20
22
|
require "nurse_andrea/engine" if defined?(Rails::Engine)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nurse_andrea
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ago AI LLC
|
|
@@ -28,6 +28,7 @@ files:
|
|
|
28
28
|
- lib/nurse_andrea/backfill.rb
|
|
29
29
|
- lib/nurse_andrea/component_telemetry.rb
|
|
30
30
|
- lib/nurse_andrea/configuration.rb
|
|
31
|
+
- lib/nurse_andrea/deploy.rb
|
|
31
32
|
- lib/nurse_andrea/engine.rb
|
|
32
33
|
- lib/nurse_andrea/http_client.rb
|
|
33
34
|
- lib/nurse_andrea/instrumentation_subscriber.rb
|
|
@@ -43,6 +44,7 @@ files:
|
|
|
43
44
|
- lib/nurse_andrea/queue_depth_reporter.rb
|
|
44
45
|
- lib/nurse_andrea/railtie.rb
|
|
45
46
|
- lib/nurse_andrea/sanitizer.rb
|
|
47
|
+
- lib/nurse_andrea/self_filter.rb
|
|
46
48
|
- lib/nurse_andrea/version.rb
|
|
47
49
|
- nurse_andrea.gemspec
|
|
48
50
|
homepage: https://nurseandrea.io
|