Skip to content

Releases: dezsirazvan/ez_logs_agent

v0.2.1 — bulk capture polish

05 Jun 20:15

Choose a tag to compare

Polish pass on 0.2.0's bulk-database capture, plus hot-path perf work across all capturers.

Fixed

  • Bulk-op row counts on Postgres. The PG adapter does not populate payload[:row_count] for plain DELETE/UPDATE notifications, so 0.2.0 shipped row_count: 0 for the cases that matter most. BulkDatabaseCapturer now prepends a tiny shim onto ActiveRecord::Relation#delete_all / #update_all that stashes the returned row count and back-fills it onto the just-pushed event via Buffer.peek_last. No wire-shape change.
  • Model resolution in Rails dev mode. ActiveRecord::Base.descendants only sees eager-loaded models. The resolver now falls through to safe_constantize of the classified table name and verifies the reconstructed class actually owns that table, so bulk ops on lazy-autoloaded models in dev / test no longer silently drop.
  • Rails Query Log Tags noise in where_template. The parser strips /*application='X',action='Y'*/ comments before extracting the WHERE clause, so the humanized filter line reads cleanly instead of leaking instrumentation tags.

Changed

  • Framework-rewrite filter narrowed. The 0.2.0 filter that swallowed Rails-generated SET col = NULL writes was too aggressive — it also hid deliberate "null this column out" operations the customer wrote. The filter now only drops COALESCE-shaped counter bumps and empty-SET shells; honest SET col = NULL writes are captured.
  • Hot-path performance. capture_jobs, capture_database, the excluded-tables / excluded-job-classes / display-name maps, and the user-extended sensitive-key patterns are now memoized at install time across ActiveJobCapturer, DatabaseCapturer, BulkDatabaseCapturer, and SensitivePatterns. The sql.active_record subscriber uses a 5-arity block (no splat allocation) and an end_with? name-prefilter ahead of any parsing. Bulk capture overhead measured below the noise floor on a 10 ms reference query.

\xf0\x9f\x92\x8e Install: `gem "ez_logs_agent", "~> 0.2.1"`

v0.2.0

05 Jun 17:26

Choose a tag to compare

[0.2.0] — 2026-06-05

Added

  • Bulk database operations are now captured. Adds a fourth event
    source_typebulk_database — for the four ActiveRecord operations
    that bypass per-row callbacks: delete_all, update_all, insert_all,
    upsert_all. Implemented via a narrowly-filtered
    ActiveSupport::Notifications.subscribe("sql.active_record") subscription
    (Capturers::BulkDatabaseCapturer) — not a replacement for the existing
    callback-based DatabaseCapturer; the two run side by side under the
    same capture_database config flag.

    The new wire shape carries model_class, operation, row_count,
    where_template + sanitized where_binds, plus an operation-specific
    field (set for update_all, columns for insert_all/upsert_all).
    Insert/upsert ship column NAMES only — no values, per the product
    decision that bulk-row PII shouldn't ride the wire.

    Cascade case (dependent: :delete_all on a parent destroy) is
    captured automatically, since it produces the same SQL shape — the
    reader sees the parent destroy AND the cascade as sibling rows on the
    timeline.

    Resource attribution uses a resource_id: "bulk:<row_count>" sentinel,
    since individual row IDs are not knowable from the SQL without
    changing the customer's operation (which would violate the read-only
    principle).

Changed

  • Sanitizer::SENSITIVE_PATTERNS and the previous in-class
    DatabaseCapturer::SENSITIVE_PATTERNS (which had drifted) are now a
    single source of truth: EzLogsAgent::SensitivePatterns::PATTERNS.
    Both capturers + the new BulkDatabaseCapturer consult the same list.
    The merged list is the UNION of the previous two — no patterns
    removed; passwd, pwd, cvv, cvc, pem, cipher, nonce,
    salt, digest, signature, hmac all continue to be masked.
  • encrypts :foo introspection (Rails 7+ model.class.encrypted_attributes)
    is now exposed as the standalone EzLogsAgent::EncryptedAttributes
    module, so both the per-row and bulk capturers consult it via the
    same path. Behavior unchanged for per-row.

Limits (documented)

  • Raw connection.execute(sql) calls are not captured (no
    notifications fire under sql.active_record with a recognizable
    shape). Use the typed bulk methods to get visibility.
  • Specific row IDs affected by a bulk op are not captured — only the
    filter rule (WHERE columns + values) and row count. For per-row
    detail, use find_each(&:destroy) style which fires per-row
    callbacks.

v0.1.10

05 Jun 17:25

Choose a tag to compare

[0.1.10] — 2026-06-05

Fixed

  • Sanitizer no longer collapses ActiveJob keyword-argument hashes
    (those tagged with _aj_ruby2_keywords) to "[Object]" at the
    depth-3 cap. ActionMailer puts kwargs at two wrapper layers — an
    outer {"args" => [kwargs_hash], "_aj_ruby2_keywords" => ["args"]}
    payload and the kwargs hash itself, also marked. Each layer is
    framework noise; the depth budget now skips them so real kwargs
    survive the wire (e.g. CompanyMailer.deleted(admin_email:, ...)
    now ships admin_email/company_name/deleted_at instead of a
    single "[Object]").

The carve-out is narrow: only hashes that actually carry the
_aj_ruby2_keywords marker are exempt. Customer-data hashes
without the marker still hit the depth cap unchanged, and
sensitive-key filtering (passwords, tokens, …) still runs on the
real kwargs entries — the wrapper is free to descend into, but
nothing inside it is exempt from masking. No wire-format change.

v0.1.9

05 Jun 07:31

Choose a tag to compare

Fixed

  • Sanitizer no longer collapses ActiveJob record references ({"_aj_globalid" => "gid://app/Model/id"}) to "[Object]" at the depth-3 cap. These one-key wrapper hashes pass through verbatim so the server can display which record a job ran on (e.g. ActionMailer's Record 1 field now reads User #42 instead of [Object]).

The carve-out is narrow: only the exact {"_aj_globalid" => "gid://..."} shape is exempt. Multi-key hashes, non-GID values, and any other nested structure still hit the existing graph-protection rules (depth cap, array truncation, non-primitive collapse) unchanged. No wire-format change.

v0.1.8

05 Jun 07:31

Choose a tag to compare

Changed

  • Install template (rails generate ez_logs_agent:install) now pre-fills config.server_url with the real SaaS endpoint (https://app.ezlogs.io) and config.project_token with ENV["EZLOGS_API_KEY"], uncommented. Self-hosters override via ENV["EZLOGS_SERVER_URL"]. New customers only need to set one env var (the API key); they no longer have to know to uncomment the URL line or guess the right value.
  • Documentation (QUICKSTART.md, CONFIGURATION.md, FAQ.md) uses the real product URLs (app.ezlogs.io, ezlogs.io/pricing) instead of your-ezlogs-server.com placeholders.

No wire-format or runtime-behavior changes. Existing customers' already-generated initializer files are untouched — the generator doesn't rewrite them. Only fresh installs see the new defaults.

v0.1.7

28 May 16:30

Choose a tag to compare

Changed

  • Gem homepage now points at the product site (https://ezlogs.io/)
    instead of the GitHub mirror, so the RubyGems "Homepage" link sends
    installers to the product. source_code_uri still points at the
    mirror. Metadata-only release; no code or wire change.

v0.1.6

28 May 16:18

Choose a tag to compare

Added

  • Optional actor.principal sub-field ({ id:, label? }) on the wire,
    carrying the human a kind: "agent" or kind: "hybrid" actor is
    acting on behalf of. Drops silently if malformed; existing callers
    unaffected. Lets the server narrate agent actions as
    "Claude updated employee, on behalf of Razvan" instead of
    attributing the change to either party alone.

Internal

  • Dropped a stray gemspec bump to sidekiq ~> 8.1 that landed via an
    auto-merged dependabot PR without re-resolving Gemfile.lock. Dev
    deps are back in sync with the lockfile (rails ~> 7.0,
    sqlite3 ~> 1.6, sidekiq ~> 7.0); no runtime change for customers.

v0.1.5

17 May 11:58

Choose a tag to compare

Security

  • DatabaseCapturer no longer captures columns the host app declared
    encrypts :foo on. Rails 7+ decrypts attributes in memory before
    saved_changes fires, so without this guard the plaintext of every
    encrypted column was landing on the wire and in the EZLogs UI on
    every create / update. The new policy is declarative: at capture
    time we read record.class.encrypted_attributes (Rails 7+) and drop
    every name in that set, regardless of column name. If the host app
    encrypted it, we never capture it. Upgrade is strongly recommended
    for any deployment whose models use encrypts. Customers running
    0.1.4 or earlier should also scrub historical events for the
    affected column names — the data leaked in the past will stay in
    the event store until masked.
  • SENSITIVE_PATTERNS (the secondary name-based denylist) now also
    matches private_key, public_key, signing_key, pem, cipher,
    nonce, salt, digest, signature, hmac. Belt-and-suspenders
    for columns that carry sensitive material but weren't declared
    encrypts (legacy code, manual hashing, externally-generated
    material).

v0.1.4

16 May 23:32

Choose a tag to compare

Fixed

  • ActiveJobCapturer#sidekiq_adapter? no longer triggers Rails to
    autoload ActiveJob::QueueAdapters::SidekiqAdapter. Rails registers
    that constant for lazy autoload even when sidekiq isn't in the host's
    bundle; the old is_a? check forced the adapter file to load, which
    requires sidekiq and raised Gem::LoadError: sidekiq is not part of the bundle on every job run for hosts using SolidQueue, GoodJob, or
    any other non-Sidekiq adapter. The check now compares the adapter
    class name string and never references the constant.

v0.1.3

16 May 23:01

Choose a tag to compare

Fixed

  • Include lib/tasks/ez_logs_agent.rake in the published gem. 0.1.2's
    gemspec used lib/**/*.{rb,tt} which didn't match .rake files; the
    railtie's rake_tasks do; load 'tasks/...'; end then raised
    LoadError on boot, breaking assets:precompile in any host app's
    Docker build. 0.1.2 yanked.

Note

  • 0.1.0, 0.1.1, 0.1.2 are all yanked. Use 0.1.3 or later.