Skip to content

feat(logging): add an admin dashboard with charts - #866

Draft
josephfusco wants to merge 4 commits into
mainfrom
feat/logging-dashboard
Draft

josephfusco wants to merge 4 commits into
mainfrom
feat/logging-dashboard

Conversation

@josephfusco

@josephfusco josephfusco commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Adds a Dashboard page under GraphQL Logs that charts log entries, errors and top operations over the last 24 hours, 7 days or 30 days.

Closes #452

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5
Used for: Assisting with building the logging dashboard.

Add a Dashboard submenu under GraphQL Logs that shows, for the last 24 hours, 7 days or 30 days: summary tiles, log entries over time (errors stacked on top), entries by level and the top operations. Aggregation runs in SQL through a new LogStatsInterface with a WordPress database implementation, and results are cached in a short-lived transient. Charts are server-rendered inline SVG with a data table fallback, so no JavaScript or build step is needed.
@josephfusco josephfusco added this to the WPGraphQL Logging Plugin milestone Oct 30, 2026
@josephfusco josephfusco added [Type] Feature A new feature within an existing module [Area] Logging Issues for the WPGraphQL Logging plugin labels Oct 30, 2026
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

📦 Plugin Artifacts Ready!

Download from GitHub Actions run

Available plugins:

  • ✅ wpgraphql-logging.zip

See the "Artifacts" section at the bottom of the Actions run page

…oard

Daily buckets were fixed 24-hour blocks counted from local midnight, so after a daylight saving change the last hour of the day could fall outside the window and labels could slip a day. Daily ranges now use local calendar-day boundaries built from hourly SQL counts. Labels are no longer cached, so each user sees dates in their own locale. Also drops the unvalidated dashboard data filter, which could break the template, and truncates long operation names in the table (full name in the title attribute).
Add wpunit tests for DashboardPage (capability check, menu registration, range validation, DST-aware windows, folding hourly counts into days, caching, custom stats services, escaping of operation names) and for TimeSeriesChart (scale, well-formed accessible SVG, escaping, empty data, label thinning). The e2e spec now sends operationName, because the dashboard groups operations by the name the client sends.
Render the summary tiles from one list and the table bars from one helper. Draw each table bar inside a full-width track so bar lengths stay proportional; previously a max-width cap made large values look the same. Shorten long operation names without stripping characters, so names containing markup are shown escaped rather than blank. Document the dashboard, its filters and how to support it from a custom log store.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved defects misattribute logs across DST day boundaries, merge the valid operation name "null" into unnamed operations, and serve existing cached data even when caching is disabled.

4 open issues
What changed in this PR

Adds a dashboard under GraphQL Logs to visualize logging activity, addressing #452.

Changes:

  • Adds summary tiles, time-series charts, level breakdowns, and top operations for selectable time ranges.
  • Introduces cached database aggregation and an interface for custom log stores.
  • Adds dashboard styling, automated tests, and usage documentation.
File Description
plugins/​wpgraphql-logging/​tests/​wpunit/​Logger/​Database/​WordPressDatabaseLogStatsTest.php Tests database aggregation and operation grouping.
plugins/​wpgraphql-logging/​tests/​wpunit/​Admin/​DashboardPageTest.php Tests page access, time windows, caching, and rendering.
plugins/​wpgraphql-logging/​tests/​wpunit/​Admin/​Dashboard/​TimeSeriesChartTest.php Tests SVG output, scaling, and escaping.
plugins/​wpgraphql-logging/​tests/​e2e/​utils.js Adds dashboard navigation helper.
plugins/​wpgraphql-logging/​tests/​e2e/​specs/​dashboard.spec.js Tests dashboard navigation and logged operations.
plugins/​wpgraphql-logging/​tests/​e2e/​plugins/​reset-wpgraphql-logging-settings/​reset-wpgraphql-logging-settings.php Clears dashboard caches between tests.
plugins/​wpgraphql-logging/​src/​Plugin.php Initializes the dashboard page.
plugins/​wpgraphql-logging/​src/​Logger/​Database/​WordPressDatabaseLogStats.php Implements SQL-based log statistics.
plugins/​wpgraphql-logging/​src/​Logger/​Api/​LogStatsInterface.php Defines the statistics provider contract.
plugins/​wpgraphql-logging/​src/​Admin/​View/​Templates/​WPGraphQLLoggerDashboard.php Renders dashboard summaries, charts, and tables.
plugins/​wpgraphql-logging/​src/​Admin/​DashboardPage.php Handles registration, ranges, caching, and data preparation.
plugins/​wpgraphql-logging/​src/​Admin/​Dashboard/​TimeSeriesChart.php Renders server-side stacked SVG charts.
plugins/​wpgraphql-logging/​readme.txt Lists the dashboard feature.
plugins/​wpgraphql-logging/​assets/​css/​dashboard/​wp-graphql-logging-dashboard.css Styles dashboard layouts and charts.
docs/​plugins/​wpgraphql-logging/​index.md Documents metrics, ranges, and cache configuration.
docs/​plugins/​wpgraphql-logging/​how-to/​update-log-store-service/​index.md Documents dashboard support for custom log stores.

Review effort: Balanced

Comment on lines +247 to +250
$day = $now->setTime( 0, 0 )->modify( sprintf( '-%d days', $bucket_count - 1 ) );
for ( $i = 0; $i < $bucket_count; $i++ ) {
$bucket_starts[] = $day->getTimestamp();
$day = $day->modify( '+1 day' );
}

$cache_key = self::CACHE_KEY_PREFIX . $range;
$cached = get_transient( $cache_key );
Comment on lines +531 to +534
$hours = (int) ceil( ( $window['end'] - $window['start'] ) / HOUR_IN_SECONDS );
$hourly = $stats->get_time_series( $start, HOUR_IN_SECONDS, max( 1, $hours ) );

return self::fold_series( $hourly, $window['start'], HOUR_IN_SECONDS, $window['bucket_starts'] );
*
* @var string
*/
protected const OPERATION_SQL = "COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(context, '$.operation_name')), 'null'), '')";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Area] Logging Issues for the WPGraphQL Logging plugin [Type] Feature A new feature within an existing module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore: Add dashboard to admin for the Logging Plugin

2 participants