You've already forked wp-prometheus
Initial plugin setup (v0.0.1)
Some checks failed
Create Release Package / build-release (push) Failing after 48s
Some checks failed
Create Release Package / build-release (push) Failing after 48s
- Create initial WordPress plugin structure - Add Prometheus metrics collector with default metrics - Implement authenticated /metrics endpoint with Bearer token - Add license management integration - Create admin settings page under Settings > Metrics - Set up Gitea CI/CD pipeline for automated releases - Add extensibility via wp_prometheus_collect_metrics hook Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
148
src/Endpoint/MetricsEndpoint.php
Normal file
148
src/Endpoint/MetricsEndpoint.php
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
/**
|
||||
* Metrics endpoint class.
|
||||
*
|
||||
* @package WP_Prometheus
|
||||
*/
|
||||
|
||||
namespace Magdev\WpPrometheus\Endpoint;
|
||||
|
||||
use Magdev\WpPrometheus\Metrics\Collector;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* MetricsEndpoint class.
|
||||
*
|
||||
* Provides the /metrics endpoint for Prometheus scraping.
|
||||
*/
|
||||
class MetricsEndpoint {
|
||||
|
||||
/**
|
||||
* Metrics collector instance.
|
||||
*
|
||||
* @var Collector
|
||||
*/
|
||||
private Collector $collector;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Collector $collector Metrics collector instance.
|
||||
*/
|
||||
public function __construct( Collector $collector ) {
|
||||
$this->collector = $collector;
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize WordPress hooks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function init_hooks(): void {
|
||||
add_action( 'init', array( $this, 'register_endpoint' ) );
|
||||
add_action( 'template_redirect', array( $this, 'handle_request' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the metrics endpoint rewrite rule.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_endpoint(): void {
|
||||
add_rewrite_rule(
|
||||
'^metrics/?$',
|
||||
'index.php?wp_prometheus_metrics=1',
|
||||
'top'
|
||||
);
|
||||
|
||||
add_rewrite_tag( '%wp_prometheus_metrics%', '([^&]+)' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the metrics endpoint request.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle_request(): void {
|
||||
if ( ! get_query_var( 'wp_prometheus_metrics' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Authenticate the request.
|
||||
if ( ! $this->authenticate() ) {
|
||||
status_header( 401 );
|
||||
header( 'WWW-Authenticate: Bearer realm="WP Prometheus Metrics"' );
|
||||
header( 'Content-Type: text/plain; charset=utf-8' );
|
||||
echo 'Unauthorized';
|
||||
exit;
|
||||
}
|
||||
|
||||
// Output metrics.
|
||||
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 $this->collector->render();
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the metrics request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function authenticate(): bool {
|
||||
$auth_token = get_option( 'wp_prometheus_auth_token', '' );
|
||||
|
||||
// If no token is set, deny access.
|
||||
if ( empty( $auth_token ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for Bearer token in Authorization header.
|
||||
$auth_header = $this->get_authorization_header();
|
||||
if ( ! empty( $auth_header ) && preg_match( '/Bearer\s+(.*)$/i', $auth_header, $matches ) ) {
|
||||
return hash_equals( $auth_token, $matches[1] );
|
||||
}
|
||||
|
||||
// Check for token in query parameter (less secure but useful for testing).
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Auth token check.
|
||||
if ( isset( $_GET['token'] ) && hash_equals( $auth_token, sanitize_text_field( wp_unslash( $_GET['token'] ) ) ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Authorization header from the request.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_authorization_header(): string {
|
||||
if ( isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) {
|
||||
return sanitize_text_field( wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] ) );
|
||||
}
|
||||
|
||||
if ( isset( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) {
|
||||
return sanitize_text_field( wp_unslash( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) );
|
||||
}
|
||||
|
||||
if ( function_exists( 'apache_request_headers' ) ) {
|
||||
$headers = apache_request_headers();
|
||||
if ( isset( $headers['Authorization'] ) ) {
|
||||
return sanitize_text_field( $headers['Authorization'] );
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user