這邊以Tp為例子,Laravel 差不多也是一樣的,其實學會了這個框架複寫可以做很多有趣的事情
在我以往的開發的過程中,會寫一些錯誤的日誌,但是一般運營那邊沒有反饋,我們也不太會在意日誌,所以一般小機率的報錯也不會有人察覺,這樣不好,不好。
在當下網際網路寒冬,容不得我們半點馬虎,所以還是要認真對待自己的工作,報錯的時候第一時間知道,偷偷的改掉。
藉助免費的釘釘訊息通知,可以很方便實現我們客戶端的通知,但是也不能讓程式一直 傳送這個錯誤資訊吧,所以還是要做限制的,一天同一個錯誤不超過我們自己指定的數量。
- 繼承方式 修改 Log 原始碼加入釘釘通知邏輯
- 站在在巨人的肩膀上觸發具體的釘釘通知
檢視 config/log.php
檔案程式碼,看到框架已經相容了多渠道配置的方式,比如這邊可以用file的方式,當然也可以擴充套件es或者kafka的驅動方式
├─log
│ │ Channel.php
│ │ ChannelSet.php
│ │
│ └─driver
│ File.php
│ Socket.php
其實如何寫擴充套件,官方文件也沒有寫,這個就需要結合大家的經驗去做了。這就需要查閱原始碼才可以實現了。
當我配置一個渠道為fileNotice
執行一下程式報:Driver [FileNotice] not supported
我們就可以根據 這個not supported
關鍵詞找到具體報錯的位置了。
/**
* 獲取驅動類
* @param string $type
* @return string
*/
protected function resolveClass(string $type): string
{
if ($this->namespace || false !== strpos($type, '\\')) {
$class = false !== strpos($type, '\\') ? $type : $this->namespace . Str::studly($type);
if (class_exists($class)) {
return $class;
}
}
throw new InvalidArgumentException("Driver [$type] not supported.");
}
以上就是具體報錯的位置,從這邊的判斷,如果包含反斜槓,也就是名稱空間+類 就直接引用了,最終我的配置檔案這樣寫
<?php
// +----------------------------------------------------------------------
// | 日誌設定
// +----------------------------------------------------------------------
return [
// 預設日誌記錄通道
'default' => env('log.channel', 'fileNotice'),
// 日誌記錄級別
'level' => [],
// 日誌型別記錄的通道 ['error'=>'email',...]
'type_channel' => [],
// 關閉全域性日誌寫入
'close' => false,
// 全域性日誌處理 支援閉包
'processor' => null,
// 日誌通道列表
'channels' => [
'file' => [
// 日誌記錄方式
'type' => 'File',
// 日誌儲存目錄
'path' => '',
// 單檔案日誌寫入
'single' => false,
// 獨立日誌級別
'apart_level' => [],
// 最大日誌檔案數量
'max_files' => 0,
// 使用JSON格式記錄
'json' => false,
// 日誌處理
'processor' => null,
// 關閉通道日誌寫入
'close' => false,
// 日誌輸出格式化
'format' => '[%s][%s] %s',
// 是否實時寫入
'realtime_write' => false,
],
'fileNotice' => [
// 日誌記錄方式
'type' => 'app\log\FileNotice',
// 日誌儲存目錄
'path' => '',
// 單檔案日誌寫入
'single' => false,
// 獨立日誌級別
'apart_level' => [],
// 最大日誌檔案數量
'max_files' => 0,
// 使用JSON格式記錄
'json' => false,
// 日誌處理
'processor' => null,
// 關閉通道日誌寫入
'close' => false,
// 日誌輸出格式化
'format' => '[%s][%s] %s',
// 是否實時寫入
'realtime_write' => false,
//釘釘token
'token' => 'xxx',
//釘釘secret
'secret' => 'xxx',
],
// 其它日誌通道配置
],
];
這邊新增了釘釘token
的配置項和secret
的配置項,這邊可以靈活的使用 env 不同環境之間的切換
接下去建立具體的日誌檔案 app/log/FileNotice
,我們繼承檔案 File 型別就好了
<?php
namespace app\log;
use think\log\driver\File;
class FileNotice extends File
{
}
現在可以複寫具體的類和方法了,差一個釘釘傳送的功能,這個之前論壇老哥已經推薦過訊息傳送的包,直接引用即可。
composer require guanguans/notify -vvv
save 是複製過來的方法 具體實現程式碼:
<?php
namespace app\log;
use Guanguans\Notify\Factory;
use think\log\driver\File;
class FileNotice extends File
{
/**
* 日誌寫入介面
* @access public
* @param array $log 日誌資訊
* @return bool
*/
public function save(array $log): bool
{
$destination = $this->getMasterLogFile();
$path = dirname($destination);
!is_dir($path) && mkdir($path, 0755, true);
$info = [];
// 日誌資訊封裝
$time = \DateTime::createFromFormat('0.u00 U', microtime())->setTimezone(new \DateTimeZone(date_default_timezone_get()))->format($this->config['time_format']);
foreach ($log as $type => $val) {
$message = [];
foreach ($val as $msg) {
if (!is_string($msg)) {
$msg = var_export($msg, true);
}
$message[] = $this->config['json'] ?
json_encode(['time' => $time, 'type' => $type, 'msg' => $msg], $this->config['json_options']) :
sprintf($this->config['format'], $time, $type, $msg);
}
if (true === $this->config['apart_level'] || in_array($type, $this->config['apart_level'])) {
// 獨立記錄的日誌級別
$filename = $this->getApartLevelFile($path, $type);
$this->write($message, $filename);
continue;
}
$send_num = cache($msg) ?? 0;
//這邊寫入釘釘傳送的邏輯
if ($type == 'error' && $send_num < 1) {
Factory::dingTalk()
->setToken($this->config['token'])
->setSecret($this->config['secret'])
->setMessage((new \Guanguans\Notify\Messages\DingTalk\LinkMessage([
'title' => '錯誤詳情',
'text' => $msg,
'messageUrl' => $this->config['messageUrl'],
'picUrl' => 'https://avatars.githubusercontent.com/u/22309277?v=4',
])))
->send();
cache($msg, $send_num+1, 24 * 3600);
}
$info[$type] = $message;
}
if ($info) {
return $this->write($info, $destination);
}
return true;
}
}
觸發
Log::error('測試報錯');
效果:
寒冬來了,有義務 分享給瑟瑟發抖的各位
本作品採用《CC 協議》,轉載必須註明作者和本文連結