Skip to content

Commit f76000c

Browse files
committed
Add event pub/sub and context how-to guides
Added new documentation for WPGraphQL Logging event pub/sub system and context injection (docs/how-to/events_pub_sub.md, docs/how-to/events_add_context.md), updated index and events reference docs to link and describe these features, and added a screenshot for context data. Removed unused .gitkeep from examples.
1 parent ad55712 commit f76000c

File tree

6 files changed

+344
-128
lines changed

6 files changed

+344
-128
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
## How to add context data to a logged WPGraphQL event
2+
3+
This guide shows two supported ways to inject custom context data into events that WPGraphQL Logging records:
4+
5+
- Programmatic transform API (recommended for plugins/themes using PHP namespaces)
6+
- WordPress filter API (easy to drop into any project)
7+
8+
Refer to the [Events Reference](../reference/events.md) for the list of available event names.
9+
10+
11+
![Adding custom context data to WPGraphQL events](../screenshots/event_add_context_data.png)
12+
*Example of custom context data being added to a WPGraphQL event log entry*
13+
14+
15+
### Option A — Programmatic transform API
16+
17+
Use the `WPGraphQL\Logging\Plugin::transform()` helper to mutate the event payload before it is logged and emitted.
18+
19+
```php
20+
<?php
21+
use WPGraphQL\Logging\Plugin;
22+
use WPGraphQL\Logging\Events\Events;
23+
use Monolog\Level;
24+
25+
// Add custom context to the PRE_REQUEST event
26+
add_action( 'init', function() {
27+
Plugin::transform( Events::PRE_REQUEST, function( array $payload ): array {
28+
// $payload has keys: 'context' (array) and 'level' (Monolog\Level)
29+
$payload['context']['environment'] = wp_get_environment_type();
30+
$payload['context']['app_id'] = 'my-headless-app';
31+
32+
// Optional: change the log level for this specific event
33+
// $payload['level'] = Level::Debug;
34+
35+
return $payload;
36+
}, 10 );
37+
} );
38+
```
39+
40+
You can target any event constant from `WPGraphQL\Logging\Events\Events`, for example:
41+
42+
- `Events::PRE_REQUEST` (maps to `do_graphql_request`)
43+
- `Events::BEFORE_GRAPHQL_EXECUTION` (maps to `graphql_before_execute`)
44+
- `Events::BEFORE_RESPONSE_RETURNED` (maps to `graphql_return_response`)
45+
- `Events::REQUEST_DATA` (filter `graphql_request_data`)
46+
- `Events::REQUEST_RESULTS` (filter `graphql_request_results`)
47+
- `Events::RESPONSE_HEADERS_TO_SEND` (filter `graphql_response_headers_to_send`)
48+
49+
50+
### Option B — WordPress filter API
51+
52+
Every event also exposes a WordPress filter bridge you can hook into to modify the payload. The filter name pattern is:
53+
54+
- `wpgraphql_logging_filter_{event_name}`
55+
56+
Where `{event_name}` is the raw WPGraphQL hook name (the constant value). For example, to inject context before the response is returned:
57+
58+
```php
59+
<?php
60+
add_filter( 'wpgraphql_logging_filter_graphql_return_response', function( array $payload ) {
61+
// $payload has 'context' and 'level'
62+
$payload['context']['trace_id'] = uniqid( 'trace_', true );
63+
$payload['context']['feature_flag'] = defined('MY_FEATURE') ? (bool) MY_FEATURE : false;
64+
return $payload; // You must return the modified payload
65+
}, 10, 1 );
66+
```
67+
68+
Another example for the request data stage:
69+
70+
```php
71+
<?php
72+
add_filter( 'wpgraphql_logging_filter_graphql_request_data', function( array $payload ) {
73+
$payload['context']['client'] = [
74+
'ip' => $_SERVER['REMOTE_ADDR'] ?? null,
75+
'agent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
76+
];
77+
return $payload;
78+
}, 10, 1 );
79+
```
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
## How to use the WPGraphQL Logging events pub/sub system
2+
3+
The plugin exposes a lightweight pub/sub bus around key WPGraphQL lifecycle events and bridges them to standard WordPress actions/filters. You can:
4+
5+
- Subscribe (read-only) to observe event payloads
6+
- Transform payloads before core code logs and emits them
7+
- Publish your own custom events for your app/plugins
8+
9+
See the [Events Reference](../reference/events.md) for available built-in events and their mappings.
10+
11+
12+
### Core concepts
13+
14+
- Subscribe (read-only): `Plugin::on( $event, callable $listener, $priority )`
15+
- Transform (mutate): `Plugin::transform( $event, callable $transform, $priority )`
16+
- Emit (publish): `Plugin::emit( $event, array $payload )`
17+
18+
Priorities run ascending (lower numbers first). Transforms must return the updated payload array; subscribers receive the payload and do not return.
19+
20+
21+
### Programmatic API (recommended)
22+
23+
```php
24+
<?php
25+
use WPGraphQL\Logging\Plugin;
26+
use WPGraphQL\Logging\Events\Events;
27+
use Monolog\Level;
28+
29+
// 1) Subscribe (read-only) to inspect context for the pre-request event
30+
add_action( 'init', function() {
31+
Plugin::on( Events::PRE_REQUEST, function( array $payload ): void {
32+
$context = $payload['context'] ?? [];
33+
// e.g., inspect or trigger side effects
34+
// error_log( 'Incoming operation: ' . ( $context['operation_name'] ?? '' ) );
35+
}, 10 );
36+
} );
37+
38+
// 2) Transform the payload before it is logged/emitted by core code
39+
add_action( 'init', function() {
40+
Plugin::transform( Events::BEFORE_RESPONSE_RETURNED, function( array $payload ): array {
41+
$payload['context']['env'] = wp_get_environment_type();
42+
43+
// Optionally change severity for this event instance
44+
if ( ! empty( $payload['context']['errors'] ) ) {
45+
$payload['level'] = Level::Error;
46+
}
47+
return $payload;
48+
}, 5 ); // lower priority runs earlier
49+
} );
50+
51+
// 3) Emit your own custom event anywhere in your code
52+
add_action( 'user_register', function( $user_id ) {
53+
Plugin::emit( 'my_plugin/user_registered', [
54+
'context' => [ 'user_id' => (int) $user_id ],
55+
] );
56+
} );
57+
```
58+
59+
Notes:
60+
61+
- Built-in events are transformed internally before they are logged and then published.
62+
- `emit()` publishes to subscribers and the WordPress action bridge; it does not apply transforms by itself.
63+
- If you want the “transform then publish” pattern for your custom event, call `EventManager::transform( $event, $payload )` yourself before publishing.
64+
65+
66+
### WordPress bridge (actions and filters)
67+
68+
For each event, the system also fires a WordPress action and applies a WordPress filter so you can interact without the PHP helpers.
69+
70+
- Action: `wpgraphql_logging_event_{event_name}` (fires after subscribers run)
71+
- Filter: `wpgraphql_logging_filter_{event_name}` (used when core transforms a payload)
72+
73+
Examples:
74+
75+
```php
76+
<?php
77+
// Observe the raw pre-request payload via WordPress action
78+
add_action( 'wpgraphql_logging_event_do_graphql_request', function( array $payload ) {
79+
// e.g., send metrics to an external system
80+
}, 10, 1 );
81+
82+
// Inject extra context before the response is logged
83+
add_filter( 'wpgraphql_logging_filter_graphql_return_response', function( array $payload ) {
84+
$payload['context']['trace_id'] = uniqid( 'trace_', true );
85+
$payload['context']['app_name'] = 'headless-site';
86+
return $payload;
87+
}, 10, 1 );
88+
```
89+
90+
91+
### Practical example - Send data to external service
92+
93+
```php
94+
<?php
95+
use WPGraphQL\Logging\Plugin;
96+
use WPGraphQL\Logging\Events\Events;
97+
98+
Plugin::on(Events::BEFORE_RESPONSE_RETURNED, function(array $payload): void {
99+
$context = $payload['context'];
100+
if (array_key_exists('errors', $context)) {
101+
$level = 400;
102+
$level_name = 'ERROR';
103+
} else {
104+
$level = 200;
105+
$level_name = 'INFO';
106+
}
107+
108+
109+
// Example call (replace values as needed)
110+
$result = send_log_to_external_api_endpoint( [
111+
'level' => $level,
112+
'level_name' => $level_name,
113+
'query' => $context['query'] ?? '',
114+
'context' => $context,
115+
'message' => 'Test'
116+
] );
117+
}, 10);
118+
119+
```
120+
121+
>[!NOTE]
122+
> You should be able to a handler too if you want to log data to that service with the Logger Service
123+
124+
125+
126+
### Troubleshooting
127+
128+
- If your transform isn’t taking effect, ensure you’re targeting the correct event and that your callable returns the modified array.
129+
- If you only call `emit()`, transforms won’t run automatically; they only run where core calls `transform()`.
130+
- Use priorities to control ordering with other plugins (`5` runs before `10`).

plugins/wpgraphql-logging/docs/index.md

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@
22

33
## Table of Contents
44

5-
@TODO - Regenerate
6-
7-
- [Overview](#overview)
8-
- [Getting Started](#getting-started)
9-
- [Features](#features)
10-
- [Usage](#usage)
5+
- [Project Structure](#project-structure)
6+
- [Key Features](#key-features)
7+
- [Installation](#installation)
118
- [Configuration](#configuration)
12-
- [Admin & Settings](#admin--settings)
13-
- [Extending the Functionality](#extending-the-functionality)
14-
- [Testing](#testing)
9+
- [Admin Interface](#admin-interface)
10+
- [Uninstallation and Data Cleanup](#uninstallation-and-data-cleanup)
11+
- [How‑to Guides](#how‑to-guides)
12+
- [Reference](#reference)
1513

1614
---
1715

@@ -47,32 +45,43 @@ wpgraphql-logging/
4745

4846
## Key Features
4947

50-
@TODO
51-
52-
- **Query event lifecycle logging**
48+
- **End-to-end GraphQL lifecycle logging**
5349
- **Pre Request** (`do_graphql_request`): captures `query`, `variables`, `operation_name`.
54-
- **Before Execution** (`graphql_before_execute`): includes a snapshot of request `params`.
55-
- **Before Response Returned** (`graphql_return_response`): inspects `response` and automatically upgrades level to Error when GraphQL `errors` are present (adds `errors` to context when found).
50+
- **Before Execution** (`graphql_before_execute`): snapshots request `params`.
51+
- **Before Response Returned** (`graphql_return_response`): inspects `response`; auto-elevates level to Error when GraphQL `errors` are present (adds `errors` to context).
5652

57-
- **Built-in pub/sub event bus**
58-
- In-memory event manager with priorities: `subscribe(event, listener, priority)` and `publish(event, payload)`.
59-
- Transform pipeline: `transform(event, payload)` lets you mutate `context` and `level` before logging/publishing.
53+
- **Developer-friendly pub/sub and transform system**
54+
- Programmatic API: `Plugin::on($event, $listener)`, `Plugin::transform($event, $callable)`, `Plugin::emit($event, $payload)`.
55+
- Prioritized execution: lower priority runs earlier for both subscribers and transforms.
6056
- WordPress bridges: actions `wpgraphql_logging_event_{event}` and filters `wpgraphql_logging_filter_{event}` to integrate with standard hooks.
57+
- Safe-by-default: exceptions in listeners/transforms are caught and logged; they do not break the pipeline.
58+
- See: Reference › Events (`docs/reference/events.md`) and How‑to guides (`docs/how-to/events_pub_sub.md`, `docs/how-to/events_add_context.md`).
59+
60+
- **Extensible Monolog pipeline**
61+
- Default handler: `WordPressDatabaseHandler` stores logs in `{$wpdb->prefix}wpgraphql_logging`.
62+
- Add handlers via filter `wpgraphql_logging_default_handlers` (e.g., file, Slack, HTTP, etc.).
63+
- Add processors via filter `wpgraphql_logging_default_processors` (e.g., enrich records with user/site data).
64+
- Customize `default_context` via `wpgraphql_logging_default_context`.
65+
- Use `LoggerService::get_instance()` to build custom channels, handlers, processors.
6166

62-
- **Monolog-powered logging pipeline**
63-
- Default handler: stores logs in a WordPress table (`{$wpdb->prefix}wpgraphql_logging`).
67+
- **Configurable rule-based logging**
68+
- Built-in rules: enabled toggle, IP restrictions, exclude queries, sampling rate, null query guard, response logging toggle.
69+
- All rules are orchestrated by a `RuleManager` ensuring logs only emit when all rules pass.
70+
- Extend rules: hook `wpgraphql_logging_rule_manager` to add custom `LoggingRuleInterface` implementations.
6471

6572
- **Automated data management**
66-
- **Daily cleanup scheduler**: Automatically removes old logs based on retention settings.
67-
- **Configurable retention period**: Set how many days to keep log data (default: 30 days).
68-
- **Manual cleanup**: Admin interface to trigger immediate cleanup of old logs.
69-
- **Data sanitization**: Remove sensitive fields from logged data for privacy compliance.
73+
- **Daily cleanup scheduler**: removes old logs based on retention.
74+
- **Configurable retention period**: choose days to keep (default 30).
75+
- **Manual cleanup**: trigger from the admin UI.
76+
- **Data sanitization**: built-in `DataSanitizationProcessor` removes/anonymizes/truncates sensitive fields with recommended or custom rules.
7077

71-
- **Simple developer API**
72-
- `Plugin::on()` to subscribe, `Plugin::emit()` to publish, `Plugin::transform()` to modify payloads.
78+
- **Admin UI for operations**
79+
- Logs list view with filters (level, date range) and CSV export.
80+
- Bulk delete actions and visibility controls.
7381

74-
- **Safe-by-default listeners/transforms**
75-
- Exceptions in listeners/transforms are caught and logged without breaking the pipeline.
82+
- **Composable and testable architecture**
83+
- Clear separation: Events bus, Logger service, Rules, Processors, Handlers.
84+
- Designed for extension via interfaces, filters, and helper APIs.
7685

7786
---
7887

@@ -172,29 +181,22 @@ define( 'WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN', true );
172181
> **Data Loss Warning**: When `WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN` is defined as `true`, deactivating the plugin will permanently delete all logged data and drop the plugin's database tables. This action is irreversible.
173182
174183

175-
## Reference
176-
177-
The plugin is developer focussed and can be extended in multiple ways.
178-
179-
## Admin - (admin configuration, view and functionality)
184+
## How‑to Guides
180185

181-
- [Actions/Filters](reference/admin.md)
186+
### Admin
182187
- [How to add a new Settings tab to WPGraphQL Logging](how-to/admin_add_new_tab.md)
183188
- [How to add a new field to an existing tab and query it](how-to/admin_add_fields.md)
184189
- [How to add a new column to the Logs admin grid](how-to/admin_add_view_column.md)
185190

191+
### Events
192+
- [How to add context data to a logged WPGraphQL event](how-to/events_add_context.md)
193+
- [How to use the WPGraphQL Logging events pub/sub system](how-to/events_pub_sub.md)
186194

187-
@TODO - How to guides
188-
189-
## Events - (Event Management, Adding and extending events, Using the pub/sub)
190-
- [Actions/Filters](reference/events.md)
191-
192-
@TODO - How to guides
193-
194-
## Logging - (Logging Service, Monolog Handlers & Processors, Rule Manager, Data Management)
195-
- [Actions/Filters](reference/logging.md)
196-
197-
@TODO - How to guides
195+
### Logging
196+
- @TODO — add how‑to guides for LoggerService, handlers, processors, rules
198197

198+
## Reference
199199

200-
----
200+
- Admin: [Actions/Filters](reference/admin.md)
201+
- Events: [Actions/Filters](reference/events.md)
202+
- Logging: [Actions/Filters](reference/logging.md)

0 commit comments

Comments
 (0)