Laravel daily log created with wrong permissions

2019-01-08 03:37发布

I have a script that I run using php artisan (with root user), and sometimes it causes the daily log file to be created before the apache www-data user does - which means that when a real user uses my web application, I get the folder permission error:

Failed to open stream: Permission denied

I change the permissions back to www-data everytime but I want to solve this by having the log file always created with the correct permissions.

I've considered creating a cron job that creates the file or touches it to make sure it has the right permission everyday, but I'm looking for a better solution that doesn't rely on another script.

We've also considered wrapping php artisan in another script to make sure that it is always run with the www-data credentials, but somethings that we want to do are actually root procedures that apache should not be allowed to do.

Any more suggestions?

13条回答
爷、活的狠高调
2楼-- · 2019-01-08 04:14

The best way I found is that fideloper suggest, http://fideloper.com/laravel-log-file-name, you can set laravel log configuration without touch Log class. Have differents names for Console programs and Http programs, I think, is the best solution.

查看更多
Rolldiameter
3楼-- · 2019-01-08 04:18

Add something like the following to the start of your app/start/artisan.php file (this is with 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);
}

Adjust the path if the daily log file you mention is not the standard Laravel log file. You also may not want to change the group or set the permissions as I am doing here. The above sets the group to www-data and sets group write permissions. I've then added my regular user to the www-data group so that running artisan commands as my regular user can still write to the log.

A related tweak is to put the following at the start of your app/start/global.php file:

umask(0002);

If you do this the chmod line above becomes moot. With the umask set to this, any new files PHP (and therefore Laravel) makes will have their permissions masked only so that "other" users won't have write permissions. This means directories will start as rwxrwxr-x and files as rw-rw-r--. So if www-data is running PHP, any cache and log files it makes will be writeable by default by anyone in that user's main group, which is www-data.

查看更多
疯言疯语
4楼-- · 2019-01-08 04:21

I had this worked very simple way:

I ran into the same problem on Laravel 5.6

In config/logging.php I just updated daily channel's path value with php_sapi_name() in it.

This creates seperate durectory for different php_sapi_name and puts log file with the time stamp into their perticular directory.

'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
            'level' => 'debug',
            'days' => 7,
        ]

So for me,

  • Log files are created under fpm-fcgi directory: Logs from website, owner: www-data
  • Log files are created under cli directory: from the artisan command(cronjob). owner: root

More info on Laravel 5.6 logging: https://laravel.com/docs/5.6/logging

Here is my config/logging.php file:

<?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',
        ],
    ],
];
查看更多
beautiful°
5楼-- · 2019-01-08 04:21

Laravel 5.1

In our case we wanted to create log files so that the all the processes and users in deploy group had read/write permissions - so we needed new created files with permission 0664. Default for new log files is 0644. So this was our solution.

Also we added a formatter to add newlines and a more readable log

$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);
});

Also it's possible to combine this with the accepted answer

$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);
});
查看更多
仙女界的扛把子
6楼-- · 2019-01-08 04:23

One non-Laravel way to make this work is to simply executure your cronjob as www-data.

eg 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

查看更多
beautiful°
7楼-- · 2019-01-08 04:24

Laravel 5.5

Add this code to 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);
});
  • It will store files like this: laravel-2018-01-27-cli-raph.log and laravel-2018-01-27-fpm-cgi-raph.log which is more readable.
  • New lines are preserved (as of default Laravel behavior)
  • It works with Laravel Log Viewer

Laravel 5.6

You have to create a class for your logger:

<?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;
    }
}

Then, you have to register it in config/logging.php:

'channels' => [
    'custom' => [
        'driver' => 'custom',
        'via' => App\Logging\CreateCustomLogger::class,
    ],
],

Same behavior as for 5.5:

  • It will store files like this: laravel-2018-01-27-cli-raph.log and laravel-2018-01-27-fpm-cgi-raph.log which is more readable.
  • New lines are preserved (as of default Laravel behavior)
  • It works with Laravel Log Viewer
查看更多
登录 后发表回答