Files
citrus-cms/app/Functions/notification-log-helper.php
2026-04-28 21:14:25 +03:00

329 lines
11 KiB
PHP

<?php
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Carbon\Carbon;
/**
* Log scheduler execution
*
* @param string $action Action: 'schedule_run_started', 'schedule_run_completed', 'command_scheduled'
* @param array $data Additional data
* @return void
*/
function logSchedulerExecution(string $action, array $data = [])
{
try {
$timestamp = now()->toDateTimeString();
$logData = [
'timestamp' => $timestamp,
'action' => $action,
'data' => $data,
];
$message = "[Scheduler] {$action}";
if (!empty($data)) {
$message .= " | " . json_encode($data, JSON_UNESCAPED_UNICODE);
}
Log::info($message, $logData);
// Write to dedicated notification log file
// Use storage_path() to write directly to storage/logs/ directory
$logDir = storage_path('logs');
$logFile = $logDir . '/notifications-' . date('Y-m-d') . '.log';
// Determine status for log file
$status = 'scheduled';
if ($action === 'command_finished') {
$status = 'finished';
} elseif ($action === 'schedule_run_started') {
$status = 'started';
} elseif ($action === 'schedule_run_completed') {
$status = 'completed';
}
$logLine = sprintf(
"[%s] %s | SCHEDULER | %s\n",
$timestamp,
str_pad($status, 10),
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
);
// Use file_put_contents with FILE_APPEND flag
file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX);
} catch (\Exception $e) {
Log::error('Failed to write scheduler log', [
'error' => $e->getMessage(),
'action' => $action
]);
}
}
/**
* Log notification command execution
*
* @param string $commandName Command name (e.g., 'notifications:check-deleted-joints')
* @param string $status Status: 'started', 'completed', 'skipped', 'error'
* @param array $data Additional data to log
* @return void
*/
function logNotificationCommand(string $commandName, string $status, array $data = [])
{
try {
$timestamp = now()->toDateTimeString();
$logData = [
'timestamp' => $timestamp,
'command' => $commandName,
'status' => $status,
'data' => $data,
];
// Log to Laravel's default log
$message = "[Notification Command] {$commandName} - {$status}";
if (!empty($data)) {
$message .= " | " . json_encode($data, JSON_UNESCAPED_UNICODE);
}
switch ($status) {
case 'started':
Log::info($message, $logData);
break;
case 'completed':
Log::info($message, $logData);
break;
case 'skipped':
Log::info($message, $logData);
break;
case 'error':
Log::error($message, $logData);
break;
default:
Log::info($message, $logData);
}
// Also write to dedicated notification log file
// Use storage_path() to write directly to storage/logs/ directory
$logDir = storage_path('logs');
$logFile = $logDir . '/notifications-' . date('Y-m-d') . '.log';
$logLine = sprintf(
"[%s] %s | %s | %s\n",
$timestamp,
str_pad($status, 10),
str_pad($commandName, 50),
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
);
// Use file_put_contents with FILE_APPEND flag
file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX);
} catch (\Exception $e) {
// Fallback to Laravel log if file write fails
Log::error('Failed to write notification log', [
'error' => $e->getMessage(),
'command' => $commandName,
'status' => $status
]);
}
}
/**
* Log notification command start
*
* @param string $commandName
* @return void
*/
function logNotificationStart(string $commandName)
{
logNotificationCommand($commandName, 'started', [
'time' => now()->toTimeString(),
]);
}
/**
* Log notification command completion
*
* @param string $commandName
* @param int $sentCount Number of notifications sent
* @param int $recordCount Number of records found
* @param int $newCount Number of new records (if applicable)
* @param float|null $duration Execution duration in seconds
* @return void
*/
function logNotificationComplete(string $commandName, int $sentCount = 0, int $recordCount = 0, int $newCount = 0, ?float $duration = null)
{
logNotificationCommand($commandName, 'completed', [
'sent_count' => $sentCount,
'record_count' => $recordCount,
'new_count' => $newCount,
'duration_seconds' => $duration ? round($duration, 2) : null,
]);
}
/**
* Log notification command skip
*
* @param string $commandName
* @param string $reason Reason for skipping
* @return void
*/
function logNotificationSkip(string $commandName, string $reason)
{
logNotificationCommand($commandName, 'skipped', [
'reason' => $reason,
]);
}
/**
* Log notification command error
*
* @param string $commandName
* @param string $errorMessage
* @param array $context Additional context
* @return void
*/
function logNotificationError(string $commandName, string $errorMessage, array $context = [])
{
logNotificationCommand($commandName, 'error', array_merge([
'error' => $errorMessage,
], $context));
}
/**
* Get notification log summary for a specific date
*
* @param string|null $date Date in Y-m-d format (default: today)
* @return array
*/
function getNotificationLogSummary(?string $date = null): array
{
$date = $date ?: date('Y-m-d');
$logFile = storage_path('logs/notifications-' . $date . '.log');
if (!file_exists($logFile)) {
return [
'date' => $date,
'total_executions' => 0,
'completed' => 0,
'skipped' => 0,
'errors' => 0,
'total_notifications_sent' => 0,
'commands' => [],
];
}
$content = file_get_contents($logFile);
$lines = explode("\n", trim($content));
$summary = [
'date' => $date,
'total_executions' => 0,
'completed' => 0,
'skipped' => 0,
'errors' => 0,
'total_notifications_sent' => 0,
'commands' => [],
];
foreach ($lines as $line) {
if (empty(trim($line))) continue;
// Parse log line: [timestamp] status | command | data
// Handle both command logs and scheduler logs
if (preg_match('/\[([^\]]+)\]\s+(\w+)\s+\|\s+([^\|]+)\s+\|\s+(.+)/', $line, $matches)) {
$timestamp = $matches[1];
$status = trim($matches[2]);
$command = trim($matches[3]);
$dataJson = trim($matches[4]);
// Check if it's a scheduler log
if ($command === 'SCHEDULER') {
$data = json_decode($dataJson, true);
if (isset($data['command'])) {
// Scheduler log for a specific command
$scheduledCommand = $data['command'];
if ($status === 'scheduled') {
// Command was scheduled to run
if (!isset($summary['commands'][$scheduledCommand])) {
$summary['commands'][$scheduledCommand] = [
'executions' => 0,
'completed' => 0,
'skipped' => 0,
'errors' => 0,
'total_sent' => 0,
'scheduled_count' => 0,
];
}
$summary['commands'][$scheduledCommand]['scheduled_count']++;
}
// Note: 'finished' status is just informational, actual completion is logged by command itself
}
continue;
}
$summary['total_executions']++;
if ($status === 'completed') {
$summary['completed']++;
$data = json_decode($dataJson, true);
if (isset($data['sent_count'])) {
$summary['total_notifications_sent'] += $data['sent_count'];
}
if (!isset($summary['commands'][$command])) {
$summary['commands'][$command] = [
'executions' => 0,
'completed' => 0,
'skipped' => 0,
'errors' => 0,
'total_sent' => 0,
'scheduled_count' => 0,
];
}
$summary['commands'][$command]['executions']++;
$summary['commands'][$command]['completed']++;
if (isset($data['sent_count'])) {
$summary['commands'][$command]['total_sent'] += $data['sent_count'];
}
} elseif ($status === 'skipped') {
$summary['skipped']++;
if (!isset($summary['commands'][$command])) {
$summary['commands'][$command] = [
'executions' => 0,
'completed' => 0,
'skipped' => 0,
'errors' => 0,
'total_sent' => 0,
'scheduled_count' => 0,
];
}
$summary['commands'][$command]['executions']++;
$summary['commands'][$command]['skipped']++;
} elseif ($status === 'error') {
$summary['errors']++;
if (!isset($summary['commands'][$command])) {
$summary['commands'][$command] = [
'executions' => 0,
'completed' => 0,
'skipped' => 0,
'errors' => 0,
'total_sent' => 0,
'scheduled_count' => 0,
];
}
$summary['commands'][$command]['executions']++;
$summary['commands'][$command]['errors']++;
}
}
}
return $summary;
}