Skip to content

Commit e91e12c

Browse files
committed
Add guides for custom logger handlers, processors, and rules
Added new how-to documentation for extending WPGraphQL Logging with custom Monolog handlers, processors, and rules. Updated index and reference docs to link to these guides and clarified terminology and navigation. Minor improvements to existing docs for accuracy and consistency.
1 parent f76000c commit e91e12c

File tree

8 files changed

+484
-194
lines changed

8 files changed

+484
-194
lines changed

plugins/wpgraphql-logging/docs/how-to/events_pub_sub.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Plugin::on(Events::BEFORE_RESPONSE_RETURNED, function(array $payload): void {
119119
```
120120

121121
>[!NOTE]
122-
> You should be able to a handler too if you want to log data to that service with the Logger Service
122+
> You can also add a custom handler if you want to log data to that service via the LoggerService.
123123
124124

125125

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
## How to Add a New Handler (File Logging)
2+
3+
This guide shows how to log to a file using a Monolog handler, either in addition to the default WordPress database handler or as a replacement. It also covers per-instance overrides.
4+
5+
### What is a Handler?
6+
7+
Handlers decide where logs are written. By default, WPGraphQL Logging uses a custom `WordPressDatabaseHandler` to store logs in the database. You can add more destinations (files, streams, third-party services) or replace the defaults.
8+
9+
>[!NOTE]
10+
> See <https://seldaek.github.io/monolog/doc/02-handlers-formatters-processors.html> for a list of handlers and processors
11+
12+
### Option A: Add a file handler globally (in addition to the default)
13+
14+
Use the `wpgraphql_logging_default_handlers` filter to push a `StreamHandler` that writes to a file. The default database handler will remain enabled.
15+
16+
```php
17+
<?php
18+
use Monolog\Handler\StreamHandler;
19+
use Monolog\Level;
20+
21+
add_filter( 'wpgraphql_logging_default_handlers', function( array $handlers ) {
22+
$path = WP_CONTENT_DIR . '/logs/wpgraphql_logging.log';
23+
if ( ! file_exists( dirname( $path ) ) ) {
24+
// Ensure directory exists
25+
wp_mkdir_p( dirname( $path ) );
26+
}
27+
28+
// Log ERROR and higher to a file, in addition to the default DB handler
29+
$handlers[] = new StreamHandler( $path, Level::Error );
30+
return $handlers;
31+
});
32+
```
33+
34+
### Option B: Replace the default handler globally (file only)
35+
36+
Return your own array of handlers from the same filter to replace the default handler entirely.
37+
38+
```php
39+
<?php
40+
use Monolog\Handler\StreamHandler;
41+
use Monolog\Level;
42+
43+
add_filter( 'wpgraphql_logging_default_handlers', function( array $handlers ) {
44+
$path = WP_CONTENT_DIR . '/logs/wpgraphql_logging.log';
45+
if ( ! file_exists( dirname( $path ) ) ) {
46+
wp_mkdir_p( dirname( $path ) );
47+
}
48+
49+
// Replace defaults: file handler only, log everything from DEBUG and up
50+
return [ new StreamHandler( $path, Level::Debug ) ];
51+
});
52+
```
53+
54+
### Option C: Override handlers per logger instance
55+
56+
You can bypass the global defaults for a specific logger channel by passing handlers to `LoggerService::get_instance()`.
57+
58+
```php
59+
<?php
60+
use Monolog\Handler\StreamHandler;
61+
use Monolog\Level;
62+
use WPGraphQL\Logging\Logger\LoggerService;
63+
use WPGraphQL\Logging\Logger\Handlers\WordPressDatabaseHandler;
64+
65+
// Add file handler in addition to the DB handler for this specific channel
66+
$handlers = [
67+
new WordPressDatabaseHandler(),
68+
new StreamHandler( WP_CONTENT_DIR . '/logs/wpgraphql-channel.log', Level::Info ),
69+
];
70+
71+
$logger = LoggerService::get_instance( 'file_plus_db', $handlers );
72+
$logger->info( 'Per-instance handlers configured' );
73+
74+
// Or replace defaults for the instance (file only)
75+
$fileOnly = LoggerService::get_instance( 'file_only', [
76+
new StreamHandler( WP_CONTENT_DIR . '/logs/wpgraphql-file-only.log', Level::Warning ),
77+
] );
78+
$fileOnly->warning( 'This goes only to the file' );
79+
```
80+
81+
### Tips
82+
83+
- Ensure the logs directory is writable by the web server user.
84+
- Consider `Monolog\\Handler\\RotatingFileHandler` to rotate files by day and limit disk usage.
85+
- You can combine multiple handlers (e.g., database + file + Slack) either globally (filter) or per instance.
86+
87+
### Related
88+
89+
- See the [Logger reference](../reference/logging.md#filter-wpgraphql_logging_default_handlers) for `wpgraphql_logging_default_handlers` and other hooks.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
## How to Add a New Processor
2+
3+
This guide shows how to create and register a custom processor that logs the current WordPress environment (e.g. `production`, `staging`, `development`).
4+
5+
### What is a Processor?
6+
7+
Processors in Monolog add or transform data on each log record before handlers write it. They can modify the `context` or `extra` arrays on a record.
8+
9+
### Step 1: Create a processor class
10+
11+
Create a PHP class that implements `Monolog\Processor\ProcessorInterface` and returns the updated `LogRecord`.
12+
13+
```php
14+
<?php
15+
namespace MyPlugin\Logging;
16+
17+
use Monolog\LogRecord;
18+
use Monolog\Processor\ProcessorInterface;
19+
20+
class EnvironmentProcessor implements ProcessorInterface {
21+
public function __invoke( LogRecord $record ): LogRecord {
22+
$record->extra['environment'] = wp_get_environment_type();
23+
return $record;
24+
}
25+
}
26+
```
27+
28+
### Step 2: Register the processor globally
29+
30+
Use the `wpgraphql_logging_default_processors` filter to add your processor to all logger instances.
31+
32+
```php
33+
<?php
34+
add_filter( 'wpgraphql_logging_default_processors', function( array $processors ) {
35+
$processors[] = new \MyPlugin\Logging\EnvironmentProcessor();
36+
return $processors;
37+
});
38+
```
39+
40+
### (Optional) Per-instance registration
41+
42+
Register the processor for a specific logger channel by passing it to `LoggerService::get_instance()`.
43+
44+
```php
45+
<?php
46+
use WPGraphQL\Logging\Logger\LoggerService;
47+
48+
$logger = LoggerService::get_instance( 'env_channel', null, [ new \MyPlugin\Logging\EnvironmentProcessor() ] );
49+
$logger->info( 'Environment test' );
50+
```
51+
52+
53+
You should see `environment` in the log record's `extra` data (e.g. in the Logs admin UI or your chosen handler output).
54+
55+
### Related
56+
57+
- See the [Logger reference](../reference/logging.md#filter-wpgraphql_logging_default_processors) for hooks you can use to customize processors: `wpgraphql_logging_default_processors`.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
## How to Add a New Rule (Query must contain string)
2+
3+
This guide shows how to create a custom logging rule that only passes when the GraphQL query contains a specific substring, and how to register it with the RuleManager.
4+
5+
### What is a Rule?
6+
7+
Rules implement `WPGraphQL\Logging\Logger\Rules\LoggingRuleInterface` and are evaluated by the `RuleManager`. All rules must pass for logging to proceed.
8+
9+
Interface reference (methods):
10+
- `passes( array $config, ?string $query_string ): bool`
11+
- `get_name(): string`
12+
13+
### Step 1: Create the rule class
14+
15+
Create a class that implements the interface and returns true only if the query contains a given substring.
16+
17+
```php
18+
<?php
19+
namespace MyPlugin\Logging\Rules;
20+
21+
use WPGraphQL\Logging\Logger\Rules\LoggingRuleInterface;
22+
23+
class ContainsStringRule implements LoggingRuleInterface {
24+
public function __construct( private readonly string $needle ) {}
25+
26+
public function passes( array $config, ?string $query_string = null ): bool {
27+
if ( ! is_string( $query_string ) || '' === trim( $query_string ) ) {
28+
return false; // No query => fail
29+
}
30+
return stripos( $query_string, $this->needle ) !== false;
31+
}
32+
33+
public function get_name(): string {
34+
// Ensure unique name per rule; adjust if you need multiple variants
35+
return 'contains_string_rule';
36+
}
37+
}
38+
```
39+
40+
### Step 2: Register the rule with the RuleManager
41+
42+
Use the `wpgraphql_logging_rule_manager` filter to add your rule. This runs when the logger helper initializes rules.
43+
44+
```php
45+
<?php
46+
add_filter( 'wpgraphql_logging_rule_manager', function( $rule_manager ) {
47+
// Only pass when the query contains the word "GetPost"
48+
$rule_manager->add_rule( new \MyPlugin\Logging\Rules\ContainsStringRule( 'GetPost' ) );
49+
return $rule_manager;
50+
});
51+
```
52+
53+
### Step 3: Verify
54+
55+
- GraphQL requests whose query string contains `GetPost` will be logged (assuming other rules also pass).
56+
- Requests without that substring will be skipped by this rule, causing `is_enabled` to be false.
57+
58+
### Related
59+
60+
- See the [Logger reference](../reference/logging.md#filter-wpgraphql_logging_rule_manager) for the `wpgraphql_logging_rule_manager` filter.

plugins/wpgraphql-logging/docs/index.md

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
- [Project Structure](#project-structure)
66
- [Key Features](#key-features)
7-
- [Installation](#installation)
8-
- [Configuration](#configuration)
9-
- [Admin Interface](#admin-interface)
7+
- [Setup](#setup)
8+
- [Basic Configuration](#basic-configuration)
9+
- [Viewing Logs](#viewing-logs)
1010
- [Uninstallation and Data Cleanup](#uninstallation-and-data-cleanup)
1111
- [How‑to Guides](#how‑to-guides)
1212
- [Reference](#reference)
@@ -23,14 +23,14 @@ wpgraphql-logging/
2323
│ ├── Admin/ # Admin settings, menu, and settings page logic
2424
│ ├── Settings/ # Admin settings functionality for displaying and saving data.
2525
│ ├── Events/ # Event logging, pub/sub event manager for extending the logging.
26-
│ ├── Logger/ # Logging logic, logger service, Monolog handlers & processors
27-
│ ├── Database/ # Database Entity and Helper
28-
│ ├── Handlers/ # Monolog WordPress Database Handler for logging data
29-
│ ├── Processors/ # Monolog Processors for data sanitzation and adding request headers.
30-
│ ├── Rules/ # Rules and Rule Manager on whether we log a query
26+
│ ├── Logger/ # Logger service, Monolog handlers & processors
27+
│ ├── Database/ # Database entity and helper
28+
│ ├── Handlers/ # Monolog WordPress database handler for logging data
29+
│ ├── Processors/ # Monolog processors for data sanitization and request headers
30+
│ ├── Rules/ # Rules and RuleManager to decide whether to log a query
3131
│ ├── Scheduler/ # Automated data cleanup and maintenance tasks
3232
│ ├── Plugin.php # Main plugin class (entry point)
33-
│ └── Autoload.php # PSR-4 autoloader
33+
│ └── Autoloader.php # PSR-4 autoloader
3434
├── tests/ # All test suites
3535
│ ├── wpunit/ # WPBrowser/Codeception unit tests
3636
├── [wpgraphql-logging.php]
@@ -100,10 +100,10 @@ Once the plugin is activated, you can activate and configure the plugin under Se
100100
- **Log Points**: A multi-select field to choose the specific WPGraphQL lifecycle events for which data should be logged.
101101
- **Log Response**: A toggle to determine whether the GraphQL response body should be included in the log. Disabling this can reduce the size of your log data.
102102

103-
>[Note]
104-
> The configuration for these rules are set in a rule manager service which checks to see if a event should be logged, based on whether it passes all rules or not. More docs on the rule manager can be found here @TODO
103+
>[!NOTE]
104+
> Logging enablement is determined by a set of rules managed by a `RuleManager`. All rules must pass to log a request. See the Logger reference for the RuleManager hook: [wpgraphql_logging_rule_manager](reference/logging.md#trait-loggerlogginghelper).
105105
106-
You want to add a new rule. See our guide here @TODO
106+
You want to add a new rule. See: How‑to guides (`docs/how-to/logger_add_new_rule.md`).
107107

108108

109109
### Data Management
@@ -131,7 +131,7 @@ Once configured to log data you can find logs under "GraphQL Logs" in the WordPr
131131

132132
![Admin View](screenshots/admin_view.png)
133133

134-
This extends the WordPress WP List Table class but you can do the following.
134+
This extends the WordPress `WP_List_Table` class but you can do the following.
135135

136136
### Download the log
137137

@@ -153,17 +153,14 @@ You can filter the log by
153153

154154
![Admin View with Filters](screenshots/admin_view_filters.png)
155155

156-
>[Note]
157-
> We only show the `info` and `error` levels as these are the only levels logged out of the box. If you need to change this, you can update the admin template. See @TODO
156+
>[!NOTE]
157+
> The default UI highlights Info and Error levels. To customize visible columns and sorting, filter `wpgraphql_logging_logs_table_column_headers` (see Admin reference).
158158
159159

160160
### Bulk Actions
161161

162162
Currently you can delete selected or all logs.
163163

164-
If you want to customize this. @TODO
165-
166-
167164

168165
## Uninstallation and Data Cleanup
169166

@@ -193,7 +190,11 @@ define( 'WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN', true );
193190
- [How to use the WPGraphQL Logging events pub/sub system](how-to/events_pub_sub.md)
194191

195192
### Logging
196-
- @TODO — add how‑to guides for LoggerService, handlers, processors, rules
193+
194+
- [How to Add a New Handler (File Logging)](how-to/logger_add_new_handler.md)
195+
- [How to Add a New Processor](how-to/logger_add_new_processor.md)
196+
- [How to Add a New Rule (Query must contain string)](how-to/logger_add_new_rule.md)
197+
197198

198199
## Reference
199200

plugins/wpgraphql-logging/docs/reference/admin.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
The WPGraphQL Logging plugin provides several filters and actions in the Admin area that allow developers to extend and customize functionality. This reference documents all available hooks with real-world examples.
44

5+
## Table of Contents
6+
7+
- [SettingsPage](#class-settingspage)
8+
- [Settings\ConfigurationHelper](#class-settingsconfigurationhelper)
9+
- [Settings\SettingsFormManager](#class-settingssettingsformmanager)
10+
- [ViewLogsPage](#class-viewlogspage)
11+
- [Settings\Templates\admin.php and View Templates](#class-settingstemplatesadminphp-and-view-templates)
12+
13+
514
---
615

716

plugins/wpgraphql-logging/docs/reference/events.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
The WPGraphQL Logging plugin exposes a lightweight pub/sub system for WPGraphQL lifecycle events and bridges them to standard WordPress actions/filters.
44

5+
## Table of Contents
6+
7+
- [Events\Events](#class-eventsevents)
8+
- [Events\EventManager](#class-eventseventmanager)
9+
10+
511
---
612

713
### Class: `Events\Events`
@@ -18,7 +24,6 @@ Constants that map to WPGraphQL core hooks:
1824

1925
Use these with the `Plugin` helpers or the `EventManager` directly.
2026

21-
@TODO See the how to guide on logging a new event.
2227

2328
---
2429

0 commit comments

Comments
 (0)