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]equals500.no_demo_slow_requests: logs only when[event:duration_ms]is at least3000.no_demo_ajax_requests: logs only when[event:is_ajax]equals1.no_demo_traces_deleted: logs[event:deleted_count]on thetraces_deletedevent.
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.