Laravel gracefully added enterprise WeChat/fly book robot log notification


  • /Add register in app/Providers/AppServiceProvider.php file
 use use Illuminate\Support\Facades\Log; use App\Handler\FeishuWebhookHandler; use App\Handler\WorkWeixinWebhookHandler; use Monolog\Logger as Monolog; Log::extend('feishu',function ($app,$config){ return new Monolog($this->parseChannel($config), [ $this->prepareHandler(new FeishuWebhookHandler($config)), ]); }); Log::extend('work_weixin',function ($app,$config){ return new Monolog($this->parseChannel($config), [ $this->prepareHandler(new WorkWeixinWebhookHandler($config)), ]); });
  • /Add channels array in the config/loging.php file
 'feishu'=>[ 'driver' => 'feishu', 'level' => env('LOG_LEVEL', 'debug'), 'host' => env('LOG_FEISHU_HOST',' https://open.feishu.cn '), 'url' =>  env('LOG_FEISHU_URL',''), 'token' => env('LOG_FEISHU_TOKEN',''), 'lock_time'=>10//The same error content is locked for 10 seconds ], 'work_weixin'=>[//WeChat 'driver' => 'work_weixin', 'level' => env('LOG_LEVEL', 'debug'), 'host' => env('LOG_WORK_WEIXIN_HOST',' https://qyapi.weixin.qq.com '), 'url' =>  env('LOG_WORK_WEIXIN_URL','/cgi-bin/webhook/send'), 'token' => env('LOG_WORK_WEIXIN_TOKEN',''), 'lock_time'=>10//The same error content is locked for 10 seconds ],
  • Create processing file class
  1. /App/Handler/FeishuWebhookHandler.php Call of flying book robot
 <? php declare(strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano < j.boggiano@seld.be > * * For the full copyright and license information,  please view the LICENSE * file that was distributed with this source code. */ namespace App\Handler; use GuzzleHttp\Client as GuzzleHttpClient; use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\RequestOptions; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Log; use Monolog\Handler\AbstractProcessingHandler; use Monolog\Handler\Slack\SlackRecord; use Swoole\Coroutine; /** * Sends notifications through Slack Webhooks * * @author Haralan Dobrev < hkdobrev@gmail.com > * @see     https://api.slack.com/incoming-webhooks */ class FeishuWebhookHandler extends AbstractProcessingHandler { /** * Slack Webhook token * @var string */ protected $webhookUrl; /** * Instance of the SlackRecord util class preparing data for Slack API. * @var SlackRecord */ protected $token=''; protected $lock_time = 0; public function __construct($config) { if (! extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the FeishuWebhookHandler'); } $bubble = $config['bubble'] ??  true; parent::__construct($config['level'], $bubble); $this->webhookUrl = $config['host'].$ config['url']; $this->token = $config['token']; $this->lock_time = Arr::get($config,'lock_time',0)?: 0; } public function getWebhookUrl(): string { return $this->webhookUrl; } protected function makeSign($time = '') { $timestamp = $time ? $ time : time(); $secret = $this->token; $string = "{$timestamp}\n{$secret}"; return base64_encode(hash_hmac('sha256', "", $string, true)); } /** * {@inheritDoc} */ protected function write(array $record): void { if($this->lock_time){ $key = 'logs_feishu_lock:'.md5(Arr::get($record,'message','')); if(Cache::get($key)){ return; } Cache::put($key,1,now()->addSecond($this->lock_time)); } $timestamp = time(); $postData = [ "timestamp" => $timestamp, "sign" => $this->makeSign($timestamp), "msg_type" => "text", "content" => [ "text" => $this->getFormatter()->format($record), ] ]; $sendCallBack = $this->sendCallBack(); if(Coroutine::getcid()>0){ Coroutine\go($sendCallBack,$postData); }else{ register_shutdown_function($sendCallBack,$postData); } } /** *Send message callback function * @return \Closure */ protected function sendCallBack(){ return function ($postData){ try { $client = new GuzzleHttpClient([ 'timeout' => 5, ]); $response = $client->request('POST', $this->webhookUrl, [ 'headers' => [ 'content-type' => 'application/json', ], RequestOptions::JSON => $postData, ]); $body = $response->getBody()->getContents(); $data = json_decode($body, true); if (Arr::get($data, 'StatusMessage') != ' success') { $error = ['action' => __METHOD__, 'post_data' => $postData, 'response' => $data]; Log::channel('daily')->error('FeishuBot sendMsg Exception',$error); } } catch (GuzzleException $e) { $error = [ 'action' => __METHOD__, $e->getCode() => $e->getMessage(), 'post_data' => $postData]; Log::channel('daily')->error('FeishuBot sendMsg Exception',$error); } }; } }
  1. /App/Handler/WorkWeixinWebhookHandler.php Enterprise WeChat robot call
 <? php declare(strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano < j.boggiano@seld.be > * * For the full copyright and license information,  please view the LICENSE * file that was distributed with this source code. */ namespace App\Handler; use GuzzleHttp\Client as GuzzleHttpClient; use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\RequestOptions; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Log; use Monolog\Handler\AbstractProcessingHandler; use Monolog\Handler\Slack\SlackRecord; use Swoole\Coroutine; use function Swoole\Coroutine; /** * Sends notifications through Slack Webhooks * * @author Haralan Dobrev < hkdobrev@gmail.com > * @see     https://api.slack.com/incoming-webhooks */ class WorkWeixinWebhookHandler extends AbstractProcessingHandler { /** * Slack Webhook token * @var string */ protected $webhookUrl; /** * Instance of the SlackRecord util class preparing data for Slack API. * @var SlackRecord */ protected $token=''; protected $lock_time = 0; public function __construct($config) { if (! extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the WorkWeixinWebhookHandler'); } $bubble = $config['bubble'] ??  true; parent::__construct($config['level'], $bubble); $this->webhookUrl = $config['host'].$ config['url']; $this->token = $config['token']; $this->lock_time = Arr::get($config,'lock_time',0)?: 0; } public function getWebhookUrl(): string { return $this->webhookUrl; } /** * {@inheritDoc} */ protected function write(array $record): void { if($this->lock_time){ $key = 'logs_work_weixin_lock:'.md5(Arr::get($record,'message','')); if(Cache::get($key)){ return; } Cache::put($key,1,now()->addSecond($this->lock_time)); } $postData = [ 'msgtype'=>'markdown', 'markdown'=>[ 'content'=>$this->getFormatter()->format($record) ] ]; $sendCallBack = $this->sendCallBack(); if(Coroutine::getcid()>0){ Coroutine\go($sendCallBack,$postData); }else{ register_shutdown_function($sendCallBack,$postData); } } /** *Send message callback function * @return \Closure */ protected function sendCallBack(){ return function ($postData){ try { $client = new GuzzleHttpClient([ 'timeout' => 5, ]); $response = $client->request('POST', $this->webhookUrl, [ RequestOptions::HEADERS=> [ 'Content-Type' => 'application/json', ], RequestOptions::BODY => json_encode($postData), RequestOptions::QUERY=>[ 'key'=>$this->token ] ]); $body = $response->getBody()->getContents(); $data = json_decode($body, true); if (Arr::get($data, 'errcode') !==  0) { $error = [ 'action' => __METHOD__, 'post_data' => $postData, 'response' => $data?:$ body ]; Log::channel('daily')->error('WorkWeixin sendMsg Exception',$error); } } catch (GuzzleException $e) { $error = [ 'action' => __METHOD__, $e->getCode() => $e->getMessage(), 'post_data' => $postData ]; Log::channel('daily')->error('WorkWeixin sendMsg Exception',$error); } }; } }

give the thumbs-up Cancel Like Collection Cancel Collection

<<Previous: Leetcode PHP -- D141 66 Plus One

>>Next: There is no next article