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 +4 -4
- data/CHANGELOG.md +34 -0
- data/README.md +21 -23
- data/lib/pinqloq/client.rb +9 -1
- data/lib/pinqloq/http/ingest_api_client.rb +1 -1
- data/lib/pinqloq/logger.rb +1 -19
- data/lib/pinqloq/options.rb +2 -4
- data/lib/pinqloq/rack/request_logging.rb +1 -11
- data/lib/pinqloq/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 914e5824e9dd8331e2c0ccb92e166d8e4f00ac14e49c19430d0106bf2eb1dd53
|
|
4
|
+
data.tar.gz: 7c3de9222525f8f1ee6d7faf746065711a49da6af8f57b3d2f34467427e6d957
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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:
|
|
59
|
-
pinqloq_options: pinqloq.options,
|
|
57
|
+
logger: pinqloq_client.logger,
|
|
60
58
|
exclude_paths: ["/health"]
|
|
61
59
|
|
|
62
|
-
at_exit {
|
|
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 `
|
|
69
|
+
Use `pinqloq_client.enqueue` to send structured application events:
|
|
72
70
|
|
|
73
71
|
```ruby
|
|
74
|
-
|
|
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`
|
|
86
|
-
|
|
87
|
-
`device_identifier` and no global fallback
|
|
88
|
-
|
|
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
|
|
93
|
-
request header
|
|
94
|
-
|
|
95
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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 `
|
|
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
|
|
data/lib/pinqloq/client.rb
CHANGED
|
@@ -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
|
|
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 =
|
|
140
|
+
device_identifier = nil if device_identifier&.empty?
|
|
141
141
|
|
|
142
142
|
{
|
|
143
143
|
logLevel: entry.log_level,
|
data/lib/pinqloq/logger.rb
CHANGED
|
@@ -2,39 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
module Pinqloq
|
|
4
4
|
class Logger
|
|
5
|
-
|
|
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
|
data/lib/pinqloq/options.rb
CHANGED
|
@@ -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
|
|
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
|
-
|
|
150
|
+
nil
|
|
161
151
|
end
|
|
162
152
|
|
|
163
153
|
def resolve_correlation_id(request)
|
data/lib/pinqloq/version.rb
CHANGED
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
|
|
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-
|
|
11
|
+
date: 2026-09-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|