Class: Alplus::Scope

Inherits:
Object
  • Object
show all
Defined in:
lib/alplus/scope.rb

Overview

Request-scoped ambient scope (issue #17): the server analog of the JS SDK's browser withScope. Alplus.set_user/set_tag/set_context/ add_breadcrumb write to a scope that lives on Thread.current (fiber-local storage in Ruby -- see Thread#[]), so a value set once at the top of a request (RackMiddleware) applies to every capture inside that request without threading it through every call site, and never bleeds into a different request handled on a reused thread-pool thread.

Constant Summary collapse

MAX_BREADCRUMBS =

Server ceiling (Envelope::SERVER_MAX_BREADCRUMBS) -- kept as a literal here rather than requiring envelope first (Scope loads before Envelope in alplus.rb), and re-asserted by Envelope.cap_breadcrumbs regardless.

100

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeScope

Returns a new instance of Scope.



43
44
45
46
47
48
# File 'lib/alplus/scope.rb', line 43

def initialize
  @user = nil
  @tags = {}
  @contexts = {}
  @breadcrumbs = []
end

Instance Attribute Details

Returns the value of attribute breadcrumbs.



41
42
43
# File 'lib/alplus/scope.rb', line 41

def breadcrumbs
  @breadcrumbs
end

#contextsObject (readonly)

Returns the value of attribute contexts.



41
42
43
# File 'lib/alplus/scope.rb', line 41

def contexts
  @contexts
end

#tagsObject (readonly)

Returns the value of attribute tags.



41
42
43
# File 'lib/alplus/scope.rb', line 41

def tags
  @tags
end

#userObject (readonly)

Returns the value of attribute user.



41
42
43
# File 'lib/alplus/scope.rb', line 41

def user
  @user
end

Class Method Details

.currentObject

The current thread/fiber's scope, lazily created.



23
24
25
# File 'lib/alplus/scope.rb', line 23

def current
  Thread.current[THREAD_KEY] ||= new
end

.with_clean_scopeObject

Replaces the current thread/fiber's scope with a fresh, empty one and yields; restores whatever scope (if any) was active before, even if the block raises. RackMiddleware wraps each request in this so scope set during request A never leaks into request B on a reused thread-pool thread.



32
33
34
35
36
37
38
# File 'lib/alplus/scope.rb', line 32

def with_clean_scope
  previous = Thread.current[THREAD_KEY]
  Thread.current[THREAD_KEY] = new
  yield
ensure
  Thread.current[THREAD_KEY] = previous
end

Instance Method Details

#add_breadcrumb(message: nil, category: nil, level: nil, data: nil, ts: nil) ⇒ Object

breadcrumb accepts the same keys as the wire shape (message/category/level/data/ts); ts defaults to now. Bounded ring buffer: the oldest breadcrumb is dropped once the buffer is at MAX_BREADCRUMBS.



66
67
68
69
70
# File 'lib/alplus/scope.rb', line 66

def add_breadcrumb(message: nil, category: nil, level: nil, data: nil, ts: nil)
  crumb = { message: message, category: category, level: level, data: data, ts: ts || Time.now.utc.iso8601 }.compact
  @breadcrumbs << crumb
  @breadcrumbs.shift while @breadcrumbs.length > MAX_BREADCRUMBS
end

#set_context(name, data) ⇒ Object



58
59
60
# File 'lib/alplus/scope.rb', line 58

def set_context(name, data)
  @contexts[name.to_s] = data
end

#set_tag(key, value) ⇒ Object



54
55
56
# File 'lib/alplus/scope.rb', line 54

def set_tag(key, value)
  @tags[key.to_s] = value.to_s
end

#set_user(user) ⇒ Object



50
51
52
# File 'lib/alplus/scope.rb', line 50

def set_user(user)
  @user = user
end

#snapshotObject

Immutable snapshot handed to Client at capture time — mirrors the JS SDK's ScopeSnapshot (scope.ts).



74
75
76
# File 'lib/alplus/scope.rb', line 74

def snapshot
  { user: @user, tags: @tags.dup, contexts: @contexts.dup, breadcrumbs: @breadcrumbs.dup }
end