pinqloq 1.1.2 → 1.2.1

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: b34593f2d1e32afe9a03124e36c7b3b824eb8155ba7a16156f113928e605cddf
4
- data.tar.gz: f0ac5ed9f372d187d8d15be83e4a8832bc1637e190c18773fbf36925bd8b9b60
3
+ metadata.gz: 914e5824e9dd8331e2c0ccb92e166d8e4f00ac14e49c19430d0106bf2eb1dd53
4
+ data.tar.gz: 7c3de9222525f8f1ee6d7faf746065711a49da6af8f57b3d2f34467427e6d957
5
5
  SHA512:
6
- metadata.gz: bcfb49cb5f6c33f5aa27c1f52e94e3d42f53efad2aee1808bb4c866fc36517e386bf12875257c2abf2e190a21d1b685e8d82d5c8fdf988b9ba8da424c089c0a6
7
- data.tar.gz: 976f6719d2d3ffddc12c54f9ac98f50676b1c948fd5dad6ccd516afd16d78d1c451f12eac8cae271b733626e1fa36cdd9cd28afc57bdb39903e0b3f1d0777e2e
6
+ metadata.gz: b81217eb46cbec0af99e1a03c0d09a4bd62c7b6122ed8c542ddb81693b4c1bba3ad3541aa11b10ab2ca27ec4a83fc475c512948602cafccc651f7b1209cec0d7
7
+ data.tar.gz: f83ff0b79f361ab163449c75ae131e4d200d2417471639e884be798a372641f746905c154fef79128b8ebdc3f73a80d52501e0b614570facb98d14f7e9f9863b
data/CHANGELOG.md CHANGED
@@ -5,6 +5,40 @@ All notable changes to the `pinqloq` gem are documented here. This gem follows
5
5
  `pinqloq` NuGet package and the `pinqloq` npm package — all three ship on separate cadences for
6
6
  the same platform, and mirror each other's feature set rather than their version numbers.
7
7
 
8
+ ## 1.2.1 — 2026-09-18
9
+
10
+ **Changed:**
11
+
12
+ - `device_identifier` is now optional.
13
+ - The request-logging middleware no longer rejects a request with HTTP 400 when no
14
+ `device_identifier` resolves. The log is sent without one.
15
+ - `enqueue` / `enqueue_many` no longer raise when an entry has no `device_identifier`.
16
+ - A blank `device_identifier` is now sent as `null` instead of an empty string. The ingest API
17
+ accepts logs without one and stores `null`.
18
+
19
+ **Changed (breaking):**
20
+
21
+ - `Pinqloq::Options#device_identifier` removed ([pinqponq/pinqloq-dashboard#57](https://github.com/pinqponq/pinqloq-dashboard/issues/57)).
22
+ With the field optional, a global fallback for it had nothing left to guarantee.
23
+ `device_identifier` is now set per entry on a manual `enqueue`, and resolved per request by
24
+ `resolve_device_identifier` then the `device-identifier` header — nothing after that. Drop
25
+ `device_identifier:` from `Pinqloq.create(...)`; it now raises `ArgumentError: unknown keyword`.
26
+ If you relied on it to guarantee a value, pass `resolve_device_identifier:` instead.
27
+ - `Pinqloq::Rack::RequestLogging` no longer takes `pinqloq_options:`. It only read that object to
28
+ reach the removed fallback, so the keyword is gone; remove
29
+ `pinqloq_options: pinqloq_client.options` from your `use` line or Rack raises
30
+ `ArgumentError: unknown keyword`.
31
+
32
+ ## 1.2.0 — 2026-09-12
33
+
34
+ **Added:**
35
+
36
+ - `Client#enqueue` / `Client#enqueue_many` — shortcuts for `Client#logger.enqueue` /
37
+ `Client#logger.enqueue_many`, so manual logging no longer needs the extra `.logger` hop.
38
+ `Client#logger` is unchanged and still useful when a method should only receive the logging
39
+ capability, not the whole client. Matches the Go SDK's `Client#Enqueue`/`Client#EnqueueMany`
40
+ shortcuts.
41
+
8
42
  ## 1.1.2 — 2026-09-08
9
43
 
10
44
  **Fixed:**
data/README.md CHANGED
@@ -47,19 +47,17 @@ credentials.
47
47
  ```ruby
48
48
  require "pinqloq"
49
49
 
50
- pinqloq = Pinqloq.create(
50
+ pinqloq_client = Pinqloq.create(
51
51
  secret_key: ENV.fetch("PINQLOQ_SECRET_KEY"),
52
- api_logs_collection_name: "myapp_api_logs",
53
- device_identifier: "myapp-instance-1"
52
+ api_logs_collection_name: "myapp_api_logs"
54
53
  )
55
54
 
56
55
  # Rack app / Rails config/application.rb / config.ru
57
56
  use Pinqloq::Rack::RequestLogging,
58
- logger: pinqloq.logger,
59
- pinqloq_options: pinqloq.options,
57
+ logger: pinqloq_client.logger,
60
58
  exclude_paths: ["/health"]
61
59
 
62
- at_exit { pinqloq.shutdown }
60
+ at_exit { pinqloq_client.shutdown }
63
61
  ```
64
62
 
65
63
  The middleware captures the HTTP method, path, and status code as searchable metadata. The
@@ -68,10 +66,10 @@ request body, response body, request headers, and response headers go to the log
68
66
 
69
67
  ## Manual Logging
70
68
 
71
- Use `pinqloq.logger` to send structured application events:
69
+ Use `pinqloq_client.enqueue` to send structured application events:
72
70
 
73
71
  ```ruby
74
- pinqloq.logger.enqueue(
72
+ pinqloq_client.enqueue(
75
73
  Pinqloq::LogEntry.new(
76
74
  event: "order.created",
77
75
  device_identifier: order.customer_id,
@@ -82,23 +80,24 @@ pinqloq.logger.enqueue(
82
80
  )
83
81
  ```
84
82
 
85
- `event` and `device_identifier` are required on every entry. Leave `device_identifier` unset on
86
- an entry to inherit the global `device_identifier` option. `enqueue` raises if an entry has no
87
- `device_identifier` and no global fallback is set — a missing required field fails loudly rather
88
- than being silently dropped.
83
+ `event` is required on every entry.
84
+
85
+ `device_identifier` is optional and has no global fallback: set it per entry, and an entry that
86
+ leaves it unset is stored without one.
87
+
88
+ `pinqloq_client.logger` still returns the same `Logger` — useful when you want to pass just the
89
+ logging capability into a function without handing it the whole client.
89
90
 
90
91
  ## Add Request Metadata
91
92
 
92
- By default the middleware reads the required `device_identifier` from the `device-identifier`
93
- request header automatically. Override how it is resolved with `resolve_device_identifier`; the
94
- override wins, and if it returns nil/blank the middleware falls back to the `device-identifier`
95
- header, then to the global `device_identifier` option. If none of these resolve a value, the
96
- middleware rejects the request with **HTTP 400** before it runs.
93
+ By default the middleware reads the optional `device_identifier` from the `device-identifier`
94
+ request header. Override how it is resolved with `resolve_device_identifier`. The override wins;
95
+ if it returns nil/blank, the middleware falls back to the `device-identifier` header. If neither
96
+ resolves a value, the log is stored without a `device_identifier`.
97
97
 
98
98
  ```ruby
99
99
  use Pinqloq::Rack::RequestLogging,
100
- logger: pinqloq.logger,
101
- pinqloq_options: pinqloq.options,
100
+ logger: pinqloq_client.logger,
102
101
  exclude_paths: ["/health"],
103
102
  resolve_device_identifier: ->(request) { request.session[:user_id] },
104
103
  resolve_app_version_name: ->(request) { request.get_header("HTTP_X_APP_VERSION") },
@@ -118,7 +117,7 @@ The request-logging middleware fills it with no configuration: the caller's `cor
118
117
  request header when present, otherwise a generated UUID.
119
118
 
120
119
  ```ruby
121
- pinqloq.logger.enqueue(
120
+ pinqloq_client.enqueue(
122
121
  Pinqloq::LogEntry.new(
123
122
  event: "order.created",
124
123
  device_identifier: order.customer_id,
@@ -142,8 +141,7 @@ redacts by **name**, exactly like the Node.js SDK:
142
141
 
143
142
  ```ruby
144
143
  use Pinqloq::Rack::RequestLogging,
145
- logger: pinqloq.logger,
146
- pinqloq_options: pinqloq.options,
144
+ logger: pinqloq_client.logger,
147
145
  redact_fields: ["ssn_last_four"],
148
146
  redact_paths: ["/payment"]
149
147
  ```
@@ -156,7 +154,7 @@ list.
156
154
  ## Security and Reliability
157
155
 
158
156
  Logs are buffered in memory and sent in batches by a single background thread. Buffered logs may
159
- be lost if the process is terminated without a graceful shutdown — call `pinqloq.shutdown` on
157
+ be lost if the process is terminated without a graceful shutdown — call `pinqloq_client.shutdown` on
160
158
  exit (`at_exit`, a `Rails.application.config.after_initialize` shutdown hook, or your process
161
159
  manager's stop signal handler).
162
160
 
@@ -16,11 +16,19 @@ module Pinqloq
16
16
  @buffer = Buffering::LogBuffer.new(options.queue_capacity)
17
17
  api_client = Http::IngestApiClient.new(options)
18
18
  @dispatcher = Buffering::LogDispatcher.new(@buffer, api_client, options)
19
- @logger = Logger.new(@buffer, @dispatcher, options)
19
+ @logger = Logger.new(@buffer, @dispatcher)
20
20
 
21
21
  @dispatcher.start
22
22
  end
23
23
 
24
+ def enqueue(entry, on_sent: nil, on_failed: nil)
25
+ @logger.enqueue(entry, on_sent: on_sent, on_failed: on_failed)
26
+ end
27
+
28
+ def enqueue_many(entries, on_sent: nil, on_failed: nil)
29
+ @logger.enqueue_many(entries, on_sent: on_sent, on_failed: on_failed)
30
+ end
31
+
24
32
  def shutdown
25
33
  @dispatcher.shutdown
26
34
  end
@@ -137,7 +137,7 @@ module Pinqloq
137
137
  app_version_name = (app_version_name && !app_version_name.empty?) ? entry.app_version_name : @options.app_version_name
138
138
 
139
139
  device_identifier = entry.device_identifier&.strip
140
- device_identifier = (device_identifier && !device_identifier.empty?) ? entry.device_identifier : (@options.device_identifier || "")
140
+ device_identifier = nil if device_identifier&.empty?
141
141
 
142
142
  {
143
143
  logLevel: entry.log_level,
@@ -2,39 +2,21 @@
2
2
 
3
3
  module Pinqloq
4
4
  class Logger
5
- DEVICE_IDENTIFIER_REQUIRED_MESSAGE =
6
- "Pinqloq: device_identifier is required. Set it on the entry, or configure the global " \
7
- "Options#device_identifier fallback."
8
-
9
- def initialize(buffer, dispatcher, options)
5
+ def initialize(buffer, dispatcher)
10
6
  @buffer = buffer
11
7
  @dispatcher = dispatcher
12
- @options = options
13
8
  end
14
9
 
15
10
  def enqueue(entry, on_sent: nil, on_failed: nil)
16
- ensure_device_identifier!(entry)
17
11
  written = @buffer.enqueue(entry, on_sent: on_sent, on_failed: on_failed)
18
12
  @dispatcher.notify_enqueued
19
13
  written
20
14
  end
21
15
 
22
16
  def enqueue_many(entries, on_sent: nil, on_failed: nil)
23
- entries.each { |entry| ensure_device_identifier!(entry) }
24
17
  written = @buffer.enqueue_many(entries, on_sent: on_sent, on_failed: on_failed)
25
18
  @dispatcher.notify_enqueued
26
19
  written
27
20
  end
28
-
29
- private
30
-
31
- def ensure_device_identifier!(entry)
32
- entry_value = entry.device_identifier&.strip
33
- global_value = @options.device_identifier&.strip
34
-
35
- return if (entry_value && !entry_value.empty?) || (global_value && !global_value.empty?)
36
-
37
- raise DEVICE_IDENTIFIER_REQUIRED_MESSAGE
38
- end
39
21
  end
40
22
  end
@@ -11,7 +11,7 @@ module Pinqloq
11
11
  DEFAULT_HTTP_TIMEOUT = 10.0
12
12
 
13
13
  attr_reader :secret_key, :api_logs_collection_name, :bulk_path, :batch_size,
14
- :flush_interval, :queue_capacity, :http_timeout, :app_version_name, :device_identifier
14
+ :flush_interval, :queue_capacity, :http_timeout, :app_version_name
15
15
 
16
16
  def initialize(
17
17
  secret_key:,
@@ -21,8 +21,7 @@ module Pinqloq
21
21
  flush_interval: DEFAULT_FLUSH_INTERVAL,
22
22
  queue_capacity: DEFAULT_QUEUE_CAPACITY,
23
23
  http_timeout: DEFAULT_HTTP_TIMEOUT,
24
- app_version_name: nil,
25
- device_identifier: nil
24
+ app_version_name: nil
26
25
  )
27
26
  raise ArgumentError, "Pinqloq: secret_key is required." if secret_key.nil? || secret_key.strip.empty?
28
27
 
@@ -34,7 +33,6 @@ module Pinqloq
34
33
  @queue_capacity = [1, queue_capacity].max
35
34
  @http_timeout = [0.001, http_timeout].max
36
35
  @app_version_name = app_version_name
37
- @device_identifier = device_identifier
38
36
  end
39
37
  end
40
38
  end
@@ -19,11 +19,6 @@ module Pinqloq
19
19
  DEVICE_IDENTIFIER_HEADER_NAME = "device-identifier"
20
20
  CORRELATION_ID_HEADER_NAME = "correlation-id"
21
21
 
22
- DEVICE_IDENTIFIER_REQUIRED_MESSAGE =
23
- "Pinqloq: the required device_identifier could not be resolved. Send the " \
24
- "'device-identifier' request header, or configure resolve_device_identifier, or set " \
25
- "Options#device_identifier."
26
-
27
22
  SERVER_ERROR_STATUS_THRESHOLD = 500
28
23
  CLIENT_ERROR_STATUS_THRESHOLD = 400
29
24
 
@@ -32,7 +27,6 @@ module Pinqloq
32
27
  def initialize(
33
28
  app,
34
29
  logger:,
35
- pinqloq_options:,
36
30
  exclude_paths: [],
37
31
  resolve_device_identifier: nil,
38
32
  resolve_app_version_name: nil,
@@ -43,7 +37,6 @@ module Pinqloq
43
37
  )
44
38
  @app = app
45
39
  @logger = logger
46
- @pinqloq_options = pinqloq_options
47
40
  @exclude_paths = exclude_paths
48
41
  @resolve_device_identifier = resolve_device_identifier
49
42
  @resolve_app_version_name = resolve_app_version_name
@@ -60,9 +53,6 @@ module Pinqloq
60
53
  return @app.call(env) if PathMatch.matches_any_prefix?(path, @exclude_paths)
61
54
 
62
55
  device_identifier = resolve_device_identifier(request)
63
- if device_identifier.nil? || device_identifier.strip.empty?
64
- return [400, { "Content-Type" => "text/plain" }, [DEVICE_IDENTIFIER_REQUIRED_MESSAGE]]
65
- end
66
56
 
67
57
  redact_plan = build_redact_plan(path)
68
58
  started_at = monotonic_now
@@ -157,7 +147,7 @@ module Pinqloq
157
147
  header = request.get_header(rack_header_key(DEVICE_IDENTIFIER_HEADER_NAME))
158
148
  return header unless header.nil? || header.strip.empty?
159
149
 
160
- @pinqloq_options.device_identifier
150
+ nil
161
151
  end
162
152
 
163
153
  def resolve_correlation_id(request)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pinqloq
4
- VERSION = "1.1.2"
4
+ VERSION = "1.2.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pinqloq
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - pinqponq
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-09 00:00:00.000000000 Z
11
+ date: 2026-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack