Class: Smplkit::Audit::Events
- Inherits:
-
Object
- Object
- Smplkit::Audit::Events
- Defined in:
- lib/smplkit/audit/events.rb
Overview
Audit events surface — accessed via client.audit.events.
#record is fire-and-forget by default — the call enqueues the event
onto an in-memory bounded buffer and returns immediately. Pass
flush: true to block until the event is durable before continuing.
In stateless mode (+buffered: false+ on the client) there is no buffer:
every #record performs one blocking POST and raises on failure.
#list and #get are synchronous reads.
Instance Method Summary collapse
- #_close ⇒ Object
-
#flush(timeout: 5.0) ⇒ void
Block until the in-memory buffer is drained or the timeout elapses.
-
#get(event_id) ⇒ Smplkit::Audit::AuditEvent
Single-event retrieval.
-
#initialize(api, environment: nil, buffered: true) ⇒ Events
constructor
A new instance of Events.
-
#list(event_type: nil, resource_type: nil, resource_id: nil, actor_type: nil, actor_id: nil, category: nil, occurred_at_range: nil, search: nil, environments: nil, page_size: nil, page_after: nil) ⇒ Smplkit::Audit::ListEventsPage
List audit events for the authenticated account.
-
#record(event_type:, resource_type:, resource_id:, occurred_at: nil, actor_type: nil, actor_id: nil, actor_label: nil, category: nil, severity: nil, data: nil, idempotency_key: nil, do_not_forward: false, flush: false, flush_timeout: 5.0) ⇒ void
Record an audit event.
Constructor Details
#initialize(api, environment: nil, buffered: true) ⇒ Events
Returns a new instance of Events.
14 15 16 17 18 19 20 21 |
# File 'lib/smplkit/audit/events.rb', line 14 def initialize(api, environment: nil, buffered: true) @api = api @environment = environment # Stateless mode installs no buffer at all — no worker thread, no # background state — so a client may be constructed per request in # serverless or edge runtimes. @buffer = buffered ? EventBuffer.new(api) : nil end |
Instance Method Details
#_close ⇒ Object
257 258 259 260 |
# File 'lib/smplkit/audit/events.rb', line 257 def _close @buffer&.close nil end |
#flush(timeout: 5.0) ⇒ void
This method returns an undefined value.
Block until the in-memory buffer is drained or the timeout elapses.
Useful for draining buffered events at process shutdown or after a batch of fire-and-forget records. A no-op in stateless mode (+buffered: false+), where every record is already durable on return.
250 251 252 253 |
# File 'lib/smplkit/audit/events.rb', line 250 def flush(timeout: 5.0) @buffer&.flush(timeout: timeout) nil end |
#get(event_id) ⇒ Smplkit::Audit::AuditEvent
Single-event retrieval.
158 159 160 161 |
# File 'lib/smplkit/audit/events.rb', line 158 def get(event_id) resp = Smplkit::Audit.call_api { @api.get_event(event_id) } AuditEvent.from_resource(resp.data) end |
#list(event_type: nil, resource_type: nil, resource_id: nil, actor_type: nil, actor_id: nil, category: nil, occurred_at_range: nil, search: nil, environments: nil, page_size: nil, page_after: nil) ⇒ Smplkit::Audit::ListEventsPage
List audit events for the authenticated account.
Filters apply server-side. actor_id is matched as a literal string
against whatever the recording call stored. Pagination uses an opaque
cursor (+page_after+); the returned page exposes #next_cursor when
more pages are available.
search is an optional free-text filter: pass a string to return only
events whose resource_id or description contains it as a
case-insensitive substring; omit it (the default) to disable text
filtering. A search filter must be scoped — combine it with
occurred_at_range, or with both resource_type and resource_id —
or the request is rejected.
environments scopes the read to a set of environments: pass an array
of environment keys and/or the reserved "smplkit" control-plane
bucket; the values are sent comma-separated as filter[environment].
Omit it (the default) to scope the read to the client's configured
environment; with no configured environment the filter is left off
entirely.
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/smplkit/audit/events.rb', line 214 def list(event_type: nil, resource_type: nil, resource_id: nil, actor_type: nil, actor_id: nil, category: nil, occurred_at_range: nil, search: nil, environments: nil, page_size: nil, page_after: nil) # Generated client opts use snake_case keys that internally map # to the JSON:API ``filter[*]`` / ``page[*]`` query-string format # (see default_api.rb#list_events_with_http_info). Without the # underscores these silently fall through and the filters never # reach the server. opts = {} opts[:filter_event_type] = event_type if event_type opts[:filter_resource_type] = resource_type if resource_type opts[:filter_resource_id] = resource_id if resource_id opts[:filter_actor_type] = actor_type if actor_type opts[:filter_actor_id] = actor_id if actor_id opts[:filter_category] = category if category opts[:filter_occurred_at] = occurred_at_range if occurred_at_range opts[:filter_search] = search if search resolved_environment = Smplkit::Audit.resolve_environment_filter(environments, @environment) opts[:filter_environment] = resolved_environment if resolved_environment opts[:page_size] = page_size if page_size opts[:page_after] = page_after if page_after resp = Smplkit::Audit.call_api { @api.list_events(opts) } events = (resp.data || []).map { |r| AuditEvent.from_resource(r) } ListEventsPage.new(events, Smplkit::Audit.next_cursor(resp.links&._next)) end |
#record(event_type:, resource_type:, resource_id:, occurred_at: nil, actor_type: nil, actor_id: nil, actor_label: nil, category: nil, severity: nil, data: nil, idempotency_key: nil, do_not_forward: false, flush: false, flush_timeout: 5.0) ⇒ void
This method returns an undefined value.
Record an audit event.
In the default buffered mode this enqueues for asynchronous delivery
and returns immediately — the buffer's worker thread performs the
actual POST with retry on transient failures. When flush: true,
the call blocks until the buffer has drained or flush_timeout
elapses; use it when the caller needs the event durable before
continuing (CLI tools, in-test assertions, or any flow about to
terminate the process).
In stateless mode (+buffered: false+ on the client) every call performs one blocking POST and raises one of the SDK's typed errors on failure; +flush+/+flush_timeout+ are meaningless there and ignored.
Actor attribution (+actor_type+, actor_id, actor_label) is
customer-supplied and free-form. The audit service stores
whatever the caller passed and never backfills from the request
credential — supply the fields explicitly when you want the
event attributed.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/smplkit/audit/events.rb', line 89 def record(event_type:, resource_type:, resource_id:, occurred_at: nil, actor_type: nil, actor_id: nil, actor_label: nil, category: nil, severity: nil, data: nil, idempotency_key: nil, do_not_forward: false, flush: false, flush_timeout: 5.0) raise ArgumentError, "event_type is required" if event_type.nil? || event_type.to_s.empty? raise ArgumentError, "resource_type is required" if resource_type.nil? || resource_type.to_s.empty? raise ArgumentError, "resource_id is required" if resource_id.nil? || resource_id.to_s.empty? # Pydantic validation on the server expects an ISO-8601 string # for ``occurred_at`` — Ruby's ``Time#to_s`` (which is what the # generated client falls back to during JSON serialization) # emits ``"2026-05-07 04:43:23 UTC"`` and trips the gate. Coerce # Time/DateTime to ``.iso8601`` here so end users can pass the # native Ruby type. normalized_occurred_at = if occurred_at.respond_to?(:iso8601) occurred_at.iso8601 else occurred_at end # Server-side validation also rejects ``data: null`` (the field # is required-non-null in the OpenAPI schema). Always default to # an empty hash so users who omit ``data:`` don't trip the gate. attrs = SmplkitGeneratedClient::Audit::Event.new( event_type: event_type, resource_type: resource_type, resource_id: resource_id, occurred_at: normalized_occurred_at, actor_type: actor_type, actor_id: actor_id, actor_label: actor_label, category: category, severity: severity, data: data || {}, do_not_forward: do_not_forward ) # Stamp the client's configured environment onto the event body — the # body-driven replacement for the old +X-Smplkit-Environment+ header # (ADR-055). Left off when nil so a single-environment credential # resolves it server-side. Assigning conditionally (rather than passing # +environment: nil+ through the constructor) keeps the field out of the # serialized body entirely when unconfigured. attrs.environment = @environment unless @environment.nil? resource = SmplkitGeneratedClient::Audit::EventResource.new( id: "", type: "event", attributes: attrs ) body = SmplkitGeneratedClient::Audit::EventRequest.new(data: resource) if @buffer.nil? # Stateless path: one blocking POST per call — the same wire call # the buffer's worker performs, but failures surface to the caller # as the SDK's typed errors instead of being retried in background. opts = idempotency_key ? { idempotency_key: idempotency_key } : {} Smplkit::Audit.call_api { @api.record_event(body, opts) } return nil end @buffer.enqueue(body, idempotency_key) @buffer.flush(timeout: flush_timeout) if flush nil end |