fractal-ruby 0.1.0 → 0.1.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 +8 -2
- data/README.md +2 -8
- data/VERSION +1 -1
- data/lib/fractal/analytics.rb +1 -0
- data/lib/fractal/error_reporter.rb +23 -8
- data/lib/fractal/event_builder.rb +2 -1
- data/lib/fractal/fingerprint.rb +129 -3
- data/lib/fractal/identity.rb +7 -0
- data/lib/fractal/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 615b951995ae41b5f65de476b803939adbe4f7961cbfb74386a3aaeabe3b553f
|
|
4
|
+
data.tar.gz: a1f0e0c5ea5d68348b8909ac43671dd9b1e17a0824250adf4060f914adb59920
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b2d2d7f93927d401c308962682cfc37d0b3f28f50285bce8c0689f412474197ac0776086c6cfe343042c14e4c2da0857271e4dda729aa320b9dfd0dfb8660eff
|
|
7
|
+
data.tar.gz: 275083871077a6fb4b2c9d0babd6a1849a28c1deccf6fe699feb942222f7a844bfd99ccd341d1730e65b35fe4ef06f269069870e9d1a2d5512c68c89e0427c78
|
data/CHANGELOG.md
CHANGED
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
All notable changes to the `fractal-ruby` gem. The version lives in `VERSION`;
|
|
4
4
|
`ci/check_version_sync.sh` keeps `lib/fractal/version.rb`, this file and the lockfiles in step.
|
|
5
5
|
|
|
6
|
+
## 0.1.1
|
|
7
|
+
|
|
8
|
+
- **402 wording:** a `402 free_plan_locked` from the collector (the Free plan is locked and the
|
|
9
|
+
organization is on it, #555, ADR 0016) is now logged as that, instead of "this plan has no
|
|
10
|
+
error tracking". Error reporting still stops for the rest of the process on either 402.
|
|
11
|
+
|
|
6
12
|
## 0.1.0
|
|
7
13
|
|
|
8
|
-
First version (#495, ADR 0003).
|
|
9
|
-
from the path.
|
|
14
|
+
First version (#495, ADR 0003). Published to rubygems.org on 2026-10-12 (#497); Fractal's own app
|
|
15
|
+
uses it from the path.
|
|
10
16
|
|
|
11
17
|
- **Errors**, extracted from Fractal's in-repo self-reporter (`lib/self_report/`, #426): a Railtie
|
|
12
18
|
adds an outermost Rack middleware and a `Rails.error` subscriber; events are built from an
|
data/README.md
CHANGED
|
@@ -8,7 +8,7 @@ same conformance check.
|
|
|
8
8
|
Requires Ruby 3.2+ and Rails 7.1+ (ADR 0003). The core (transport, buffers, scrubber, fingerprint,
|
|
9
9
|
`track`) is plain Ruby; the Railtie is the supported entry point for the first release.
|
|
10
10
|
|
|
11
|
-
>
|
|
11
|
+
> Published on rubygems.org as `fractal-ruby`. Fractal's own app uses it from the path:
|
|
12
12
|
> `gem "fractal-ruby", path: "sdks/ruby"`.
|
|
13
13
|
|
|
14
14
|
## Setup
|
|
@@ -81,6 +81,7 @@ Delivery is **at least once**: a request whose response is lost is retried and s
|
|
|
81
81
|
| | Default | Override |
|
|
82
82
|
| --- | --- | --- |
|
|
83
83
|
| Player | the scope's user (`Fractal.set_user`, or Warden), else `user_resolver`, else `"anonymous"` inside a request and `"system"` outside one (jobs, rake, boot) | `track(..., player_id:)`, `anonymous_player_id`, `system_player_id` |
|
|
84
|
+
| Account | the same id as the player whenever a user is known; never sent for the `anonymous` and `system` buckets. A game client that calls `set_account_id` with the same id counts as the same player in the dashboard | not separately configurable |
|
|
84
85
|
| Session | a hash of the Rack session id (the raw id is never sent); with no session (jobs, cookie-less APIs), one session per player per UTC day | `track(..., session_token:)`, `Fractal.set_session(token)`, `session_resolver` |
|
|
85
86
|
| End-user address | the request's address (`request.remote_ip`, which honours your trusted proxies) | `track(..., client_ip:)`, `send_client_ip = false` |
|
|
86
87
|
|
|
@@ -137,13 +138,6 @@ tags and skips the push with a warning; re-run it by hand (`workflow_dispatch`)
|
|
|
137
138
|
set. The key needs the "push rubygem" scope, on an account whose MFA level is "UI and gem signin":
|
|
138
139
|
at "UI and API" every push asks for an OTP that CI cannot give.
|
|
139
140
|
|
|
140
|
-
**Before the first deploy that advertises the gem.** The Settings quick start and the help article
|
|
141
|
-
(`content/help/{en,es}/sdk-integration/ruby.md`) tell customers to add `gem "fractal-ruby"`, and
|
|
142
|
-
the name is not registered on rubygems.org until the first push. Push 0.1.0 by hand from the
|
|
143
|
-
owning account (or set the secret and dispatch the workflow) before running `bin/deploy`: until
|
|
144
|
-
then the install line fails and the name is free for anyone to claim. Shipping the copy ahead of
|
|
145
|
-
the push was an owner decision (2026-10-12), not an oversight.
|
|
146
|
-
|
|
147
141
|
`spec/fractal/package_spec.rb` builds the gem the same way and checks what is inside it.
|
|
148
142
|
|
|
149
143
|
## License
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.1
|
data/lib/fractal/analytics.rb
CHANGED
|
@@ -175,6 +175,7 @@ module Fractal
|
|
|
175
175
|
"player_id" => player,
|
|
176
176
|
"session_token" => session_token.to_s.empty? ? session_for(scope, player) : session_token.to_s
|
|
177
177
|
}
|
|
178
|
+
event["account_id"] = player if @identity.account?(player)
|
|
178
179
|
ip = client_ip.to_s.empty? ? client_ip_for(scope) : client_ip.to_s
|
|
179
180
|
ip = serialisable_ip(ip) if ip
|
|
180
181
|
event["client_ip"] = ip if ip
|
|
@@ -59,8 +59,8 @@ module Fractal
|
|
|
59
59
|
log(:error, "report failed: #{e.class}")
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
# Delivers up to MAX_POSTS_PER_FLUSH batches
|
|
63
|
-
#
|
|
62
|
+
# Delivers up to MAX_POSTS_PER_FLUSH batches, one per player with the player in the context
|
|
63
|
+
# (the gem's choice: /v1/errors also takes a per-error player_id). Never raises.
|
|
64
64
|
def flush(deadline: nil)
|
|
65
65
|
reset_after_fork
|
|
66
66
|
unless enabled?
|
|
@@ -234,7 +234,7 @@ module Fractal
|
|
|
234
234
|
when 402
|
|
235
235
|
@mutex.synchronize { @disabled = true }
|
|
236
236
|
discard_buffer
|
|
237
|
-
log(:warn, "collector answered 402:
|
|
237
|
+
log(:warn, "collector answered 402: #{payment_required_reason(response.body)}. Error reporting is off for the rest of this process")
|
|
238
238
|
when 429, 500..599
|
|
239
239
|
failed(entries, requeue: true)
|
|
240
240
|
log(:warn, "collector answered #{response.code}; will retry")
|
|
@@ -244,6 +244,19 @@ module Fractal
|
|
|
244
244
|
end
|
|
245
245
|
end
|
|
246
246
|
|
|
247
|
+
# The collector answers 402 for two reasons; the handling is the same, the wording is not.
|
|
248
|
+
def payment_required_reason(body)
|
|
249
|
+
json = JSON.parse(body.to_s)
|
|
250
|
+
code = json["code"] if json.is_a?(Hash)
|
|
251
|
+
if code == "free_plan_locked"
|
|
252
|
+
"the Free plan is locked and this organization is on it (ADR 0016); choose a paid plan to send data"
|
|
253
|
+
else
|
|
254
|
+
"this plan has no error tracking"
|
|
255
|
+
end
|
|
256
|
+
rescue JSON::ParserError
|
|
257
|
+
"this plan has no error tracking"
|
|
258
|
+
end
|
|
259
|
+
|
|
247
260
|
def succeeded(entries, body)
|
|
248
261
|
@breaker.success!
|
|
249
262
|
bump(:sent_events, entries.size)
|
|
@@ -268,13 +281,15 @@ module Fractal
|
|
|
268
281
|
|
|
269
282
|
def payload(player_id, entries)
|
|
270
283
|
os = Etc.uname
|
|
284
|
+
context = {
|
|
285
|
+
player_id: player_id, session_token: "", platform: "server", app_version: @config.app_version.to_s,
|
|
286
|
+
environment: @config.environment, runtime_version: "ruby #{RUBY_VERSION}", os_name: os[:sysname],
|
|
287
|
+
os_version: os[:release], sdk_version: Fractal.sdk_version
|
|
288
|
+
}
|
|
289
|
+
context[:account_id] = player_id if Identity.new(@config).account?(player_id)
|
|
271
290
|
{
|
|
272
291
|
sent_at: Time.now.utc.iso8601(3),
|
|
273
|
-
context:
|
|
274
|
-
player_id: player_id, session_token: "", platform: "server", app_version: @config.app_version.to_s,
|
|
275
|
-
environment: @config.environment, runtime_version: "ruby #{RUBY_VERSION}", os_name: os[:sysname],
|
|
276
|
-
os_version: os[:release], sdk_version: Fractal.sdk_version
|
|
277
|
-
},
|
|
292
|
+
context: context,
|
|
278
293
|
errors: entries.map do |entry|
|
|
279
294
|
entry.event.merge("occurrence_count" => entry.count, "timestamp" => entry.first_at.iso8601(3))
|
|
280
295
|
end
|
|
@@ -68,7 +68,8 @@ module Fractal
|
|
|
68
68
|
text.scrub("?")
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
# environment
|
|
71
|
+
# environment is also a tag: the collector stores the error's own environment as a column
|
|
72
|
+
# since #485 (ADR 0017), and the tag is kept for errors ingested before that.
|
|
72
73
|
def tags(source, controller, job)
|
|
73
74
|
tags = { "environment" => @config.environment, "source" => source.to_s }
|
|
74
75
|
tags["controller_action"] = "#{controller.controller_path}##{controller.action_name}" if controller.respond_to?(:controller_path)
|
data/lib/fractal/fingerprint.rb
CHANGED
|
@@ -53,6 +53,50 @@ module Fractal
|
|
|
53
53
|
RUBY_LINE_PATTERN = /\A((?:\[(?:gem|ruby|other)\] )?\S+\.rb):\d+(:in )/
|
|
54
54
|
RUBY_ERB_LINE_PATTERN = /\A((?:\[(?:gem|ruby|other)\] )?\S+\.erb):\d+:in .*\z/
|
|
55
55
|
|
|
56
|
+
# minidump-stackwalk (rust-minidump) human report: "Thread 3 {name} (crashed) - tid: 7" (an
|
|
57
|
+
# unnamed thread leaves a double space), then frames
|
|
58
|
+
# " 0 module!function [file.cc : 58 + 0x3]", " 0 module!function + 0x2c" or " 0 module + 0x429e".
|
|
59
|
+
# A Rails backend never reports one; the extractor is here so this port matches every shared
|
|
60
|
+
# vector. Behaviour for Ruby traces is unchanged, so it needs no gem release of its own.
|
|
61
|
+
STACKWALK_CRASHED_THREAD_PATTERN = /\AThread \d+ .*\(crashed\) - tid:/
|
|
62
|
+
STACKWALK_FRAME_INDEX_PATTERN = /\A\d+\s+/
|
|
63
|
+
STACKWALK_SOURCE_LINE_PATTERN = / : \d+(?: \+ 0x[0-9a-fA-F]+)?\]\z/
|
|
64
|
+
STACKWALK_FUNC_OFFSET_PATTERN = /\A(\S+!.+?) \+ 0x[0-9a-fA-F]+\z/
|
|
65
|
+
|
|
66
|
+
# A Rails backend never reports a C# trace either; the extractor is here for the same reason
|
|
67
|
+
# as the stackwalk one: this port must match every shared vector (the Unity SDK, ADR 0023 §9).
|
|
68
|
+
# Behaviour for Ruby traces is unchanged, so it needs no gem release of its own.
|
|
69
|
+
# C# frames come in three shapes (ADR 0023 §9). A shape is STRONG when it ends in a tail that no
|
|
70
|
+
# other format prints, and only a strong frame makes csharp_frame claim a trace:
|
|
71
|
+
# Mono "at Game.Player.TakeDamage (System.Int32 amount) [0x0001a] in /proj/Player.cs:42"
|
|
72
|
+
# (IL2CPP: "[0x00000] in <000...>:0"): the " in <path>:N" tail.
|
|
73
|
+
# CoreCLR "at Game.Player.TakeDamage(Int32 amount) in /src/Player.cs:line 42": the
|
|
74
|
+
# " in <path>:line N" tail.
|
|
75
|
+
# Unity "Game.Player.TakeDamage (System.Int32 amount) (at Assets/Player.cs:42)": the
|
|
76
|
+
# "(at <path>:N)" tail. Also strong, with no tail: "UnityEngine.Debug:LogError (object)",
|
|
77
|
+
# a "Type:Method" frame of the engine itself, which starts every Debug.Log trace.
|
|
78
|
+
# The same shapes without their tail are WEAK, because other formats print them too: a JVM frame
|
|
79
|
+
# reads "at pkg.Type.method(SourceFile)", and "word:word (text)" is also a message line or a gin
|
|
80
|
+
# "path.go:42 (0x14a2b3c)" line. A weak line is a frame only inside a trace that a strong frame claims.
|
|
81
|
+
# Explicit character classes only (no \s, \w, \d), so Go's RE2 and Onigmo cannot disagree.
|
|
82
|
+
CSHARP_MONO_FRAME_PATTERN = /\Aat (?:\(wrapper [a-z-]+\) )?([^ ()]+) ?\(([^()]*)\) (?:(?:\[0x[0-9a-fA-F]+\]|<0x[0-9a-fA-F]+(?: \+ 0x[0-9a-fA-F]+)?>) )?in .+:[0-9]+\z/
|
|
83
|
+
CSHARP_CORECLR_FRAME_PATTERN = /\Aat ([^ ():]*[.][^ ():]+)\(([^():]*)\)( in .+:line [0-9]+)?\z/
|
|
84
|
+
CSHARP_UNITY_FRAME_PATTERN = /\A(?:\(wrapper [a-z-]+\) )?([^ ():]+(?::[^ ():]+)?) ?\(([^()]*)\)( \(at .+:[0-9]+\))?\z/
|
|
85
|
+
|
|
86
|
+
# A tail-less "Type:Method (args)" frame under one of these is a strong marker.
|
|
87
|
+
CSHARP_UNITY_ENGINE_COLON_PREFIXES = %w[UnityEngine. UnityEditor.].freeze
|
|
88
|
+
|
|
89
|
+
# What the JVM prints between the parentheses of a frame that has no line number, and the endings
|
|
90
|
+
# of its bare source file name ("(Foo.java)").
|
|
91
|
+
CSHARP_JVM_LOCATIONS = [ "SourceFile", "Native Method", "Unknown Source" ].freeze
|
|
92
|
+
CSHARP_JVM_SOURCE_SUFFIXES = %w[.java .kt .kts .scala .groovy].freeze
|
|
93
|
+
|
|
94
|
+
# Engine, runtime and library namespaces, plus the SDK's own ("Fractal." and its facade class
|
|
95
|
+
# "FractalSDK."). The trailing "." keeps a game namespace such as "UnityChan." in-app.
|
|
96
|
+
CSHARP_NOT_IN_APP_PREFIXES = %w[
|
|
97
|
+
UnityEngine. UnityEditor. Unity. System. Mono. TMPro. Microsoft. Cysharp. Fractal. FractalSDK.
|
|
98
|
+
].freeze
|
|
99
|
+
|
|
56
100
|
module_function
|
|
57
101
|
|
|
58
102
|
# generate_fingerprint is the SHA256 fingerprint used to group errors,
|
|
@@ -126,9 +170,12 @@ module Fractal
|
|
|
126
170
|
def normalize_top_frame(stack_trace)
|
|
127
171
|
return "" if stack_trace.nil? || stack_trace.empty?
|
|
128
172
|
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
|
|
173
|
+
# stackwalk_frame sits first: a native crash report lists loaded modules and their paths, which
|
|
174
|
+
# no other detector should get a chance to misread. ruby_frame and csharp_frame precede
|
|
175
|
+
# js_frame: js_stack_trace? fires on any " at ", which a Ruby 3.3+ eval frame
|
|
176
|
+
# ("(eval at app/x.rb:3):1:in 'm'") contains and every Mono and .NET frame starts with.
|
|
177
|
+
# Keep in sync with frameExtractors in Go.
|
|
178
|
+
%i[stackwalk_frame godot_frame ruby_frame csharp_frame js_frame go_frame lua_frame].each do |extractor|
|
|
132
179
|
frame, matched = send(extractor, stack_trace)
|
|
133
180
|
return frame if matched
|
|
134
181
|
end
|
|
@@ -153,6 +200,27 @@ module Fractal
|
|
|
153
200
|
""
|
|
154
201
|
end
|
|
155
202
|
|
|
203
|
+
# Frame 0 of the crashed thread in a minidump-stackwalk report, without its frame index, source
|
|
204
|
+
# line or a symbolicated function's "+ 0x" offset. An unsymbolicated "module + 0x..." keeps its
|
|
205
|
+
# offset: it is all that identifies the frame.
|
|
206
|
+
def stackwalk_frame(stack_trace)
|
|
207
|
+
in_crashed = false
|
|
208
|
+
stack_trace.split("\n").each do |line|
|
|
209
|
+
trimmed = line.strip
|
|
210
|
+
unless in_crashed
|
|
211
|
+
in_crashed = STACKWALK_CRASHED_THREAD_PATTERN.match?(trimmed)
|
|
212
|
+
next
|
|
213
|
+
end
|
|
214
|
+
next unless STACKWALK_FRAME_INDEX_PATTERN.match?(trimmed)
|
|
215
|
+
|
|
216
|
+
frame = trimmed.sub(STACKWALK_FRAME_INDEX_PATTERN, "")
|
|
217
|
+
frame = frame.sub(STACKWALK_SOURCE_LINE_PATTERN, "]")
|
|
218
|
+
frame = frame.sub(STACKWALK_FUNC_OFFSET_PATTERN, '\\1')
|
|
219
|
+
return [ frame, true ]
|
|
220
|
+
end
|
|
221
|
+
[ "", false ]
|
|
222
|
+
end
|
|
223
|
+
|
|
156
224
|
def godot_stack_trace?(stack_trace)
|
|
157
225
|
stack_trace.include?("GDScript backtrace") || stack_trace.include?("res://")
|
|
158
226
|
end
|
|
@@ -280,6 +348,64 @@ module Fractal
|
|
|
280
348
|
[ first, true ]
|
|
281
349
|
end
|
|
282
350
|
|
|
351
|
+
# Unity log, Mono and .NET (CoreCLR) traces. Claims a trace only when one line is a strong C#
|
|
352
|
+
# frame; then the first frame, strong or weak, outside CSHARP_NOT_IN_APP_PREFIXES, else the first
|
|
353
|
+
# frame, as "Type.Method(args)". A claimed trace with no in-app frame still matches, so it never
|
|
354
|
+
# reaches js_frame, which would keep the IL offset, the path and the line number. One pass over
|
|
355
|
+
# the lines, so the cost is linear in the size of the trace.
|
|
356
|
+
def csharp_frame(stack_trace)
|
|
357
|
+
first = nil
|
|
358
|
+
first_in_app = nil
|
|
359
|
+
claimed = false
|
|
360
|
+
stack_trace.split("\n").each do |line|
|
|
361
|
+
frame, strong = csharp_parse_frame(line.strip)
|
|
362
|
+
next if frame.nil?
|
|
363
|
+
|
|
364
|
+
claimed ||= strong
|
|
365
|
+
first ||= frame
|
|
366
|
+
first_in_app ||= frame if CSHARP_NOT_IN_APP_PREFIXES.none? { |prefix| frame.start_with?(prefix) }
|
|
367
|
+
return [ first_in_app, true ] if claimed && first_in_app
|
|
368
|
+
end
|
|
369
|
+
claimed ? [ first, true ] : [ "", false ]
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# One trimmed line as [normalized C# frame, strong], or nil when it is not a frame (a message
|
|
373
|
+
# line, "Rethrow as X: msg", "--- End of stack trace ... ---", a frame of another language).
|
|
374
|
+
# strong says whether the line alone proves a C# trace.
|
|
375
|
+
def csharp_parse_frame(line)
|
|
376
|
+
if (m = CSHARP_MONO_FRAME_PATTERN.match(line))
|
|
377
|
+
[ csharp_normalize_frame(m[1], m[2]), true ]
|
|
378
|
+
elsif (m = CSHARP_CORECLR_FRAME_PATTERN.match(line))
|
|
379
|
+
# With no tail the parentheses can hold a JVM location in place of an argument list. Such a
|
|
380
|
+
# line is a Java frame even inside a trace that Mono frames claim (Unity on Android).
|
|
381
|
+
return nil if m[3].nil? && csharp_jvm_location?(m[2])
|
|
382
|
+
|
|
383
|
+
[ csharp_normalize_frame(m[1], m[2]), !m[3].nil? ]
|
|
384
|
+
elsif (m = CSHARP_UNITY_FRAME_PATTERN.match(line))
|
|
385
|
+
# Without the "(at path:N)" tail only the "Type:Method" colon marks a Unity frame.
|
|
386
|
+
return nil if m[3].nil? && !m[1].include?(":")
|
|
387
|
+
|
|
388
|
+
strong = !m[3].nil? || CSHARP_UNITY_ENGINE_COLON_PREFIXES.any? { |prefix| m[1].start_with?(prefix) }
|
|
389
|
+
[ csharp_normalize_frame(m[1], m[2]), strong ]
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# "SourceFile" (R8 / ProGuard), "Native Method", "Unknown Source", or a bare source file name.
|
|
394
|
+
def csharp_jvm_location?(args)
|
|
395
|
+
return true if CSHARP_JVM_LOCATIONS.include?(args)
|
|
396
|
+
return false if args.include?(" ") || args.include?(",")
|
|
397
|
+
|
|
398
|
+
CSHARP_JVM_SOURCE_SUFFIXES.any? { |suffix| args.end_with?(suffix) }
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# "Type.Method(args)": Unity's "Type:Method" becomes "Type.Method", no space before "(", one
|
|
402
|
+
# space after each comma, single spaces inside an argument. The argument list stays: it tells
|
|
403
|
+
# overloads apart. split(",", -1) keeps a trailing empty argument, as Go's strings.Split does.
|
|
404
|
+
def csharp_normalize_frame(name, args)
|
|
405
|
+
parts = args.split(",", -1).map { |part| part.split(/ +/).reject(&:empty?).join(" ") }
|
|
406
|
+
"#{name.gsub(":", ".")}(#{parts.join(", ")})"
|
|
407
|
+
end
|
|
408
|
+
|
|
283
409
|
def strip_line_col(line)
|
|
284
410
|
line.sub(LINE_COL_PATTERN) { $1 }
|
|
285
411
|
end
|
data/lib/fractal/identity.rb
CHANGED
|
@@ -17,6 +17,13 @@ module Fractal
|
|
|
17
17
|
resolve(controller) || bucket(scope: scope, controller: controller)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
# A server has no install, so a known user is sent as the account id as well as the player id,
|
|
21
|
+
# and a backend and a game client that use the same id count as one player (ADR 0004 §7). The
|
|
22
|
+
# two buckets are not accounts: nobody is signed in.
|
|
23
|
+
def account?(player_id)
|
|
24
|
+
!player_id.empty? && player_id != @config.anonymous_player_id && player_id != @config.system_player_id
|
|
25
|
+
end
|
|
26
|
+
|
|
20
27
|
# Who the work belongs to when no user is known: anonymous inside a request, system outside.
|
|
21
28
|
def bucket(scope:, controller: nil)
|
|
22
29
|
controller || scope.request? ? @config.anonymous_player_id : @config.system_player_id
|
data/lib/fractal/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fractal-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Fractal
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
12
|
description: Reports a Rails app's exceptions to Fractal's /v1/errors and sends server-side
|
|
13
13
|
analytics events to /v1/batch, from a background thread that never slows a request.
|
|
@@ -57,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
57
57
|
- !ruby/object:Gem::Version
|
|
58
58
|
version: '0'
|
|
59
59
|
requirements: []
|
|
60
|
-
rubygems_version: 3.6.
|
|
60
|
+
rubygems_version: 3.6.9
|
|
61
61
|
specification_version: 4
|
|
62
62
|
summary: Error tracking and analytics for Ruby on Rails backends, reporting to Fractal.
|
|
63
63
|
test_files: []
|