logister-ruby 0.2.4 → 0.2.7

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: '08b202068c5d0907d8c8d08b3490dfbc34af5863df48c2e7a491a9a4c18e5307'
4
- data.tar.gz: ba465c7050af6b92e27a36ffd985b9eedbd667ab6be211dd9e1db457e501ff6d
3
+ metadata.gz: bbdcfea4a9984f610510aa30780b8d94a54059bf329c387e5b47997f805ecafb
4
+ data.tar.gz: 242e70a27ab5bcebcc11b1c99ce6f3acf7164a5a0ad5e482afd107bfa4fb705f
5
5
  SHA512:
6
- metadata.gz: 55b1680278af20b4779519debd47e7f111348e5132323d07116a02cd7a26b27dd556094e479cdb871f1db64db74dc92b09fc7d52288c982048b9b084fa751b81
7
- data.tar.gz: f05606399bc43607512dee0c332212f30f7d1d6352dd0c6ba3c6ce39f3fc91fb8fa61b107de1ae045736360dd026afe947cf3e3ef01fef49f353cc2d23e6e4bf
6
+ metadata.gz: 58f9a2d891eec80c14c18a40ced354cdd3b19c98e88b583d709943c3b2aeab73d5af208d050566cf1ef9fc023f547972180f381a4648d585c5cd841622d145d3
7
+ data.tar.gz: 8175e3a5b27a40ced8c9844acd56ff460e0c9655bd514e14feb94ee9edec02cbdb1b6021ef9deb6411a3fb837891c935d812d032707124c5f32147ed52ca3083
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.2.7 - 2026-05-22
4
+
5
+ - Added `Logister.report_span` and opt-in Rails request span capture for request load waterfall charts.
6
+
7
+ ## v0.2.6 - 2026-05-22
8
+
9
+ - Added README guidance for using Ruby reports with the Logister project Insights beta, including practical metric, transaction, log, check-in, and custom attribute examples.
10
+ - Added a tag-based release workflow that publishes the gem to RubyGems with trusted publishing and then creates or updates the matching GitHub release.
11
+
12
+ ## v0.2.5 - 2026-05-21
13
+
14
+ - Added metric value/unit options to `Logister.report_metric` while keeping the existing context/tags API.
15
+ - Added per-check-in environment, release, occurred-at, trace ID, and request ID options to `Logister.report_check_in`.
16
+
3
17
  ## v0.2.4 - 2026-05-21
4
18
 
5
19
  - Enriched every Ruby error report with shared runtime, deployment, breadcrumb, and dependency context, including manual `Logister.report_error` calls.
data/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # logister-ruby
2
2
 
3
- `logister-ruby` is the Ruby and Rails client for sending errors, logs, metrics, transactions, and check-ins to Logister.
3
+ `logister-ruby` is the Ruby and Rails client for sending errors, logs, metrics, transactions, spans, and check-ins to Logister.
4
4
 
5
5
  Install it from RubyGems as `logister-ruby`.
6
6
 
7
7
  ## Table Of Contents
8
8
 
9
9
  - [What this gem is for](#what-this-gem-is-for)
10
+ - [Package Links](#package-links)
10
11
  - [Self-hosted backend](#self-hosted-backend)
11
12
  - [Install From RubyGems](#install-from-rubygems)
12
13
  - [Configuration](#configuration)
@@ -17,6 +18,7 @@ Install it from RubyGems as `logister-ruby`.
17
18
  - [Breadcrumbs and dependencies](#breadcrumbs-and-dependencies)
18
19
  - [ActiveJob error context](#activejob-error-context)
19
20
  - [Manual reporting](#manual-reporting)
21
+ - [Using project Insights beta](#using-project-insights-beta)
20
22
  - [Documentation](#documentation)
21
23
  - [Release](#release)
22
24
 
@@ -29,6 +31,13 @@ Use this gem when you want a Ruby or Rails app to send telemetry into the Logist
29
31
  - Product docs: https://docs.logister.org/
30
32
  - RubyGems package: https://rubygems.org/gems/logister-ruby
31
33
 
34
+ ## Package Links
35
+
36
+ - RubyGems package: https://rubygems.org/gems/logister-ruby
37
+ - GitHub releases: https://github.com/taimoorq/logister-ruby/releases
38
+ - Source repository: https://github.com/taimoorq/logister-ruby
39
+ - Integration docs: https://docs.logister.org/integrations/ruby/
40
+
32
41
  ## Self-hosted backend
33
42
 
34
43
  Use the open source Logister app repository to self-host the ingestion UI/API backend:
@@ -77,6 +86,7 @@ Logister.configure do |config|
77
86
  config.max_dependencies = 20
78
87
  config.capture_sql_breadcrumbs = true
79
88
  config.sql_breadcrumb_min_duration_ms = 25.0
89
+ config.capture_request_spans = true
80
90
 
81
91
  config.feature_flags_resolver = lambda do |request:, user:, **|
82
92
  { new_checkout: user&.respond_to?(:beta?) && user.beta? }
@@ -120,6 +130,7 @@ end
120
130
 
121
131
  If Rails is present, the gem installs middleware that reports unhandled exceptions automatically.
122
132
  It also attaches richer context such as trace IDs, route/response/performance info, breadcrumbs, dependency calls, and user metadata when available.
133
+ Set `config.capture_request_spans = true` to emit root `server` spans for request load waterfall charts while keeping existing transaction events.
123
134
  Manual `Logister.report_error` calls use the same shared enrichment path, so Ruby apps get runtime, deployment, breadcrumb, dependency, user, and nested exception cause context even when an error is reported outside the Rails middleware.
124
135
 
125
136
  ## Database load metrics (ActiveRecord)
@@ -174,6 +185,8 @@ Logister.report_error(StandardError.new("Something failed"), tags: { area: "chec
174
185
 
175
186
  Logister.report_metric(
176
187
  message: "checkout.completed",
188
+ value: 1,
189
+ unit: "count",
177
190
  level: "info",
178
191
  context: { duration_ms: 123 },
179
192
  tags: { region: "us-east-1" }
@@ -186,6 +199,16 @@ Logister.report_transaction(
186
199
  context: { trace_id: "trace-123", request_id: "req-123" }
187
200
  )
188
201
 
202
+ Logister.report_span(
203
+ name: "render checkout",
204
+ duration_ms: 82.1,
205
+ trace_id: "trace-123",
206
+ parent_span_id: "span-root",
207
+ kind: "render",
208
+ status: "ok",
209
+ context: { route: "POST /checkout" }
210
+ )
211
+
189
212
  Logister.report_log(
190
213
  message: "payment provider timeout",
191
214
  level: "warn",
@@ -195,13 +218,85 @@ Logister.report_log(
195
218
  Logister.report_check_in(
196
219
  slug: "nightly-reconcile",
197
220
  status: "ok",
198
- expected_interval_seconds: 900
221
+ expected_interval_seconds: 900,
222
+ duration_ms: 248.3,
223
+ trace_id: "trace-123",
224
+ request_id: "req-123"
199
225
  )
200
226
  ```
201
227
 
228
+ ## Using project Insights beta
229
+
230
+ The Logister project Insights tab combines Inbox, Activity, and Performance signals into live dashboard views. Ruby apps get the most useful Insights experience when every event carries stable deployment context plus a few low-cardinality custom attributes.
231
+
232
+ Use `config.environment`, `config.release`, and top-level scalar `context` values for the dimensions you want to filter by:
233
+
234
+ ```ruby
235
+ Logister.configure do |config|
236
+ config.environment = Rails.env
237
+ config.release = ENV["RELEASE_SHA"]
238
+ config.service = "billing-web"
239
+ end
240
+
241
+ Logister.report_metric(
242
+ message: "queue.depth",
243
+ value: Sidekiq::Queue.new("billing").size,
244
+ unit: "jobs",
245
+ context: {
246
+ service: "billing-worker",
247
+ queue: "billing",
248
+ region: "us-east-1",
249
+ tenant_tier: "enterprise"
250
+ }
251
+ )
252
+
253
+ Logister.report_transaction(
254
+ name: "POST /checkout",
255
+ duration_ms: 184.7,
256
+ status: 200,
257
+ context: {
258
+ service: "billing-web",
259
+ route: "POST /checkout",
260
+ feature_flag: "new_checkout",
261
+ tenant_tier: "enterprise"
262
+ }
263
+ )
264
+
265
+ Logister.report_log(
266
+ message: "payment provider retry",
267
+ level: "warn",
268
+ context: {
269
+ service: "billing-worker",
270
+ provider: "stripe",
271
+ queue: "billing"
272
+ }
273
+ )
274
+
275
+ Logister.report_check_in(
276
+ slug: "nightly-reconcile",
277
+ status: "ok",
278
+ expected_interval_seconds: 3600,
279
+ duration_ms: 842.7,
280
+ context: {
281
+ service: "billing-worker",
282
+ queue: "reconcile"
283
+ }
284
+ )
285
+ ```
286
+
287
+ Practical Insights recipes:
288
+
289
+ - Release validation: send `release`, then filter the Insights tab to the new release and compare errors, transaction P95, database query timing, and custom metrics.
290
+ - Queue monitoring: report metrics such as `queue.depth`, `queue.latency`, and `jobs.retry_count` with a stable `queue` context key.
291
+ - Performance triage: send transaction events with `route`, `service`, and `tenant_tier` so slow routes can be filtered beside errors and logs.
292
+ - Instrumentation audit: open Insights after deploy and confirm errors, logs, metrics, transactions, spans, and check-ins all appear in the recent stream.
293
+
294
+ Keep dashboard dimensions stable and low-cardinality. Good custom attribute keys include `service`, `region`, `queue`, `route`, `tenant_tier`, `provider`, and `feature_flag`. Avoid raw IDs, emails, request bodies, SQL text, and per-user values as top-level Insights dimensions.
295
+
202
296
  ## Documentation
203
297
 
204
298
  - Ruby integration docs: https://docs.logister.org/integrations/ruby/
299
+ - Insights beta guide: https://docs.logister.org/product/#insights-beta
205
300
  - Main Logister docs: https://docs.logister.org/
206
301
  - [Contributing](CONTRIBUTING.md)
207
302
  - [Code of Conduct](CODE_OF_CONDUCT.md)
@@ -210,13 +305,28 @@ Logister.report_check_in(
210
305
 
211
306
  ## Release
212
307
 
213
- Use Bundler's built-in release flow:
308
+ This repo runs CI on commits and pull requests. Version tags run the release workflow so RubyGems and GitHub Releases stay aligned:
214
309
 
215
310
  ```bash
216
311
  # 1) bump version in lib/logister/version.rb
217
312
  # 2) update CHANGELOG.md
218
313
  # 3) commit changes
219
- bundle exec rake release
314
+ # 4) push a matching tag, for example:
315
+ git tag -a v0.2.7 -m "Release logister-ruby v0.2.7"
316
+ git push origin main v0.2.7
220
317
  ```
221
318
 
222
- `rake release` will build the gem, create a git tag, push commits/tags, and push to RubyGems.
319
+ The `.github/workflows/release.yml` workflow verifies the tag matches `Logister::VERSION`, runs tests, builds the gem, publishes to RubyGems with trusted publishing, and then creates or updates the matching GitHub release from `CHANGELOG.md`.
320
+
321
+ Before tag releases can publish the gem, configure a RubyGems trusted publisher for:
322
+
323
+ - GitHub owner: `taimoorq`
324
+ - Repository: `logister-ruby`
325
+ - Workflow file: `.github/workflows/release.yml`
326
+ - Environment: leave blank unless you also add a GitHub release environment to the workflow
327
+
328
+ Manual publishing is still possible with Bundler's built-in release flow when needed:
329
+
330
+ ```bash
331
+ bundle exec rake release
332
+ ```
@@ -7,7 +7,7 @@ module Logister
7
7
  :async, :queue_size, :max_retries, :retry_base_interval,
8
8
  :capture_db_metrics, :db_metric_min_duration_ms, :db_metric_sample_rate,
9
9
  :feature_flags_resolver, :dependency_resolver, :anonymize_ip,
10
- :max_breadcrumbs, :max_dependencies,
10
+ :max_breadcrumbs, :max_dependencies, :capture_request_spans,
11
11
  :capture_sql_breadcrumbs, :sql_breadcrumb_min_duration_ms
12
12
 
13
13
  def initialize
@@ -40,6 +40,7 @@ module Logister
40
40
  @anonymize_ip = false
41
41
  @max_breadcrumbs = 40
42
42
  @max_dependencies = 20
43
+ @capture_request_spans = false
43
44
  @capture_sql_breadcrumbs = true
44
45
  @sql_breadcrumb_min_duration_ms = 25.0
45
46
  end
@@ -30,6 +30,7 @@ module Logister
30
30
  copy_setting(app, config, :anonymize_ip)
31
31
  copy_setting(app, config, :max_breadcrumbs)
32
32
  copy_setting(app, config, :max_dependencies)
33
+ copy_setting(app, config, :capture_request_spans)
33
34
  copy_setting(app, config, :capture_sql_breadcrumbs)
34
35
  copy_setting(app, config, :sql_breadcrumb_min_duration_ms)
35
36
  end
@@ -3,6 +3,7 @@
3
3
  require 'digest'
4
4
  require 'time'
5
5
  require 'set'
6
+ require 'securerandom'
6
7
  require_relative 'context_helpers'
7
8
  require_relative 'context_store'
8
9
 
@@ -64,16 +65,29 @@ module Logister
64
65
  @client.publish(payload)
65
66
  end
66
67
 
67
- def report_metric(message:, level: 'info', context: {}, tags: {}, fingerprint: nil)
68
+ def report_metric(message:, value: nil, unit: nil, level: 'info', context: {}, tags: {}, fingerprint: nil)
68
69
  return false if ignored_environment?
69
70
  return false if ignored_path?(context)
70
71
 
72
+ metric_context = context.merge(tags: tags)
73
+ if value
74
+ metric_context = metric_context.merge(
75
+ metric: {
76
+ name: message,
77
+ value: value,
78
+ unit: unit
79
+ }.compact,
80
+ value: value,
81
+ unit: unit
82
+ ).compact
83
+ end
84
+
71
85
  payload = build_payload(
72
86
  event_type: 'metric',
73
87
  level: level,
74
88
  message: message,
75
89
  fingerprint: fingerprint || metric_fingerprint(message),
76
- context: context.merge(tags: tags)
90
+ context: metric_context
77
91
  )
78
92
 
79
93
  payload = apply_before_notify(payload)
@@ -105,6 +119,65 @@ module Logister
105
119
  @client.publish(payload)
106
120
  end
107
121
 
122
+ def report_span(
123
+ name:,
124
+ duration_ms:,
125
+ trace_id: nil,
126
+ request_id: nil,
127
+ span_id: nil,
128
+ parent_span_id: nil,
129
+ kind: 'internal',
130
+ status: nil,
131
+ started_at: nil,
132
+ ended_at: nil,
133
+ context: {},
134
+ tags: {},
135
+ fingerprint: nil
136
+ )
137
+ return false if ignored_environment?
138
+ return false if ignored_path?(context)
139
+
140
+ started_at ||= Time.now.utc - (duration_ms.to_f / 1000.0)
141
+ span_id ||= SecureRandom.hex(8)
142
+ trace_id ||= span_id
143
+
144
+ payload = build_payload(
145
+ event_type: 'span',
146
+ level: status.to_s == 'error' ? 'error' : 'info',
147
+ message: name,
148
+ fingerprint: fingerprint || metric_fingerprint("span:#{kind}:#{name}"),
149
+ context: context.merge(
150
+ name: name,
151
+ trace_id: trace_id,
152
+ request_id: request_id,
153
+ span_id: span_id,
154
+ parent_span_id: parent_span_id,
155
+ span_kind: kind,
156
+ kind: kind,
157
+ status: status,
158
+ duration_ms: duration_ms,
159
+ started_at: normalize_timestamp(started_at),
160
+ ended_at: ended_at && normalize_timestamp(ended_at),
161
+ tags: tags
162
+ ).compact
163
+ )
164
+
165
+ payload[:started_at] = normalize_timestamp(started_at)
166
+ payload[:ended_at] = normalize_timestamp(ended_at) if ended_at
167
+ payload[:duration_ms] = duration_ms
168
+ payload[:trace_id] = trace_id
169
+ payload[:request_id] = request_id if request_id
170
+ payload[:span_id] = span_id
171
+ payload[:parent_span_id] = parent_span_id if parent_span_id
172
+ payload[:kind] = kind
173
+ payload[:status] = status if status
174
+
175
+ payload = apply_before_notify(payload)
176
+ return false unless payload
177
+
178
+ @client.publish(payload)
179
+ end
180
+
108
181
  def report_log(message:, level: 'info', context: {}, tags: {}, fingerprint: nil)
109
182
  return false if ignored_environment?
110
183
  return false if ignored_path?(context)
@@ -123,7 +196,19 @@ module Logister
123
196
  @client.publish(payload)
124
197
  end
125
198
 
126
- def report_check_in(slug:, status: 'ok', expected_interval_seconds: 300, duration_ms: nil, context: {}, level: nil)
199
+ def report_check_in(
200
+ slug:,
201
+ status: 'ok',
202
+ expected_interval_seconds: 300,
203
+ duration_ms: nil,
204
+ context: {},
205
+ level: nil,
206
+ environment: nil,
207
+ release: nil,
208
+ occurred_at: nil,
209
+ trace_id: nil,
210
+ request_id: nil
211
+ )
127
212
  return false if ignored_environment?
128
213
 
129
214
  payload = build_payload(
@@ -135,9 +220,14 @@ module Logister
135
220
  check_in_slug: slug,
136
221
  check_in_status: status,
137
222
  expected_interval_seconds: expected_interval_seconds,
138
- duration_ms: duration_ms
223
+ duration_ms: duration_ms,
224
+ environment: environment,
225
+ release: release,
226
+ trace_id: trace_id,
227
+ request_id: request_id
139
228
  ).compact
140
229
  )
230
+ payload[:occurred_at] = normalize_timestamp(occurred_at) if occurred_at
141
231
 
142
232
  payload = apply_before_notify(payload)
143
233
  return false unless payload
@@ -222,6 +312,10 @@ module Logister
222
312
  }
223
313
  end
224
314
 
315
+ def normalize_timestamp(timestamp)
316
+ timestamp.respond_to?(:utc) ? timestamp.utc.iso8601 : timestamp.to_s
317
+ end
318
+
225
319
  def apply_before_notify(payload)
226
320
  hook = @configuration.before_notify
227
321
  return payload unless hook.respond_to?(:call)
@@ -53,10 +53,41 @@ module Logister
53
53
  viewRuntimeMs: numeric(payload[:view_runtime])
54
54
  }.compact
55
55
  )
56
+
57
+ report_request_span(payload, request_id) if capture_request_spans?
56
58
  rescue StandardError => e
57
59
  logger.warn("logister request subscriber (process_action) failed: #{e.class} #{e.message}")
58
60
  end
59
61
 
62
+ def report_request_span(payload, request_id)
63
+ duration_ms = numeric(payload[:duration])
64
+ return unless duration_ms&.positive?
65
+
66
+ route = "#{payload[:controller]}##{payload[:action]}"
67
+ started_at = Time.now.utc - (duration_ms / 1000.0)
68
+
69
+ Logister.report_span(
70
+ name: route,
71
+ kind: "server",
72
+ status: payload[:status].to_i >= 500 ? "error" : "ok",
73
+ trace_id: request_id,
74
+ request_id: request_id,
75
+ duration_ms: duration_ms,
76
+ started_at: started_at,
77
+ context: {
78
+ route: route,
79
+ request_id: request_id,
80
+ method: payload[:method],
81
+ path: payload[:path],
82
+ status: payload[:status],
83
+ timing_breakdown: {
84
+ db: numeric(payload[:db_runtime]),
85
+ render: numeric(payload[:view_runtime])
86
+ }.compact
87
+ }
88
+ )
89
+ end
90
+
60
91
  def handle_sql_breadcrumb(started, finished, payload)
61
92
  config = configuration
62
93
  return unless config&.capture_sql_breadcrumbs
@@ -94,6 +125,12 @@ module Logister
94
125
  nil
95
126
  end
96
127
 
128
+ def capture_request_spans?
129
+ configuration&.capture_request_spans
130
+ rescue StandardError
131
+ false
132
+ end
133
+
97
134
  def logger
98
135
  configuration&.logger || Logger.new($stdout)
99
136
  rescue StandardError
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Logister
4
- VERSION = '0.2.4'
4
+ VERSION = '0.2.7'
5
5
  end
data/lib/logister.rb CHANGED
@@ -35,6 +35,10 @@ module Logister
35
35
  reporter.report_transaction(**kwargs)
36
36
  end
37
37
 
38
+ def report_span(**kwargs)
39
+ reporter.report_span(**kwargs)
40
+ end
41
+
38
42
  def report_log(**kwargs)
39
43
  reporter.report_log(**kwargs)
40
44
  end
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
7
7
  spec.email = ['support@logister.org']
8
8
 
9
9
  spec.summary = 'Ruby and Rails client for sending events to Logister'
10
- spec.description = 'Ruby and Rails client for reporting errors, logs, metrics, transactions, and check-ins to the Logister backend, including self-hosted installs.'
10
+ spec.description = 'Ruby and Rails client for reporting errors, logs, metrics, transactions, spans, and check-ins to the Logister backend, including self-hosted installs.'
11
11
  spec.homepage = 'https://github.com/taimoorq/logister-ruby'
12
12
  spec.license = 'MIT'
13
13
  spec.required_ruby_version = '>= 3.1.0'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logister-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Logister
@@ -52,7 +52,7 @@ dependencies:
52
52
  - !ruby/object:Gem::Version
53
53
  version: '13.0'
54
54
  description: Ruby and Rails client for reporting errors, logs, metrics, transactions,
55
- and check-ins to the Logister backend, including self-hosted installs.
55
+ spans, and check-ins to the Logister backend, including self-hosted installs.
56
56
  email:
57
57
  - support@logister.org
58
58
  executables: []