Module: Insika::Telemetry

Defined in:
lib/insika/telemetry.rb,
lib/insika/telemetry/pricing.rb,
lib/insika/telemetry/recorder.rb

Overview

OPT-IN observability: OTEL mounted at the edge, core untouched. Rides the Event Stream — the Recorder consumes the events and emits spans and metrics. Off (the default) -> setup returns nil and nothing is loaded or instrumented (parity, zero overhead). The OTEL gems are only REQUIRED lazily in setup (enabled), never at core load — like ruby_llm in the Executor.

Turn on: INSIKA_OTEL=1 OR the standard OTEL envs (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_TRACES_EXPORTER). The destination/protocol follows the OTEL SDK's default config (env) — SigNoz/Tempo/Jaeger/Collector. The OTEL_* keys are the OpenTelemetry SDK's own env and stay verbatim; only our opt-in toggle is renamed (INSIKA_OTEL, with the HARNESS_OTEL alias still read).

Metrics ride the same switch and the SAME standard env: the SDK registers a periodic metric reader when the OTLP metrics exporter is loadable, and OTEL_METRICS_EXPORTER=none turns metrics off while traces stay on. No Insika-specific toggle is invented for it.

Defined Under Namespace

Classes: OTelSpan, OTelTracer, Pricing, Recorder

Class Method Summary collapse

Class Method Details

.attach(event_stream:, recorder:, parent: nil) ⇒ Object

Wires the Recorder to the Event Stream: subscribes to ALL events and feeds the recorder in a long-lived fiber (sibling of serving). Call INSIDE the reactor (serving arm). No-op if recorder is nil. -> the Subscription (or nil).



59
60
61
62
63
64
65
66
# File 'lib/insika/telemetry.rb', line 59

def attach(event_stream:, recorder:, parent: nil)
  return nil if recorder.nil? # nil BEFORE touching the reactor (disabled path)

  parent ||= Async::Task.current
  sub = event_stream.subscribe
  parent.async { sub.each { |e| recorder.record(e) } }
  sub
end

.enabled?(env = ENV) ⇒ Boolean

Returns:

  • (Boolean)


27
28
29
30
31
# File 'lib/insika/telemetry.rb', line 27

def enabled?(env = ENV)
  truthy(Insika::EnvSchema.read("INSIKA_OTEL", env)) ||
    present?(env["OTEL_EXPORTER_OTLP_ENDPOINT"]) ||
    present?(env["OTEL_TRACES_EXPORTER"])
end

.load_metrics_sdkObject

The metrics SDK is OPTIONAL: absent from the bundle -> traces only, never a boot failure. Present -> SDK.configure picks it up and registers the periodic reader from the standard OTEL_METRICS_* env.



84
85
86
87
88
89
90
# File 'lib/insika/telemetry.rb', line 84

def load_metrics_sdk
  require "opentelemetry-metrics-sdk"
  require "opentelemetry-exporter-otlp-metrics"
  @metrics_sdk = true
rescue LoadError
  @metrics_sdk = false
end

.metrics?Boolean

Did setup wire the metric instruments too (SDK present, at least one reader)? Only meaningful after setup — it exists for the boot banners.

Returns:

  • (Boolean)


54
# File 'lib/insika/telemetry.rb', line 54

def metrics? = @metrics == true

.otel_meterObject

-> the OTEL meter | nil. nil whenever nothing would drain the instruments — SDK absent, or every metric reader disabled (OTEL_METRICS_EXPORTER=none). Recording into a provider with no reader would accumulate a point per attribute set forever, so "no reader" MUST mean "no meter".



96
97
98
99
100
101
102
103
# File 'lib/insika/telemetry.rb', line 96

def otel_meter
  return nil unless @metrics_sdk

  provider = OpenTelemetry.meter_provider
  return nil unless provider.respond_to?(:metric_readers) && !provider.metric_readers.empty?

  provider.meter("insika")
end

.present?(value) ⇒ Boolean

Returns:

  • (Boolean)


79
# File 'lib/insika/telemetry.rb', line 79

def present?(value) = Insika::Coercion.present?(value)

.pricing(env = ENV) ⇒ Object

Operator-declared rates (USD per million tokens) as JSON in INSIKA_MODEL_PRICING. Unset/malformed -> an empty table -> no cost is reported.



70
71
72
73
# File 'lib/insika/telemetry.rb', line 70

def pricing(env = ENV)
  table = Pricing.parse(Insika::EnvSchema.read("INSIKA_MODEL_PRICING", env))
  table.empty? ? nil : table
end

.setup(service_name: "insika", env: ENV) ⇒ Object

-> Recorder wired to the real OTEL | nil (disabled). Idempotent per process (configures the SDK once). It's the gem BOUNDARY: not covered by unit tests (like the Executor's create_chat); the Recorder's logic is tested with a fake tracer.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/insika/telemetry.rb', line 36

def setup(service_name: "insika", env: ENV)
  return nil unless enabled?(env)

  require "opentelemetry/sdk"
  require "opentelemetry/exporter/otlp"
  load_metrics_sdk
  unless @configured
    OpenTelemetry::SDK.configure { |c| c.service_name = service_name }
    @configured = true
  end
  meter = otel_meter
  @metrics = !meter.nil?
  Recorder.new(tracer: OTelTracer.new(OpenTelemetry.tracer_provider.tracer("insika")),
               meter: meter, pricing: pricing(env))
end

.truthy(value) ⇒ Object

One home for "is this flag on?" — EnvSchema, which is also what validates the :boolean keys in insika env/doctor. A local copy is how the deployment's egress flags drifted into accepting only "1".



78
# File 'lib/insika/telemetry.rb', line 78

def truthy(value) = Insika::EnvSchema.truthy?(value)