我每次都会将权限更改回www-data,但我希望通过始终以正确的权限创建日志文件来解决此问题。Failed to open stream: Permission denied
我已考虑创建一个cron作业来创建文件或触摸文件,以确保每天都具有正确的权限,但我正在寻找不依赖于另一个脚本的更好的解决方法。
我们还考虑将php artisan包装在另一个脚本中,以确保始终使用www-data凭据运行,但有些操作实际上是root过程,Apache不应该被允许执行。还有其他建议吗?
我每次都会将权限更改回www-data,但我希望通过始终以正确的权限创建日志文件来解决此问题。Failed to open stream: Permission denied
Laravel 5.6.10及以上版本的配置文件(config/logging.php
)中,single
和daily
驱动程序均支持permission
元素:
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
'days' => 7,
'permission' => 0664,
],
在引导脚本中无需使用Monolog。
具体来说,在https://github.com/laravel/framework/commit/4d31633dca9594c9121afbbaa0190210de28fed8中添加了支持。
'permission' => 0664
对我来说可行(不带引号) - Syclone重要提示:本答案与laravel 5.5+不兼容。请查看此答案:Custom (dynamic) log file names with laravel5.6
让我们从什么是常量开始。
你有一个由root
运行的php artisan
命令。
可以安全地假设该命令每天都会执行。
解决方法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-'.posix_getpwuid(posix_geteuid())['name'].'.log');
如果您的www-data用户创建错误日志,结果将是:storage/logs/laravel-www-data-2015-4-27.log
。storage/logs/laravel-root-2015-4-27.log
。
解决方案2:
更改Artisan命令使用的日志,在您的php脚本中。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能够按用户划分日志,因此更好,因为这样就不会发生任何错误。
编辑:正如Jason指出的那样,get_current_user()
返回脚本所有者的名称。因此,为了应用第一种解决方案,请将你的 Artisan 类文件的所有者更改为所需的用户名。
get_current_user()
返回当前PHP脚本的所有者(根据php.net说明),而不是当前运行脚本的用户。我使用php_sapi_name()
代替,它会提供PHP处理程序的名称(例如apache或cli),这通常会以不同的用户身份运行。 - Jason对于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);
});
当然,你还可以使用许多其他处理程序。
setfacl -d -m g:www-data:rw /full/path/to/laravel/storage/logs
,然后运行 php artisan cache:clear
和 composer dump-autoload
。 - Sawny我在Laravel 5.6上遇到了同样的问题。
在config/logging.php
文件中,我只需将daily通道的路径值更新为php_sapi_name()
。
这将为不同的php_sapi_name创建单独的目录,并将日志文件放置在它们各自的目录中。
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
'level' => 'debug',
'days' => 7,
]
对我而言,
fpm-fcgi
目录下:来自网站的日志,owner: www-data
cli
目录下:来自终端命令(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',
],
],
];
artisan config:cache
命令缓存配置,那么这个方法就不会生效,因为该命令会在命令行 SAPI 中创建一个配置缓存文件,该文件将同时用于命令行和 Web 请求。 - leebget_current_user
不起作用,但是 php_sapi_name
起作用(尽管看起来更丑)。 - Richard Fu对我来说,这个问题不仅限于日志权限...我遇到过与 bootstrap/cache 和 storage 文件夹相关的任何问题,其中一个用户创建文件/文件夹时,另一个用户由于标准的 644 和 755 权限而无法编辑/删除。
典型的情况包括:
apache 用户创建的bootstrap/cache/compiled.php 文件无法被 composer 用户在执行 composer install 命令时编辑
apache 用户创建了缓存,composer 用户无法清除
理想状态是,无论哪个用户创建文件/文件夹,需要访问的其他用户都具有与原始作者完全相同的权限。
简洁版:
下面是操作步骤。
我们需要创建一个名为 laravel 的共享用户组,该组由需要访问 storage 和 bootstrap/cache 目录的所有用户组成。 接下来,我们需要确保新创建的文件和文件夹具有 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 & 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
## optional: enable any daemons we disabled like Apache & Queues
仅出于调试目的,我发现将日志拆分为cli/web +用户对于我的情况非常有益,因此我稍微修改了Sam Wilson的答案。我的用例是队列在自己的用户下运行,因此它有助于区分使用cli(例如单元测试)和队列守护程序的composer用户之间的区别。
$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);
});
除了使用 Laravel 之外,使其工作的一种非常规方法是将 Cron 作业作为 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
Laravel 5.1
在我们的案例中,我们想要创建所有日志文件,以便部署组中的所有内容都具有读写权限。因此,我们需要使用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);
});
将以下代码添加到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
,更易读。您需要为记录器创建一个类:
<?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,
],
],
laravel-2018-01-27-cli-raph.log
和 laravel-2018-01-27-fpm-cgi-raph.log
,更易读。(Laravel 5.6) 我最近遇到了同样的问题,我只需在/app/Console/Kernel.php
中设置一个定时命令即可。
$schedule->exec('chown -R www-data:www-data /var/www/**********/storage/logs')->everyMinute();
我知道这有点过度,但它非常有效,并且自那以后我没有遇到任何问题。
cron
任务,在每天午夜时分(当然要在正确的用户下)touch
一个新的日志文件。 - Ben Haroldphp artisan
。 - Ben Haroldsudo crontab -u www-data -e
以www-data用户身份执行cron。 - Nil Llisterri