Class: Smplkit::Logging::LoggingClient

Inherits:
Object
  • Object
show all
Defined in:
lib/smplkit/logging/client.rb

Overview

Synchronous logging runtime namespace.

Obtained via Smplkit::Client#logging. Manages the discovery and level application for a customer’s logging frameworks via pluggable adapters. CRUD has moved to mgmt.loggers.* / mgmt.log_groups.*.

Level resolution is client-side: the server stores raw configuration and the SDK walks the chain (env override → base → group chain →dot-notation ancestry) to compute each managed logger’s effective level. See Resolution.

Change-listener contract — every call the SDK makes to adapter.apply_level(logger_id, new_level) is paired with exactly one listener notification for that logger, and every notification corresponds to exactly one adapter apply. A trigger that moves N loggers’ effective levels invokes the global listener N times (once per logger), each invocation also fires every matching key-scoped listener for that id. There are no batch / summary events and no deletion-flavored events — logger / group deletions only emit listener invocations for dependents whose computed effective level actually moved; the deleted key itself emits nothing.

Instance Method Summary collapse

Constructor Details

#initialize(parent, manage:, metrics:, logging_base_url:, app_base_url:) ⇒ LoggingClient

Returns a new instance of LoggingClient.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/smplkit/logging/client.rb', line 29

def initialize(parent, manage:, metrics:, logging_base_url:, app_base_url:)
  @parent = parent
  @manage = manage
  @metrics = metrics
  @logging_base_url = logging_base_url
  @app_base_url = app_base_url
  @adapters = []
  @installed = false
  @global_listeners = []
  @key_listeners = Hash.new { |h, k| h[k] = [] }
  @lock = Mutex.new
  # original_name → normalized_id for every adapter-discovered logger.
  # We keep originals so adapter.apply_level receives whatever the
  # framework's registry indexes by.
  @name_map = {}
  # normalized_id → resolution-cache entry.
  @loggers_cache = {}
  # group id → resolution-cache entry. Without this, any managed
  # logger with +level=null+ that inherits from a group silently
  # keeps whatever level its adapter had at startup.
  @groups_cache = {}
  # normalized_id → last-applied resolved level (string). Drives the
  # lockstep between adapter.apply_level and listener notifications:
  # we only push (and fire) when the freshly-resolved level differs
  # from what's recorded here.
  @resolved_levels = {}
end

Instance Method Details

#_closeObject



129
130
131
132
# File 'lib/smplkit/logging/client.rb', line 129

def _close
  @adapters.each(&:uninstall_hook) if @installed
  @installed = false
end

#adaptersObject



96
97
98
# File 'lib/smplkit/logging/client.rb', line 96

def adapters
  @adapters.dup
end

#delete(name) ⇒ Object



108
109
110
# File 'lib/smplkit/logging/client.rb', line 108

def delete(name)
  @manage.loggers.delete(name)
end

#get(name) ⇒ Object



100
101
102
# File 'lib/smplkit/logging/client.rb', line 100

def get(name)
  @manage.loggers.get(name)
end

#installObject Also known as: start

Install the logging integration.

Auto-loads the stdlib-logger adapter (always) and the semantic-logger adapter (when the gem is available). Customer explicit registration via register_adapter wins over auto-load.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/smplkit/logging/client.rb', line 62

def install
  return self if @installed

  auto_load_adapters if @adapters.empty?

  @adapters.each do |adapter|
    discovered = adapter.discover
    discovered.each { |(name, _explicit, effective)| observe_logger(adapter, name, effective) }
    adapter.install_hook { |name, _explicit, effective| observe_logger(adapter, name, effective) }
  end

  flush_initial_registration
  fetch_and_apply(trigger: "install", source: "manual")

  @ws_manager = @parent._ensure_ws
  @ws_manager.on("logger_changed") { |data| handle_logger_changed(data) }
  @ws_manager.on("logger_deleted") { |data| handle_logger_deleted(data) }
  @ws_manager.on("group_changed") { |data| handle_group_changed(data) }
  @ws_manager.on("group_deleted") { |data| handle_group_deleted(data) }
  @ws_manager.on("loggers_changed") { |data| handle_loggers_changed(data) }
  @installed = true
  self
end

#list(page_number: nil, page_size: nil) ⇒ Object



104
105
106
# File 'lib/smplkit/logging/client.rb', line 104

def list(page_number: nil, page_size: nil)
  @manage.loggers.list(page_number: page_number, page_size: page_size)
end

#on_change(name = nil, &block) ⇒ Object

Raises:

  • (ArgumentError)


118
119
120
121
122
123
124
125
126
127
# File 'lib/smplkit/logging/client.rb', line 118

def on_change(name = nil, &block)
  raise ArgumentError, "on_change requires a block" unless block

  if name.nil?
    @global_listeners << block
  else
    @key_listeners[Normalize.normalize_logger_name(name)] << block
  end
  block
end

#refreshObject

Re-fetch all loggers and groups and re-apply resolved levels. Fires listeners only for loggers whose effective level moved.



114
115
116
# File 'lib/smplkit/logging/client.rb', line 114

def refresh
  fetch_and_apply(trigger: "refresh", source: "manual")
end

#register_adapter(adapter) ⇒ Object



87
88
89
90
91
92
93
94
# File 'lib/smplkit/logging/client.rb', line 87

def register_adapter(adapter)
  unless adapter.is_a?(Adapters::Base)
    raise ArgumentError, "adapter must implement Smplkit::Logging::Adapters::Base"
  end

  @adapters << adapter
  self
end