nexus_semantic_logger 1.17.0 → 1.34.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3868c4fe94f7eca85f77a015f5cf2d8e9b6ed2ef97667de52ee2fc194999421b
4
- data.tar.gz: dd16b36754be0d34c5b705a2771677d127984712ddf7adb01d960073204057e6
3
+ metadata.gz: 2fec2fab7ed4208841df5e24feb89f5492dcf7e7da927a66c213ba320f10d70c
4
+ data.tar.gz: 560a758d31cf9bf3d773f85f588c977ba74b5acfd18a417dc2ce7fbd50c3762f
5
5
  SHA512:
6
- metadata.gz: 8ac8fd1cb30a5ff48caf5ab7e049c652507ba58e1596b60a79279934ceaf7e95c8e4d4cdebba8f65bdb0bab3e9830c9443cc9e09cd0d5fac7be53e631d75a1c1
7
- data.tar.gz: ac48fb7f2a1bed19cc6d05ef22cd4c5e9d193cf4d02e700bf00f48d2df8ce2c44d9e2fca48c2a6c088b6fb0889d02b960af17fc8448cc70841cb092a597e4485
6
+ metadata.gz: 00c2dc1aa81205934c9ddc44e8a9c1135bc75f8a3191cb2d0b23c38af98ac2da1c311f034d54eb0f865a7b7237da1ec056658a4031300ed67e4e79e0700fd2c4
7
+ data.tar.gz: 54421ea76eb1c16ad584b4a547452bfa0ecb430ef37ccbcd15ada51f63a30c89f8e800bb6404a3c94fc830dcfe22277540a8fbf557c4a8d28c0d5038456c6d27
data/.gitignore CHANGED
@@ -1,5 +1,3 @@
1
1
  .idea/
2
2
  .vscode/
3
3
  results/
4
- Gemfile.lock
5
- gemfiles/*.gemfile.lock
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,36 @@
1
+ image: "ruby:3.2.2"
2
+
3
+ stages:
4
+ - release
5
+ - test
6
+
7
+ before_script:
8
+ - gem install bundler --no-document
9
+ - bundle install --jobs $(nproc) "${FLAGS[@]}"
10
+
11
+ rspec:
12
+ script:
13
+ - bundle exec rspec
14
+
15
+ rubocop:
16
+ script:
17
+ - bundle exec rubocop
18
+
19
+ release:
20
+ stage: release
21
+ rules:
22
+ - if: '$CI_COMMIT_TAG'
23
+ script:
24
+ - mkdir -p ~/.gem
25
+ - cp $RUBYGEMS_CREDENTIALS ~/.gem/credentials
26
+ - chmod 0600 ~/.gem/credentials
27
+ - gem update --system
28
+ - ruby --version
29
+ - gem env version
30
+ - sed -i "s/0.0.0/$CI_COMMIT_TAG/g" lib/nexus_semantic_logger/version.rb
31
+ - gem build nexus_semantic_logger.gemspec
32
+ - gem push nexus_semantic_logger*.gem
33
+ artifacts:
34
+ paths:
35
+ - nexus_semantic_logger*.gem
36
+ expire_in: 30 days
data/Gemfile CHANGED
@@ -3,7 +3,6 @@ source 'https://rubygems.org'
3
3
 
4
4
  gemspec
5
5
 
6
- gem 'appraisal'
7
6
  gem 'rubocop'
8
7
  gem 'rubocop-shopify', "~> 1.0.4", require: false
9
8
 
data/README.md CHANGED
@@ -60,20 +60,6 @@ For example, to increment a count:
60
60
  NexusSemanticLogger.metrics.increment('nexus.users.registration.complete')
61
61
  ```
62
62
 
63
- ### Running shell commands
64
-
65
- Use `NexusSemanticLogger.shell.capture3` as a drop-in replacement for `Open3.capture3`:
66
-
67
- ```
68
- stdout, stderr, status = NexusSemanticLogger.shell.capture3('7z', 'x', archive_path)
69
- ```
70
-
71
- Each call is wrapped in a Datadog APM span (`shell.exec`) and emits `nexus.shell.duration_ms`,
72
- `nexus.shell.peak_rss_mb` (the child's peak RSS, sampled from procfs) and `nexus.shell.executions`
73
- metrics tagged with `command:<binary>` and `outcome:<success|failure|signaled|exception>`, plus an
74
- info log line. A child killed by the kernel OOM killer shows up as `outcome:signaled` with
75
- `termsig: 9` and its last-observed peak RSS.
76
-
77
63
  # Local gem development
78
64
 
79
65
  Steps to run this gem from local sources in one the nexus 'staged build' rails components:
@@ -46,7 +46,6 @@ module NexusSemanticLogger
46
46
  config.after_initialize do
47
47
  require("nexus_semantic_logger/extensions/action_dispatch/debug_exceptions") if defined?(
48
48
  ::ActionDispatch::DebugExceptions)
49
- warn_on_incompatible_rails_semantic_logger
50
49
  end
51
50
  end
52
51
 
@@ -86,29 +85,5 @@ module NexusSemanticLogger
86
85
  # Ensure logging is immediately flushed.
87
86
  $stdout.sync = true
88
87
  end
89
-
90
- # Rails 8.1 needs rails_semantic_logger 5.x and no gemspec can express that, so detect the
91
- # broken pairing at boot.
92
- def self.warn_on_incompatible_rails_semantic_logger
93
- return unless incompatible_rails_semantic_logger?
94
-
95
- logger.warn(
96
- 'rails_semantic_logger 4.x cannot log ActiveRecord events on this Rails version, every ' \
97
- 'sql.active_record event will log a NoMethodError instead of the query. Add ' \
98
- '`gem "rails_semantic_logger", ">= 5.1"` to your Gemfile so bundler refuses this ' \
99
- 'pairing, then `bundle update rails_semantic_logger semantic_logger`.'
100
- )
101
- end
102
-
103
- # Rails 8.1 moved ActiveRecord::RuntimeRegistry.sql_runtime onto a stats object, which
104
- # rails_semantic_logger only handles from 5.0. Apps carrying their own shim restore
105
- # sql_runtime and so read as compatible here.
106
- def self.incompatible_rails_semantic_logger?
107
- defined?(::ActiveRecord::RuntimeRegistry) &&
108
- !::ActiveRecord::RuntimeRegistry.respond_to?(:sql_runtime) &&
109
- Gem::Version.new(RailsSemanticLogger::VERSION) < Gem::Version.new('5.0')
110
- end
111
-
112
- private_class_method :warn_on_incompatible_rails_semantic_logger, :incompatible_rails_semantic_logger?
113
88
  end
114
89
  end
@@ -22,6 +22,7 @@ module NexusSemanticLogger
22
22
  hash[:source] = :rails
23
23
  level = hash.delete(:level)
24
24
  hash[:status] = level
25
+ hash[:railsenv] = Rails.env
25
26
  hash[:service] = @service
26
27
  hash.delete(:application)
27
28
  hash.delete(:environment)
@@ -18,6 +18,7 @@ module NexusSemanticLogger
18
18
  # Note that 'env' is NOT sent- that is set as the default on the agent e.g. staging, canary, production.
19
19
  # It does not necessarily align with the Rails env, and we do not want to double tag the env.
20
20
  global_tags = [
21
+ "railsenv:#{Rails.env}",
21
22
  "service:#{service}",
22
23
  "container_name:#{container_name}",
23
24
  "pod_name:#{pod_name}",
@@ -41,6 +42,7 @@ module NexusSemanticLogger
41
42
  # Trace tags API is Hash<String,String>, see https://www.rubydoc.info/gems/ddtrace/Datadog/Tracing
42
43
  # Should match the global tags, but as a Hash.
43
44
  c.tags = {
45
+ railsenv: Rails.env,
44
46
  service: service,
45
47
  container_name: container_name,
46
48
  pod_name: pod_name,
@@ -56,7 +58,7 @@ module NexusSemanticLogger
56
58
  c.profiling.enabled = dd_tracer_enabled
57
59
  end
58
60
 
59
- c.tracing.instrument(:rails, service_name: service, request_queuing: true, web_service_name: service)
61
+ c.tracing.instrument(:rails, service_name: service)
60
62
 
61
63
  c.logger.level = Logger::WARN # datadog info logging is too verbose.
62
64
  end
@@ -14,19 +14,8 @@ module ActionDispatch
14
14
  # log_rescued_responses? is a rails7 feature, but this gem is also used on rails6. Check for its existence.
15
15
  return if respond_to?('log_rescued_responses?') && !log_rescued_responses?(request) && wrapper.rescue_response?
16
16
 
17
- # Silence deprecations emitted while logging the exception. The API changed in Rails 7.1: the
18
- # ActiveSupport::Deprecation singleton was deprecated and its class-level `silence` was removed in 7.2,
19
- # replaced by Rails.application.deprecators. Calling the removed singleton on >= 7.2 raises NoMethodError
20
- # inside render_exception (before the exception is logged), which swallowed all exception logging and
21
- # produced empty 500s. Use whichever API the Rails version provides, mirroring rails_semantic_logger.
22
- if (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR >= 1) || Rails::VERSION::MAJOR > 7
23
- Rails.application.deprecators.silence do
24
- ActionController::Base.logger.fatal(wrapper.exception)
25
- end
26
- else
27
- ActiveSupport::Deprecation.silence do
28
- ActionController::Base.logger.fatal(wrapper.exception)
29
- end
17
+ ActiveSupport::Deprecation.silence do
18
+ ActionController::Base.logger.fatal(wrapper.exception)
30
19
  end
31
20
  end
32
21
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module NexusSemanticLogger
3
- # Leave this as 1.17.0 in order for CI process to replace with the tagged version.
4
- VERSION = '1.17.0'
3
+ # Leave this as 1.34.4 in order for CI process to replace with the tagged version.
4
+ VERSION = '1.34.4'
5
5
  end
@@ -5,18 +5,12 @@ require 'nexus_semantic_logger/datadog_formatter'
5
5
  require 'nexus_semantic_logger/datadog_singleton'
6
6
  require 'nexus_semantic_logger/datadog_tracer'
7
7
  require 'nexus_semantic_logger/logger_metrics_subscriber'
8
- require 'nexus_semantic_logger/traced_shell'
9
8
 
10
9
  module NexusSemanticLogger
11
10
  # Get application wide object for sending metrics.
12
11
  def self.metrics
13
12
  DatadogSingleton.instance
14
13
  end
15
-
16
- # Get application wide object for running instrumented shell commands.
17
- def self.shell
18
- @shell ||= TracedShell.new
19
- end
20
14
  end
21
15
 
22
16
  # Patch access to LEVELS array.
@@ -14,14 +14,11 @@ Gem::Specification.new do |spec|
14
14
  end
15
15
  spec.require_paths = ['lib']
16
16
  spec.add_dependency('amazing_print', '~> 1.4.0')
17
- spec.add_dependency('datadog', '~> 2.24') # For datadog tracing/profiling.
18
- spec.add_dependency('dogstatsd-ruby', '~> 5.7') # For custom application metrics.
19
- spec.add_dependency('google-protobuf', '>= 3.25.5') # 3.25.x doesn't support ruby >= 3.4; allow 4.x too.
17
+ spec.add_dependency('datadog', '~> 2.7.0') # For datadog tracing/profiling.
18
+ spec.add_dependency('dogstatsd-ruby', '~> 5.6.1') # For custom application metrics.
19
+ spec.add_dependency('google-protobuf', '~> 3.25.5')
20
20
  spec.add_dependency('net_tcp_client', '~> 2.2.0') # For TCP logging.
21
- # Widened so bundler can resolve per app. Rails 8.1 needs rails_semantic_logger >= 5.1 (no 4.x
22
- # release supports it), and 5.x requires railties >= 7.2 plus semantic_logger >= 5.1, so apps on
23
- # Rails 7.1 still resolve 4.x and newer apps take 5.x.
24
- spec.add_dependency('rails_semantic_logger', '>= 4.17', '< 6')
25
- spec.add_dependency('semantic_logger', '>= 4.16.1', '< 6')
21
+ spec.add_dependency('rails_semantic_logger', '~> 4.17.0')
22
+ spec.add_dependency('semantic_logger', '<= 4.16.0')
26
23
  spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
27
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexus_semantic_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.0
4
+ version: 1.34.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johnathon Harris
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-29 00:00:00.000000000 Z
11
+ date: 2024-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: amazing_print
@@ -30,40 +30,40 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.24'
33
+ version: 2.7.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.24'
40
+ version: 2.7.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: dogstatsd-ruby
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '5.7'
47
+ version: 5.6.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '5.7'
54
+ version: 5.6.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: google-protobuf
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: 3.25.5
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 3.25.5
69
69
  - !ruby/object:Gem::Dependency
@@ -84,59 +84,41 @@ dependencies:
84
84
  name: rails_semantic_logger
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '4.17'
90
- - - "<"
87
+ - - "~>"
91
88
  - !ruby/object:Gem::Version
92
- version: '6'
89
+ version: 4.17.0
93
90
  type: :runtime
94
91
  prerelease: false
95
92
  version_requirements: !ruby/object:Gem::Requirement
96
93
  requirements:
97
- - - ">="
98
- - !ruby/object:Gem::Version
99
- version: '4.17'
100
- - - "<"
94
+ - - "~>"
101
95
  - !ruby/object:Gem::Version
102
- version: '6'
96
+ version: 4.17.0
103
97
  - !ruby/object:Gem::Dependency
104
98
  name: semantic_logger
105
99
  requirement: !ruby/object:Gem::Requirement
106
100
  requirements:
107
- - - ">="
101
+ - - "<="
108
102
  - !ruby/object:Gem::Version
109
- version: 4.16.1
110
- - - "<"
111
- - !ruby/object:Gem::Version
112
- version: '6'
103
+ version: 4.16.0
113
104
  type: :runtime
114
105
  prerelease: false
115
106
  version_requirements: !ruby/object:Gem::Requirement
116
107
  requirements:
117
- - - ">="
118
- - !ruby/object:Gem::Version
119
- version: 4.16.1
120
- - - "<"
108
+ - - "<="
121
109
  - !ruby/object:Gem::Version
122
- version: '6'
110
+ version: 4.16.0
123
111
  description:
124
112
  email: john.harris@nexusmods.com
125
113
  executables: []
126
114
  extensions: []
127
115
  extra_rdoc_files: []
128
116
  files:
129
- - ".github/workflows/ci.yml"
130
117
  - ".gitignore"
131
- - ".rspec"
118
+ - ".gitlab-ci.yml"
132
119
  - ".rubocop.yml"
133
- - Appraisals
134
120
  - Gemfile
135
121
  - README.md
136
- - gemfiles/rails_7_1.gemfile
137
- - gemfiles/rails_7_2.gemfile
138
- - gemfiles/rails_8_0.gemfile
139
- - gemfiles/rails_8_1.gemfile
140
122
  - lib/nexus_semantic_logger.rb
141
123
  - lib/nexus_semantic_logger/appender_filter.rb
142
124
  - lib/nexus_semantic_logger/application.rb
@@ -146,12 +128,10 @@ files:
146
128
  - lib/nexus_semantic_logger/extensions/action_dispatch/debug_exceptions.rb
147
129
  - lib/nexus_semantic_logger/logger_metrics_subscriber.rb
148
130
  - lib/nexus_semantic_logger/sneakers_metrics.rb
149
- - lib/nexus_semantic_logger/traced_shell.rb
150
131
  - lib/nexus_semantic_logger/version.rb
151
132
  - lib/puma/plugin/README.md
152
133
  - lib/puma/plugin/nexus_puma_statsd.rb
153
134
  - nexus_semantic_logger.gemspec
154
- - renovate.json
155
135
  homepage:
156
136
  licenses: []
157
137
  metadata: {}
@@ -170,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
150
  - !ruby/object:Gem::Version
171
151
  version: '0'
172
152
  requirements: []
173
- rubygems_version: 3.4.10
153
+ rubygems_version: 3.5.23
174
154
  signing_key:
175
155
  specification_version: 4
176
156
  summary: semantic_logger usage for nexus
@@ -1,52 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- tags: ["*"]
7
- pull_request:
8
-
9
- jobs:
10
- rspec:
11
- runs-on: ubuntu-latest
12
- strategy:
13
- fail-fast: false
14
- matrix:
15
- gemfile: [rails_7_1, rails_7_2, rails_8_0, rails_8_1]
16
- env:
17
- BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
18
- steps:
19
- - uses: actions/checkout@v4
20
- - uses: ruby/setup-ruby@v1
21
- with:
22
- ruby-version: "3.2.2"
23
- - run: bundle install --jobs 4
24
- - run: bundle exec rspec
25
-
26
- rubocop:
27
- runs-on: ubuntu-latest
28
- steps:
29
- - uses: actions/checkout@v4
30
- - uses: ruby/setup-ruby@v1
31
- with:
32
- ruby-version: "3.2.2"
33
- - run: bundle install --jobs 4
34
- - run: bundle exec rubocop
35
-
36
- release:
37
- needs: [rspec, rubocop]
38
- if: startsWith(github.ref, 'refs/tags/')
39
- runs-on: ubuntu-latest
40
- steps:
41
- - uses: actions/checkout@v4
42
- - uses: ruby/setup-ruby@v1
43
- with:
44
- ruby-version: "3.2.2"
45
- - run: bundle install --jobs 4
46
- - name: Build and push gem to RubyGems
47
- env:
48
- GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
49
- run: |
50
- sed -i "s/0.0.0/${GITHUB_REF_NAME}/g" lib/nexus_semantic_logger/version.rb
51
- gem build nexus_semantic_logger.gemspec
52
- gem push nexus_semantic_logger-*.gem
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --require spec_helper
2
- --format documentation
data/Appraisals DELETED
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- appraise "rails-7-1" do
4
- gem "railties", "~> 7.1.0"
5
- end
6
-
7
- appraise "rails-7-2" do
8
- gem "railties", "~> 7.2.0"
9
- end
10
-
11
- appraise "rails-8-0" do
12
- gem "railties", "~> 8.0.0"
13
- end
14
-
15
- appraise "rails-8-1" do
16
- gem "railties", "~> 8.1.0"
17
- # No 4.x release of rails_semantic_logger works on Rails 8.1, and bundler will not upgrade past
18
- # 4.x on its own when an older lockfile exists.
19
- gem "rails_semantic_logger", "~> 5.1"
20
- end
@@ -1,11 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "appraisal"
6
- gem "rubocop"
7
- gem "rubocop-shopify", "~> 1.0.4", require: false
8
- gem "rspec"
9
- gem "railties", "~> 7.1.0"
10
-
11
- gemspec path: "../"
@@ -1,11 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "appraisal"
6
- gem "rubocop"
7
- gem "rubocop-shopify", "~> 1.0.4", require: false
8
- gem "rspec"
9
- gem "railties", "~> 7.2.0"
10
-
11
- gemspec path: "../"
@@ -1,11 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "appraisal"
6
- gem "rubocop"
7
- gem "rubocop-shopify", "~> 1.0.4", require: false
8
- gem "rspec"
9
- gem "railties", "~> 8.0.0"
10
-
11
- gemspec path: "../"
@@ -1,12 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "appraisal"
6
- gem "rubocop"
7
- gem "rubocop-shopify", "~> 1.0.4", require: false
8
- gem "rspec"
9
- gem "railties", "~> 8.1.0"
10
- gem "rails_semantic_logger", "~> 5.1"
11
-
12
- gemspec path: "../"
@@ -1,163 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'open3'
3
- require 'semantic_logger'
4
-
5
- module NexusSemanticLogger
6
- # Instrumented replacement for Open3.capture3, so child processes (7z, unrar, yara, ...) are
7
- # observable. Each call produces:
8
- # - a Datadog APM span ('shell.exec', resource = binary basename) tagged with the command line,
9
- # exit status, terminating signal and peak RSS
10
- # - statsd metrics: nexus.shell.duration_ms (timing), nexus.shell.peak_rss_mb (distribution)
11
- # and nexus.shell.executions (count), tagged with command:<binary> and
12
- # outcome:<success|failure|signaled|exception>
13
- # - an info log line with the same payload
14
- #
15
- # Peak RSS is the child's kernel-maintained high-water mark (VmHWM in /proc/<pid>/status),
16
- # sampled while the child runs. Linux only; nil elsewhere. Direct child only - grandchildren
17
- # are not measured. A process killed by the kernel OOM killer reports outcome:signaled with
18
- # termsig 9 and the last-sampled peak RSS, which is exactly the evidence an OOM postmortem needs.
19
- class TracedShell
20
- include SemanticLogger::Loggable
21
-
22
- SPAN_NAME = 'shell.exec'
23
- METRIC_PREFIX = 'nexus.shell'
24
- RSS_POLL_INTERVAL_SECONDS = 0.05
25
- COMMAND_LOG_MAX_CHARS = 500
26
-
27
- # Drop-in replacement for Open3.capture3.
28
- # A leading env Hash and trailing spawn options are supported as with Open3; the env Hash is
29
- # excluded from spans/logs since it may hold secrets.
30
- # @return [Array(String, String, Process::Status)] stdout, stderr, status.
31
- def capture3(*cmd, stdin_data: '', binmode: false, **opts)
32
- binary = command_basename(cmd)
33
- started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
34
- outcome = 'exception'
35
- status = nil
36
- peak_rss_kb = nil
37
- trace(binary, cmd) do |span|
38
- stdout, stderr, status, peak_rss_kb = run_capture3(cmd, stdin_data, binmode, opts)
39
- outcome = outcome_for(status)
40
- annotate_span(span, status, peak_rss_kb)
41
- [stdout, stderr, status]
42
- end
43
- ensure
44
- duration_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at) * 1000).round
45
- record(cmd, outcome, duration_ms, status, peak_rss_kb)
46
- end
47
-
48
- private
49
-
50
- def trace(binary, cmd, &block)
51
- return yield(nil) unless defined?(Datadog::Tracing)
52
-
53
- Datadog::Tracing.trace(SPAN_NAME, resource: binary, type: 'system') do |span|
54
- span.set_tag('shell.command', command_string(cmd))
55
- block.call(span)
56
- end
57
- end
58
-
59
- # Open3.capture3 semantics, reimplemented over popen3 so the child pid is available to the
60
- # RSS poller while it runs.
61
- def run_capture3(cmd, stdin_data, binmode, opts)
62
- Open3.popen3(*cmd, **opts) do |stdin, stdout, stderr, wait_thr|
63
- if binmode
64
- stdin.binmode
65
- stdout.binmode
66
- stderr.binmode
67
- end
68
- poller = start_rss_poller(wait_thr)
69
- out_reader = Thread.new { stdout.read }
70
- err_reader = Thread.new { stderr.read }
71
- begin
72
- stdin.write(stdin_data) if stdin_data && !stdin_data.empty?
73
- rescue Errno::EPIPE
74
- # Child exited without consuming stdin; Open3.capture3 ignores this too.
75
- end
76
- stdin.close
77
- status = wait_thr.value
78
- [out_reader.value, err_reader.value, status, poller&.value]
79
- end
80
- end
81
-
82
- def start_rss_poller(wait_thr)
83
- return nil unless procfs?
84
-
85
- pid = wait_thr.pid
86
- Thread.new do
87
- peak_kb = nil
88
- while wait_thr.alive?
89
- sample = read_vm_hwm_kb(pid)
90
- peak_kb = sample if sample && (peak_kb.nil? || sample > peak_kb)
91
- sleep(RSS_POLL_INTERVAL_SECONDS)
92
- end
93
- peak_kb
94
- end
95
- end
96
-
97
- # VmHWM is the process's peak RSS as maintained by the kernel, so each sample is itself a
98
- # high-water mark; the true peak can only be missed by the process exiting within one poll.
99
- def read_vm_hwm_kb(pid)
100
- File.read("/proc/#{pid}/status")[/^VmHWM:\s*(\d+)\s*kB/, 1]&.to_i
101
- rescue SystemCallError, IOError
102
- nil
103
- end
104
-
105
- def procfs?
106
- return @procfs if defined?(@procfs)
107
-
108
- @procfs = File.exist?('/proc/self/status')
109
- end
110
-
111
- def outcome_for(status)
112
- return 'success' if status.success?
113
- return 'signaled' if status.signaled?
114
-
115
- 'failure'
116
- end
117
-
118
- def annotate_span(span, status, peak_rss_kb)
119
- return unless span
120
-
121
- span.set_tag('shell.exit_status', status.exitstatus) if status.exitstatus
122
- span.set_tag('shell.termsig', status.termsig) if status.signaled?
123
- span.set_tag('shell.peak_rss_mb', to_mb(peak_rss_kb)) if peak_rss_kb
124
- end
125
-
126
- def record(cmd, outcome, duration_ms, status, peak_rss_kb)
127
- tags = ["command:#{command_basename(cmd)}", "outcome:#{outcome}"]
128
- metrics = NexusSemanticLogger.metrics
129
- metrics.timing("#{METRIC_PREFIX}.duration_ms", duration_ms, tags: tags)
130
- metrics.increment("#{METRIC_PREFIX}.executions", tags: tags)
131
- peak_rss_mb = peak_rss_kb && to_mb(peak_rss_kb)
132
- metrics.distribution("#{METRIC_PREFIX}.peak_rss_mb", peak_rss_mb, tags: tags) if peak_rss_mb
133
-
134
- payload = {
135
- command: command_string(cmd),
136
- outcome: outcome,
137
- duration_ms: duration_ms,
138
- exit_status: status&.exitstatus,
139
- termsig: status&.signaled? ? status.termsig : nil,
140
- peak_rss_mb: peak_rss_mb,
141
- }.compact
142
- logger.info('Shell command finished.', payload)
143
- end
144
-
145
- # Binary basename for span resource and metric tags; deliberately low cardinality.
146
- def command_basename(cmd)
147
- first = cmd.first.is_a?(Hash) ? cmd[1] : cmd.first
148
- first = first.first if first.is_a?(Array) # [binary, argv0] form
149
- return 'unknown' unless first.is_a?(String)
150
-
151
- File.basename(first.split(' ').first.to_s)
152
- end
153
-
154
- def command_string(cmd)
155
- parts = cmd.reject { |part| part.is_a?(Hash) }
156
- parts.flatten.join(' ').slice(0, COMMAND_LOG_MAX_CHARS)
157
- end
158
-
159
- def to_mb(kb)
160
- kb.fdiv(1024).round(1)
161
- end
162
- end
163
- end
data/renovate.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
- "extends": [
4
- "config:recommended"
5
- ],
6
- "vulnerabilityAlerts": {
7
- "dependencyDashboardApproval": false,
8
- "labels": ["security"]
9
- },
10
- "osvVulnerabilityAlerts": true,
11
- "reviewers": ["team:platform-engineering"],
12
- "assignees": ["team:platform-engineering"],
13
- "packageRules": [
14
- {
15
- "matchManagers": ["github-actions"],
16
- "groupName": "GitHub Actions",
17
- "dependencyDashboardApproval": false
18
- }
19
- ]
20
- }