laravelS 記錄accesslog日誌,服務慢查詢預警

哪吒的狗腿子發表於2022-02-17

親測生產可用

在網上拼拼湊湊的答案,和自己的想法做了個accesslog,可以記錄在日誌內統計不喜勿噴

功能包含

  1. mysql 慢查詢
  2. 統計sql出現的頻率 和 那些sql 最耗時

laravels實現accessLog,mysql慢查詢報警,cache報警本地debug除錯

  1. cache慢查詢
  2. 介面慢查詢報警
  3. accesslog 日誌

    廢話不說上程式碼/lumen+swoole

  4. lumen bootstrap/app.php 新增全域性中介軟體
     $app->middleware([
          \App\Http\Middleware\Common\AfterTestMiddleware::class,
     ]);
  5. app/Http/Middleware/Common/AfterTestMiddleware.php
     public function handle($request, Closure $next)
     {
         $response =  $next($request);
         TestLog::TestLogFunc();
         return $response;
     }
  6. app/Providers/EventServiceProvider.php 增加 \App\Listeners\QueryListener::class
public function handle(QueryExecuted $event)
{
          $data = request()->get('mysql ',['number'=>0,'result'=>[]]);
          $sql = str_replace('%', "'%%'", $event->sql);
          $sql = str_replace('?', '"' . '%s' . '"', $sql);
          $binding_sql = vsprintf($sql, $event->bindings);
          $data['number'] += 1;
          // 開啟debug
          if (env('APP_DEBUG') == 'true'){
              $data['result'][$binding_sql][] = ['time'=>$event->time.'ms','sql'=>$binding_sql];
          }
          // 報警
          if ($event->time >= 500 ) {
              $binding_sql = vsprintf($sql, $event->bindings);
              $data['slowsql'][$binding_sql] = ['time' => $event->time . 'ms', 'detail' => $event->detail];
              // 釘釘告警 sql慢查詢
              request()->offsetSet('mysql ',$data);
          }
}
<?php
namespace TEST;

class TestLog
{
    /**
     * 記錄access log
     */
    public static function TestLogFunc()
    {
        try {
            // 拼接日誌
            $content = self::xxxxxxx();
            // 寫入日誌
            self::write($content);
            // 檢測是否有慢請求
           $request_time = ((microtime(true) - request()->server('REQUEST_TIME_FLOAT')) * 1000);
            // 判斷是否超時
            if ( 1000 <= $request_time){
                    // 釘釘通知 慢請求
            }

        }catch (\Exception $exception){
            return;
        }
    }

    /**
     * 拼接日誌 日誌格式:[請求時間] 請求方式 狀態碼 路由 引數list 客戶端ip db次數 cache次數 響應時間 hader頭資訊
     *
     * @param $err_code
     * @return string
     */
    public static function xxxxxxx($err_code = 200){
        $request_time = ((microtime(true) - request()->server('REQUEST_TIME_FLOAT')) * 1000);
        $map = request()->all();
        $dbMap = request()->get('mysql',['number'=>0,'result'=>[]]);
        $cacheMap = request()->get('cache',['number'=>0,'result'=>[]]);
        unset($map['mysql'],$map['cache']);
        // access log 拼接
        $content = sprintf('[%s] %s %s %s %s %s db=%s cache=%s time=%dms %s %s',
            date('Y-m-d H:i:s'),
            request()->getMethod(),
            $err_code,
            request()->getPathInfo(),
            json_encode($map,320),
            request()->server('HTTP_X_FORWARDED_FOR') ? request()->server('HTTP_X_FORWARDED_FOR')  : request()->server('REMOTE_ADDR'),
            $dbMap['number'],
            $cacheMap['number'],
            $request_time,
            json_encode(request()->header(),320),
            isset($dbMap['slowsql']) ? 'slowsql='.json_encode($dbMap['slowsql']) : ''
        );
        return $content;
    }

    /**
     *
     * @param $content
     * @param $fileName
     */
    public static function write($content){
        // 守護程式模式 直接寫入檔案
        if (env('DAEMONIZE') == true){
            $fileName =  '/access-' . date('Y-m-d') . '.log';
            file_put_contents($fileName, $content . PHP_EOL, FILE_APPEND);
        }else {
            $fileObject = fopen("php://stdout", "w");
            fwrite($fileObject, $content.PHP_EOL);
            fclose($fileObject);
        }
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章