Module: MetrixWire

Defined in:
lib/metrixwire.rb,
lib/metrixwire/rack.rb,
lib/metrixwire/span.rb,
lib/metrixwire/trace.rb,
lib/metrixwire/config.rb,
lib/metrixwire/context.rb,
lib/metrixwire/railtie.rb,
lib/metrixwire/version.rb,
lib/metrixwire/transport.rb,
lib/metrixwire/instrument/pg.rb,
lib/metrixwire/instrument/redis.rb,
lib/metrixwire/instrument/mysql2.rb,
lib/metrixwire/instrument/helpers.rb,
lib/metrixwire/instrument/sqlite3.rb,
lib/metrixwire/instrument/net_http.rb,
lib/metrixwire/instrument/rack_builder.rb,
lib/metrixwire/instrument/active_support.rb,
lib/metrixwire/instrument/source_location.rb

Overview

Zero-config APM SDK for Ruby. Call MetrixWire.init once (or, in Rails, just add the gem + set METRIXWIRE_KEY and it's fully automatic). Every HTTP request becomes a trace and every DB query / outbound HTTP call / cache op within it becomes a span. There is no manual span API and no middleware to wire up.

Non-blocking: traces are batched on a background thread with a short send timeout, and ALL transport errors are swallowed — instrumentation must never throw into or block the host application.

Defined Under Namespace

Modules: Context, Instrument Classes: Config, Rack, Railtie, Span, Trace, Transport

Constant Summary collapse

VERSION =
"0.2.4"

Class Method Summary collapse

Class Method Details

.capture_exception(err) ⇒ Object

Escape hatch mirroring Node/PHP: attach an exception to the active trace for frameworks the SDK can't hook automatically. NOT a manual span API.



87
88
89
90
91
92
93
# File 'lib/metrixwire.rb', line 87

def capture_exception(err)
  trace = Context.current
  trace&.capture_exception(err)
  nil
rescue StandardError
  nil
end

.capture_source?Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/metrixwire.rb', line 67

def capture_source?
  @config ? @config.capture_source : true
end

.enabled?Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/metrixwire.rb', line 63

def enabled?
  @config ? @config.enabled : false
end

.endpointObject



71
72
73
# File 'lib/metrixwire.rb', line 71

def endpoint
  @config ? @config.endpoint : nil
end

.enqueue(trace) ⇒ Object

Enqueue a finished trace for delivery. Internal — used by instrumentation.



76
77
78
# File 'lib/metrixwire.rb', line 76

def enqueue(trace)
  @transport&.enqueue(trace)
end

.exception_meta(err) ⇒ Object

Build the ExceptionMeta hash from an arbitrary error. Keeps the top ~8 backtrace frames — enough to fingerprint and guide a fix.



111
112
113
114
115
116
117
118
119
120
121
# File 'lib/metrixwire.rb', line 111

def exception_meta(err)
  return nil if err.nil?

  {
    type: err.class.name.to_s,
    message: err.respond_to?(:message) ? err.message.to_s : err.to_s,
    stack: (err.respond_to?(:backtrace) && err.backtrace ? err.backtrace.first(8).join("\n") : nil)
  }.compact
rescue StandardError
  nil
end

.flushObject

Manually flush the queue (e.g. before a short-lived process exits).



81
82
83
# File 'lib/metrixwire.rb', line 81

def flush
  @transport&.flush_sync
end

.init(opts = {}) ⇒ Object

Initialize the SDK. Args fall back to ENV: METRIXWIRE_KEY, METRIXWIRE_ENDPOINT, METRIXWIRE_ENABLED. Idempotent — a second call is a no-op. Auto-installs every instrumentation whose library is present.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/metrixwire.rb', line 36

def init(opts = {})
  return if @config # already initialised

  @config = Config.new(opts || {})
  @transport = Transport.new(@config)

  warn("[metrixwire] no apiKey provided — SDK disabled.") if @config.api_key.empty? && !opts_disabled?(opts)

  if @config.enabled
    @transport.start
    install_all
  end
  nil
rescue StandardError => e
  # init itself must never break the host app.
  begin
    warn("[metrixwire] init failed: #{e.message}")
  rescue StandardError
    nil
  end
  nil
end

.initialized?Boolean

Returns:

  • (Boolean)


59
60
61
# File 'lib/metrixwire.rb', line 59

def initialized?
  !@config.nil?
end

.iso8601(time) ⇒ Object

ISO8601 UTC with millisecond precision, e.g. "2026-07-14T10:00:00.000Z".



103
104
105
106
107
# File 'lib/metrixwire.rb', line 103

def iso8601(time)
  time.utc.strftime("%Y-%m-%dT%H:%M:%S.%LZ")
rescue StandardError
  Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.%LZ")
end

.memory_delta_mb(start_kb) ⇒ Object

Memory delta in MB since start_kb. Returns 0 when unavailable.



140
141
142
143
144
145
146
147
148
149
# File 'lib/metrixwire.rb', line 140

def memory_delta_mb(start_kb)
  return 0 if start_kb.nil?

  now = rss_kb
  return 0 if now.nil?

  ((now - start_kb) / 1024.0).round
rescue StandardError
  0
end

.monotonic_msObject

Monotonic milliseconds — safe for measuring durations (never goes back).



98
99
100
# File 'lib/metrixwire.rb', line 98

def monotonic_ms
  Process.clock_gettime(Process::CLOCK_MONOTONIC) * 1000.0
end

.rss_kbObject

Current process RSS in KB (best-effort, portable-ish). Used to compute a per-request memory delta for the memory_spike detector.



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/metrixwire.rb', line 125

def rss_kb
  # Linux: read RSS pages straight from /proc (no fork, fast).
  if File.readable?("/proc/self/statm")
    status = File.read("/proc/self/statm")
    pages = status.split[1].to_i
    return pages * (page_size / 1024)
  end
  # macOS / BSD: shell out to ps (cheap, once per request boundary).
  out = `ps -o rss= -p #{Process.pid} 2>/dev/null`.to_s.strip
  out.empty? ? nil : out.to_i
rescue StandardError
  nil
end