Skip to content

ECA plugins

native_observability_eca_bridge exposes the two events from Events to ECA (Event-Condition-Action) as selectable triggers, so a site builder can react to them from the ECA model UI without writing PHP.

The plugin and its deriver

A single ECA event plugin, NativeObservabilityEvent, is decorated with ECA's own attribute:

namespace Drupal\native_observability_eca_bridge\Plugin\ECA\Event;

#[EcaEvent(
  id: 'native_observability',
  label: new TranslatableMarkup('Native Observability'),
  category: new TranslatableMarkup('Native Observability'),
  description: new TranslatableMarkup('Events dispatched by the Native Observability module when traces are recorded or deleted.'),
  deriver: NativeObservabilityEventDeriver::class,
  version_introduced: '1.0.0',
)]
class NativeObservabilityEvent extends EventBase {
  public static function definitions(): array;
  protected function buildEventData(): array;
}

NativeObservabilityEventDeriver (class NativeObservabilityEventDeriver extends EventDeriverBase) inflates the array returned by NativeObservabilityEvent::definitions() into individual ECA plugin IDs. ECA requires that each Symfony event name map to exactly one ECA plugin definition, which is why threshold-based filtering (for example, only slow requests) is expressed as an ECA condition on a token, not as a separate event variant.

definitions() itself comes from Drupal\native_observability_eca_bridge\Eca\NativeObservabilityEventDefinitions::definitions(), a plain class with no ECA base-class dependency, kept separate so the event definition contract can be unit-tested without the optional ECA runtime installed. It returns two derivatives:

Derivative ID Plugin ID as selected in ECA Symfony event Event class
trace_recorded native_observability:trace_recorded NativeObservabilityEvents::TRACE_RECORDED TraceRecordedEvent
traces_deleted native_observability:traces_deleted NativeObservabilityEvents::TRACES_DELETED TracesDeletedEvent

Tokens available in an ECA model

buildEventData() exposes the event payload as [event:*] tokens. For trace_recorded:

Token Source
[event:route] $trace['route_name']
[event:method] $trace['method'], upper case
[event:status_code] $trace['status_code']
[event:duration_ms] $trace['duration_ms']
[event:is_ajax] "1" or "0"

For traces_deleted:

Token Source
[event:deleted_count] $event->getDeletedCount()

[event:machine_name] is always available and identifies which derivative fired. All values are cast to string, since ECA's token replacement layer expects scalars.

Route exclusion needs no extra handling in this plugin: when capture.exclude_own_routes is enabled, TraceSubscriber returns before calling storage, so TRACE_RECORDED is never dispatched for the module's own routes in the first place.

Hooking in from a third-party module

No PHP is required. Once native_observability_eca_bridge is enabled (part of the INTEGRATIONS tier, drush no:preset:integrations), the ECA model UI lists "Native Observability" as an event category with two selectable events: "Trace recorded" and "Traces deleted". A model built from either one has access to the tokens above in its conditions and actions.

native_observability_eca_bridge_demo (excluded from every preset, enable it explicitly) ships five such models as config entities, useful as a starting point:

  • no_demo_log_all_traces: logs every trace unconditionally.
  • no_demo_500_errors: logs only when [event:status_code] equals 500.
  • no_demo_slow_requests: logs only when [event:duration_ms] is at least 3000.
  • no_demo_ajax_requests: logs only when [event:is_ajax] equals 1.
  • no_demo_traces_deleted: logs [event:deleted_count] on the traces_deleted event.

Each demo model uses an eca_scalar condition against a token and an eca_write_log_message action, the same pattern any custom model would use to build a Drupal Slack notification, a threshold alert, or any other no-code reaction to trace activity.