trd-rdm/stack-logger

一个可以同时记录多个通道的复合日志记录器。

v0.1.8 2023-01-30 03:14 UTC

This package is auto-updated.

Last update: 2024-09-29 05:49:59 UTC


README

简介

使用Laravel框架的logging与facades功能组成的复合型工具,可以在程序的任何一处通过facade调用,方便开发使用

目录

  1. 安装步骤
  2. 各个Logger的介绍与配置
  3. Logger的使用方法
  4. 代码示例

1. 安装步骤 [返回目录]

(1) 执行安装指令

    composer require trd-rdm/stack-logger --with-all-dependencies

(2) 注册Service Provider以使用Log Facade

打开config/app.php,在providers数组底部添加RDM\StackLogger\StackLoggerServiceProvider注册facade

'providers' => [
     /*
     * Package Service Providers...
     */
    RDM\StackLogger\StackLoggerServiceProvider::class,
]

(3) 添加注册多种loggers以支持facade功能

打开config/logging.php,将以下logger添加到channels数组中,根据需求调整stack_logger中channels的内容,但不建议添加storage

return [
    
    'channels' => [
        /**
         * Log Facade
         * 主要 logger , 以 stack driver 結合多個 custom log 同時呼叫
         * 加入 channels 的 driver 可以在 GCPLog 中呼叫
         */
        'stack_logger'   => [
            'driver'            => 'stack',
            'channels'          => ['console', 'file'],        // 指定多種 log 頻道, 可以自由添加移除 (可添加選項 : ['console', 'file', 'storage', 'stackdriver', 'telegram'])
            'ignore_exceptions' => false,
        ],    
        /**
         * 1. 螢幕輸出: 彩色字體
         */
        'console'     => [
            'driver'    => 'monolog',
            'level'     => env('LOG_LEVEL', 'debug'),   // The minimum logging level at which this handler will be triggered
            'handler'   => RDM\StackLogger\Handlers\ConsoleLogger::class,
            'formatter' => env('LOG_STDERR_FORMATTER'),
            'with'      => [
            ],
        ],
        /**
         * 2. 文件檔案 : 需要指定寫入檔案路徑
         */
        'file'        => [
            'driver'    => 'monolog',
            'level'     => env('LOG_LEVEL', 'debug'),
            'handler'   => RDM\StackLogger\Handlers\FileLogger::class,
            'formatter' => env('LOG_STDERR_FORMATTER'),
            'with'      => [
                // handler constructor 額外參數
                'default_path' => storage_path('default.log'),    // 預設檔案路徑
                'permission'   => 0775,       // The log file's permissions
                'locking'      => false,         // 	Attempt to lock the log file before writing to it
            ],
        ],
        /**
         * 3. GCP Storage 儲存空間 : 需要指定本地上傳檔案路徑 與 storage 路徑
         *
         * 結果請至 GCP Cloud Storage - Browser查看
         *
         * @link https://console.cloud.google.com/storage/browser
         */
        'storage'     => [
            'driver'    => 'monolog',
            'level'     => env('LOG_LEVEL', 'debug'),
            'handler'   => RDM\StackLogger\Handlers\GcpStorageLogger::class,
            'formatter' => env('LOG_STDERR_FORMATTER'),
            'with'      => [
                'gcp_project_id'  => 'your-gcp-project',                  // GCP Project
                'credential_path' => 'your-local-credential-file-path',          // 憑證路徑 (專案根目錄為 root)

                'bucket_id'     => 'your-storage-bucket-id',     // GCP Storage bucket 名稱
                'bucket_folder' => 'bucket-folder1/folder2',       // 此 logger 在 bucket id 底下的 root 路徑
                'bucket_path'   => '',                          // bucket_folder 底下的檔案路徑, 需要使用者用 setPath() 設置後才能寫入
                'ignore_exceptions' => false,                   // 上傳失敗時不要拋出例外
            ],
        ],

        /**
         * 4. GCP Stackdriver : 需要指定 log 名稱
         *
         * 輸出結果請至 Google Console 查詢 Log
         *
         * @link https://console.cloud.google.com/logs
         */
        'stackdriver' => [
            'driver'    => 'monolog',
            'level'     => env('LOG_LEVEL', 'debug'),
            'handler'   => RDM\StackLogger\Handlers\StackdriverLogger::class,
            'formatter' => env('LOG_STDERR_FORMATTER'),
            'with'      => [
                'name'            => 'your-stackdriver-logging-name',        // log 名稱 (在 google console 查詢過濾條件 logName 的值)
                'gcp_project_id'  => 'rdm-bbos',
                'credential_path' => '/rdm-bbos.json',          // 憑證路徑 (專案根目錄為 root)
                'batch_enabled'   => true,                      // 允許批次送出多筆 log 紀錄, 避免每次送出產生高延遲
            ],
        ],
        /**
         * 5. Telegram 通知 : 需要指定 接收者 chat_id 與 api_key 機器人群組
         */
        'telegram'    => [
            'driver'    => 'monolog',
            'level'     => env('LOG_LEVEL', 'debug'),   // The minimum logging level at which this handler will be triggered
            'handler'   => RDM\StackLogger\Handlers\TelegramLogger::class,
            'formatter' => env('LOG_STDOUT_FORMATTER'),
            'with'      => [
                'chat_ids'              => ['1378441015'],  // 收信者
                'disable_notification' => false,        // 關閉通知提示音
                'api_key'              => (env('APP_ENV') === 'prod')
                    ? env('TELEGRAM_BOT_TOKEN', 'xxxxx')    // 正式 Bot
                    : env('TELEGRAM_BOT_TOKEN', 'xxxxx'),   // 測試 Bot
            ],
        ],

    ]
];

调整stack_logger的channels以选择你需要的channels,并对以下五种log设置参数。这五种log都是monolog log,关于这些参数定义可以参考Laravel Logging - Creating Monolog Handler Channel

2. Logger各自的介绍与配置 [返回目录]

打开config/logging.php中可以看到新添加入的logger底下将各自作介绍。

  1. stack_logger

    首先stack_logger即GCPLog Facade功能,它是一种Laravel Log stack类型

    需要设置的参数有

    • channels: 添加或移除你需要的log名称,可以开启或关闭指定log功能,让你在调用此log时可以一次执行多种channels中的log,而不用分别调用。

    例如,如果channel中包含'console', 'file', 'storage', 'stackdriver', 'telegram'。

    则调用以下这一行

    Log::channel('stack_logger')->info('info message');

    相当于执行以下几行

    Log::channel('console')->info('info message');
    Log::channel('file')->info('info message');
    Log::channel('storage')->info('info message');
    Log::channel('stackdriver')->info('info message');
    Log::channel('telegram')->info('info message');
  2. console

    屏幕输出,即传统意义上的print,只是根据log等级会有不同的文字色彩,根据信息重要程度增加辨识度。

    需要设置的参数有

    • level: 什么等级(含)以上的log才需要被执行,例如将level设置为'info',则debug等级的log不会印到屏幕上
  3. file

    写入本地文件。

    需要设置的参数有

    • default_path: 指定预写入的log文件路径
  4. storage

    上传文件到Google Cloud Storage,使用此log的话每写入一行log就会,同步上传file logger设置的文件内容到你指定的Storage Bucket文件之中。

    * 请注意两次调用storage logger(上传)的时间间隔过短,会使Google API上传抛出异常,如果想要忽略异常的话,请将ignore_exceptions参数设成true

    需要设置的参数有

    • gcp_project_id: GCP项目名称
    • credential_path: GCP API凭证文件,请设置本地相对于项目根目录的文件路径
    • bucket_id: Storage Bucket名称
    • bucket_folder: Storage文件在bucket底下的文件夹,通常执行时不变动
    • bucket_path: Storage文件在bucket_folder底下的路径
    • ignore_exceptions: 写log(上传文件)失败时不抛出异常
  5. stackdriver

    写入的log会通过GCP API传送到Google Stackdriver存储,可以通过GCP Log记录文件探索工具查看,查询时的过滤条件就可以带入 logName="your-stackdriver-logging-name",以查到执行结果,目前此stackdriver log记录是30日后会自动消失。

    需要设置的参数有

    • gcp_project_id: GCP项目名称
    • credential_path: GCP API凭证文件,请设置本地相对于项目根目录的文件路径
    • name: log名称,在google console查询过滤条件logName的值
    • [batch_enabled: 允许批量送出多笔log记录,避免每次送出API产生高延迟,影响程序效率
  6. telegram

    通过telegram bot通知发送消息给指定一位或多位收信者。

    需要设置的参数有

    • chat_ids: 收信者的telegram user id
    • disable_notification: 关闭通知提示音
    • api_key: 注册机器人时Telegram官方提供的Telegram Bot API Token

3. Logger 使用方法 [返回目录]

您可以使用集成到 stack_logger 驱动的 GCPLog Facade(以下简称 GCPLog)。
也可以使用 Laravel 原生的 Log Facade(以下简称 Log)进行日志记录。

但是 Log 只支持 PSR-3 标准的接口函数,您无法在程序执行期间动态修改 config/logging.php 中的参数,以修改 logger 参数,例如设置文件路径等,执行期间对 config 的更改不会影响到已经建立的静态(static)实例的 Log

GCPLog 提供了一些接口,让您能够在执行期间设置参数,以及集成部分日志记录之外的调试函数,方便程序员开发。

以下为 GCPLog 支持的函数介绍

代码示例 [返回目录]

  1. Log 成功与错误消息 跳至函数

    use RDM\StackLogger\Facades\GCPLog;
    use \Psr\Log\LogLevel;
    
    // 成功訊息 
    GCPLog::info('success');
    
    // 同上成功訊息
    GCPLog::log(LogLevel::INFO, 'success', ['success' => true, 'result' => []]);
    
    try {
            // ...
    } catch (\Exception $exception) {
        // 錯誤訊息
        GCPLog::error('something wrong');
        
        // 印出漂亮格式的錯誤訊息
        GCPLog::renderException($exception);
    
        // 匯出例外訊息成 HTML 檔
        GCPLog:dumpExceptionPrettyPage($exception, storage_path('exception.html'));
    }
  2. 设置 Log 路径 跳至函数

    use RDM\StackLogger\Facades\GCPLog;
    
    // 設置路徑參數
    GCPLog::setLocalLogPath(storage_path('logs/err.log'))    // 設置 log 檔案參數
        ->setStackDriverLogName('stack-driver-log-name');       // 設置 stackdriver log 名稱
       
    GCPLog::info("message");
    
    // 讀取路徑參數
    fprintf("All messages are written at file %s", GCPLog::getLocalLogPath());   // 取得 log 檔案路徑
    fprintf("All messages are export to stackdriver: %s", GCPLog::getStackDriverLink());     // 取得 stackdriver log 存取連結
  3. Telegram 跳至函数

    use RDM\StackLogger\Facades\GCPLog;
    try {
        $john_user_id = '12345';
        GCPLog::setTelegramChatIds([$john_user_id])  // 設置收訊者
            ->disableTelegramNotification();        // 關閉通知聲響   
        
        GCPLog::info('<b>TITLE</b> message');    // 送出通知 (支援 html 格式,若要避免請使用 `htmlspecialchars()` 跳脫或是 <pre> 包覆)
    } catch (\Throwable $e) {
       // html tag 限制 https://core.telegram.org/api/entities#allowed-entities
       // 最大文字長度 : 4096 字元
       dump($e);
    }

    如果 config/logging.php 默认调用通道 channels.stack_logger.channels 中没有 telegram,则应使用 调用内部 logger 函数

    GCPLog::telegram()->info('<b>TITLE</b> message');
  4. 计时器 1 跳至函数

    use RDM\StackLogger\Facades\GCPLog;
    
    GCPLog::watch();     // 開始計時
    
    /*
    * Code Block 1
    */
    
    GCPLog::timing('執行 Code Block 1');
    
    /*
    * Code Block 2
    */
    GCPLog::timing('執行 Code Block 2');
    
    /**
    範例輸出結果:
    執行 Code Block 1 1.500 sec
    執行 Code Block 2 1.500 sec
    */
  5. 计时器 2 跳至函数

    use RDM\StackLogger\Facades\GCPLog;
    
    $timer = GCPLog::createTimer();
    $timer->setDescription('執行 Code Block 1');
    
    for($i = 5; $i > 0; $i--) {
      $timer->start();
      sleep(1);
      $timer->stop();
       sleep(2);
    }
    echo (string)$timer;
    
    /**
    範例輸出結果:
    執行 Code Block 1 花費 : 5.01 秒
    */
  6. SQL Log 跳至函数

    use RDM\StackLogger\Facades\GCPLog;
    use Illuminate\Support\Facades\DB;
    
    $connection = 'mysql';
    GCPLog::enableMysqlGeneralLog($connection);   // 啟用 mysql general log
    
    DB::connection($connection)->table('users')->get(); // send query
    
    GCPLog::disableMysqlGeneralLog($connection);   // 停用 mysql general log
  7. 调用内部 logger:当函数 config/logging.php 默认调用通道 channels.stack_logger.channels 中不包含的通道时,可以使用此方法单独调用。 跳至函数

    use RDM\StackLogger\Facades\GCPLog;
    use Illuminate\Support\Facades\DB;
    
    // 選取 GCPLog 中的特定 logger, 執行其內部函式 
    GCPLog::file()->setPath(storage_path('laravel.log'));     
    GCPLog::console()->info('message');
    GCPLog::telegram()->info('<b>TITLE</b> message');