Emit billing events when product usage data is disabled

What does this MR do and why?

Billing events are dropped on online-licensed self-managed and Dedicated instances that have opted out of product usage data, while the client still logs BillingEvents: billing event tracked.

Cause. Billing events use their own collector (DestinationConfiguration.billing_configuration, BillingAuthEmitter), but go through the shared Gitlab::Tracking::Destinations::Snowplow#event, which returns early unless EventEligibilityChecker#eligible? passes. That check is a telemetry opt-out (snowplow_enabled? || ProductUsageDataSetting.enabled?); the EE override exempts only Duo events, so secrets_read / secrets_stored are dropped. Gitlab::BillingEvents::Client#record_usage ignored the result and logged success anyway.

Fix.

  1. Snowplow#event skips the eligibility check when destination_configuration.billing?. This covers every billing caller, rather than listing billable event names next to the Duo exemption.
  2. Snowplow#event now returns whether the event was handed to the emitter (true / false instead of the counter / nil). No other caller uses the return value.
  3. record_usage logs BillingEvents: billing event tracked only when the event was emitted, and the existing BillingEvents: billing event emission skipped otherwise. The internal event is still tracked in every case.

The regular (non-billing) destination keeps dropping events when Snowplow and product usage data are disabled.

Resolves #632871 (closed)

Open item: product/privacy sign-off

The issue asks for product/privacy confirmation that billing usage may be sent when an instance has opted out of product usage data (the Duo exemption is precedent), and for the product usage data docs to be updated. Neither is in this MR yet: the docs change should follow the sign-off on the issue.

Cost and caveats

  • No extra queries: the eligibility check (two settings reads) is skipped on the billing path rather than added.
  • In development and with Snowplow Micro verification, Gitlab::Tracking.billing_tracker is a SnowplowMicro with the micro configuration (billing? == false), so the eligibility check still applies there; the client now logs emission skipped in that case instead of tracked.

How to set up and validate locally

  1. Use an online cloud licence, keep snowplow_enabled off, and disable product usage data: GITLAB_PRODUCT_USAGE_DATA_ENABLED=false (or turn off gitlab_product_usage_data_enabled).
  2. Enable billing_event_tracking (until !260610 (merged) removes it) and secrets_manager_emit_secret_read_events.
  3. In a Rails console outside development mode (or stub Gitlab::Tracking.snowplow_micro_enabled? to false):
    Gitlab::Tracking.billing_tracker.event('test', 'secrets_read') # => true (was nil before)
    Gitlab::Tracking.tracker.event('test', 'some_event')           # => false
  4. Trigger a CI secret read and check log/application_json.log for BillingEvents: billing event tracked.

Specs

  • spec/lib/gitlab/tracking/destinations/snowplow_spec.rb: with Snowplow and product usage data disabled, using the real EventEligibilityChecker, the regular destination drops the event and the billing destination emits it; #event returns true / false.
  • spec/lib/gitlab/billing_events/client_spec.rb: when the tracker does not emit, the client logs emission skipped, not tracked, and still tracks the internal event.
  • Each production change was reverted on its own and a spec fails without it.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

🤖 Generated with Claude Code

Merge request reports

Loading
Loading