You've already forked wp-prometheus
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 19d75ab7b2 | |||
| fa63857f5f | |||
| 41f16a9fbd | |||
| f984e3eb23 |
@@ -18,7 +18,7 @@ jobs:
|
|||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
php-version: '8.3'
|
php-version: '8.3'
|
||||||
extensions: mbstring, xml, zip, intl, gettext
|
extensions: mbstring, xml, zip, intl, gettext, redis, apcu
|
||||||
tools: composer:v2
|
tools: composer:v2
|
||||||
|
|
||||||
- name: Get version from tag
|
- name: Get version from tag
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,3 +4,6 @@ wp-plugins
|
|||||||
wp-core
|
wp-core
|
||||||
vendor/
|
vendor/
|
||||||
releases/*
|
releases/*
|
||||||
|
|
||||||
|
# Marketing texts (not for distribution)
|
||||||
|
MARKETING.md
|
||||||
|
|||||||
23
CHANGELOG.md
23
CHANGELOG.md
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.4.2] - 2026-02-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Option to disable early mode in admin settings (Metrics tab)
|
||||||
|
- Support for `WP_PROMETHEUS_DISABLE_EARLY_MODE` environment variable
|
||||||
|
- Early mode status display in settings
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Early mode can now be disabled for users who need the `wp_prometheus_collect_metrics` hook for custom metrics
|
||||||
|
- Updated translations with new early mode strings (English and German)
|
||||||
|
|
||||||
|
## [0.4.1] - 2026-02-02
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed memory exhaustion when wp-fedistream (Twig-based) plugin is active
|
||||||
|
- Added early metrics endpoint handler that intercepts `/metrics` requests before full WordPress initialization
|
||||||
|
- Removed content filters (`the_content`, `the_excerpt`, `get_the_excerpt`, `the_title`) during metrics collection to prevent recursion
|
||||||
|
- Skip third-party extensibility hooks during early metrics mode to avoid conflicts
|
||||||
|
- Changed `template_redirect` hook to `parse_request` for earlier request interception
|
||||||
|
|
||||||
## [0.4.0] - 2026-02-02
|
## [0.4.0] - 2026-02-02
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
44
CLAUDE.md
44
CLAUDE.md
@@ -291,6 +291,50 @@ add_action( 'wp_prometheus_collect_metrics', function( $collector ) {
|
|||||||
|
|
||||||
## Session History
|
## Session History
|
||||||
|
|
||||||
|
### 2026-02-02 - Early Mode Toggle (v0.4.2)
|
||||||
|
|
||||||
|
- Added option to disable early mode for users who need extensibility
|
||||||
|
- Implementation:
|
||||||
|
- Added `wp_prometheus_disable_early_mode` WordPress option
|
||||||
|
- Added `WP_PROMETHEUS_DISABLE_EARLY_MODE` environment variable support
|
||||||
|
- Option check in `wp_prometheus_early_metrics_check()` before early interception
|
||||||
|
- Environment variable accepts `1`, `true`, `yes`, `on` (case-insensitive)
|
||||||
|
- Admin UI in Metrics tab:
|
||||||
|
- "Early Mode" section with description of functionality
|
||||||
|
- Checkbox to disable early metrics interception
|
||||||
|
- Environment override notice when env var is set
|
||||||
|
- Current status indicator showing early mode state
|
||||||
|
- **Key Learning**: Balancing compatibility vs extensibility
|
||||||
|
- Early mode fixes memory issues but disables `wp_prometheus_collect_metrics` hook
|
||||||
|
- Users with custom metrics need the hook, so early mode must be optional
|
||||||
|
- Default remains enabled (safe) with explicit opt-out for advanced users
|
||||||
|
|
||||||
|
### 2026-02-02 - Plugin Compatibility Fix (v0.4.1)
|
||||||
|
|
||||||
|
- Fixed memory exhaustion (1GB limit) when wp-fedistream (Twig-based) plugin is active
|
||||||
|
- Root cause: Infinite recursion through WordPress hook system when content filters trigger Twig rendering
|
||||||
|
- Solution: Early metrics endpoint interception before full WordPress initialization
|
||||||
|
- Implementation changes:
|
||||||
|
- Added `wp_prometheus_early_metrics_check()` in bootstrap file (wp-prometheus.php)
|
||||||
|
- Checks REQUEST_URI for `/metrics` pattern before `plugins_loaded` fires
|
||||||
|
- Defines `WP_PROMETHEUS_EARLY_METRICS` constant to signal early mode
|
||||||
|
- Removes content filters (`the_content`, `the_excerpt`, `get_the_excerpt`, `the_title`)
|
||||||
|
- Collector skips `wp_prometheus_collect_metrics` action in early mode
|
||||||
|
- Changed MetricsEndpoint from `template_redirect` to `parse_request` hook
|
||||||
|
- **Key Learning**: WordPress plugin loading order and hook timing
|
||||||
|
- Plugins load alphabetically, so wp-fedistream ('f') loads before wp-prometheus ('p')
|
||||||
|
- `template_redirect` fires too late - after themes and Twig initialize
|
||||||
|
- `parse_request` fires earlier but still after plugin files load
|
||||||
|
- Earliest interception point: top-level code in plugin bootstrap file
|
||||||
|
- **Key Learning**: Content filter recursion in WordPress
|
||||||
|
- `get_the_excerpt()` internally triggers `apply_filters('the_content', ...)`
|
||||||
|
- This creates unexpected recursion vectors when Twig templates process content
|
||||||
|
- Solution: Remove all content-related filters before metrics collection
|
||||||
|
- **Key Learning**: Isolating metrics collection from WordPress template system
|
||||||
|
- Use `remove_all_filters()` to clear problematic filter chains
|
||||||
|
- Skip extensibility hooks (`do_action`) when in isolated early mode
|
||||||
|
- Exit immediately after output to prevent further WordPress processing
|
||||||
|
|
||||||
### 2026-02-02 - Persistent Storage (v0.4.0)
|
### 2026-02-02 - Persistent Storage (v0.4.0)
|
||||||
|
|
||||||
- Added persistent storage support for metrics:
|
- Added persistent storage support for metrics:
|
||||||
|
|||||||
Binary file not shown.
@@ -3,7 +3,7 @@
|
|||||||
# This file is distributed under the GPL v2 or later.
|
# This file is distributed under the GPL v2 or later.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: WP Prometheus 0.4.0\n"
|
"Project-Id-Version: WP Prometheus 0.4.2\n"
|
||||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-prometheus/issues\n"
|
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-prometheus/issues\n"
|
||||||
"POT-Creation-Date: 2026-02-02T00:00:00+00:00\n"
|
"POT-Creation-Date: 2026-02-02T00:00:00+00:00\n"
|
||||||
"PO-Revision-Date: 2026-02-02T00:00:00+00:00\n"
|
"PO-Revision-Date: 2026-02-02T00:00:00+00:00\n"
|
||||||
@@ -879,3 +879,43 @@ msgstr "APCu funktioniert. Speicher: %s belegt."
|
|||||||
#: src/Metrics/StorageFactory.php
|
#: src/Metrics/StorageFactory.php
|
||||||
msgid "APCu fetch operation returned unexpected value."
|
msgid "APCu fetch operation returned unexpected value."
|
||||||
msgstr "APCu-Abrufoperation hat unerwarteten Wert zurueckgegeben."
|
msgstr "APCu-Abrufoperation hat unerwarteten Wert zurueckgegeben."
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early Mode"
|
||||||
|
msgstr "Fruehzeitiger Modus"
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early mode intercepts /metrics requests before full WordPress initialization. This prevents memory exhaustion issues caused by some plugins (e.g., Twig-based themes/plugins) but disables the wp_prometheus_collect_metrics hook for custom metrics."
|
||||||
|
msgstr "Der fruehzeitige Modus faengt /metrics-Anfragen vor der vollstaendigen WordPress-Initialisierung ab. Dies verhindert Speichererschoepfungsprobleme, die durch einige Plugins verursacht werden (z.B. Twig-basierte Themes/Plugins), deaktiviert jedoch den wp_prometheus_collect_metrics-Hook fuer benutzerdefinierte Metriken."
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early mode is configured via WP_PROMETHEUS_DISABLE_EARLY_MODE environment variable. Admin settings will be ignored."
|
||||||
|
msgstr "Der fruehzeitige Modus ist ueber die Umgebungsvariable WP_PROMETHEUS_DISABLE_EARLY_MODE konfiguriert. Admin-Einstellungen werden ignoriert."
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Disable Early Mode"
|
||||||
|
msgstr "Fruehzeitigen Modus deaktivieren"
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Disable early metrics interception"
|
||||||
|
msgstr "Fruehzeitige Metriken-Abfangung deaktivieren"
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "When disabled, metrics are collected through normal WordPress template loading. This enables the wp_prometheus_collect_metrics hook for custom metrics but may cause issues with some plugins."
|
||||||
|
msgstr "Wenn deaktiviert, werden Metriken ueber das normale WordPress-Template-Laden erfasst. Dies aktiviert den wp_prometheus_collect_metrics-Hook fuer benutzerdefinierte Metriken, kann jedoch Probleme mit einigen Plugins verursachen."
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early mode is active (this request was served via early interception)"
|
||||||
|
msgstr "Fruehzeitiger Modus ist aktiv (diese Anfrage wurde ueber fruehzeitige Abfangung verarbeitet)"
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early mode is disabled"
|
||||||
|
msgstr "Fruehzeitiger Modus ist deaktiviert"
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early mode is enabled (active for /metrics requests)"
|
||||||
|
msgstr "Fruehzeitiger Modus ist aktiviert (aktiv fuer /metrics-Anfragen)"
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Clear all accumulated runtime metric data (HTTP requests, database queries). This is useful for testing or starting fresh."
|
||||||
|
msgstr "Alle gesammelten Laufzeit-Metrikdaten loeschen (HTTP-Anfragen, Datenbank-Abfragen). Dies ist nuetzlich zum Testen oder fuer einen Neuanfang."
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# This file is distributed under the GPL v2 or later.
|
# This file is distributed under the GPL v2 or later.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: WP Prometheus 0.4.0\n"
|
"Project-Id-Version: WP Prometheus 0.4.2\n"
|
||||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-prometheus/issues\n"
|
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-prometheus/issues\n"
|
||||||
"POT-Creation-Date: 2026-02-02T00:00:00+00:00\n"
|
"POT-Creation-Date: 2026-02-02T00:00:00+00:00\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@@ -876,3 +876,43 @@ msgstr ""
|
|||||||
#: src/Metrics/StorageFactory.php
|
#: src/Metrics/StorageFactory.php
|
||||||
msgid "APCu fetch operation returned unexpected value."
|
msgid "APCu fetch operation returned unexpected value."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early Mode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early mode intercepts /metrics requests before full WordPress initialization. This prevents memory exhaustion issues caused by some plugins (e.g., Twig-based themes/plugins) but disables the wp_prometheus_collect_metrics hook for custom metrics."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early mode is configured via WP_PROMETHEUS_DISABLE_EARLY_MODE environment variable. Admin settings will be ignored."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Disable Early Mode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Disable early metrics interception"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "When disabled, metrics are collected through normal WordPress template loading. This enables the wp_prometheus_collect_metrics hook for custom metrics but may cause issues with some plugins."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early mode is active (this request was served via early interception)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early mode is disabled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Early mode is enabled (active for /metrics requests)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/Admin/Settings.php
|
||||||
|
msgid "Clear all accumulated runtime metric data (HTTP requests, database queries). This is useful for testing or starting fresh."
|
||||||
|
msgstr ""
|
||||||
|
|||||||
@@ -118,6 +118,12 @@ class Settings {
|
|||||||
'sanitize_callback' => array( $this, 'sanitize_metrics' ),
|
'sanitize_callback' => array( $this, 'sanitize_metrics' ),
|
||||||
) );
|
) );
|
||||||
|
|
||||||
|
register_setting( 'wp_prometheus_metrics_settings', 'wp_prometheus_disable_early_mode', array(
|
||||||
|
'type' => 'boolean',
|
||||||
|
'sanitize_callback' => 'rest_sanitize_boolean',
|
||||||
|
'default' => false,
|
||||||
|
) );
|
||||||
|
|
||||||
// Auth token section.
|
// Auth token section.
|
||||||
add_settings_section(
|
add_settings_section(
|
||||||
'wp_prometheus_auth_section',
|
'wp_prometheus_auth_section',
|
||||||
@@ -420,6 +426,66 @@ class Settings {
|
|||||||
<span id="wp-prometheus-reset-spinner" class="spinner" style="float: none;"></span>
|
<span id="wp-prometheus-reset-spinner" class="spinner" style="float: none;"></span>
|
||||||
</p>
|
</p>
|
||||||
<div id="wp-prometheus-reset-message" style="display: none; margin-top: 10px;"></div>
|
<div id="wp-prometheus-reset-message" style="display: none; margin-top: 10px;"></div>
|
||||||
|
|
||||||
|
<hr style="margin: 30px 0;">
|
||||||
|
|
||||||
|
<?php $this->render_early_mode_section(); ?>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render early mode section.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function render_early_mode_section(): void {
|
||||||
|
$disabled = get_option( 'wp_prometheus_disable_early_mode', false );
|
||||||
|
$env_override = false !== getenv( 'WP_PROMETHEUS_DISABLE_EARLY_MODE' );
|
||||||
|
$early_active = defined( 'WP_PROMETHEUS_EARLY_METRICS' ) && WP_PROMETHEUS_EARLY_METRICS;
|
||||||
|
?>
|
||||||
|
<h3><?php esc_html_e( 'Early Mode', 'wp-prometheus' ); ?></h3>
|
||||||
|
<p class="description">
|
||||||
|
<?php esc_html_e( 'Early mode intercepts /metrics requests before full WordPress initialization. This prevents memory exhaustion issues caused by some plugins (e.g., Twig-based themes/plugins) but disables the wp_prometheus_collect_metrics hook for custom metrics.', 'wp-prometheus' ); ?>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<?php if ( $env_override ) : ?>
|
||||||
|
<div class="notice notice-info inline" style="padding: 12px; margin: 15px 0;">
|
||||||
|
<strong><?php esc_html_e( 'Environment Override Active', 'wp-prometheus' ); ?></strong>
|
||||||
|
<p><?php esc_html_e( 'Early mode is configured via WP_PROMETHEUS_DISABLE_EARLY_MODE environment variable. Admin settings will be ignored.', 'wp-prometheus' ); ?></p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<table class="form-table" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><?php esc_html_e( 'Disable Early Mode', 'wp-prometheus' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="wp_prometheus_disable_early_mode" value="1"
|
||||||
|
<?php checked( $disabled ); ?>
|
||||||
|
<?php disabled( $env_override ); ?>>
|
||||||
|
<?php esc_html_e( 'Disable early metrics interception', 'wp-prometheus' ); ?>
|
||||||
|
</label>
|
||||||
|
<p class="description">
|
||||||
|
<?php esc_html_e( 'When disabled, metrics are collected through normal WordPress template loading. This enables the wp_prometheus_collect_metrics hook for custom metrics but may cause issues with some plugins.', 'wp-prometheus' ); ?>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><?php esc_html_e( 'Current Status', 'wp-prometheus' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<?php if ( $early_active ) : ?>
|
||||||
|
<span class="dashicons dashicons-yes-alt" style="color: green;"></span>
|
||||||
|
<?php esc_html_e( 'Early mode is active (this request was served via early interception)', 'wp-prometheus' ); ?>
|
||||||
|
<?php elseif ( $disabled || $env_override ) : ?>
|
||||||
|
<span class="dashicons dashicons-dismiss" style="color: gray;"></span>
|
||||||
|
<?php esc_html_e( 'Early mode is disabled', 'wp-prometheus' ); ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="dashicons dashicons-yes-alt" style="color: green;"></span>
|
||||||
|
<?php esc_html_e( 'Early mode is enabled (active for /metrics requests)', 'wp-prometheus' ); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ class MetricsEndpoint {
|
|||||||
*/
|
*/
|
||||||
private function init_hooks(): void {
|
private function init_hooks(): void {
|
||||||
add_action( 'init', array( $this, 'register_endpoint' ) );
|
add_action( 'init', array( $this, 'register_endpoint' ) );
|
||||||
add_action( 'template_redirect', array( $this, 'handle_request' ) );
|
// Use parse_request instead of template_redirect to handle the request early,
|
||||||
|
// before themes and other plugins (like Twig-based ones) can interfere.
|
||||||
|
add_action( 'parse_request', array( $this, 'handle_request' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,10 +68,13 @@ class MetricsEndpoint {
|
|||||||
/**
|
/**
|
||||||
* Handle the metrics endpoint request.
|
* Handle the metrics endpoint request.
|
||||||
*
|
*
|
||||||
|
* Called during parse_request to intercept before themes/plugins load.
|
||||||
|
*
|
||||||
|
* @param \WP $wp WordPress environment instance.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function handle_request(): void {
|
public function handle_request( \WP $wp ): void {
|
||||||
if ( ! get_query_var( 'wp_prometheus_metrics' ) ) {
|
if ( empty( $wp->query_vars['wp_prometheus_metrics'] ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,9 +121,14 @@ class Collector {
|
|||||||
/**
|
/**
|
||||||
* Fires after default metrics are collected.
|
* Fires after default metrics are collected.
|
||||||
*
|
*
|
||||||
|
* Skip in early metrics mode to avoid triggering third-party hooks
|
||||||
|
* that may cause recursion issues (e.g., Twig-based plugins).
|
||||||
|
*
|
||||||
* @param Collector $collector The metrics collector instance.
|
* @param Collector $collector The metrics collector instance.
|
||||||
*/
|
*/
|
||||||
do_action( 'wp_prometheus_collect_metrics', $this );
|
if ( ! defined( 'WP_PROMETHEUS_EARLY_METRICS' ) || ! WP_PROMETHEUS_EARLY_METRICS ) {
|
||||||
|
do_action( 'wp_prometheus_collect_metrics', $this );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Plugin Name: WP Prometheus
|
* Plugin Name: WP Prometheus
|
||||||
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wp-prometheus
|
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wp-prometheus
|
||||||
* Description: Prometheus metrics endpoint for WordPress with extensible hooks for custom metrics.
|
* Description: Prometheus metrics endpoint for WordPress with extensible hooks for custom metrics.
|
||||||
* Version: 0.4.0
|
* Version: 0.4.2
|
||||||
* Requires at least: 6.4
|
* Requires at least: 6.4
|
||||||
* Requires PHP: 8.3
|
* Requires PHP: 8.3
|
||||||
* Author: Marco Graetsch
|
* Author: Marco Graetsch
|
||||||
@@ -21,12 +21,116 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Early metrics endpoint handler.
|
||||||
|
*
|
||||||
|
* Intercepts /metrics requests before full WordPress initialization to avoid
|
||||||
|
* conflicts with other plugins that may cause issues during template loading.
|
||||||
|
* This runs at plugin load time, before plugins_loaded hook.
|
||||||
|
*/
|
||||||
|
function wp_prometheus_early_metrics_check(): void {
|
||||||
|
// Only handle /metrics requests.
|
||||||
|
$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
|
||||||
|
$path = wp_parse_url( $request_uri, PHP_URL_PATH );
|
||||||
|
|
||||||
|
if ( ! preg_match( '#/metrics/?$#', $path ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if early mode is disabled via environment variable.
|
||||||
|
$env_disable = getenv( 'WP_PROMETHEUS_DISABLE_EARLY_MODE' );
|
||||||
|
if ( false !== $env_disable && in_array( strtolower( $env_disable ), array( '1', 'true', 'yes', 'on' ), true ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if early mode is disabled via option.
|
||||||
|
// We can use get_option() here because WordPress core is already loaded.
|
||||||
|
if ( get_option( 'wp_prometheus_disable_early_mode', false ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if autoloader exists.
|
||||||
|
$autoloader = __DIR__ . '/vendor/autoload.php';
|
||||||
|
if ( ! file_exists( $autoloader ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once $autoloader;
|
||||||
|
|
||||||
|
// Check license validity.
|
||||||
|
if ( ! \Magdev\WpPrometheus\License\Manager::is_license_valid() ) {
|
||||||
|
return; // Let normal flow handle unlicensed state.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticate.
|
||||||
|
$auth_token = get_option( 'wp_prometheus_auth_token', '' );
|
||||||
|
if ( empty( $auth_token ) ) {
|
||||||
|
status_header( 401 );
|
||||||
|
header( 'WWW-Authenticate: Bearer realm="WP Prometheus Metrics"' );
|
||||||
|
header( 'Content-Type: text/plain; charset=utf-8' );
|
||||||
|
echo 'Unauthorized';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Bearer token.
|
||||||
|
$auth_header = '';
|
||||||
|
if ( isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) {
|
||||||
|
$auth_header = sanitize_text_field( wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] ) );
|
||||||
|
} elseif ( isset( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) {
|
||||||
|
$auth_header = sanitize_text_field( wp_unslash( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
$authenticated = false;
|
||||||
|
if ( ! empty( $auth_header ) && preg_match( '/Bearer\s+(.*)$/i', $auth_header, $matches ) ) {
|
||||||
|
$authenticated = hash_equals( $auth_token, $matches[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check query parameter fallback.
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Auth token check.
|
||||||
|
if ( ! $authenticated && isset( $_GET['token'] ) ) {
|
||||||
|
$authenticated = hash_equals( $auth_token, sanitize_text_field( wp_unslash( $_GET['token'] ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $authenticated ) {
|
||||||
|
status_header( 401 );
|
||||||
|
header( 'WWW-Authenticate: Bearer realm="WP Prometheus Metrics"' );
|
||||||
|
header( 'Content-Type: text/plain; charset=utf-8' );
|
||||||
|
echo 'Unauthorized';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set flag to indicate early metrics mode - Collector will skip extensibility hooks.
|
||||||
|
define( 'WP_PROMETHEUS_EARLY_METRICS', true );
|
||||||
|
|
||||||
|
// Remove all content filters to prevent recursion with Twig-based plugins.
|
||||||
|
remove_all_filters( 'the_content' );
|
||||||
|
remove_all_filters( 'the_excerpt' );
|
||||||
|
remove_all_filters( 'get_the_excerpt' );
|
||||||
|
remove_all_filters( 'the_title' );
|
||||||
|
|
||||||
|
// Output metrics and exit immediately.
|
||||||
|
$collector = new \Magdev\WpPrometheus\Metrics\Collector();
|
||||||
|
|
||||||
|
status_header( 200 );
|
||||||
|
header( 'Content-Type: text/plain; version=0.0.4; charset=utf-8' );
|
||||||
|
header( 'Cache-Control: no-cache, no-store, must-revalidate' );
|
||||||
|
header( 'Pragma: no-cache' );
|
||||||
|
header( 'Expires: 0' );
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Prometheus format.
|
||||||
|
echo $collector->render();
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try early metrics handling before full plugin initialization.
|
||||||
|
wp_prometheus_early_metrics_check();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin version.
|
* Plugin version.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
define( 'WP_PROMETHEUS_VERSION', '0.4.0' );
|
define( 'WP_PROMETHEUS_VERSION', '0.4.2' );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin file path.
|
* Plugin file path.
|
||||||
|
|||||||
Reference in New Issue
Block a user