feat: implement automatic metrics collection and monitoring system

This commit is contained in:
infosave2007
2025-11-10 15:19:36 +03:00
parent 3e9ccb5f8d
commit be3416eddc
7 changed files with 114 additions and 13 deletions
+10 -2
View File
@@ -36,16 +36,24 @@ COPY apache.conf /etc/apache2/sites-available/000-default.conf
RUN chown -R www-data:www-data /var/www/html \
&& chmod -R 755 /var/www/html/public
# Setup cron for client expiration and traffic limit checks (runs every hour)
# Setup cron jobs
RUN echo "0 * * * * www-data cd /var/www/html && /usr/local/bin/php bin/check_expired_clients.php >> /var/log/cron.log 2>&1" > /etc/cron.d/amnezia-cron \
&& echo "0 * * * * www-data cd /var/www/html && /usr/local/bin/php bin/check_traffic_limits.php >> /var/log/cron.log 2>&1" >> /etc/cron.d/amnezia-cron \
&& echo "*/3 * * * * root /bin/bash /var/www/html/bin/monitor_metrics.sh >> /var/log/metrics_monitor.log 2>&1" >> /etc/cron.d/amnezia-cron \
&& chmod 0644 /etc/cron.d/amnezia-cron \
&& crontab /etc/cron.d/amnezia-cron \
&& touch /var/log/cron.log
&& touch /var/log/cron.log \
&& touch /var/log/metrics_monitor.log \
&& touch /var/log/metrics_collector.log
# Make monitor script executable
RUN chmod +x /var/www/html/bin/monitor_metrics.sh
# Create startup script
RUN echo '#!/bin/bash\n\
service cron start\n\
# Start metrics collector on container startup\n\
/bin/bash /var/www/html/bin/monitor_metrics.sh\n\
apache2-foreground' > /start.sh \
&& chmod +x /start.sh
+25 -2
View File
@@ -31,12 +31,10 @@ cp .env.example .env
# For Docker Compose V2 (recommended)
docker compose up -d
docker compose exec web composer install
docker compose exec -d web php bin/collect_metrics.php
# Or for older Docker Compose V1
docker-compose up -d
docker-compose exec web composer install
docker-compose exec -d web php bin/collect_metrics.php
```
Access: http://localhost:8082
@@ -143,6 +141,26 @@ curl -X POST http://localhost:8082/api/servers/1/restore \
-d '{"backup_id": 123}'
```
### Automatic Monitoring and Metrics Collection
**Metrics collector runs automatically** on container startup and is monitored by cron every 3 minutes. If the process crashes, it will be automatically restarted.
Check metrics collector logs:
```bash
docker compose exec web tail -f /var/log/metrics_collector.log
```
Check monitoring script logs:
```bash
docker compose exec web tail -f /var/log/metrics_monitor.log
```
Restart metrics collector manually:
```bash
docker compose exec web pkill -f collect_metrics.php
# It will be auto-restarted within 3 minutes by the monitoring script
```
### Automatic Client Expiration Check
**Runs automatically in Docker container** every hour to disable expired clients.
@@ -281,4 +299,9 @@ migrations/ - SQL migrations (executed in alphabetical order)
## License
MIT
## Support the Project
If you find this project helpful, you can support its development through a donation via Tribute: https://t.me/tribute/app?startapp=dzX1
# amneziavpnphp
+20 -1
View File
@@ -21,8 +21,21 @@ date_default_timezone_set('UTC');
// Enable error logging
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/metrics_collector_errors.log');
echo "[" . date('Y-m-d H:i:s') . "] Metrics collector started\n";
// Write PID file for monitoring
$pidFile = '/var/run/collect_metrics.pid';
file_put_contents($pidFile, getmypid());
// Register shutdown function to clean up PID file
register_shutdown_function(function() use ($pidFile) {
if (file_exists($pidFile)) {
unlink($pidFile);
}
});
echo "[" . date('Y-m-d H:i:s') . "] Metrics collector started (PID: " . getmypid() . ")\n";
// Main loop
while (true) {
@@ -79,6 +92,12 @@ while (true) {
} catch (Exception $e) {
echo "[" . date('Y-m-d H:i:s') . "] FATAL ERROR: " . $e->getMessage() . "\n";
error_log("[FATAL] Metrics collector error: " . $e->getMessage());
echo "Retrying in 30 seconds...\n\n";
sleep(30);
} catch (Error $e) {
echo "[" . date('Y-m-d H:i:s') . "] CRITICAL ERROR: " . $e->getMessage() . "\n";
error_log("[CRITICAL] Metrics collector error: " . $e->getMessage());
echo "Retrying in 30 seconds...\n\n";
sleep(30);
}
+42
View File
@@ -0,0 +1,42 @@
#!/bin/bash
# Monitor and restart metrics collector if it's not running
# This script checks if collect_metrics.php is running and restarts it if needed
SCRIPT_PATH="/var/www/html/bin/collect_metrics.php"
LOG_FILE="/var/log/metrics_monitor.log"
PID_FILE="/var/run/collect_metrics.pid"
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
# Check if the process is running
is_running() {
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if ps -p "$PID" > /dev/null 2>&1; then
# Check if it's actually our script
if ps -p "$PID" -o args= | grep -q "collect_metrics.php"; then
return 0
fi
fi
fi
return 1
}
# Start the metrics collector
start_collector() {
log_message "Starting metrics collector..."
/usr/local/bin/php "$SCRIPT_PATH" >> /var/log/metrics_collector.log 2>&1 &
echo $! > "$PID_FILE"
log_message "Metrics collector started with PID: $(cat $PID_FILE)"
}
# Main logic
if is_running; then
log_message "Metrics collector is running (PID: $(cat $PID_FILE))"
else
log_message "Metrics collector is not running - starting it"
start_collector
fi
+2 -2
View File
@@ -40,9 +40,9 @@ class VpnClient {
public static function create(int $serverId, int $userId, string $name, ?int $expiresInDays = null): int {
$pdo = DB::conn();
// Sanitize client name (replace spaces and special characters)
// Sanitize client name (replace only spaces with underscores, allow any other characters including Cyrillic)
$name = trim($name);
$name = preg_replace('/[^a-zA-Z0-9_-]/', '_', $name);
$name = str_replace(' ', '_', $name);
// Get server data
$server = new VpnServer($serverId);
+10 -1
View File
@@ -597,7 +597,16 @@ Router::get('/clients/{id}/download', function ($params) {
}
$config = $client->getConfig();
$filename = preg_replace('/[^a-zA-Z0-9_-]/', '_', $clientData['name']) . '.conf';
// Check if name contains non-Latin characters
$hasNonLatin = preg_match('/[^a-zA-Z0-9_-]/', $clientData['name']);
if ($hasNonLatin) {
// Use user_(client_id)_s(server_id).conf format for non-Latin names
$filename = 'user_' . $clientData['id'] . '_s' . $clientData['server_id'] . '.conf';
} else {
// Use client name for Latin characters
$filename = $clientData['name'] . '.conf';
}
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $filename . '"');
+5 -5
View File
@@ -95,8 +95,8 @@
<h3 class="font-bold mb-4">{{ t('clients.create') }}</h3>
<form method="POST" action="/servers/{{ server.id }}/clients/create" class="space-y-3" id="createClientForm">
<div>
<input name="name" placeholder="{{ t('clients.name') }}" required class="w-full px-3 py-2 border rounded" id="clientName" pattern="[a-zA-Z0-9_-]+" title="Only letters, numbers, underscore and dash allowed">
<p class="text-xs text-gray-500 mt-1">Spaces and special characters will be replaced with underscore</p>
<input name="name" placeholder="{{ t('clients.name') }}" required class="w-full px-3 py-2 border rounded" id="clientName">
<p class="text-xs text-gray-500 mt-1">Spaces will be replaced with underscore. All characters allowed including Cyrillic.</p>
</div>
<div>
<label class="block text-sm text-gray-600 mb-1">{{ t('clients.expiration') }}</label>
@@ -304,12 +304,12 @@ document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('createClientForm');
const clientNameInput = document.getElementById('clientName');
// Auto-sanitize client name on input
// Auto-replace spaces with underscores
if (clientNameInput) {
clientNameInput.addEventListener('input', function(e) {
// Replace spaces and special characters with underscore
// Replace only spaces with underscore, allow all other characters including Cyrillic
let value = e.target.value;
let sanitized = value.replace(/[^a-zA-Z0-9_-]/g, '_');
let sanitized = value.replace(/ /g, '_');
if (value !== sanitized) {
e.target.value = sanitized;
}