ask-opentelemetry 0.1.1 → 0.1.3

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: d507a221f80f69247296fbd1d633b2e1e505771cbbc30f2eead059408bf276db
4
- data.tar.gz: f666f00ebed72dbeadacda333aa95f17e9af5ffa2370d568d6255947764db6aa
3
+ metadata.gz: 353c1cc499049b3465c9df2f6d0d97e728dbb393a7feb824e95219ebd4839e19
4
+ data.tar.gz: ebdd2a7ac236e8cb7a11c020674ff13515d7d517f70338ac329fe6ea2a39d760
5
5
  SHA512:
6
- metadata.gz: f3088109bac83c159ecfd88cc0c1a8eaa8bf2225aafd61e55db4f0d25ec59333603d4ad547acdd770d94d567d5198c7b7e3e74e0be63bcb36ccb46622176fb9f
7
- data.tar.gz: '080c03b38ecd18b6890d72fd0778715d7aa389b5f19dcd8e185273826890389776df4d9ab2203174e55ca7f3c2313eb30fab6f5c3463d873313d5b735e001cce'
6
+ metadata.gz: 3f5c948e46acbad10230f443ee5807e33b8bc833a1dd40d853e994ea58f943e1a4e2d0db7235e1fb3b87afb360670741e5697584346ff2ffd74ddce86781f190
7
+ data.tar.gz: 8153b315f9fcab444a8e56f8ae0d74b669a661f9a75d7c35f37860e3a4b03276db86efd187847ba7b70f312274a34945c48c839a3264628c583341e75323ba63
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## [0.1.3] - 2026-08-06
2
+
3
+ ### Fixed
4
+ - `llm.duration_ms` was microsecond values labeled as milliseconds
5
+ (`(event.duration * 1000)` — event.duration is already in ms; a 0.2s call
6
+ showed 203052). Now `event.duration.round(2)` — real milliseconds.
7
+
8
+ ## [0.1.2] - 2026-08-06
9
+
10
+ ### Fixed
11
+ - `llm.input_tokens`/`llm.output_tokens` span attributes read from the nested
12
+ `usage` payload hash (ask-agent enriches it after the call returns; the
13
+ instrumenter shallow-copies the top-level payload). Top-level keys still
14
+ work for other emitters. `llm.duration_ms` now reflects the real LLM call
15
+ duration thanks to the ask-agent event fix.
16
+
1
17
  ## [0.1.1] - 2026-06-25
2
18
 
3
19
  ### Changed
data/README.md CHANGED
@@ -5,10 +5,10 @@
5
5
 
6
6
  OpenTelemetry tracing for the ask-rb ecosystem. Subscribes to
7
7
  `ask-instrumentation` events and creates OpenTelemetry spans for chat
8
- completions, tool calls, embeddings, and image generation.
9
-
10
- Works with any OpenTelemetry-compatible backend: Langfuse, Datadog, Honeycomb,
11
- Jaeger, Arize Phoenix, and more.
8
+ completions, tool calls, embeddings, and image generation. Backend-agnostic:
9
+ the exporter is configured with the standard OpenTelemetry SDK, so spans go
10
+ to any OpenTelemetry-compatible backend (Langfuse, Datadog, Honeycomb, Jaeger,
11
+ Arize Phoenix, and more).
12
12
 
13
13
  ## Installation
14
14
 
@@ -22,66 +22,37 @@ gem "ask-instrumentation"
22
22
  ```ruby
23
23
  require "ask/open_telemetry"
24
24
 
25
- # Subscribe to all ask events and create OpenTelemetry spans
26
25
  Ask::OpenTelemetry.install
27
26
  ```
28
27
 
29
- ### In Rails
28
+ That's it. Every `Ask::Instrumentation` event is now wrapped in a span. The
29
+ call is idempotent; subsequent calls are no-ops.
30
30
 
31
- The Railtie auto-installs no manual setup required:
32
-
33
- ```ruby
34
- # Gemfile
35
- gem "ask-opentelemetry"
36
- gem "ask-instrumentation"
37
- ```
38
-
39
- That's it. Spans are created automatically for every LLM operation.
31
+ In a Rails app, the Railtie calls `Ask::OpenTelemetry.install` automatically:
32
+ no manual setup required.
40
33
 
41
34
  ## Spans Created
42
35
 
43
- | Event | Span Name | Key Attributes |
44
- |---|---|---|
45
- | `chat.ask` | `llm.chat` | provider, model, input_tokens, output_tokens, duration_ms |
46
- | `chat.stream.ask` | `llm.chat` | provider, model, input_tokens, output_tokens, duration_ms |
47
- | `tool.ask` | `llm.tool` | provider, tool, tool_args |
48
- | `embedding.ask` | `llm.embedding` | provider, model, input_tokens |
49
- | `image.ask` | `llm.image` | provider, model, image.size, duration_ms |
50
-
51
- ### Standard Attributes
52
-
53
- All spans include:
36
+ | Event | Span |
37
+ |---|---|
38
+ | `chat.ask`, `chat.stream.ask` | `llm.chat` |
39
+ | `tool.ask` | `llm.tool` |
40
+ | `embedding.ask` | `llm.embedding` |
41
+ | `image.ask` | `llm.image` |
54
42
 
55
- - `llm.provider` The LLM provider (e.g., `openai`, `anthropic`)
56
- - `llm.model` — The model identifier (e.g., `gpt-4`, `claude-3`)
57
- - `llm.duration_ms` The duration of the LLM operation in milliseconds
58
- - `llm.input_tokens` Input token count (when available)
59
- - `llm.output_tokens` — Output token count (when available)
43
+ Span attributes use the `llm.*` namespace: `llm.provider`, `llm.model`,
44
+ `llm.input_tokens`, `llm.output_tokens`, `llm.duration_ms`, `llm.tool`,
45
+ `llm.tool_args`, and `llm.image.size` when present. Any context set via
46
+ `Ask::Instrumentation.with_metadata` is forwarded as `llm.metadata.*`
47
+ attributes.
60
48
 
61
- ### Metadata Attributes
49
+ ## Configuration
62
50
 
63
- Any context set via `Ask::Instrumentation.with_metadata` is forwarded as
64
- `llm.metadata.*` attributes:
51
+ `Ask::OpenTelemetry.install` is the entire public API; there is no exporter
52
+ configuration on the gem itself. Configure the exporter once with the standard
53
+ OpenTelemetry SDK before calling `install`:
65
54
 
66
55
  ```ruby
67
- Ask::Instrumentation.with_metadata(user_id: 42, session_id: "abc") do
68
- # The resulting span has:
69
- # llm.metadata.user_id = 42
70
- # llm.metadata.session_id = "abc"
71
- end
72
- ```
73
-
74
- ## Backend Examples
75
-
76
- ### Langfuse
77
-
78
- [Langfuse](https://langfuse.com) provides LLM observability (cost tracking,
79
- evaluations, prompt management) via OpenTelemetry.
80
-
81
- **Using Langfuse Cloud:**
82
-
83
- ```ruby
84
- require "ask/open_telemetry"
85
56
  require "opentelemetry-sdk"
86
57
  require "opentelemetry-exporter-otlp"
87
58
 
@@ -89,12 +60,7 @@ OpenTelemetry::SDK.configure do |c|
89
60
  c.service_name = "my-app"
90
61
  c.add_span_processor(
91
62
  OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
92
- OpenTelemetry::Exporter::OTLP::Exporter.new(
93
- endpoint: "https://cloud.langfuse.com/api/public/otel/v1/traces",
94
- headers: {
95
- "Authorization" => "Basic #{Base64.strict_encode64("#{LANGFUSE_PUBLIC_KEY}:#{LANGFUSE_SECRET_KEY}")}"
96
- }
97
- )
63
+ OpenTelemetry::Exporter::OTLP::Exporter.new(endpoint: "https://otlp.example.com")
98
64
  )
99
65
  )
100
66
  end
@@ -102,87 +68,17 @@ end
102
68
  Ask::OpenTelemetry.install
103
69
  ```
104
70
 
105
- **Using Langfuse Self-Hosted:**
71
+ ## Full documentation
106
72
 
107
- ```ruby
108
- OpenTelemetry::SDK.configure do |c|
109
- c.service_name = "my-app"
110
- c.add_span_processor(
111
- OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
112
- OpenTelemetry::Exporter::OTLP::Exporter.new(
113
- endpoint: "https://your-instance.langfuse.com/api/public/otel/v1/traces",
114
- headers: {
115
- "Authorization" => "Basic #{Base64.strict_encode64("#{LANGFUSE_PUBLIC_KEY}:#{LANGFUSE_SECRET_KEY}")}"
116
- }
117
- )
118
- )
119
- )
120
- end
121
- ```
122
-
123
- ### Datadog
124
-
125
- ```ruby
126
- require "ask/open_telemetry"
127
- require "opentelemetry-sdk"
128
- require "opentelemetry-exporter-otlp"
129
-
130
- OpenTelemetry::SDK.configure do |c|
131
- c.service_name = "my-app"
132
- c.add_span_processor(
133
- OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
134
- OpenTelemetry::Exporter::OTLP::Exporter.new(
135
- endpoint: "https://otlp.datadoghq.com",
136
- headers: { "DD-API-KEY" => ENV["DD_API_KEY"] }
137
- )
138
- )
139
- )
140
- end
141
-
142
- Ask::OpenTelemetry.install
143
- ```
144
-
145
- ### Honeycomb
146
-
147
- ```ruby
148
- require "ask/open_telemetry"
149
- require "opentelemetry-sdk"
150
- require "opentelemetry-exporter-otlp"
151
-
152
- OpenTelemetry::SDK.configure do |c|
153
- c.service_name = "my-app"
154
- c.add_span_processor(
155
- OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
156
- OpenTelemetry::Exporter::OTLP::Exporter.new(
157
- endpoint: "https://api.honeycomb.io:443",
158
- headers: { "x-honeycomb-team" => ENV["HONEYCOMB_API_KEY"] }
159
- )
160
- )
161
- )
162
- end
163
-
164
- Ask::OpenTelemetry.install
165
- ```
166
-
167
- ## API
168
-
169
- ### `.install`
170
-
171
- Subscribe to all `.ask` events and start creating spans. Idempotent — calling
172
- multiple times only subscribes once.
173
-
174
- ```ruby
175
- Ask::OpenTelemetry.install
176
- ```
73
+ The full ask-rb documentation lives at https://ask-rb.github.io/ask-docs.
74
+ https://ask-rb.github.io/ask-docs/production/opentelemetry covers
75
+ ask-opentelemetry in depth, including per-backend setup examples. API
76
+ reference: https://ask-rb.github.io/ask-docs/reference/api.
177
77
 
178
78
  ## Development
179
79
 
180
- ```bash
181
- git clone https://github.com/ask-rb/ask-opentelemetry.git
182
- cd ask-opentelemetry
183
80
  bundle install
184
81
  bundle exec rake test
185
- ```
186
82
 
187
83
  ## License
188
84
 
@@ -29,7 +29,10 @@ module Ask
29
29
  return unless span_name
30
30
 
31
31
  tracer.in_span(span_name, attributes: attributes_for(event)) do |span|
32
- span.set_attribute("llm.duration_ms", (event.duration * 1000).round(2))
32
+ # event.duration is already MILLISECONDS — multiplying by 1000
33
+ # produced microsecond values labeled as ms (a 0.2s call showed
34
+ # llm_duration_ms=203052).
35
+ span.set_attribute("llm.duration_ms", event.duration.round(2))
33
36
  end
34
37
  end
35
38
 
@@ -44,9 +47,12 @@ module Ask
44
47
  attrs["llm.provider"] = payload[:provider] if payload[:provider]
45
48
  attrs["llm.model"] = payload[:model] if payload[:model]
46
49
 
47
- # Token tracking (when available)
48
- attrs["llm.input_tokens"] = payload[:input_tokens] if payload[:input_tokens]
49
- attrs["llm.output_tokens"] = payload[:output_tokens] if payload[:output_tokens]
50
+ # Token tracking (when available). Chat events emitted by ask-agent
51
+ # enrich a shared nested +usage+ hash after the call returns (tokens
52
+ # are only known then); other emitters pass them at the top level.
53
+ usage = payload[:usage] || payload
54
+ attrs["llm.input_tokens"] = usage[:input_tokens] if usage[:input_tokens]
55
+ attrs["llm.output_tokens"] = usage[:output_tokens] if usage[:output_tokens]
50
56
 
51
57
  # Tool-specific
52
58
  attrs["llm.tool"] = payload[:tool_name] if payload[:tool_name]
@@ -1,5 +1,5 @@
1
1
  module Ask
2
2
  module OpenTelemetry
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.3"
4
4
  end
5
5
  end
@@ -2,6 +2,11 @@ require "ask/instrumentation"
2
2
  require "opentelemetry-api"
3
3
  require_relative "open_telemetry/version"
4
4
 
5
+ # Rails discovers gem railties only when they are required, so load the
6
+ # railtie from the entry file once Rails itself is on the stack (the
7
+ # documented pattern: "require my_gem/railtie if defined?(Rails::Railtie)").
8
+ require_relative "open_telemetry/railtie" if defined?(Rails::Railtie)
9
+
5
10
  module Ask
6
11
  # OpenTelemetry tracing for the ask-rb ecosystem.
7
12
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ask-opentelemetry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaka Ruto