potential fix for logging on server

This commit is contained in:
tom.hempel
2026-06-01 22:50:22 +02:00
parent e5ac069dc4
commit e4d55f4c90
5 changed files with 138 additions and 6 deletions

View File

@ -10,7 +10,8 @@
* - web_change: POST/PUT/PATCH/DELETE from the management website (incl. translation labels)
* - web_export: Website downloads (CSV/ZIP/JSON exports, translation bundle)
*
* Set QDB_API_LOG=0 to disable. Logs live under logs/api/ (gitignored).
* Set QDB_API_LOG=0 to disable. Set QDB_API_LOG_DIR for a custom path.
* Default directory is uploads/logs/api (writable by PHP alongside the database).
*/
/** @var list<string> */
@ -28,11 +29,98 @@ function qdb_api_log_enabled(): bool
function qdb_api_log_dir(): string
{
static $resolved = null;
if ($resolved !== null) {
return $resolved;
}
$custom = qdb_env_get('QDB_API_LOG_DIR');
if ($custom !== null && $custom !== '') {
return rtrim($custom, '/\\');
$resolved = rtrim($custom, '/\\');
return $resolved;
}
return dirname(__DIR__) . '/logs/api';
$root = dirname(__DIR__);
foreach ([$root . '/uploads/logs/api', $root . '/logs/api'] as $candidate) {
if (qdb_api_log_dir_is_usable($candidate)) {
$resolved = $candidate;
return $resolved;
}
}
$resolved = $root . '/uploads/logs/api';
return $resolved;
}
function qdb_api_log_dir_is_usable(string $dir): bool
{
if (is_dir($dir)) {
return is_writable($dir);
}
$parent = dirname($dir);
if (is_dir($parent) && is_writable($parent)) {
return true;
}
if (@mkdir($dir, 0775, true)) {
return is_writable($dir);
}
return is_dir($dir) && is_writable($dir);
}
/**
* Diagnostics for admin UI (permissions, path, enabled flag).
*
* @return array<string, mixed>
*/
function qdb_api_log_status(): array
{
$dir = qdb_api_log_dir();
$enabled = qdb_api_log_enabled();
$exists = is_dir($dir);
$writable = false;
$probeError = null;
if ($enabled) {
if (!$exists) {
if (!@mkdir($dir, 0775, true)) {
$probeError = 'Cannot create directory: ' . $dir;
}
$exists = is_dir($dir);
}
if ($exists && !is_writable($dir)) {
$probeError = 'Directory exists but is not writable by PHP: ' . $dir;
} elseif ($exists) {
$probe = $dir . '/.write_probe';
if (@file_put_contents($probe, (string)time() . "\n", LOCK_EX) === false) {
$probeError = 'Cannot write files in: ' . $dir;
} else {
$writable = true;
@unlink($probe);
}
}
}
$phpUser = null;
if (function_exists('posix_geteuid') && function_exists('posix_getpwuid')) {
$info = posix_getpwuid(posix_geteuid());
if (is_array($info) && !empty($info['name'])) {
$phpUser = (string)$info['name'];
}
}
return [
'enabled' => $enabled,
'dir' => $dir,
'exists' => $exists,
'writable' => $writable,
'error' => $probeError,
'php_user' => $phpUser,
'fix_hint' => $writable || !$enabled
? null
: 'On the server run: mkdir -p ' . $dir . ' && chown -R www-data:www-data '
. dirname($dir) . ' && chmod -R 775 ' . dirname($dir)
. ' (adjust www-data to your PHP user). Or set QDB_API_LOG_DIR in .env to a writable path.',
];
}
function qdb_api_log_max_bytes(): int
@ -421,13 +509,24 @@ function qdb_api_log_change_scalar(mixed $v): string|int|float|bool|null
function qdb_api_log_append_line(string $line): void
{
$dir = qdb_api_log_dir();
if (!is_dir($dir) && !@mkdir($dir, 0755, true) && !is_dir($dir)) {
throw new RuntimeException("Cannot create log directory: $dir");
if (!is_dir($dir) && !@mkdir($dir, 0775, true) && !is_dir($dir)) {
$err = error_get_last();
throw new RuntimeException(
'Cannot create log directory: ' . $dir
. ($err ? ' (' . ($err['message'] ?? '') . ')' : '')
);
}
if (!is_writable($dir)) {
throw new RuntimeException('Log directory not writable: ' . $dir);
}
$path = qdb_api_log_resolve_write_path($dir);
if (@file_put_contents($path, $line, FILE_APPEND | LOCK_EX) === false) {
throw new RuntimeException("Cannot write API log: $path");
$err = error_get_last();
throw new RuntimeException(
'Cannot write API log: ' . $path
. ($err ? ' (' . ($err['message'] ?? '') . ')' : '')
);
}
}
@ -507,6 +606,7 @@ function qdb_api_log_read_entries(string $date, string $activityFilter = '', int
'files' => array_map('basename', $files),
'truncated' => $truncated,
'kinds' => QDB_API_LOG_ACTIVITIES,
'logStatus' => qdb_api_log_status(),
];
}