Ежедневный журнал Laravel, созданный с неправильными разрешениями
У меня есть script, который я запускаю с помощью php-artisan (с root), и иногда он заставляет ежедневный файл журнала создаваться до apache www-data user does - что означает, что когда реальный пользователь использует мое веб-приложение, я получаю ошибку разрешения папки:
Не удалось открыть поток: Permission denied
Я каждый раз меняю разрешения на www-datastrong > , но я хочу решить это, всегда создавая файл журнала с правильными разрешениями.
Я подумал о создании задания cron, которое создает файл или касается его, чтобы каждый день иметь правильное разрешение, но я ищу лучшее решение, которое не зависит от другого script.
Мы также рассмотрели возможность переноса php-artisan в другой script, чтобы убедиться, что он всегда запускается с учетными данными www-datastrong > , но что-то, что мы хотим сделать, на самом деле root, которые нельзя разрешить apache.
Другие предложения?
Ответы
Ответ 1
Начнем с того, что является постоянным.
У вас есть команда php artisan
, выполняемая root
.
Можно с уверенностью предположить, что эта команда выполняется ежедневно.
Решение № 1:
Учитывая, что пользователь, создающий файлы, является тем, у кого есть разрешение на его запись по умолчанию, мы можем разделить журналы следующим образом:
App/start/global.php
/*
|--------------------------------------------------------------------------
| Application Error Logger
|--------------------------------------------------------------------------
|
| Here we will configure the error logger setup for the application which
| is built on top of the wonderful Monolog library. By default we will
| build a basic log file setup which creates a single file for logs.
|
*/
Log::useDailyFiles(storage_path().'/logs/laravel-'.get_current_user().'.log');
Если ваш пользователь www-data должен был создать журнал ошибок, это приведет к: storage/logs/laravel-www-data-2015-4-27.log
.
Если ваш пользователь root должен создать журнал ошибок, это приведет к: storage/logs/laravel-root-2015-4-27.log
.
Решение № 2:
Измените журнал, используемый вашей командой artisan, в вашем php script.
В вашей функции run()
добавьте эту строку в начале:
Log::useFiles(storage_path().'/logs/laravel-'.__CLASS__.'-'.Carbon::now()->format('Y-m-d').'.log');
Если ваше имя класса ArtisanRunner
, то ваш файл журнала будет:
storage/logs/laravel-ArtisanRunner-2015-4-27.log
.
Вывод: Решение номер 1 лучше, учитывая, что он определяет ваши журналы пользователем, и, следовательно, ошибок не будет.
EDIT: Как отметил Джейсон, get_current_user()
возвращает имя владельца script. Следовательно, для решения № 1, chown
ваши файлы класса Artisan, чтобы указать имя пользователя.
Ответ 2
Для Laravel 5.1 я использую следующее в нижней части bootstrap/app.php
(как указано в документах):
/**
* Configure Monolog.
*/
$app->configureMonologUsing(function(Monolog\Logger $monolog) {
$filename = storage_path('logs/laravel-'.php_sapi_name().'.log');
$handler = new Monolog\Handler\RotatingFileHandler($filename);
$monolog->pushHandler($handler);
});
Есть много других обработчиков, которые вы можете использовать, конечно.
Ответ 3
Laravel версии 5.6.10 и выше имеет поддержку элемента permission
в конфигурации (config/logging.php
) для single
и daily
драйвера:
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
'days' => 7,
'permission' => 0664,
],
Не нужно манипулировать с Monolog в скрипте начальной загрузки.
В частности, поддержка была добавлена в https://github.com/laravel/framework/commit/4d31633dca9594c9121afbbaa0190210de28fed8.
Ответ 4
Для таких целей вы должны использовать расширенный ACL для ваших файлов и каталогов. setfacl
будет вашим ответом здесь. Если вы хотите дать пользователю www-data права на запись в файлы root в определенном каталоге, вы можете сделать это следующим образом:
setfacl -d -m default:www-data:you-chosen-group:rwx /my/folder
После этого вы устанавливаете права доступа к rwx
для пользователя www-data для всех файлов в /my/folder/
независимо от того, кто их создал. Пожалуйста, посмотрите этот и этот вопрос для справки. Кроме того, вы можете проверить документы для setfacl
.
Позвольте мне знать, если это помогает.
Ответ 5
Для меня эта проблема была намного больше, чем права доступа к журналу... У меня были проблемы со всем, что связано с папками начальной загрузки/кэша и хранилища, когда один пользователь создавал файл/папку, а другой не мог редактировать/удалять из-за стандартного 644 и 755 разрешений.
Типичные сценарии:
-
Файл bootstrap/cache/compiled.php, созданный пользователем apache, но недоступный для редактирования пользователем composer при выполнении команды установки composer
-
Пользователь apache, создающий кеш, который нельзя очистить с помощью пользователя composer
- Страшные условия гонки бревен, описанные выше.
Мечта заключается в том, что независимо от того, какой пользователь создает файл/папку, другие пользователи, которым требуется доступ, имеют точно такие же права доступа, что и первоначальный автор.
TL; DR?
Вот как это сделано.
Нам нужно создать общую группу пользователей с именем laravel, которая состоит из всех пользователей, которым необходим доступ к каталогам хранилища и начальной загрузки/кэша. Далее нам нужно убедиться, что вновь созданные файлы и папки имеют группу laravel и разрешения 664 и 775 соответственно.
Это легко сделать для существующих файлов/каталогов, но для настройки правил создания файлов/папок по умолчанию требуется немного волшебства...
## create user group
sudo groupadd laravel
## add composer user to group
sudo gpasswd -a composer-user laravel
## add web server to group
sudo gpasswd -a apache laravel
## jump to laravel path
sudo cd /path/to/your/beautiful/laravel-application
## optional: temporary disable any daemons that may read/write files/folders
## For example Apache and Queues
## optional: if you've been playing around with permissions
## consider resetting all files and directories to the default
sudo find ./ -type d -exec chmod 755 {} \;
sudo find ./ -type f -exec chmod 644 {} \;
## give users part of the laravel group the standard RW and RWX
## permissions for the existing files and folders respectively
sudo chown -R :laravel ./storage
sudo chown -R :laravel ./bootstrap/cache
sudo find ./storage -type d -exec chmod 775 {} \;
sudo find ./bootstrap/cache -type d -exec chmod 775 {} \;
sudo find ./storage -type f -exec chmod 664 {} \;
sudo find ./bootstrap/cache -type f -exec chmod 664 {} \;
## give the newly created files/directories the group of the parent directory
## e.g. the laravel group
sudo find ./bootstrap/cache -type d -exec chmod g+s {} \;
sudo find ./storage -type d -exec chmod g+s {} \;
## let newly created files/directories inherit the default owner
## permissions up to maximum permission of rwx e.g. new files get 664,
## folders get 775
sudo setfacl -R -d -m g::rwx ./storage
sudo setfacl -R -d -m g::rwx ./bootstrap/cache
## Reboot so group file permissions refresh (required on Debian and Centos)
sudo shutdown now -r
Чисто для целей отладки я обнаружил, что разделение журналов на пользователей cli/web + было выгодно, поэтому я слегка изменил ответ Сэма Уилсона. Мой пример использования: очередь запускалась под собственным пользователем, поэтому он помогал различать пользователя-композитора, использующего cli (например, юнит-тесты), и демона очереди.
$app->configureMonologUsing(function(MonologLogger $monolog) {
$processUser = posix_getpwuid(posix_geteuid());
$processName= $processUser['name'];
$filename = storage_path('logs/laravel-'.php_sapi_name().'-'.$processName.'.log');
$handler = new MonologHandlerRotatingFileHandler($filename);
$monolog->pushHandler($handler);
});
Ответ 6
У меня это работало очень простым способом:
Я столкнулся с той же проблемой на Laravel 5.6
В config/logging.php
я только что обновил значение ежедневного пути к каналу с помощью php_sapi_name()
.
Это создает отдельную директорию для разных php_sapi_name и помещает файл журнала с отметкой времени в их директорию perticular.
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
'level' => 'debug',
'days' => 7,
]
Так что для меня,
- Файлы журналов
fpm-fcgi
каталоге fpm-fcgi
: журналы с веб-сайта, owner: www-data
- Файлы журналов создаются в каталоге
cli
: из команды artisan (cronjob). owner: root
Дополнительная информация о регистрации в Laravel 5.6: https://laravel.com/docs/5.6/logging.
Вот мой файл config/logging.php
:
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Log Channel
|--------------------------------------------------------------------------
|
| This option defines the default log channel that gets used when writing
| messages to the logs. The name specified in this option should match
| one of the channels defined in the "channels" configuration array.
|
*/
'default' => env('LOG_CHANNEL', 'stack'),
/*
|--------------------------------------------------------------------------
| Log Channels
|--------------------------------------------------------------------------
|
| Here you may configure the log channels for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Drivers: "single", "daily", "slack", "syslog",
| "errorlog", "custom", "stack"
|
*/
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['daily'],
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
'level' => 'debug',
'days' => 7,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => 'Laravel Log',
'level' => 'critical',
],
'syslog' => [
'driver' => 'syslog',
'level' => 'debug',
],
'errorlog' => [
'driver' => 'errorlog',
'level' => 'debug',
],
],
];
Ответ 7
Laravel 5.1
В нашем случае мы хотели создать все файлы журнала, чтобы все в группе deploy
имели права на чтение/запись. Поэтому нам нужно было создать все новые файлы с разрешениями 0664
, а не по умолчанию 0644
.
Мы также добавили форматер, чтобы добавить новые строки для лучшей читаемости:
$app->configureMonologUsing(function(Monolog\Logger $monolog) {
$filename = storage_path('/logs/laravel.log');
$handler = new Monolog\Handler\RotatingFileHandler($filename, 0, \Monolog\Logger::DEBUG, true, 0664);
$handler->setFormatter(new \Monolog\Formatter\LineFormatter(null, null, true, true));
$monolog->pushHandler($handler);
});
Также возможно совместить это с принятым ответом
$app->configureMonologUsing(function(Monolog\Logger $monolog) {
$filename = storage_path('/logs/laravel-' . php_sapi_name() . '.log');
$handler = new Monolog\Handler\RotatingFileHandler($filename, 0, \Monolog\Logger::DEBUG, true, 0664);
$handler->setFormatter(new \Monolog\Formatter\LineFormatter(null, null, true, true));
$monolog->pushHandler($handler);
});
Ответ 8
Добавьте в начало своего файла app/start/artisan.php
что-то вроде следующего: это с Laravel 4):
// If effectively root, touch the log file and make sure it belongs to www-data
if (posix_geteuid() === 0) {
$file = storage_path() . '/logs/laravel.log';
touch($file);
chown($file, 'www-data');
chgrp($file, 'www-data');
chmod($file, 0664);
}
Отрегулируйте путь, если ежедневный файл журнала, который вы упомянули, не является стандартным файлом журнала Laravel. Вы также можете не захотеть изменить группу или установить разрешения, как я здесь делаю. Вышеупомянутое устанавливает группу в www-data
и задает права на запись группы. Затем я добавил своего обычного пользователя в группу www-data
, чтобы запускать команды artisan, поскольку мой обычный пользователь все еще может записывать в журнал.
Связанная настройка заключается в том, чтобы поставить следующее в начале вашего файла app/start/global.php
:
umask(0002);
Если вы делаете это chmod
линия выше становится спорным. С учетом этого umask любые новые файлы PHP (и, следовательно, Laravel) будут иметь свои разрешения, маскированные только для того, чтобы у "других" пользователей не было прав на запись. Это означает, что каталоги будут начинаться как rwxrwxr-x
и файлы как rw-rw-r--
. Поэтому, если www-data
запускает PHP, любые файлы кэша и журнала, которые он делает, будут по умолчанию записываться любым в этой основной группе пользователей, которая www-data
.
Ответ 9
Laravel 5.5
Добавьте этот код в bootstrap/app.php
:
$app->configureMonologUsing(function (Monolog\Logger $monolog) {
$filename = storage_path('logs/' . php_sapi_name() . '-' . posix_getpwuid(posix_geteuid())['name'] . '.log');
$monolog->pushHandler($handler = new Monolog\Handler\RotatingFileHandler($filename, 30));
$handler->setFilenameFormat('laravel-{date}-{filename}', 'Y-m-d');
$formatter = new \Monolog\Formatter\LineFormatter(null, null, true, true);
$formatter->includeStacktraces();
$handler->setFormatter($formatter);
});
- В нем будут храниться такие файлы:
laravel-2018-01-27-cli-raph.log
и laravel-2018-01-27-fpm-cgi-raph.log
которые более читабельны. - Новые строки сохраняются (по умолчанию в Laravel)
- Работает с Laravel Log Viewer
Ларавел 5.6
Вы должны создать класс для вашего регистратора:
<?php
namespace App;
use Monolog\Logger as MonologLogger;
class Logger {
public function __invoke(array $config)
{
$monolog = new MonologLogger('my-logger');
$filename = storage_path('logs/' . php_sapi_name() . '-' . posix_getpwuid(posix_geteuid())['name'] . '.log');
$monolog->pushHandler($handler = new \Monolog\Handler\RotatingFileHandler($filename, 30));
$handler->setFilenameFormat('laravel-{date}-{filename}', 'Y-m-d');
$formatter = new \Monolog\Formatter\LineFormatter(null, null, true, true);
$formatter->includeStacktraces();
$handler->setFormatter($formatter);
return $monolog;
}
}
Затем вы должны зарегистрировать его в config/logging.php
:
'channels' => [
'custom' => [
'driver' => 'custom',
'via' => App\Logging\CreateCustomLogger::class,
],
],
То же поведение, что и для 5.5:
- В нем будут храниться такие файлы:
laravel-2018-01-27-cli-raph.log
и laravel-2018-01-27-fpm-cgi-raph.log
которые более читабельны. - Новые строки сохраняются (по умолчанию в Laravel)
- Работает с Laravel Log Viewer
Ответ 10
Laravel 5.4
\Log::getMonolog()->popHandler();
\Log::useDailyFiles(storage_path('/logs/laravel-').get_current_user().'.log');
добавить в boot
функцию в AppServiceProvider
Ответ 11
Один не способ Laravel сделать эту работу - просто выполнить ваш cronjob как www-data.
например, https://askubuntu.com/questions/189189/how-to-run-crontab-as-userwww-data
/etc/crontab
*/5 * * * * www-data php /var/www/public/voto_m/artisan top >/dev/null 2>&1
Ответ 12
(Laravel 5.6) Недавно я столкнулся с той же проблемой, и я просто установил запланированную команду для запуска в /app/Console/Kernel.php
.
$schedule->exec('chown -R www-data:www-data/var/www/**********/storage/logs')->everyMinute();
Я знаю, что это немного излишне, но это работает как шарм, и с тех пор не было никаких проблем.
Ответ 13
Ларавел 5.8
Laravel 5.8 позволяет вам установить имя журнала в config/logging.php
.
Таким образом, используя предыдущие ответы и комментарии, если вы хотите присвоить журналу имя, используя как фактическое имя пользователя posix, так и значение php_sapi_name()
, вам нужно всего лишь изменить набор имен журнала. Использование ежедневного драйвера позволяет выполнять ротацию журналов для каждой комбинации пользователь /API, что гарантирует, что журнал всегда будет меняться учетной записью, которая может изменять журналы.
Я также добавил проверку для функций posix, которые могут не существовать в вашей локальной среде, и в этом случае имя журнала по умолчанию соответствует стандарту.
Предполагая, что вы используете канал журнала по умолчанию "ежедневно", вы можете изменить ключ "каналы" следующим образом:
# config/logging.php
'channels' => [
...
'daily' => [
'driver' => 'daily',
'path' => storage_path(
function_exists('posix_getpwuid')
&& function_exists('posix_geteuid')
? 'logs/laravel'
. '-' . php_sapi_name()
. '-' . posix_getpwuid(posix_geteuid())['name']
. '.log'
: 'logs/laravel.log'),
'level' => 'debug',
'days' => 15,
],
...
Это приведет к созданию имени журнала, которое должно быть уникальным для каждой комбинации, например laravel-cli-sfscs-2019-05-15.log
или laravel-apache2handler-apache-2019-05-15.log
зависимости от вашей точки доступа.
Ответ 14
Вы можете просто изменить разрешение файла журнала в вашей команде ремесленника:
$path = storage_path('log/daily.log');
chown($path, get_current_user());
где get_current_user() вернет пользователя текущего скрипта.
Другими словами, daily.log
всегда будет иметь www-data
качестве своего владельца, даже если вы инициализируете скрипт как root
пользователь.
Ответ 15
Лучший способ найти, что fideloper предлагает http://fideloper.com/laravel-log-file-name, вы можете настроить конфигурацию журнала laravel без касания класса Log.
У меня есть разные имена для консольных программ и программ Http, я думаю, это лучшее решение.