danielme85/laravel-log-to-db

自定义 Laravel 日志通道处理器,可以将日志事件存储到 SQL 或 MongoDB 数据库中。使用 Laravel 本地日志功能。

v4.1.1 2024-02-24 17:23 UTC

README

GitHub PHP from Packagist GitHub release GitHub tag Codecov CodeFactor CircleCI

嗨,这是一个自定义的 Laravel 5.6+ 日志通道处理器,可以将日志事件存储到 SQL 或 MongoDB 数据库中。通过 Monolog 使用 Laravel 本地日志功能。

⚠️ 对于 Laravel 10 及更高版本,请使用此包的版本 4 或更高版本。
对于 Laravel 5.6 到 9,请使用版本 3.x.x。

安装

使用 composer require 或将以下内容添加到 composer.json 中。

composer require danielme85/laravel-log-to-db

如果您使用 SQL 数据库服务器存储日志事件,可以使用包含的迁移。MongoDB 驱动程序不需要迁移。将迁移文件(您也可以在此处进行任何更改或手动将其复制到数据库/migrations 文件夹)复制到您的应用程序中。

php artisan vendor:publish --tag=migrations --provider="danielme85\LaravelLogToDB\ServiceProvider"

运行 Laravel 迁移 artisan 命令。

php artisan migrate

对于可选的 MongoDB 支持,您需要安装 jenseegers/mongodb 扩展到 Laravel

#Optional mongodb support, not required!

composer require jenssegers/mongodb

配置

从 Laravel 5.6 及更高版本开始,您将有一个新的配置文件:"config/logging.php"。您需要在 "channels" 下添加一个数组以配置 Log-to-DB,如下所示

'database' => [
    'driver' => 'custom',
    'via' => danielme85\LaravelLogToDB\LogToDbHandler::class
    ...
    ],

这是开始所需的最小日志配置设置。请注意,数组索引 'database' 可以是您喜欢的任何字符串,只要它在此日志配置中是唯一的。您还可以给日志通道一个名称,稍后可以在 DB 表的列中引用此名称,这样您就可以有多个日志到数据库的通道。

'channels' => [
    'stack' => [
        'name' => 'Log Stack',
        'driver' => 'stack',
        'channels' => ['database', 'other-database', 'file'],
    ],
    'database' => [
        'driver' => 'custom',
        'via' => danielme85\LaravelLogToDB\LogToDbHandler::class,
        'name' => 'Basic DB Logging'
    ],
    'other-database' => [
        'driver' => 'custom',
        'via' => danielme85\LaravelLogToDB\LogToDbHandler::class,
        //'model' => App\Model\Log::class, //Your own optional custom model
        'level' => env('APP_LOG_LEVEL', 'debug'),
        'name' => 'My DB Log with a bunch more settings',
        'connection' => 'default',
        'collection' => 'log',
        'detailed' => true,
        'queue' => false,
        'queue_name' => '',
        'queue_connection' => '',
        'max_records' => false,
        'max_hours' => false,
        'processors' => [
              //Monolog\Processor\HostnameProcessor::class
              // ..
         ]
    ],
    ...
]
  • driver = 必须触发日志驱动程序。
  • via = 日志处理器类。
  • level = 触发此日志通道的最小错误级别。
  • name = 将与日志事件一起存储的通道名称。请注意,如果您使用的是堆栈驱动程序,则使用堆栈数组中的名称值。
  • connection = 要使用的 DB 连接(默认为 'default')。
  • collection = DB 表或集合名称。(默认:log)。
  • detailed = 在异常(如堆栈跟踪)上存储详细日志(默认:true)。
  • processors = 额外处理器的数组。这些将在记录的数据中的 'extra' 字段中添加更多信息。有关处理器的更多信息 更多信息关于处理器

有关一些这些选项的更多信息: https://laravel.net.cn/docs/9.x/logging#customizing-monolog-for-channels

在 'logtodb.php' 配置文件中,有一些默认设置和配置日志器的更多信息。如果您想使用供应商发布命令对其进行编辑,可以将其复制到项目中。

php artisan vendor:publish --tag=config --provider="danielme85\LaravelLogToDB\ServiceProvider"

您还可以在 .env 文件中更改这些设置。

LOG_DB_CONNECTION='default'
LOG_DB_DETAILED=false
LOG_DB_MAX=100
LOG_DB_QUEUE=false
LOG_DB_QUEUE_NAME='logToDBQueue'
LOG_DB_QUEUE_CONNECTION='default'
LOG_DB_MAX_COUNT=false
LOG_DB_MAX_HOURS=false
LOG_DB_DATETIME_FORMAT='Y-m-d H:i:s:ms'

请注意:从 v2.2.0 开始,datetime 列将按 logtodb.php 配置文件中给出的格式作为字符串保存,或在 .env 文件中的 LOG_DB_DATETIME_FORMAT 值。

配置优先级顺序

使用 log-to-db 时,您可以在三个地方更改不同的选项

  1. 配置文件:config/logtodb.php(在执行 vendor:publish 后)。
  2. 您的 .env 文件将覆盖 logtodb.php 配置文件中的设置。
  3. Laravel 日志配置文件:config/logging.php。您需要在此处添加一个自定义数组,如上所述,您可以在该数组中指定/覆盖特定日志通道的配置设置。

第1点和第2点设置的配置值将作为默认值应用于您在Laravel日志配置(config/logging.php)中“channels”数组中添加的所有新日志通道。

日志工作队列

保存日志事件时使用队列工作器可能是个好主意。这样,您的服务器就不必等待保存过程完成。您需要配置Laravel队列设置并运行队列监听器。[运行队列工作器](https://laravel.net.cn/docs/6.x/queues#running-the-queue-worker)

队列可以在以下任何位置启用/禁用

  • LOG_DB_QUEUE = true | 在 .env 文件中
  • queue_db_saves => true | 在 config/logtodb.php 文件中
  • queue => true | 在日志通道配置数组中 -> config/logging.php

使用

由于这是一个针对Laravel的自定义日志通道,因此所有“标准”的生成日志事件等方法都应该与Laravel Log Facade一起工作。更多信息请见[日志文档](https://laravel.net.cn/docs/6.x/logging)。

Log::debug("This is an test DEBUG log event");
Log::info("This is an test INFO log event");
Log::notice("This is an test NOTICE log event");
Log::warning("This is an test WARNING log event");
Log::error("This is an test ERROR log event");
Log::critical("This is an test CRITICAL log event");
Log::alert("This is an test ALERT log event");
Log::emergency("This is an test EMERGENCY log event");

您也可以将日志记录到特定的日志通道:Log::channel('database')->debug("这是一个测试DEBUG日志事件");

获取日志

此通道的日志通过Eloquent模型构建器完成。LogToDB::model($channel, $connection, $collection); 可以省略所有函数变量和config/logtodb.php中的默认设置。

$model = LogToDB::model();
$model->get(); //All logs for default channel/connection

获取日志的更多示例

$logs = LogToDB::model()->get();
$logs = LogToDB::model()->where('level_name', '=', 'INFO')->get();

当获取特定通道或数据库连接和集合的日志时,您可以使用与config/logging.php匹配的通道名称或config/databases.php中的连接名称。如果需要,您还可以在获取模型时指定集合/表名称作为第三个函数变量。

$logsFromDefault = LogDB::model()->get(); //Get the logs from the default log channel and default connection.
$logsFromChannel = LogDB::model('database')->get(); //Get logs from the 'database' log channel.
$logsFromChannel = LogDB::model('customname')->get(); //Get logs from the 'customname' log channel.
$logsFromMysql   = LogToDB::model(null, 'mysql')->get(); //Get all logs from the mysql connection (from Laravel database config)
$logsFromMongoDB = LogToDB::model(null, 'mongodb')->get(); //Get all logs from the mongodb connection (from Laravel database config)
$logsFromMysqlTable  = LogToDB::model(null, 'mysql', 'table')->get(); //Get all logs from the mysql table: 'table'

自定义 Eloquent 模型

由于Laravel预计将使用静态定义的集合/表名称,因此使用您自己的模型可能更好,以更稳健的方式。您可以通过在配置中引用它并添加“LogToDbCreateObject”特性来使用您自己的Eloquent模型。

SQL
namespace App\Models;

use danielme85\LaravelLogToDB\Models\LogToDbCreateObject;
use Illuminate\Database\Eloquent\Model;

class CustomLog extends Model
{
    use LogToDbCreateObject;

    protected $table = 'log';
    protected $connection = 'mysql';
    
}
MongoDB
namespace App\Models;
use danielme85\LaravelLogToDB\Models\LogToDbCreateObject;
use Jenssegers\Mongodb\Eloquent\Model as Eloquent;

class CustomLogMongo extends Eloquent
{
    use LogToDbCreateObject;

    protected $collection = 'log';
    protected $connection = 'mongodb';

}

LOG_DB_MODEL='App\Models\CustomLog'

警告:通过动态Eloquent模型(默认行为)获取模型可能会产生一些副作用,因为表和连接是动态声明的,而不是在模型类中分配属性。某些函数可能会损坏,如LogToDB::model->all(),而LogToDB::model->where()->get()将按正常工作。使用您自己的模型可以避免这些问题。

模型闭包和观察者

您可以在上述自定义应用程序模型上添加闭包,或者为默认的LogToDb模型添加模型观察者
创建观察者

<?php
namespace App\Observers;

use danielme85\LaravelLogToDB\Models\DBLog;

class LogObserver
{
    public function created(DBLog $log)
    {
        //
    }
}

然后将它添加到您的AppServiceProvider(或调用app boot函数的另一个提供者)。

   namespace App\Providers;
   
   use App\Observers\LogObserver;
   use danielme85\LaravelLogToDB\LogToDB;
   use Illuminate\Support\ServiceProvider;
   
   class AppServiceProvider extends ServiceProvider
   {
       public function boot()
       {
           LogToDB::model()->observe(LogObserver::class);
       }
   }

添加表/扩展集合

SQL日志处理器期望以下模式

Schema::create('log', function (Blueprint $table) {
      $table->increments('id');
      $table->text('message')->nullable();
      $table->string('channel')->nullable();
      $table->integer('level')->default(0);
      $table->string('level_name', 20);
      $table->integer('unix_time');
      $table->text('datetime')->nullable();
      $table->longText('context')->nullable();
      $table->text('extra')->nullable();
      $table->timestamps();
 });

这是本插件附带迁移。您可以添加任意数量的表,并在'collection'配置值中引用它们。集合=表,我使用集合这个术语,因为它适用于SQL和非SQL。MongoDB不需要迁移。

默认情况下不会添加索引,所以如果您基于特定的时间范围或类型获取大量日志结果:添加一些索引可能是个好主意。

日志清理

有一些配置值您可以设置,以指定保留日志记录的最大数量或最大记录年龄(以小时为单位)。

  • logging.php通道数组 -> (max_records, max_hours)。
  • .env文件 -> (LOG_DB_MAX_COUNT, LOG_DB_MAX_HOURS)。

这些选项默认设置为false,在运行“log:delete” artisan命令之前必须将它们设置为所需的整数。

php artisan log:delete

此命令将根据上述设置删除记录。将此命令添加到Console/kernel.php,或手动在cron等中运行以启用自动清理。

手动清理

存在一个辅助函数,用于删除最旧的日志事件并保留指定数量

LogToDB::removeOldestIfMoreThan(100);

或者根据日期(必须是strtotime()支持的有效日期/日期时间) https://php.ac.cn/manual/en/function.strtotime.php

LogToDB::model()->removeOlderThan('2019-01-01');
LogToDB::model()->removeOlderThan('2019-01-01 23:00:00');

处理器

Monolog附带了一组处理器,这些处理器将生成额外的数据并填充'extra'字段。我还在这个包的src/Processors目录下添加了一些示例处理器。要启用处理器,可以将它们添加到日志配置数组中

'database' => [
    'driver' => 'custom',
    'via' => danielme85\LaravelLogToDB\LogToDbHandler::class
    ...
    'processors' => [
        \danielme85\LaravelLogToDB\Processors\PhpVersionProcessor::class,
        Monolog\Processor\HostnameProcessor::class,
    ]

您也可以创建自己的自定义处理器,确保它们实现了Monolog\Processor\ProcessorInterface

自定义处理器的示例
<?php

namespace App\CustomProcessors;

use Monolog\Processor\ProcessorInterface;

class PhpVersionProcessor implements ProcessorInterface {
     /**
     * @return array The processed record
     */
     public function __invoke(array $record) {
         $record['extra']['php_version'] = phpversion();
         
         return $record;
     }
}

更多的logging.php配置示例

'default' => env('LOG_CHANNEL', 'stack'),

'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['database', 'mongodb', 'single'],
    ],
    
    'database' => [
        'driver' => 'custom',
        'via' => danielme85\LaravelLogToDB\LogToDbHandler::class,
        'level' => env('APP_LOG_LEVEL', 'debug'),
        'connection' => 'default',
        'collection' => 'log'
        'detailed' => true,
        'queue' => true
        'queue_name' => 'logQueue'
        'queue_connection' => 'redis',
        'max_records' => 1000,
        'max_hours' => 24,
    ],
    
    'mongodb' => [
        'driver' => 'custom',
        'via' => danielme85\LaravelLogToDB\LogToDbHandler::class,
        'level' => 'debug',
        'connection' => 'mongodb',
        'collection' => 'log',
        'detailed' => true,
        'queue' => true
        'queue_name' => 'logQueue'
        'queue_connection' => 'redis'
    ],
    
    'limited' => [
        'driver' => 'custom',
        'via' => danielme85\LaravelLogToDB\LogToDbHandler::class,
        'level' => 'warning',
        'detailed' => false,
        'max_rows' => 10,
        'name' => 'limited',
    ]
    
    'single' => [
        'driver' => 'single',
        'path' => storage_path('logs/laravel.log'),
        'level' => env('APP_LOG_LEVEL', 'debug'),
    ],
    //....
]

Lumen 安装

  • 在项目的根目录下创建一个配置文件夹(如果您还没有的话),然后在那里添加一个logging.php配置文件。以Laravel logging.php配置文件作为示例/起点。您还可以将Laravel配置文件夹中的所有其他“缺失”的配置文件添加到您的Lumen项目中。

  • 要使用这些配置文件,您必须在您的应用的bootstrap/app.php文件中加载它们(或添加自己的服务提供者文件并在该文件中加载它)。

您还需要确保通过以下方式设置logtodb所需的所有基本配置值

  • 从该插件的配置文件夹中复制logtodb.php文件
  • 或者只需将所有日志到数据库的选项添加到您的应用的config/logging.php文件中(可能是最简单的方法)。只需遵循配置部分下面的配置示例。

由于我们使用Lumen,我们需要在"bootstrap/app.php"文件中指定配置和服务提供者。

/*
|--------------------------------------------------------------------------
| Register Config Files
|--------------------------------------------------------------------------
|
| Now we will register the "app" configuration file. If the file exists in
| your configuration directory it will be loaded; otherwise, we'll load
| the default version. You may register other files below as needed.
|
*/

$app->configure('app');
//$app->configure('logtodb'); //if you copied over and want to use the base config from logtodb.
$app->configure('logging');

下一步是注册服务提供者,可以在bootstrap/app.php中或在app/Provider/AppServiceProvider中完成。

/*
|--------------------------------------------------------------------------
| Register Service Providers
|--------------------------------------------------------------------------
|
| Here we will register all of the application's service providers which
| are used to bind services into the container. Service providers are
| totally optional, so you are not required to uncomment this line.
|
*/

// $app->register(App\Providers\AppServiceProvider::class);
// $app->register(App\Providers\AuthServiceProvider::class);
// $app->register(App\Providers\EventServiceProvider::class);
$app->register(\danielme85\LaravelLogToDB\ServiceProvider::class);

添加服务提供者后,您应该能够在Lumen中运行数据库迁移

php artisan migrate --path=vendor/danielme85/laravel-log-to-db/src/migrations/2018_08_11_003343_create_log_table.php

请注意,此时您需要在Lumen中有一个正常工作的数据库连接。

然后可能就成功了... ¯_(ツ)_/¯

使用工作队列将日志写入Lumen数据库

在您可以使用队列之前,需要在Lumen中设置队列驱动程序(默认为:QUEUE_CONNECTION=sync,这基本上是没有队列)。有关Lumen文档中队列的更多信息队列(它们与Laravel大致相同)。我建议使用Redis队列驱动程序,但数据库也应该可以工作。

如何在Lumen中使Redis工作(一般方法)。

通过命令安装

 composer require predis/predis
 composer require illuminate/redis

或者添加到composer.json

...
  "require": {
        "predis/predis": "~1.0",
        "illuminate/redis": "5.0.*",
...

或安装predis的其他替代品。

在bootstrap/app.php文件中添加服务提供者并启用eloquent(如果您使用模型/模型帮助类来获取新的日志事件,则Eloquent是必需的);


$app->withFacades();
$app->withEloquent();

$app->register(Illuminate\Redis\RedisServiceProvider::class);
if (!class_exists('Redis')) {
    class_alias('Illuminate\Support\Facades\Redis', 'Redis');
}

现在您可以设置.env值以使用Redis作为队列和缓存,如果需要的话

REDIS_CLIENT=predis
QUEUE_CONNECTION=redis
CACHE_DRIVER=redis

使用 Docker 进行本地测试

有一个名为'runLocalTestInDocker.sh'的辅助bash脚本,该脚本运行以下Docker命令

docker-compose up -d mariadb mongo &&
docker-compose up php7 &&
docker-compose up php8 &&
docker-compose down

要运行Docker,需要给脚本执行权限并运行

chmod +x runLocalTestInDocker.sh && 
./runLocalTestInDocker.sh

开发由