You've already forked wp-prometheus
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 898af5e9d2 |
32
CHANGELOG.md
32
CHANGELOG.md
@@ -5,6 +5,38 @@ 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/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.4.0] - 2026-02-02
|
||||
|
||||
### Added
|
||||
|
||||
- Persistent Storage Support:
|
||||
- Redis storage adapter for shared metrics across multiple instances
|
||||
- APCu storage adapter for single-server high-performance caching
|
||||
- StorageFactory class for automatic adapter selection and fallback
|
||||
- Connection testing with detailed error messages
|
||||
- New "Storage" tab in admin settings:
|
||||
- Storage adapter selection (In-Memory, Redis, APCu)
|
||||
- Redis configuration (host, port, password, database, key prefix)
|
||||
- APCu configuration (key prefix)
|
||||
- Connection test button
|
||||
- Environment variables documentation
|
||||
- Environment variable configuration for Docker/containerized environments:
|
||||
- `WP_PROMETHEUS_STORAGE_ADAPTER` - Select storage adapter
|
||||
- `WP_PROMETHEUS_REDIS_HOST` - Redis server hostname
|
||||
- `WP_PROMETHEUS_REDIS_PORT` - Redis server port
|
||||
- `WP_PROMETHEUS_REDIS_PASSWORD` - Redis authentication
|
||||
- `WP_PROMETHEUS_REDIS_DATABASE` - Redis database index (0-15)
|
||||
- `WP_PROMETHEUS_REDIS_PREFIX` - Redis key prefix
|
||||
- `WP_PROMETHEUS_APCU_PREFIX` - APCu key prefix
|
||||
- Automatic fallback to In-Memory storage if configured adapter fails
|
||||
- Docker Compose example in admin settings
|
||||
|
||||
### Changed
|
||||
|
||||
- Settings page now has 6 tabs: License, Metrics, Storage, Custom Metrics, Dashboards, Help
|
||||
- Updated translations with all new strings (English and German)
|
||||
- Collector now uses StorageFactory for storage adapter instantiation
|
||||
|
||||
## [0.3.0] - 2026-02-02
|
||||
|
||||
### Added
|
||||
|
||||
31
CLAUDE.md
31
CLAUDE.md
@@ -234,7 +234,8 @@ wp-prometheus/
|
||||
│ ├── Metrics/
|
||||
│ │ ├── Collector.php # Prometheus metrics collector
|
||||
│ │ ├── CustomMetricBuilder.php # Custom metric CRUD
|
||||
│ │ └── RuntimeCollector.php # Runtime metrics collector
|
||||
│ │ ├── RuntimeCollector.php # Runtime metrics collector
|
||||
│ │ └── StorageFactory.php # Storage adapter factory
|
||||
│ ├── Installer.php # Activation/Deactivation
|
||||
│ ├── Plugin.php # Main plugin class
|
||||
│ └── index.php
|
||||
@@ -290,6 +291,34 @@ add_action( 'wp_prometheus_collect_metrics', function( $collector ) {
|
||||
|
||||
## Session History
|
||||
|
||||
### 2026-02-02 - Persistent Storage (v0.4.0)
|
||||
|
||||
- Added persistent storage support for metrics:
|
||||
- `StorageFactory.php` - Factory class for storage adapter instantiation
|
||||
- Redis storage adapter for shared metrics across multiple instances
|
||||
- APCu storage adapter for single-server high-performance caching
|
||||
- Automatic fallback to In-Memory if configured adapter fails
|
||||
- Added new "Storage" tab in admin settings:
|
||||
- Storage adapter selection (In-Memory, Redis, APCu)
|
||||
- Redis configuration (host, port, password, database, key prefix)
|
||||
- APCu configuration (key prefix)
|
||||
- Connection test button with detailed error messages
|
||||
- Added environment variable support for Docker deployments:
|
||||
- `WP_PROMETHEUS_STORAGE_ADAPTER` - Adapter selection
|
||||
- `WP_PROMETHEUS_REDIS_HOST`, `_PORT`, `_PASSWORD`, `_DATABASE`, `_PREFIX`
|
||||
- `WP_PROMETHEUS_APCU_PREFIX`
|
||||
- Environment variables take precedence over admin settings
|
||||
- Updated `Collector.php` to use `StorageFactory::get_adapter()`
|
||||
- Updated Help tab with storage backends documentation
|
||||
- Updated translation files with all new strings
|
||||
- **Key Learning**: promphp/prometheus_client_php storage adapters
|
||||
- Redis adapter requires options array with host, port, password, timeout
|
||||
- APCu adapter just needs a prefix string
|
||||
- Use `Redis::setPrefix()` before instantiation for custom key prefixes
|
||||
- **Key Learning**: Docker environment variable configuration
|
||||
- Use `getenv()` with explicit false check (`false !== getenv()`)
|
||||
- Environment variables should override WordPress options for containerized deployments
|
||||
|
||||
### 2026-02-02 - Custom Metrics & Dashboards (v0.3.0)
|
||||
|
||||
- Added Custom Metric Builder with full admin UI:
|
||||
|
||||
61
PLAN.md
61
PLAN.md
@@ -59,6 +59,7 @@ wp-prometheus/
|
||||
│ └── release.yml # CI/CD pipeline
|
||||
├── assets/
|
||||
│ ├── css/ # Admin/Frontend styles
|
||||
│ ├── dashboards/ # Grafana dashboard templates
|
||||
│ └── js/
|
||||
│ └── admin.js # Admin JavaScript
|
||||
├── languages/ # Translation files
|
||||
@@ -67,13 +68,17 @@ wp-prometheus/
|
||||
├── releases/ # Release packages
|
||||
├── src/
|
||||
│ ├── Admin/
|
||||
│ │ ├── DashboardProvider.php
|
||||
│ │ └── Settings.php
|
||||
│ ├── Endpoint/
|
||||
│ │ └── MetricsEndpoint.php
|
||||
│ ├── License/
|
||||
│ │ └── Manager.php
|
||||
│ ├── Metrics/
|
||||
│ │ └── Collector.php
|
||||
│ │ ├── Collector.php
|
||||
│ │ ├── CustomMetricBuilder.php
|
||||
│ │ ├── RuntimeCollector.php
|
||||
│ │ └── StorageFactory.php
|
||||
│ ├── Installer.php
|
||||
│ ├── Plugin.php
|
||||
│ └── index.php
|
||||
@@ -159,13 +164,57 @@ Alternatively, the token can be passed as a query parameter (for testing):
|
||||
https://example.com/metrics/?token=your-auth-token
|
||||
```
|
||||
|
||||
## Storage Configuration
|
||||
|
||||
The plugin supports multiple storage backends for Prometheus metrics:
|
||||
|
||||
### Available Adapters
|
||||
|
||||
| Adapter | Description | Use Case |
|
||||
| --------- | ------------------------------- | ------------------------------------- |
|
||||
| In-Memory | Default, no persistence | Development, single request metrics |
|
||||
| Redis | Shared storage across instances | Production, load-balanced environments|
|
||||
| APCu | High-performance local cache | Production, single-server deployments |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
For Docker or containerized environments, configure storage via environment variables:
|
||||
|
||||
```bash
|
||||
# Storage adapter selection
|
||||
WP_PROMETHEUS_STORAGE_ADAPTER=redis
|
||||
|
||||
# Redis configuration
|
||||
WP_PROMETHEUS_REDIS_HOST=redis
|
||||
WP_PROMETHEUS_REDIS_PORT=6379
|
||||
WP_PROMETHEUS_REDIS_PASSWORD=secret
|
||||
WP_PROMETHEUS_REDIS_DATABASE=0
|
||||
WP_PROMETHEUS_REDIS_PREFIX=WORDPRESS_PROMETHEUS_
|
||||
|
||||
# APCu configuration
|
||||
WP_PROMETHEUS_APCU_PREFIX=wp_prom
|
||||
```
|
||||
|
||||
### Docker Compose Example
|
||||
|
||||
```yaml
|
||||
services:
|
||||
wordpress:
|
||||
image: wordpress:latest
|
||||
environment:
|
||||
WP_PROMETHEUS_STORAGE_ADAPTER: redis
|
||||
WP_PROMETHEUS_REDIS_HOST: redis
|
||||
WP_PROMETHEUS_REDIS_PORT: 6379
|
||||
depends_on:
|
||||
- redis
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Version 0.3.0
|
||||
|
||||
- Custom metric builder in admin
|
||||
- Metric export/import
|
||||
- Grafana dashboard templates
|
||||
*No planned features at this time.*
|
||||
|
||||
## Dependencies
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
|
||||
// Runtime metrics reset handler.
|
||||
initResetRuntimeHandler();
|
||||
|
||||
// Storage tab handlers.
|
||||
initStorageHandlers();
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -613,4 +616,131 @@
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize storage tab handlers.
|
||||
*/
|
||||
function initStorageHandlers() {
|
||||
var $form = $('#wp-prometheus-storage-form');
|
||||
var $adapterSelect = $('#storage-adapter');
|
||||
|
||||
// Show/hide adapter-specific config.
|
||||
$adapterSelect.on('change', function() {
|
||||
var adapter = $(this).val();
|
||||
$('#redis-config').toggle(adapter === 'redis');
|
||||
$('#apcu-config').toggle(adapter === 'apcu');
|
||||
});
|
||||
|
||||
// Save storage settings.
|
||||
$form.on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
saveStorageSettings();
|
||||
});
|
||||
|
||||
// Test storage connection.
|
||||
$('#test-storage').on('click', function() {
|
||||
testStorageConnection();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Save storage settings via AJAX.
|
||||
*/
|
||||
function saveStorageSettings() {
|
||||
var $spinner = $('#wp-prometheus-storage-spinner');
|
||||
var $message = $('#wp-prometheus-storage-message');
|
||||
var $form = $('#wp-prometheus-storage-form');
|
||||
|
||||
$spinner.addClass('is-active');
|
||||
$message.hide();
|
||||
|
||||
var formData = $form.serialize();
|
||||
formData += '&action=wp_prometheus_save_storage';
|
||||
formData += '&nonce=' + wpPrometheus.storageNonce;
|
||||
|
||||
$.ajax({
|
||||
url: wpPrometheus.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
success: function(response) {
|
||||
$spinner.removeClass('is-active');
|
||||
|
||||
if (response.success) {
|
||||
var noticeClass = response.data.warning ? 'notice-warning' : 'notice-success';
|
||||
$message
|
||||
.removeClass('notice-error notice-success notice-warning')
|
||||
.addClass('notice ' + noticeClass)
|
||||
.html('<p>' + response.data.message + '</p>')
|
||||
.show();
|
||||
|
||||
if (!response.data.warning) {
|
||||
setTimeout(function() {
|
||||
location.reload();
|
||||
}, 1500);
|
||||
}
|
||||
} else {
|
||||
$message
|
||||
.removeClass('notice-success notice-warning')
|
||||
.addClass('notice notice-error')
|
||||
.html('<p>' + (response.data.message || 'An error occurred.') + '</p>')
|
||||
.show();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$spinner.removeClass('is-active');
|
||||
$message
|
||||
.removeClass('notice-success notice-warning')
|
||||
.addClass('notice notice-error')
|
||||
.html('<p>Connection error. Please try again.</p>')
|
||||
.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test storage connection via AJAX.
|
||||
*/
|
||||
function testStorageConnection() {
|
||||
var $spinner = $('#wp-prometheus-storage-spinner');
|
||||
var $message = $('#wp-prometheus-storage-message');
|
||||
var $form = $('#wp-prometheus-storage-form');
|
||||
|
||||
$spinner.addClass('is-active');
|
||||
$message.hide();
|
||||
|
||||
var formData = $form.serialize();
|
||||
formData += '&action=wp_prometheus_test_storage';
|
||||
formData += '&nonce=' + wpPrometheus.storageNonce;
|
||||
|
||||
$.ajax({
|
||||
url: wpPrometheus.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
success: function(response) {
|
||||
$spinner.removeClass('is-active');
|
||||
|
||||
if (response.success) {
|
||||
$message
|
||||
.removeClass('notice-error notice-warning')
|
||||
.addClass('notice notice-success')
|
||||
.html('<p>' + response.data.message + '</p>')
|
||||
.show();
|
||||
} else {
|
||||
$message
|
||||
.removeClass('notice-success notice-warning')
|
||||
.addClass('notice notice-error')
|
||||
.html('<p>' + (response.data.message || 'Connection test failed.') + '</p>')
|
||||
.show();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$spinner.removeClass('is-active');
|
||||
$message
|
||||
.removeClass('notice-success notice-warning')
|
||||
.addClass('notice notice-error')
|
||||
.html('<p>Connection error. Please try again.</p>')
|
||||
.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
})(jQuery);
|
||||
|
||||
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WP Prometheus 0.3.0\n"
|
||||
"Project-Id-Version: WP Prometheus 0.4.0\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"
|
||||
"PO-Revision-Date: 2026-02-02T00:00:00+00:00\n"
|
||||
@@ -617,3 +617,265 @@ msgstr "WP Prometheus erfordert installierte Composer-Abhaengigkeiten. Bitte fue
|
||||
#: wp-prometheus.php
|
||||
msgid "WP Prometheus requires PHP version %s or higher."
|
||||
msgstr "WP Prometheus erfordert PHP-Version %s oder hoeher."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage"
|
||||
msgstr "Speicher"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Metrics Storage Configuration"
|
||||
msgstr "Metriken-Speicherkonfiguration"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Configure how Prometheus metrics are stored. Persistent storage (Redis, APCu) allows metrics to survive between requests and aggregate data over time."
|
||||
msgstr "Konfigurieren Sie, wie Prometheus-Metriken gespeichert werden. Persistenter Speicher (Redis, APCu) ermoeglicht es, Metriken zwischen Anfragen zu erhalten und Daten ueber Zeit zu aggregieren."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Environment Override Active"
|
||||
msgstr "Umgebungsvariablen-Ueberschreibung aktiv"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage adapter is configured via environment variable. Admin settings will be ignored."
|
||||
msgstr "Speicher-Adapter ist ueber Umgebungsvariable konfiguriert. Admin-Einstellungen werden ignoriert."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage Fallback Active"
|
||||
msgstr "Speicher-Fallback aktiv"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Falling back to In-Memory storage."
|
||||
msgstr "Faellt zurueck auf In-Memory-Speicher."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Current Status:"
|
||||
msgstr "Aktueller Status:"
|
||||
|
||||
#. translators: %s: Active adapter name
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Using %s storage."
|
||||
msgstr "Verwende %s-Speicher."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage Adapter"
|
||||
msgstr "Speicher-Adapter"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "unavailable"
|
||||
msgstr "nicht verfuegbar"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Select the storage backend for metrics. Redis and APCu require their respective PHP extensions."
|
||||
msgstr "Waehlen Sie das Speicher-Backend fuer Metriken. Redis und APCu erfordern ihre jeweiligen PHP-Erweiterungen."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis Configuration"
|
||||
msgstr "Redis-Konfiguration"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Host"
|
||||
msgstr "Host"
|
||||
|
||||
#. translators: %s: Environment variable name
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Can be overridden with %s environment variable."
|
||||
msgstr "Kann mit Umgebungsvariable %s ueberschrieben werden."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Password"
|
||||
msgstr "Passwort"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Leave empty if not required"
|
||||
msgstr "Leer lassen, falls nicht erforderlich"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Database"
|
||||
msgstr "Datenbank"
|
||||
|
||||
#. translators: %s: Environment variable name
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis database index (0-15). Can be overridden with %s."
|
||||
msgstr "Redis-Datenbankindex (0-15). Kann mit %s ueberschrieben werden."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Key Prefix"
|
||||
msgstr "Schluessel-Praefix"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Prefix for Redis keys. Useful when sharing Redis with other applications."
|
||||
msgstr "Praefix fuer Redis-Schluessel. Nuetzlich bei gemeinsamer Redis-Nutzung mit anderen Anwendungen."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "APCu Configuration"
|
||||
msgstr "APCu-Konfiguration"
|
||||
|
||||
#. translators: %s: Environment variable name
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Prefix for APCu keys. Can be overridden with %s."
|
||||
msgstr "Praefix fuer APCu-Schluessel. Kann mit %s ueberschrieben werden."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Save Storage Settings"
|
||||
msgstr "Speicher-Einstellungen speichern"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Test Connection"
|
||||
msgstr "Verbindung testen"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Environment Variables"
|
||||
msgstr "Umgebungsvariablen"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "For Docker or containerized environments, you can configure storage using environment variables. These take precedence over admin settings."
|
||||
msgstr "Fuer Docker- oder Container-Umgebungen koennen Sie den Speicher ueber Umgebungsvariablen konfigurieren. Diese haben Vorrang vor Admin-Einstellungen."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Variable"
|
||||
msgstr "Variable"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Example"
|
||||
msgstr "Beispiel"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage adapter to use"
|
||||
msgstr "Zu verwendender Speicher-Adapter"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis server hostname"
|
||||
msgstr "Redis-Server-Hostname"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis server port"
|
||||
msgstr "Redis-Server-Port"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis authentication password"
|
||||
msgstr "Redis-Authentifizierungspasswort"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis database index"
|
||||
msgstr "Redis-Datenbankindex"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis key prefix"
|
||||
msgstr "Redis-Schluessel-Praefix"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "APCu key prefix"
|
||||
msgstr "APCu-Schluessel-Praefix"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Docker Compose Example"
|
||||
msgstr "Docker Compose-Beispiel"
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Permission denied."
|
||||
msgstr "Zugriff verweigert."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage adapter is configured via environment variable and cannot be changed."
|
||||
msgstr "Speicher-Adapter ist ueber Umgebungsvariable konfiguriert und kann nicht geaendert werden."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Invalid storage adapter."
|
||||
msgstr "Ungueltiger Speicher-Adapter."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage settings saved successfully."
|
||||
msgstr "Speicher-Einstellungen erfolgreich gespeichert."
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage settings saved, but connection test failed:"
|
||||
msgstr "Speicher-Einstellungen gespeichert, aber Verbindungstest fehlgeschlagen:"
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "In-Memory (default, no persistence)"
|
||||
msgstr "In-Memory (Standard, keine Persistenz)"
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Redis (requires PHP Redis extension)"
|
||||
msgstr "Redis (erfordert PHP-Redis-Erweiterung)"
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu (requires APCu extension)"
|
||||
msgstr "APCu (erfordert APCu-Erweiterung)"
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "PHP Redis extension is not installed."
|
||||
msgstr "PHP-Redis-Erweiterung ist nicht installiert."
|
||||
|
||||
#. translators: %s: Error message
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Redis connection failed: %s"
|
||||
msgstr "Redis-Verbindung fehlgeschlagen: %s"
|
||||
|
||||
#. translators: %s: Error message
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Redis error: %s"
|
||||
msgstr "Redis-Fehler: %s"
|
||||
|
||||
#. translators: %s: Error message
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Storage error: %s"
|
||||
msgstr "Speicherfehler: %s"
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu extension is not installed."
|
||||
msgstr "APCu-Erweiterung ist nicht installiert."
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu is installed but not enabled."
|
||||
msgstr "APCu ist installiert, aber nicht aktiviert."
|
||||
|
||||
#. translators: %s: Error message
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu error: %s"
|
||||
msgstr "APCu-Fehler: %s"
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "In-Memory storage is always available."
|
||||
msgstr "In-Memory-Speicher ist immer verfuegbar."
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Unknown storage adapter."
|
||||
msgstr "Unbekannter Speicher-Adapter."
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Could not connect to Redis server."
|
||||
msgstr "Verbindung zum Redis-Server konnte nicht hergestellt werden."
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Redis authentication failed."
|
||||
msgstr "Redis-Authentifizierung fehlgeschlagen."
|
||||
|
||||
#. translators: %s: Redis host:port
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Successfully connected to Redis at %s."
|
||||
msgstr "Erfolgreich mit Redis verbunden unter %s."
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Redis ping failed."
|
||||
msgstr "Redis-Ping fehlgeschlagen."
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu is installed but not enabled. Check your php.ini settings."
|
||||
msgstr "APCu ist installiert, aber nicht aktiviert. Pruefen Sie Ihre php.ini-Einstellungen."
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu store operation failed."
|
||||
msgstr "APCu-Speicheroperation fehlgeschlagen."
|
||||
|
||||
#. translators: %s: Memory info
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu is working. Memory: %s used."
|
||||
msgstr "APCu funktioniert. Speicher: %s belegt."
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu fetch operation returned unexpected value."
|
||||
msgstr "APCu-Abrufoperation hat unerwarteten Wert zurueckgegeben."
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WP Prometheus 0.3.0\n"
|
||||
"Project-Id-Version: WP Prometheus 0.4.0\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"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -614,3 +614,265 @@ msgstr ""
|
||||
#: wp-prometheus.php
|
||||
msgid "WP Prometheus requires PHP version %s or higher."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Metrics Storage Configuration"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Configure how Prometheus metrics are stored. Persistent storage (Redis, APCu) allows metrics to survive between requests and aggregate data over time."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Environment Override Active"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage adapter is configured via environment variable. Admin settings will be ignored."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage Fallback Active"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Falling back to In-Memory storage."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Current Status:"
|
||||
msgstr ""
|
||||
|
||||
#. translators: %s: Active adapter name
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Using %s storage."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage Adapter"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "unavailable"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Select the storage backend for metrics. Redis and APCu require their respective PHP extensions."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis Configuration"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Host"
|
||||
msgstr ""
|
||||
|
||||
#. translators: %s: Environment variable name
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Can be overridden with %s environment variable."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Leave empty if not required"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Database"
|
||||
msgstr ""
|
||||
|
||||
#. translators: %s: Environment variable name
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis database index (0-15). Can be overridden with %s."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Key Prefix"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Prefix for Redis keys. Useful when sharing Redis with other applications."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "APCu Configuration"
|
||||
msgstr ""
|
||||
|
||||
#. translators: %s: Environment variable name
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Prefix for APCu keys. Can be overridden with %s."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Save Storage Settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Test Connection"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Environment Variables"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "For Docker or containerized environments, you can configure storage using environment variables. These take precedence over admin settings."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Variable"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Example"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage adapter to use"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis server hostname"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis server port"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis authentication password"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis database index"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Redis key prefix"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "APCu key prefix"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Docker Compose Example"
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Permission denied."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage adapter is configured via environment variable and cannot be changed."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Invalid storage adapter."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage settings saved successfully."
|
||||
msgstr ""
|
||||
|
||||
#: src/Admin/Settings.php
|
||||
msgid "Storage settings saved, but connection test failed:"
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "In-Memory (default, no persistence)"
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Redis (requires PHP Redis extension)"
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu (requires APCu extension)"
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "PHP Redis extension is not installed."
|
||||
msgstr ""
|
||||
|
||||
#. translators: %s: Error message
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Redis connection failed: %s"
|
||||
msgstr ""
|
||||
|
||||
#. translators: %s: Error message
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Redis error: %s"
|
||||
msgstr ""
|
||||
|
||||
#. translators: %s: Error message
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Storage error: %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu extension is not installed."
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu is installed but not enabled."
|
||||
msgstr ""
|
||||
|
||||
#. translators: %s: Error message
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu error: %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "In-Memory storage is always available."
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Unknown storage adapter."
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Could not connect to Redis server."
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Redis authentication failed."
|
||||
msgstr ""
|
||||
|
||||
#. translators: %s: Redis host:port
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Successfully connected to Redis at %s."
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "Redis ping failed."
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu is installed but not enabled. Check your php.ini settings."
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu store operation failed."
|
||||
msgstr ""
|
||||
|
||||
#. translators: %s: Memory info
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu is working. Memory: %s used."
|
||||
msgstr ""
|
||||
|
||||
#: src/Metrics/StorageFactory.php
|
||||
msgid "APCu fetch operation returned unexpected value."
|
||||
msgstr ""
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Magdev\WpPrometheus\Admin;
|
||||
use Magdev\WpPrometheus\License\Manager as LicenseManager;
|
||||
use Magdev\WpPrometheus\Metrics\CustomMetricBuilder;
|
||||
use Magdev\WpPrometheus\Metrics\RuntimeCollector;
|
||||
use Magdev\WpPrometheus\Metrics\StorageFactory;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
@@ -51,6 +52,7 @@ class Settings {
|
||||
$this->tabs = array(
|
||||
'license' => __( 'License', 'wp-prometheus' ),
|
||||
'metrics' => __( 'Metrics', 'wp-prometheus' ),
|
||||
'storage' => __( 'Storage', 'wp-prometheus' ),
|
||||
'custom' => __( 'Custom Metrics', 'wp-prometheus' ),
|
||||
'dashboards' => __( 'Dashboards', 'wp-prometheus' ),
|
||||
'help' => __( 'Help', 'wp-prometheus' ),
|
||||
@@ -70,6 +72,8 @@ class Settings {
|
||||
add_action( 'wp_ajax_wp_prometheus_import_metrics', array( $this, 'ajax_import_metrics' ) );
|
||||
add_action( 'wp_ajax_wp_prometheus_download_dashboard', array( $this, 'ajax_download_dashboard' ) );
|
||||
add_action( 'wp_ajax_wp_prometheus_reset_runtime_metrics', array( $this, 'ajax_reset_runtime_metrics' ) );
|
||||
add_action( 'wp_ajax_wp_prometheus_save_storage', array( $this, 'ajax_save_storage' ) );
|
||||
add_action( 'wp_ajax_wp_prometheus_test_storage', array( $this, 'ajax_test_storage' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,6 +187,7 @@ class Settings {
|
||||
'importNonce' => wp_create_nonce( 'wp_prometheus_import' ),
|
||||
'dashboardNonce' => wp_create_nonce( 'wp_prometheus_dashboard' ),
|
||||
'resetRuntimeNonce' => wp_create_nonce( 'wp_prometheus_reset_runtime' ),
|
||||
'storageNonce' => wp_create_nonce( 'wp_prometheus_storage' ),
|
||||
'confirmDelete' => __( 'Are you sure you want to delete this metric?', 'wp-prometheus' ),
|
||||
'confirmReset' => __( 'Are you sure you want to reset all runtime metrics? This cannot be undone.', 'wp-prometheus' ),
|
||||
'confirmRegenerateToken' => __( 'Are you sure you want to regenerate the auth token? You will need to update your Prometheus configuration.', 'wp-prometheus' ),
|
||||
@@ -226,6 +231,9 @@ class Settings {
|
||||
case 'metrics':
|
||||
$this->render_metrics_tab();
|
||||
break;
|
||||
case 'storage':
|
||||
$this->render_storage_tab();
|
||||
break;
|
||||
case 'custom':
|
||||
$this->render_custom_metrics_tab();
|
||||
break;
|
||||
@@ -415,6 +423,282 @@ class Settings {
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render storage tab content.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function render_storage_tab(): void {
|
||||
$configured_adapter = StorageFactory::get_configured_adapter();
|
||||
$active_adapter = StorageFactory::get_active_adapter();
|
||||
$last_error = StorageFactory::get_last_error();
|
||||
$redis_config = StorageFactory::get_redis_config();
|
||||
$apcu_prefix = StorageFactory::get_apcu_prefix();
|
||||
$adapters = StorageFactory::get_available_adapters();
|
||||
|
||||
// Check environment variable overrides.
|
||||
$env_override = false !== getenv( 'WP_PROMETHEUS_STORAGE_ADAPTER' );
|
||||
?>
|
||||
<div class="wp-prometheus-storage">
|
||||
<h2><?php esc_html_e( 'Metrics Storage Configuration', 'wp-prometheus' ); ?></h2>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Configure how Prometheus metrics are stored. Persistent storage (Redis, APCu) allows metrics to survive between requests and aggregate data over time.', 'wp-prometheus' ); ?>
|
||||
</p>
|
||||
|
||||
<?php if ( $env_override ) : ?>
|
||||
<div class="notice notice-info" style="padding: 12px; margin: 15px 0;">
|
||||
<strong><?php esc_html_e( 'Environment Override Active', 'wp-prometheus' ); ?></strong>
|
||||
<p><?php esc_html_e( 'Storage adapter is configured via environment variable. Admin settings will be ignored.', 'wp-prometheus' ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $last_error ) ) : ?>
|
||||
<div class="notice notice-warning" style="padding: 12px; margin: 15px 0;">
|
||||
<strong><?php esc_html_e( 'Storage Fallback Active', 'wp-prometheus' ); ?></strong>
|
||||
<p><?php echo esc_html( $last_error ); ?></p>
|
||||
<p><?php esc_html_e( 'Falling back to In-Memory storage.', 'wp-prometheus' ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="notice notice-<?php echo $active_adapter === $configured_adapter && empty( $last_error ) ? 'success' : 'warning'; ?>" style="padding: 12px; margin: 15px 0;">
|
||||
<strong><?php esc_html_e( 'Current Status:', 'wp-prometheus' ); ?></strong>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Active adapter name */
|
||||
esc_html__( 'Using %s storage.', 'wp-prometheus' ),
|
||||
'<code>' . esc_html( ucfirst( $active_adapter ) ) . '</code>'
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
|
||||
<form id="wp-prometheus-storage-form">
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="storage-adapter"><?php esc_html_e( 'Storage Adapter', 'wp-prometheus' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<select name="adapter" id="storage-adapter" <?php disabled( $env_override ); ?>>
|
||||
<?php foreach ( $adapters as $key => $label ) : ?>
|
||||
<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $configured_adapter, $key ); ?>>
|
||||
<?php echo esc_html( $label ); ?>
|
||||
<?php if ( ! StorageFactory::is_adapter_available( $key ) && 'inmemory' !== $key ) : ?>
|
||||
(<?php esc_html_e( 'unavailable', 'wp-prometheus' ); ?>)
|
||||
<?php endif; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Select the storage backend for metrics. Redis and APCu require their respective PHP extensions.', 'wp-prometheus' ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="redis-config" style="<?php echo 'redis' === $configured_adapter ? '' : 'display: none;'; ?>">
|
||||
<h3><?php esc_html_e( 'Redis Configuration', 'wp-prometheus' ); ?></h3>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="redis-host"><?php esc_html_e( 'Host', 'wp-prometheus' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="redis_host" id="redis-host" class="regular-text"
|
||||
value="<?php echo esc_attr( $redis_config['host'] ); ?>"
|
||||
placeholder="127.0.0.1">
|
||||
<p class="description">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Environment variable name */
|
||||
esc_html__( 'Can be overridden with %s environment variable.', 'wp-prometheus' ),
|
||||
'<code>WP_PROMETHEUS_REDIS_HOST</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="redis-port"><?php esc_html_e( 'Port', 'wp-prometheus' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="number" name="redis_port" id="redis-port" class="small-text"
|
||||
value="<?php echo esc_attr( $redis_config['port'] ); ?>"
|
||||
placeholder="6379" min="1" max="65535">
|
||||
<p class="description">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Environment variable name */
|
||||
esc_html__( 'Can be overridden with %s environment variable.', 'wp-prometheus' ),
|
||||
'<code>WP_PROMETHEUS_REDIS_PORT</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="redis-password"><?php esc_html_e( 'Password', 'wp-prometheus' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="password" name="redis_password" id="redis-password" class="regular-text"
|
||||
value="<?php echo esc_attr( $redis_config['password'] ); ?>"
|
||||
placeholder="<?php esc_attr_e( 'Leave empty if not required', 'wp-prometheus' ); ?>">
|
||||
<p class="description">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Environment variable name */
|
||||
esc_html__( 'Can be overridden with %s environment variable.', 'wp-prometheus' ),
|
||||
'<code>WP_PROMETHEUS_REDIS_PASSWORD</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="redis-database"><?php esc_html_e( 'Database', 'wp-prometheus' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="number" name="redis_database" id="redis-database" class="small-text"
|
||||
value="<?php echo esc_attr( $redis_config['database'] ); ?>"
|
||||
placeholder="0" min="0" max="15">
|
||||
<p class="description">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Environment variable name */
|
||||
esc_html__( 'Redis database index (0-15). Can be overridden with %s.', 'wp-prometheus' ),
|
||||
'<code>WP_PROMETHEUS_REDIS_DATABASE</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="redis-prefix"><?php esc_html_e( 'Key Prefix', 'wp-prometheus' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="redis_prefix" id="redis-prefix" class="regular-text"
|
||||
value="<?php echo esc_attr( $redis_config['prefix'] ); ?>"
|
||||
placeholder="WORDPRESS_PROMETHEUS_">
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Prefix for Redis keys. Useful when sharing Redis with other applications.', 'wp-prometheus' ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="apcu-config" style="<?php echo 'apcu' === $configured_adapter ? '' : 'display: none;'; ?>">
|
||||
<h3><?php esc_html_e( 'APCu Configuration', 'wp-prometheus' ); ?></h3>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="apcu-prefix"><?php esc_html_e( 'Key Prefix', 'wp-prometheus' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="apcu_prefix" id="apcu-prefix" class="regular-text"
|
||||
value="<?php echo esc_attr( $apcu_prefix ); ?>"
|
||||
placeholder="wp_prom">
|
||||
<p class="description">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Environment variable name */
|
||||
esc_html__( 'Prefix for APCu keys. Can be overridden with %s.', 'wp-prometheus' ),
|
||||
'<code>WP_PROMETHEUS_APCU_PREFIX</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p class="submit">
|
||||
<button type="submit" class="button button-primary" <?php disabled( $env_override ); ?>>
|
||||
<?php esc_html_e( 'Save Storage Settings', 'wp-prometheus' ); ?>
|
||||
</button>
|
||||
<button type="button" id="test-storage" class="button button-secondary">
|
||||
<?php esc_html_e( 'Test Connection', 'wp-prometheus' ); ?>
|
||||
</button>
|
||||
<span id="wp-prometheus-storage-spinner" class="spinner" style="float: none;"></span>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<div id="wp-prometheus-storage-message" style="display: none; margin-top: 10px;"></div>
|
||||
|
||||
<hr style="margin: 30px 0;">
|
||||
|
||||
<h3><?php esc_html_e( 'Environment Variables', 'wp-prometheus' ); ?></h3>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'For Docker or containerized environments, you can configure storage using environment variables. These take precedence over admin settings.', 'wp-prometheus' ); ?>
|
||||
</p>
|
||||
|
||||
<table class="widefat striped" style="margin: 15px 0; max-width: 800px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Variable', 'wp-prometheus' ); ?></th>
|
||||
<th><?php esc_html_e( 'Description', 'wp-prometheus' ); ?></th>
|
||||
<th><?php esc_html_e( 'Example', 'wp-prometheus' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>WP_PROMETHEUS_STORAGE_ADAPTER</code></td>
|
||||
<td><?php esc_html_e( 'Storage adapter to use', 'wp-prometheus' ); ?></td>
|
||||
<td><code>redis</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WP_PROMETHEUS_REDIS_HOST</code></td>
|
||||
<td><?php esc_html_e( 'Redis server hostname', 'wp-prometheus' ); ?></td>
|
||||
<td><code>redis</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WP_PROMETHEUS_REDIS_PORT</code></td>
|
||||
<td><?php esc_html_e( 'Redis server port', 'wp-prometheus' ); ?></td>
|
||||
<td><code>6379</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WP_PROMETHEUS_REDIS_PASSWORD</code></td>
|
||||
<td><?php esc_html_e( 'Redis authentication password', 'wp-prometheus' ); ?></td>
|
||||
<td><code>secret123</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WP_PROMETHEUS_REDIS_DATABASE</code></td>
|
||||
<td><?php esc_html_e( 'Redis database index', 'wp-prometheus' ); ?></td>
|
||||
<td><code>0</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WP_PROMETHEUS_REDIS_PREFIX</code></td>
|
||||
<td><?php esc_html_e( 'Redis key prefix', 'wp-prometheus' ); ?></td>
|
||||
<td><code>MYSITE_PROM_</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WP_PROMETHEUS_APCU_PREFIX</code></td>
|
||||
<td><?php esc_html_e( 'APCu key prefix', 'wp-prometheus' ); ?></td>
|
||||
<td><code>wp_prom</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4><?php esc_html_e( 'Docker Compose Example', 'wp-prometheus' ); ?></h4>
|
||||
<pre style="background: #f1f1f1; padding: 15px; overflow-x: auto; margin: 15px 0;">services:
|
||||
wordpress:
|
||||
image: wordpress:latest
|
||||
environment:
|
||||
WP_PROMETHEUS_STORAGE_ADAPTER: redis
|
||||
WP_PROMETHEUS_REDIS_HOST: redis
|
||||
WP_PROMETHEUS_REDIS_PORT: 6379
|
||||
depends_on:
|
||||
- redis
|
||||
|
||||
redis:
|
||||
image: redis:alpine</pre>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render custom metrics tab content.
|
||||
*
|
||||
@@ -872,6 +1156,38 @@ class Settings {
|
||||
);
|
||||
$gauge->set( 42, array( 'value1', 'value2' ) );
|
||||
} );</pre>
|
||||
|
||||
<h3><?php esc_html_e( 'Storage Backends', 'wp-prometheus' ); ?></h3>
|
||||
<p><?php esc_html_e( 'The plugin supports multiple storage backends for metrics persistence:', 'wp-prometheus' ); ?></p>
|
||||
<table class="widefat striped" style="margin: 15px 0;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Adapter', 'wp-prometheus' ); ?></th>
|
||||
<th><?php esc_html_e( 'Description', 'wp-prometheus' ); ?></th>
|
||||
<th><?php esc_html_e( 'Use Case', 'wp-prometheus' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>In-Memory</strong></td>
|
||||
<td><?php esc_html_e( 'Default storage, no persistence between requests', 'wp-prometheus' ); ?></td>
|
||||
<td><?php esc_html_e( 'Development, testing', 'wp-prometheus' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Redis</strong></td>
|
||||
<td><?php esc_html_e( 'Shared storage, survives restarts', 'wp-prometheus' ); ?></td>
|
||||
<td><?php esc_html_e( 'Production, load-balanced environments', 'wp-prometheus' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>APCu</strong></td>
|
||||
<td><?php esc_html_e( 'Fast local cache, process-specific', 'wp-prometheus' ); ?></td>
|
||||
<td><?php esc_html_e( 'Production, single-server deployments', 'wp-prometheus' ); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Configure storage in the Storage tab. For Docker environments, use environment variables like WP_PROMETHEUS_STORAGE_ADAPTER.', 'wp-prometheus' ); ?>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
@@ -1210,4 +1526,102 @@ class Settings {
|
||||
|
||||
wp_send_json_success( array( 'message' => __( 'Runtime metrics have been reset.', 'wp-prometheus' ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for saving storage settings.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_save_storage(): void {
|
||||
check_ajax_referer( 'wp_prometheus_storage', 'nonce' );
|
||||
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-prometheus' ) ) );
|
||||
}
|
||||
|
||||
// Check if environment variable override is active.
|
||||
if ( false !== getenv( 'WP_PROMETHEUS_STORAGE_ADAPTER' ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Storage adapter is configured via environment variable and cannot be changed.', 'wp-prometheus' ) ) );
|
||||
}
|
||||
|
||||
$adapter = isset( $_POST['adapter'] ) ? sanitize_key( $_POST['adapter'] ) : 'inmemory';
|
||||
|
||||
// Validate adapter.
|
||||
$valid_adapters = array_keys( StorageFactory::get_available_adapters() );
|
||||
if ( ! in_array( $adapter, $valid_adapters, true ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Invalid storage adapter.', 'wp-prometheus' ) ) );
|
||||
}
|
||||
|
||||
// Build config array.
|
||||
$config = array(
|
||||
'adapter' => $adapter,
|
||||
);
|
||||
|
||||
// Redis config.
|
||||
if ( 'redis' === $adapter ) {
|
||||
$config['redis'] = array(
|
||||
'host' => isset( $_POST['redis_host'] ) ? sanitize_text_field( wp_unslash( $_POST['redis_host'] ) ) : '127.0.0.1',
|
||||
'port' => isset( $_POST['redis_port'] ) ? absint( $_POST['redis_port'] ) : 6379,
|
||||
'password' => isset( $_POST['redis_password'] ) ? sanitize_text_field( wp_unslash( $_POST['redis_password'] ) ) : '',
|
||||
'database' => isset( $_POST['redis_database'] ) ? absint( $_POST['redis_database'] ) : 0,
|
||||
'prefix' => isset( $_POST['redis_prefix'] ) ? sanitize_key( $_POST['redis_prefix'] ) : 'WORDPRESS_PROMETHEUS_',
|
||||
);
|
||||
}
|
||||
|
||||
// APCu config.
|
||||
if ( 'apcu' === $adapter ) {
|
||||
$config['apcu_prefix'] = isset( $_POST['apcu_prefix'] ) ? sanitize_key( $_POST['apcu_prefix'] ) : 'wp_prom';
|
||||
}
|
||||
|
||||
// Save configuration.
|
||||
StorageFactory::save_config( $config );
|
||||
|
||||
// Test if the new configuration works.
|
||||
$test_result = StorageFactory::test_connection( $adapter, $config['redis'] ?? array() );
|
||||
|
||||
if ( $test_result['success'] ) {
|
||||
wp_send_json_success( array(
|
||||
'message' => __( 'Storage settings saved successfully.', 'wp-prometheus' ) . ' ' . $test_result['message'],
|
||||
) );
|
||||
} else {
|
||||
wp_send_json_success( array(
|
||||
'message' => __( 'Storage settings saved, but connection test failed:', 'wp-prometheus' ) . ' ' . $test_result['message'],
|
||||
'warning' => true,
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for testing storage connection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_test_storage(): void {
|
||||
check_ajax_referer( 'wp_prometheus_storage', 'nonce' );
|
||||
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-prometheus' ) ) );
|
||||
}
|
||||
|
||||
$adapter = isset( $_POST['adapter'] ) ? sanitize_key( $_POST['adapter'] ) : 'inmemory';
|
||||
|
||||
// Build test config from form data.
|
||||
$config = array();
|
||||
if ( 'redis' === $adapter ) {
|
||||
$config = array(
|
||||
'host' => isset( $_POST['redis_host'] ) ? sanitize_text_field( wp_unslash( $_POST['redis_host'] ) ) : '127.0.0.1',
|
||||
'port' => isset( $_POST['redis_port'] ) ? absint( $_POST['redis_port'] ) : 6379,
|
||||
'password' => isset( $_POST['redis_password'] ) ? sanitize_text_field( wp_unslash( $_POST['redis_password'] ) ) : '',
|
||||
'database' => isset( $_POST['redis_database'] ) ? absint( $_POST['redis_database'] ) : 0,
|
||||
);
|
||||
}
|
||||
|
||||
$result = StorageFactory::test_connection( $adapter, $config );
|
||||
|
||||
if ( $result['success'] ) {
|
||||
wp_send_json_success( array( 'message' => $result['message'] ) );
|
||||
} else {
|
||||
wp_send_json_error( array( 'message' => $result['message'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
namespace Magdev\WpPrometheus\Metrics;
|
||||
|
||||
use Prometheus\CollectorRegistry;
|
||||
use Prometheus\Storage\InMemory;
|
||||
use Prometheus\RenderTextFormat;
|
||||
use Magdev\WpPrometheus\Metrics\CustomMetricBuilder;
|
||||
use Magdev\WpPrometheus\Metrics\StorageFactory;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
@@ -42,7 +42,7 @@ class Collector {
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->registry = new CollectorRegistry( new InMemory() );
|
||||
$this->registry = new CollectorRegistry( StorageFactory::get_adapter() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
502
src/Metrics/StorageFactory.php
Normal file
502
src/Metrics/StorageFactory.php
Normal file
@@ -0,0 +1,502 @@
|
||||
<?php
|
||||
/**
|
||||
* Storage factory for Prometheus metrics.
|
||||
*
|
||||
* @package WP_Prometheus
|
||||
*/
|
||||
|
||||
namespace Magdev\WpPrometheus\Metrics;
|
||||
|
||||
use Prometheus\Storage\Adapter;
|
||||
use Prometheus\Storage\InMemory;
|
||||
use Prometheus\Storage\Redis;
|
||||
use Prometheus\Storage\APC;
|
||||
use Prometheus\Exception\StorageException;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* StorageFactory class.
|
||||
*
|
||||
* Creates and configures storage adapters for Prometheus metrics.
|
||||
* Supports configuration via WordPress options or environment variables.
|
||||
*/
|
||||
class StorageFactory {
|
||||
|
||||
/**
|
||||
* Available storage adapters.
|
||||
*/
|
||||
public const ADAPTER_INMEMORY = 'inmemory';
|
||||
public const ADAPTER_REDIS = 'redis';
|
||||
public const ADAPTER_APCU = 'apcu';
|
||||
|
||||
/**
|
||||
* Environment variable names.
|
||||
*/
|
||||
private const ENV_STORAGE_ADAPTER = 'WP_PROMETHEUS_STORAGE_ADAPTER';
|
||||
private const ENV_REDIS_HOST = 'WP_PROMETHEUS_REDIS_HOST';
|
||||
private const ENV_REDIS_PORT = 'WP_PROMETHEUS_REDIS_PORT';
|
||||
private const ENV_REDIS_PASSWORD = 'WP_PROMETHEUS_REDIS_PASSWORD';
|
||||
private const ENV_REDIS_DATABASE = 'WP_PROMETHEUS_REDIS_DATABASE';
|
||||
private const ENV_REDIS_PREFIX = 'WP_PROMETHEUS_REDIS_PREFIX';
|
||||
private const ENV_APCU_PREFIX = 'WP_PROMETHEUS_APCU_PREFIX';
|
||||
|
||||
/**
|
||||
* Default Redis prefix.
|
||||
*/
|
||||
private const DEFAULT_REDIS_PREFIX = 'WORDPRESS_PROMETHEUS_';
|
||||
|
||||
/**
|
||||
* Default APCu prefix.
|
||||
*/
|
||||
private const DEFAULT_APCU_PREFIX = 'wp_prom';
|
||||
|
||||
/**
|
||||
* Singleton instance of the storage adapter.
|
||||
*
|
||||
* @var Adapter|null
|
||||
*/
|
||||
private static ?Adapter $instance = null;
|
||||
|
||||
/**
|
||||
* Last error message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static string $last_error = '';
|
||||
|
||||
/**
|
||||
* Get the storage adapter instance.
|
||||
*
|
||||
* @return Adapter
|
||||
*/
|
||||
public static function get_adapter(): Adapter {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = self::create_adapter();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the singleton instance (useful for testing or config changes).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function reset(): void {
|
||||
self::$instance = null;
|
||||
self::$last_error = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_last_error(): string {
|
||||
return self::$last_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available storage adapters.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function get_available_adapters(): array {
|
||||
return array(
|
||||
self::ADAPTER_INMEMORY => __( 'In-Memory (default, no persistence)', 'wp-prometheus' ),
|
||||
self::ADAPTER_REDIS => __( 'Redis (requires PHP Redis extension)', 'wp-prometheus' ),
|
||||
self::ADAPTER_APCU => __( 'APCu (requires APCu extension)', 'wp-prometheus' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a storage adapter is available on this system.
|
||||
*
|
||||
* @param string $adapter Adapter name.
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_adapter_available( string $adapter ): bool {
|
||||
switch ( $adapter ) {
|
||||
case self::ADAPTER_INMEMORY:
|
||||
return true;
|
||||
|
||||
case self::ADAPTER_REDIS:
|
||||
return extension_loaded( 'redis' );
|
||||
|
||||
case self::ADAPTER_APCU:
|
||||
return extension_loaded( 'apcu' ) && apcu_enabled();
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured storage adapter name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_configured_adapter(): string {
|
||||
// Check environment variable first.
|
||||
$env_adapter = getenv( self::ENV_STORAGE_ADAPTER );
|
||||
if ( false !== $env_adapter && ! empty( $env_adapter ) ) {
|
||||
return strtolower( $env_adapter );
|
||||
}
|
||||
|
||||
// Fall back to WordPress option.
|
||||
return get_option( 'wp_prometheus_storage_adapter', self::ADAPTER_INMEMORY );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active storage adapter name (may differ from configured if fallback occurred).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_active_adapter(): string {
|
||||
// Ensure adapter is created.
|
||||
self::get_adapter();
|
||||
|
||||
$configured = self::get_configured_adapter();
|
||||
if ( self::is_adapter_available( $configured ) && empty( self::$last_error ) ) {
|
||||
return $configured;
|
||||
}
|
||||
|
||||
return self::ADAPTER_INMEMORY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the storage adapter based on configuration.
|
||||
*
|
||||
* @return Adapter
|
||||
*/
|
||||
private static function create_adapter(): Adapter {
|
||||
$adapter = self::get_configured_adapter();
|
||||
self::$last_error = '';
|
||||
|
||||
switch ( $adapter ) {
|
||||
case self::ADAPTER_REDIS:
|
||||
return self::create_redis_adapter();
|
||||
|
||||
case self::ADAPTER_APCU:
|
||||
return self::create_apcu_adapter();
|
||||
|
||||
case self::ADAPTER_INMEMORY:
|
||||
default:
|
||||
return new InMemory();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Redis storage adapter.
|
||||
*
|
||||
* @return Adapter
|
||||
*/
|
||||
private static function create_redis_adapter(): Adapter {
|
||||
if ( ! extension_loaded( 'redis' ) ) {
|
||||
self::$last_error = __( 'PHP Redis extension is not installed.', 'wp-prometheus' );
|
||||
return new InMemory();
|
||||
}
|
||||
|
||||
$config = self::get_redis_config();
|
||||
|
||||
try {
|
||||
Redis::setPrefix( $config['prefix'] );
|
||||
|
||||
$redis = new Redis( array(
|
||||
'host' => $config['host'],
|
||||
'port' => $config['port'],
|
||||
'password' => $config['password'] ?: null,
|
||||
'timeout' => 0.5,
|
||||
'read_timeout' => 10,
|
||||
'persistent_connections' => true,
|
||||
) );
|
||||
|
||||
// Test connection by triggering initialization.
|
||||
// The Redis adapter connects lazily, so we need to check it works.
|
||||
return $redis;
|
||||
} catch ( StorageException $e ) {
|
||||
self::$last_error = sprintf(
|
||||
/* translators: %s: Error message */
|
||||
__( 'Redis connection failed: %s', 'wp-prometheus' ),
|
||||
$e->getMessage()
|
||||
);
|
||||
return new InMemory();
|
||||
} catch ( \RedisException $e ) {
|
||||
self::$last_error = sprintf(
|
||||
/* translators: %s: Error message */
|
||||
__( 'Redis error: %s', 'wp-prometheus' ),
|
||||
$e->getMessage()
|
||||
);
|
||||
return new InMemory();
|
||||
} catch ( \Exception $e ) {
|
||||
self::$last_error = sprintf(
|
||||
/* translators: %s: Error message */
|
||||
__( 'Storage error: %s', 'wp-prometheus' ),
|
||||
$e->getMessage()
|
||||
);
|
||||
return new InMemory();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create APCu storage adapter.
|
||||
*
|
||||
* @return Adapter
|
||||
*/
|
||||
private static function create_apcu_adapter(): Adapter {
|
||||
if ( ! extension_loaded( 'apcu' ) ) {
|
||||
self::$last_error = __( 'APCu extension is not installed.', 'wp-prometheus' );
|
||||
return new InMemory();
|
||||
}
|
||||
|
||||
if ( ! apcu_enabled() ) {
|
||||
self::$last_error = __( 'APCu is installed but not enabled.', 'wp-prometheus' );
|
||||
return new InMemory();
|
||||
}
|
||||
|
||||
$prefix = self::get_apcu_prefix();
|
||||
|
||||
try {
|
||||
return new APC( $prefix );
|
||||
} catch ( StorageException $e ) {
|
||||
self::$last_error = sprintf(
|
||||
/* translators: %s: Error message */
|
||||
__( 'APCu error: %s', 'wp-prometheus' ),
|
||||
$e->getMessage()
|
||||
);
|
||||
return new InMemory();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Redis configuration.
|
||||
*
|
||||
* @return array{host: string, port: int, password: string, database: int, prefix: string}
|
||||
*/
|
||||
public static function get_redis_config(): array {
|
||||
// Check environment variables first.
|
||||
$env_host = getenv( self::ENV_REDIS_HOST );
|
||||
$env_port = getenv( self::ENV_REDIS_PORT );
|
||||
$env_password = getenv( self::ENV_REDIS_PASSWORD );
|
||||
$env_database = getenv( self::ENV_REDIS_DATABASE );
|
||||
$env_prefix = getenv( self::ENV_REDIS_PREFIX );
|
||||
|
||||
// Get WordPress options as fallback.
|
||||
$options = get_option( 'wp_prometheus_redis_config', array() );
|
||||
|
||||
return array(
|
||||
'host' => ( false !== $env_host && ! empty( $env_host ) ) ? $env_host : ( $options['host'] ?? '127.0.0.1' ),
|
||||
'port' => ( false !== $env_port && ! empty( $env_port ) ) ? (int) $env_port : ( (int) ( $options['port'] ?? 6379 ) ),
|
||||
'password' => ( false !== $env_password ) ? $env_password : ( $options['password'] ?? '' ),
|
||||
'database' => ( false !== $env_database && ! empty( $env_database ) ) ? (int) $env_database : ( (int) ( $options['database'] ?? 0 ) ),
|
||||
'prefix' => ( false !== $env_prefix && ! empty( $env_prefix ) ) ? $env_prefix : ( $options['prefix'] ?? self::DEFAULT_REDIS_PREFIX ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get APCu prefix.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_apcu_prefix(): string {
|
||||
$env_prefix = getenv( self::ENV_APCU_PREFIX );
|
||||
if ( false !== $env_prefix && ! empty( $env_prefix ) ) {
|
||||
return $env_prefix;
|
||||
}
|
||||
|
||||
return get_option( 'wp_prometheus_apcu_prefix', self::DEFAULT_APCU_PREFIX );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save storage configuration.
|
||||
*
|
||||
* @param array $config Configuration array.
|
||||
* @return void
|
||||
*/
|
||||
public static function save_config( array $config ): void {
|
||||
if ( isset( $config['adapter'] ) ) {
|
||||
update_option( 'wp_prometheus_storage_adapter', sanitize_key( $config['adapter'] ) );
|
||||
}
|
||||
|
||||
if ( isset( $config['redis'] ) && is_array( $config['redis'] ) ) {
|
||||
$redis_config = array(
|
||||
'host' => sanitize_text_field( $config['redis']['host'] ?? '127.0.0.1' ),
|
||||
'port' => absint( $config['redis']['port'] ?? 6379 ),
|
||||
'password' => sanitize_text_field( $config['redis']['password'] ?? '' ),
|
||||
'database' => absint( $config['redis']['database'] ?? 0 ),
|
||||
'prefix' => sanitize_key( $config['redis']['prefix'] ?? self::DEFAULT_REDIS_PREFIX ),
|
||||
);
|
||||
update_option( 'wp_prometheus_redis_config', $redis_config );
|
||||
}
|
||||
|
||||
if ( isset( $config['apcu_prefix'] ) ) {
|
||||
update_option( 'wp_prometheus_apcu_prefix', sanitize_key( $config['apcu_prefix'] ) );
|
||||
}
|
||||
|
||||
// Reset the singleton to apply new configuration.
|
||||
self::reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test storage adapter connection.
|
||||
*
|
||||
* @param string $adapter Adapter name.
|
||||
* @param array $config Optional configuration to test.
|
||||
* @return array{success: bool, message: string}
|
||||
*/
|
||||
public static function test_connection( string $adapter, array $config = array() ): array {
|
||||
switch ( $adapter ) {
|
||||
case self::ADAPTER_REDIS:
|
||||
return self::test_redis_connection( $config );
|
||||
|
||||
case self::ADAPTER_APCU:
|
||||
return self::test_apcu_connection( $config );
|
||||
|
||||
case self::ADAPTER_INMEMORY:
|
||||
return array(
|
||||
'success' => true,
|
||||
'message' => __( 'In-Memory storage is always available.', 'wp-prometheus' ),
|
||||
);
|
||||
|
||||
default:
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __( 'Unknown storage adapter.', 'wp-prometheus' ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Redis connection.
|
||||
*
|
||||
* @param array $config Redis configuration.
|
||||
* @return array{success: bool, message: string}
|
||||
*/
|
||||
private static function test_redis_connection( array $config ): array {
|
||||
if ( ! extension_loaded( 'redis' ) ) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __( 'PHP Redis extension is not installed.', 'wp-prometheus' ),
|
||||
);
|
||||
}
|
||||
|
||||
$redis_config = ! empty( $config ) ? $config : self::get_redis_config();
|
||||
|
||||
try {
|
||||
$redis = new \Redis();
|
||||
|
||||
$connected = $redis->connect(
|
||||
$redis_config['host'],
|
||||
$redis_config['port'],
|
||||
0.5 // timeout
|
||||
);
|
||||
|
||||
if ( ! $connected ) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __( 'Could not connect to Redis server.', 'wp-prometheus' ),
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $redis_config['password'] ) ) {
|
||||
$authenticated = $redis->auth( $redis_config['password'] );
|
||||
if ( ! $authenticated ) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __( 'Redis authentication failed.', 'wp-prometheus' ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( $redis_config['database'] > 0 ) {
|
||||
$redis->select( $redis_config['database'] );
|
||||
}
|
||||
|
||||
// Test with a ping.
|
||||
$pong = $redis->ping();
|
||||
$redis->close();
|
||||
|
||||
if ( $pong ) {
|
||||
return array(
|
||||
'success' => true,
|
||||
'message' => sprintf(
|
||||
/* translators: %s: Redis host:port */
|
||||
__( 'Successfully connected to Redis at %s.', 'wp-prometheus' ),
|
||||
$redis_config['host'] . ':' . $redis_config['port']
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __( 'Redis ping failed.', 'wp-prometheus' ),
|
||||
);
|
||||
} catch ( \RedisException $e ) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => sprintf(
|
||||
/* translators: %s: Error message */
|
||||
__( 'Redis error: %s', 'wp-prometheus' ),
|
||||
$e->getMessage()
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test APCu connection.
|
||||
*
|
||||
* @param array $config APCu configuration.
|
||||
* @return array{success: bool, message: string}
|
||||
*/
|
||||
private static function test_apcu_connection( array $config ): array {
|
||||
if ( ! extension_loaded( 'apcu' ) ) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __( 'APCu extension is not installed.', 'wp-prometheus' ),
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! apcu_enabled() ) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __( 'APCu is installed but not enabled. Check your php.ini settings.', 'wp-prometheus' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Test with a simple store/fetch.
|
||||
$test_key = 'wp_prometheus_test_' . time();
|
||||
$test_value = 'test_' . wp_rand();
|
||||
|
||||
$stored = apcu_store( $test_key, $test_value, 5 );
|
||||
if ( ! $stored ) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __( 'APCu store operation failed.', 'wp-prometheus' ),
|
||||
);
|
||||
}
|
||||
|
||||
$fetched = apcu_fetch( $test_key );
|
||||
apcu_delete( $test_key );
|
||||
|
||||
if ( $fetched === $test_value ) {
|
||||
$info = apcu_cache_info( true );
|
||||
return array(
|
||||
'success' => true,
|
||||
'message' => sprintf(
|
||||
/* translators: %s: Memory info */
|
||||
__( 'APCu is working. Memory: %s used.', 'wp-prometheus' ),
|
||||
size_format( $info['mem_size'] ?? 0 )
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __( 'APCu fetch operation returned unexpected value.', 'wp-prometheus' ),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* Plugin Name: WP Prometheus
|
||||
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wp-prometheus
|
||||
* Description: Prometheus metrics endpoint for WordPress with extensible hooks for custom metrics.
|
||||
* Version: 0.3.0
|
||||
* Version: 0.4.0
|
||||
* Requires at least: 6.4
|
||||
* Requires PHP: 8.3
|
||||
* Author: Marco Graetsch
|
||||
@@ -26,7 +26,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
define( 'WP_PROMETHEUS_VERSION', '0.3.0' );
|
||||
define( 'WP_PROMETHEUS_VERSION', '0.4.0' );
|
||||
|
||||
/**
|
||||
* Plugin file path.
|
||||
|
||||
Reference in New Issue
Block a user