Module: Insika::Telemetry
- Defined in:
- lib/insika/telemetry.rb,
lib/insika/telemetry/pricing.rb,
lib/insika/telemetry/recorder.rb
Overview
OPT-IN observability (Phase 6): 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 (item 16 / P4) 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
-
.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).
- .enabled?(env = ENV) ⇒ Boolean
-
.load_metrics_sdk ⇒ Object
The metrics SDK is OPTIONAL: absent from the bundle -> traces only, never a boot failure.
-
.metrics? ⇒ Boolean
Did
setupwire the metric instruments too (SDK present, at least one reader)? Only meaningful aftersetup— it exists for the boot banners. -
.otel_meter ⇒ Object
-> the OTEL meter | nil.
- .present?(value) ⇒ Boolean
-
.pricing(env = ENV) ⇒ Object
Operator-declared rates (USD per million tokens) as JSON in INSIKA_MODEL_PRICING.
-
.setup(service_name: "insika", env: ENV) ⇒ Object
-> Recorder wired to the real OTEL | nil (disabled).
-
.truthy(value) ⇒ Object
One home for "is this flag on?" — EnvSchema, which is also what validates the :boolean keys in
insika env/doctor.
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
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_sdk ⇒ Object
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.
54 |
# File 'lib/insika/telemetry.rb', line 54 def metrics? = @metrics == true |
.otel_meter ⇒ Object
-> 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
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) |