Class: Smplkit::Logging::LoggingClient
- Inherits:
-
Object
- Object
- Smplkit::Logging::LoggingClient
- Defined in:
- lib/smplkit/logging/client.rb
Overview
The Smpl Logging client (sync).
One client exposes the full surface, reachable as client.logging (Smplkit::Client) or constructed directly:
logging = Smplkit::LoggingClient.new(environment: "production", service: "my-svc")
logging.loggers.new("sqlalchemy.engine").save
logging.install
The management surface (loggers / log_groups sub-clients) works immediately. register_adapter is a pre-install configuration call. The live surface (install / on_change / refresh) requires install first; calling on_change / refresh earlier raises NotInstalledError.
Instance Attribute Summary collapse
-
#log_groups ⇒ Object
readonly
Returns the value of attribute log_groups.
-
#loggers ⇒ Object
readonly
Returns the value of attribute loggers.
Class Method Summary collapse
-
.open(**kwargs) ⇒ Object
Construct, yield to the block, and close on exit.
Instance Method Summary collapse
- #adapters ⇒ Object
-
#close ⇒ Object
(also: #_close)
Release resources — only those this client owns.
-
#initialize(api_key = nil, environment: nil, base_url: nil, profile: nil, base_domain: nil, scheme: nil, debug: nil, extra_headers: nil, parent: nil, transport: nil, metrics: nil) ⇒ LoggingClient
constructor
A new instance of LoggingClient.
-
#install ⇒ Object
Hook smplkit into the application’s logging machinery.
-
#on_change(name = nil, &block) ⇒ Object
Register a change listener.
-
#refresh ⇒ Object
Re-fetch all loggers and groups and fire listener events for any deltas.
-
#register_adapter(adapter) ⇒ Object
Register a logging adapter.
Constructor Details
#initialize(api_key = nil, environment: nil, base_url: nil, profile: nil, base_domain: nil, scheme: nil, debug: nil, extra_headers: nil, parent: nil, transport: nil, metrics: nil) ⇒ LoggingClient
Returns a new instance of LoggingClient.
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/smplkit/logging/client.rb', line 339 def initialize(api_key = nil, environment: nil, base_url: nil, profile: nil, base_domain: nil, scheme: nil, debug: nil, extra_headers: nil, parent: nil, transport: nil, metrics: nil) @parent = parent @metrics = metrics @environment = parent.nil? ? environment : parent._environment @service = parent&._service @standalone_api_key = nil if transport.nil? @logging_http, _app_http, @app_base_url, @standalone_api_key = Logging.logging_transport( api_key: api_key, base_url: base_url, profile: profile, base_domain: base_domain, scheme: scheme, debug: debug, extra_headers: extra_headers ) else @logging_http = transport @app_base_url = nil end # Discovery buffer is owned by this client; the loggers sub-client shares # it so discovery and explicit registration drain together. @buffer = LoggerRegistrationBuffer.new @loggers = LoggersClient.new(@logging_http, buffer: @buffer) @log_groups = LogGroupsClient.new(@logging_http) # Live-surface state. @connected = false @name_map = {} # original_name → normalized_id @loggers_cache = {} # id → logger data @groups_cache = {} # id → group data @global_listeners = [] @key_listeners = Hash.new { |h, k| h[k] = [] } @adapters = [] @explicit_adapters = false @ws_manager = nil @owns_ws = false @lock = Mutex.new end |
Instance Attribute Details
#log_groups ⇒ Object (readonly)
Returns the value of attribute log_groups.
337 338 339 |
# File 'lib/smplkit/logging/client.rb', line 337 def log_groups @log_groups end |
#loggers ⇒ Object (readonly)
Returns the value of attribute loggers.
337 338 339 |
# File 'lib/smplkit/logging/client.rb', line 337 def loggers @loggers end |
Class Method Details
.open(**kwargs) ⇒ Object
Construct, yield to the block, and close on exit.
516 517 518 519 520 521 522 523 |
# File 'lib/smplkit/logging/client.rb', line 516 def self.open(**kwargs) client = new(**kwargs) begin yield client ensure client.close end end |
Instance Method Details
#adapters ⇒ Object
395 396 397 |
# File 'lib/smplkit/logging/client.rb', line 395 def adapters @adapters.dup end |
#close ⇒ Object Also known as: _close
Release resources — only those this client owns.
Uninstalls the adapter hooks, unsubscribes from the WebSocket, and tears down the owned WebSocket (standalone install). A wired client borrows the parent’s transport and WebSocket and closes neither.
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 |
# File 'lib/smplkit/logging/client.rb', line 496 def close Smplkit.debug("lifecycle", "LoggingClient.close() called") @adapters.each do |adapter| adapter.uninstall_hook rescue StandardError => e Smplkit.debug("logging", "adapter #{adapter.name} uninstall_hook failed: #{e.class}: #{e.}") end if @ws_manager ws_handlers.each { |event, handler| @ws_manager.off(event, handler) } if @owns_ws @ws_manager.stop @owns_ws = false end @ws_manager = nil end @connected = false end |
#install ⇒ Object
Hook smplkit into the application’s logging machinery.
Loads adapters, scans existing loggers, applies levels from the smplkit server, and wires WebSocket handlers for live updates. This IS the explicit consent gate — on_change / refresh require it first.
Idempotent — safe to call multiple times.
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
# File 'lib/smplkit/logging/client.rb', line 408 def install Smplkit.debug("lifecycle", "LoggingClient.install() called") @parent&._ensure_started return self if @connected # 0. Load adapters @adapters = Logging.auto_load_adapters if @adapters.empty? # 1. Discover existing loggers from all adapters (keep discovery and hook # installation as two passes — discover every adapter before any hook is # live, mirroring the Python SDK). # rubocop:disable Style/CombinableLoops @adapters.each do |adapter| existing = adapter.discover existing.each do |name, explicit_level, effective_level| @name_map[name] = Normalize.normalize_logger_name(name) @loggers.register(loggersource_for(name, explicit_level, effective_level)) end rescue StandardError => e Smplkit.debug("logging", "adapter #{adapter.name} discover failed: #{e.class}: #{e.}") end # 2. Install continuous discovery hooks @adapters.each do |adapter| adapter.install_hook { |name, explicit, effective| on_new_logger(name, explicit, effective) } rescue StandardError => e Smplkit.debug("logging", "adapter #{adapter.name} install_hook failed: #{e.class}: #{e.}") end # rubocop:enable Style/CombinableLoops # 3. Flush initial batch begin @loggers.flush rescue StandardError => e Smplkit.debug("registration", "bulk logger registration failed: #{e.class}: #{e.}") end # 4-6. Fetch, resolve, apply begin fetch_and_apply(trigger: "install()") rescue StandardError => e Smplkit.debug("resolution", "failed to fetch/apply logging levels during connect " \ "(logging: #{@logging_http&.config&.host}): #{e.class}: #{e.}") end # 7. Register WebSocket event handlers for real-time level updates @ws_manager = ensure_ws ws_handlers.each { |event, handler| @ws_manager.on(event, &handler) } @connected = true self end |
#on_change(name = nil, &block) ⇒ Object
Register a change listener.
client.logging.on_change { |event| ... } # global
client.logging.on_change("sqlalchemy.engine") { |e| ... } # key-scoped
Requires install first; raises NotInstalledError otherwise.
470 471 472 473 474 475 476 477 478 479 480 |
# File 'lib/smplkit/logging/client.rb', line 470 def on_change(name = nil, &block) require_installed raise ArgumentError, "on_change requires a block" unless block if name.nil? @global_listeners << block else @key_listeners[name] << block end block end |
#refresh ⇒ Object
Re-fetch all loggers and groups and fire listener events for any deltas.
Requires install first; raises NotInstalledError otherwise.
485 486 487 488 489 |
# File 'lib/smplkit/logging/client.rb', line 485 def refresh require_installed Smplkit.debug("resolution", "refresh() called, triggering full resolution pass") fetch_and_apply_deltas(trigger: "refresh()", source: "manual") end |
#register_adapter(adapter) ⇒ Object
Register a logging adapter. Must be called before install().
If called at least once, auto-loading is disabled — only explicitly registered adapters are used. This is a pre-install configuration call: it is intentionally NOT gated by install.
384 385 386 387 388 389 390 391 392 393 |
# File 'lib/smplkit/logging/client.rb', line 384 def register_adapter(adapter) raise "Cannot register adapters after install()" if @connected unless adapter.is_a?(Adapters::Base) raise ArgumentError, "adapter must implement Smplkit::Logging::Adapters::Base" end @explicit_adapters = true @adapters << adapter self end |