Skip to main content

id: MONITORING_LOGGING title: MONITORING LOGGING

Monitoring & Logging

Log File Locations and Rotation

Log File Locations

Application Logs

runtime/logs/
├── app.log # Main application logs
├── api.log # API-specific logs
├── admin.log # Admin panel logs
├── console.log # Console command logs
├── queue.log # Queue worker logs
└── error.log # Error logs

System Logs

/var/log/
├── nginx/
│ ├── access.log # Nginx access logs
│ └── error.log # Nginx error logs
├── php8.0-fpm.log # PHP-FPM logs
├── mysql/
│ └── error.log # MySQL error logs
├── redis/
│ └── redis-server.log # Redis server logs
└── elasticsearch/
└── elasticsearch.log # Elasticsearch logs

Log Rotation Configuration

Application Log Rotation (/etc/logrotate.d/rahvaraamat)

/var/www/rahvaraamat/runtime/logs/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 www-data www-data
}

System Log Rotation

# Nginx logs
/var/log/nginx/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 nginx nginx
}

# PHP-FPM logs
/var/log/php8.0-fpm.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 www-data www-data
}

# MySQL logs
/var/log/mysql/*.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 644 mysql mysql
}

Database Log Archiving

Log Archiving Command

# Archive logs older than 20 days to files
php yii archive/logs

# Archive without table optimization
php yii archive/logs 0

Archive Configuration (console/controllers/ArchiveController.php)

public const LOG_FILE_SUFFIX = 'log.txt';
public const LOG_FILE_NAME_DATETIME_FORMAT = 'Y.m.d_H.i.s';
public const LOG_MAX_FILE_SIZE = 104_857_600; // 100MB
public const LOG_FILE_ROW_COUNT = 1000;
public const MAX_LOG_AGE_INTERVAL = 1_728_000; // 20 days

Archive File Structure

console/runtime/archive/
├── 2024.01.15_10.30.00-2024.01.15_11.45.00/
│ └── log.txt
├── 2024.01.15_12.00.00-2024.01.15_13.15.00/
│ └── log.txt
└── 2024.01.16_09.00.00-2024.01.16_10.30.00/
└── log.txt

Error Reporting

Log Levels

Yii2 Log Levels

Logger::LEVEL_ERROR // 1 - Error messages
Logger::LEVEL_WARNING // 2 - Warning messages
Logger::LEVEL_INFO // 4 - Information messages
Logger::LEVEL_TRACE // 8 - Trace messages
Logger::LEVEL_PROFILE // 64 - Profiling messages

Application Log Configuration

'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'common\components\CustomLogDbTarget',
'levels' => ['error', 'warning', 'info'],
'except' => [
'yii\db\*',
'yii\filters\*',
'yii\web\HttpException:404',
'yii\web\Session::open',
'yii\i18n\*',
'yii\web\User*',
'yii\debug\Module::checkAccess',
'yii\httpclient\*'
],
],
],
],

Custom Database Log Target

CustomLogDbTarget (common/components/CustomLogDbTarget.php)

class CustomLogDbTarget extends DbTarget
{
private array $levelMap = [
1 => 'error',
4 => 'info',
64 => 'profile',
80 => 'beginProfile',
96 => 'endProfile',
8 => 'debug',
2 => 'warning'
];

public function export()
{
// Stores log messages to database table
// Handles transaction rollback scenarios
// Maps log levels to string representations
}
}

Log Database Schema

Log Table Structure (common/models/Log.php)

CREATE TABLE `rr_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`log_time` datetime NOT NULL,
`category` varchar(128) NOT NULL,
`level` varchar(128) NOT NULL,
`user_id` int(11) DEFAULT NULL,
`message` text DEFAULT NULL,
`prefix` text DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_log_time` (`log_time`),
KEY `idx_category` (`category`),
KEY `idx_level` (`level`)
);

Error Handling

Console Command Logging

// BaseController logging
public function log($message, $level = Logger::LEVEL_INFO)
{
$logger = Yii::getLogger();
$colors = [
Logger::LEVEL_TRACE => '1;34',
Logger::LEVEL_ERROR => '0;31',
Logger::LEVEL_WARNING => '1;35',
];

Console::stdout(sprintf("\033[%sm%s: %s\n", $colors[$level] ?? 0, date('H:i:s'), $message));

if ($level !== Logger::LEVEL_TRACE) {
$logger->log($message, $level, "application.console.{$this->id}");
}

if (in_array($level, [Logger::LEVEL_WARNING, Logger::LEVEL_ERROR])) {
$logger->flush(true);
}
}

Synchronization Logging

// BaseSyncCommand logging
public function log($message, $level = Logger::LEVEL_INFO)
{
if (($level !== Logger::LEVEL_TRACE || $this->trace) && php_sapi_name() == 'cli') {
$colors = [
Logger::LEVEL_TRACE => '1;34',
Logger::LEVEL_ERROR => '0;31',
Logger::LEVEL_WARNING => '1;35',
];
$this->output(sprintf("\033[%sm%s: %s\n", $colors[$level] ?? 0, date('H:i:s'), $message));
}

if (in_array($level, [Logger::LEVEL_WARNING, Logger::LEVEL_ERROR])) {
Yii::getLogger()->log($message, $level, $this->getApiNamespace());
Yii::getLogger()->flush(true);
}
}

Monitoring Tools

Health Check Commands

HealthCheckController (console/controllers/HealthCheckController.php)

# Kafka health check
php yii health-check/kafka

# Wowza media server health check
php yii health-check/wowza

# Subscription service health check
php yii health-check/subscription-service

Health Check Implementation

class HealthCheckController extends BaseController
{
public function actionKafka()
{
$eventManager = new EventManager();
$eventManager->publishEvent(EventTopicEnum::HEALTH_CHECK, 'check', function ($result) {
var_dump($result);
});
}

public function actionWowza()
{
$httpClient = new HttpClient;
$response = $httpClient->get(
Yii::$app->audioStreamManager->constructTestUrl(),
[
'connect_timeout' => 10,
'http_errors' => true
]
);

if ($response->getStatusCode() !== 200) {
throw new RuntimeException($response->getReasonPhrase());
}
}

public function actionSubscriptionService()
{
$brokenSubscriptions = Yii::$app->db->createCommand("
SELECT ps.id FROM `rr_payment_subscription` ps
LEFT JOIN `rr_client_account_subscription_service` cass
ON ps.client_account_id = cass.client_account_id
WHERE ps.join_date IS NOT NULL AND cass.id IS NULL;
")->queryAll();

if (count($brokenSubscriptions) > 0) {
$brokenSubscriptions = json_encode($brokenSubscriptions, JSON_THROW_ON_ERROR);
Yii::$app->mailer->compose()->setToDevelopers()
->setSubject('Missing subscription services')
->setTextBody("Subscription services are missed for $brokenSubscriptions subscriptions")->send();
}
}
}

System Monitoring Commands

Application Health Check

#!/bin/bash
# /usr/local/bin/health-check.sh
if curl -f http://localhost/api/health > /dev/null 2>&1; then
echo "Application is healthy"
exit 0
else
echo "Application is not responding"
exit 1
fi

Database Health Check

#!/bin/bash
if mysql -u rahvaraamat -p'secure_password' -e "SELECT 1" > /dev/null 2>&1; then
echo "Database is healthy"
exit 0
else
echo "Database is not responding"
exit 1
fi

Log Monitoring Commands

Application Log Monitoring

# Monitor application errors
tail -f /var/www/rahvaraamat/runtime/logs/app.log

# Monitor API requests
tail -f /var/www/rahvaraamat/runtime/logs/api.log

# Monitor queue workers
tail -f /var/www/rahvaraamat/runtime/logs/queue.log

# Monitor console commands
tail -f /var/www/rahvaraamat/runtime/logs/console.log

System Log Monitoring

# Monitor nginx access logs
tail -f /var/log/nginx/access.log

# Monitor nginx error logs
tail -f /var/log/nginx/error.log

# Monitor PHP-FPM logs
tail -f /var/log/php8.0-fpm.log

# Monitor MySQL logs
tail -f /var/log/mysql/error.log

# Monitor Redis logs
tail -f /var/log/redis/redis-server.log

# Monitor Elasticsearch logs
tail -f /var/log/elasticsearch/elasticsearch.log

Performance Monitoring Commands

System Resource Monitoring

# Check system resources
htop

# Check disk usage
df -h

# Check memory usage
free -h

# Check CPU usage
top

# Check MySQL connections
mysql -u root -p -e "SHOW PROCESSLIST;"

# Check Redis memory
redis-cli info memory

# Check Elasticsearch status
curl -X GET "localhost:9200/_cluster/health"

Application Performance Monitoring

# Check PHP-FPM status
sudo systemctl status php8.0-fpm

# Check queue worker processes
ps aux | grep "queue/worker"

# Check application memory usage
ps aux | grep php-fpm

# Monitor slow queries
sudo tail -f /var/log/mysql/slow.log

# Monitor PHP-FPM slow logs
sudo tail -f /var/log/php8.0-fpm-slow.log

Cron Job Monitoring

Health Check Cron Jobs

# Daily health checks at 6 AM
0 6 * * * php yii health-check/kafka
0 6 * * * php yii health-check/wowza
0 6 * * * php yii health-check/subscription-service

# Log archiving weekly
0 2 * * 0 php yii archive/logs

Monitoring Cron Jobs

# Application health check every 5 minutes
*/5 * * * * /usr/local/bin/health-check.sh

# Database health check every 10 minutes
*/10 * * * * /usr/local/bin/db-health-check.sh

# Log rotation daily
0 0 * * * /usr/sbin/logrotate /etc/logrotate.d/rahvaraamat

Email Notifications

Error Notification Configuration

// Subscription service error notification
if (count($brokenSubscriptions) > 0) {
Yii::$app->mailer->compose()
->setToDevelopers()
->setSubject('Missing subscription services')
->setTextBody("Subscription services are missed for $brokenSubscriptions subscriptions")
->send();
}

Developer Email Configuration

// Set to developers email group
->setToDevelopers()

Monitoring Metrics

Key Performance Indicators

  • Response Time: Average API response time
  • Error Rate: Percentage of failed requests
  • Queue Length: Number of pending background jobs
  • Database Connections: Active database connections
  • Memory Usage: Application memory consumption
  • Disk Usage: Available disk space
  • CPU Usage: Server CPU utilization

Monitoring Thresholds

# Memory usage threshold (80%)
free -h | grep Mem | awk '{if($3/$2 > 0.8) print "High memory usage"}'

# Disk usage threshold (90%)
df -h | awk '$5 > 90 {print "High disk usage: " $1 " " $5}'

# Database connection threshold (80%)
mysql -u root -p -e "SHOW STATUS LIKE 'Threads_connected';" | awk '$2 > 80 {print "High DB connections"}'