tracelit 0.1.7 → 0.1.8
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/README.md +2 -11
- data/lib/tracelit/metrics.rb +98 -0
- data/lib/tracelit/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 66ee178565bf80581941df2481fb09e981e013c335ac8a2e4c6d8845a62fb4f1
|
|
4
|
+
data.tar.gz: a40528eb98fe34dd2dd3d7399cf0e5d40ea5fd0fb83900daec8ee6728d98b846
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 19b1d323be4bc9f8f1cf531f9728d371537a5430a1e0f6eb82aba66af17ee20b5bddb819e83bd1b8d5f624444ac0a6afaeb68319bbdb380469f7c8ab1ea0945e
|
|
7
|
+
data.tar.gz: d8c722105fb3b85f0cab312ec82ea81a2de12fae214f9f555bfb7ce6c3929184f231c13f228b182c9c268ab62e3ee94751295b00f939347012cfa43ed797e81a
|
data/README.md
CHANGED
|
@@ -6,12 +6,6 @@ Official Ruby SDK for [Tracelit](https://tracelit.io) — drop-in OpenTelemetry
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
## Set up with AI
|
|
10
|
-
|
|
11
|
-
Want an AI assistant (Cursor, Claude, ChatGPT, etc.) to integrate Tracelit into your app automatically? Copy the contents of [`llm_prompt.txt`](./llm_prompt.txt) and paste it as your prompt. It covers gem installation, initializer setup, manual spans, custom metrics, and test guard — everything the AI needs in one shot.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
9
|
## Installation
|
|
16
10
|
|
|
17
11
|
Add to your `Gemfile` and run `bundle install`:
|
|
@@ -273,9 +267,6 @@ TRACELIT_ENABLED=false
|
|
|
273
267
|
|
|
274
268
|
---
|
|
275
269
|
|
|
276
|
-
##
|
|
270
|
+
## Changelog
|
|
277
271
|
|
|
278
|
-
|
|
279
|
-
bundle install
|
|
280
|
-
bundle exec rspec
|
|
281
|
-
```
|
|
272
|
+
See the [release history](https://docs.tracelit.io/changelog) on the Tracelit docs.
|
data/lib/tracelit/metrics.rb
CHANGED
|
@@ -48,6 +48,7 @@ module Tracelit
|
|
|
48
48
|
install_sidekiq_middleware if defined?(::Sidekiq)
|
|
49
49
|
install_connection_pool_poller if defined?(::ActiveRecord)
|
|
50
50
|
install_memory_poller
|
|
51
|
+
install_cpu_poller
|
|
51
52
|
rescue StandardError => e
|
|
52
53
|
OpenTelemetry.logger.warn("[Tracelit] failed to set up metrics: #{e.message}")
|
|
53
54
|
end
|
|
@@ -62,8 +63,10 @@ module Tracelit
|
|
|
62
63
|
def self.restart_pollers(config)
|
|
63
64
|
@connection_pool_poller_installed = false
|
|
64
65
|
@memory_poller_installed = false
|
|
66
|
+
@cpu_poller_installed = false
|
|
65
67
|
install_connection_pool_poller if defined?(::ActiveRecord)
|
|
66
68
|
install_memory_poller
|
|
69
|
+
install_cpu_poller
|
|
67
70
|
rescue StandardError => e
|
|
68
71
|
OpenTelemetry.logger.warn("[Tracelit] failed to restart pollers after fork: #{e.message}")
|
|
69
72
|
end
|
|
@@ -349,5 +352,100 @@ module Tracelit
|
|
|
349
352
|
rescue StandardError => e
|
|
350
353
|
OpenTelemetry.logger.warn("[Tracelit] failed to install memory poller: #{e.message}")
|
|
351
354
|
end
|
|
355
|
+
|
|
356
|
+
# Polls process CPU utilisation every 30 seconds on a daemon thread.
|
|
357
|
+
# Computes a percentage by tracking the delta in CPU time (user + system)
|
|
358
|
+
# against wall-clock elapsed time — same approach as the Go and Node SDKs.
|
|
359
|
+
#
|
|
360
|
+
# On Linux: reads /proc/self/stat (utime + stime in jiffies at 100 Hz).
|
|
361
|
+
# On macOS: reads `ps -o %cpu= -p <pid>` as a direct percentage.
|
|
362
|
+
#
|
|
363
|
+
# Emits: process.runtime.cpu.usage (%)
|
|
364
|
+
# Attributes: process.pid, process.runtime
|
|
365
|
+
def self.install_cpu_poller
|
|
366
|
+
return if @cpu_poller_installed
|
|
367
|
+
@cpu_poller_installed = true
|
|
368
|
+
|
|
369
|
+
cpu_gauge = @meter.create_gauge(
|
|
370
|
+
"process.runtime.cpu.usage",
|
|
371
|
+
description: "Process CPU utilisation percentage",
|
|
372
|
+
unit: "%"
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
pid = Process.pid
|
|
376
|
+
linux = File.exist?("/proc/self/stat")
|
|
377
|
+
interval = 30 # seconds
|
|
378
|
+
|
|
379
|
+
thread = Thread.new do
|
|
380
|
+
Thread.current[:tracelit_cpu_poller] = true
|
|
381
|
+
|
|
382
|
+
last_cpu_time = read_cpu_time_s(pid, linux)
|
|
383
|
+
last_wall_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
384
|
+
|
|
385
|
+
loop do
|
|
386
|
+
sleep interval
|
|
387
|
+
begin
|
|
388
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
389
|
+
elapsed = now - last_wall_time
|
|
390
|
+
cpu_time = read_cpu_time_s(pid, linux)
|
|
391
|
+
|
|
392
|
+
next if elapsed <= 0 || cpu_time.nil? || last_cpu_time.nil?
|
|
393
|
+
|
|
394
|
+
delta = cpu_time - last_cpu_time
|
|
395
|
+
last_cpu_time = cpu_time
|
|
396
|
+
last_wall_time = now
|
|
397
|
+
|
|
398
|
+
next if delta < 0
|
|
399
|
+
|
|
400
|
+
pct = [[delta / elapsed * 100.0, 100.0].min, 0.0].max
|
|
401
|
+
|
|
402
|
+
cpu_gauge.record(pct, attributes: {
|
|
403
|
+
"process.pid" => pid.to_s,
|
|
404
|
+
"process.runtime" => "ruby",
|
|
405
|
+
})
|
|
406
|
+
rescue StandardError
|
|
407
|
+
# Retry next cycle — never crash on a metric poll failure
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
thread.abort_on_exception = false
|
|
412
|
+
thread
|
|
413
|
+
rescue StandardError => e
|
|
414
|
+
OpenTelemetry.logger.warn("[Tracelit] failed to install CPU poller: #{e.message}")
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
# Returns cumulative CPU time (user + system) for this process in seconds.
|
|
418
|
+
# On Linux reads /proc/self/stat; on macOS/BSD falls back to ps %cpu
|
|
419
|
+
# which gives an instantaneous percentage instead (treated as fractional
|
|
420
|
+
# seconds over a 1-second window — good enough for a 30 s gauge).
|
|
421
|
+
def self.read_cpu_time_s(pid, linux)
|
|
422
|
+
if linux
|
|
423
|
+
stat = begin
|
|
424
|
+
File.read("/proc/self/stat")
|
|
425
|
+
rescue
|
|
426
|
+
return nil
|
|
427
|
+
end
|
|
428
|
+
# Format: pid (comm) state ppid ... utime stime ...
|
|
429
|
+
# comm can contain spaces — find last ')' and split from there.
|
|
430
|
+
after_comm = stat[stat.rindex(")").to_i + 1..]
|
|
431
|
+
return nil unless after_comm
|
|
432
|
+
|
|
433
|
+
fields = after_comm.split
|
|
434
|
+
# After ')': state(0) ppid(1) ... utime(11) stime(12)
|
|
435
|
+
utime = fields[11]&.to_i
|
|
436
|
+
stime = fields[12]&.to_i
|
|
437
|
+
return nil unless utime && stime
|
|
438
|
+
|
|
439
|
+
# Jiffies at 100 Hz → seconds
|
|
440
|
+
(utime + stime) / 100.0
|
|
441
|
+
else
|
|
442
|
+
# macOS/BSD: `ps` gives current CPU % directly.
|
|
443
|
+
# Return it as a fractional "seconds per second" proxy so the
|
|
444
|
+
# delta calculation above yields the right percentage.
|
|
445
|
+
out = `ps -o %cpu= -p #{Integer(pid)} 2>/dev/null`.strip
|
|
446
|
+
return nil if out.empty?
|
|
447
|
+
out.to_f / 100.0
|
|
448
|
+
end
|
|
449
|
+
end
|
|
352
450
|
end
|
|
353
451
|
end
|
data/lib/tracelit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tracelit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tracelit
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: opentelemetry-sdk
|