Mit der rasanten Entwicklung des Internets sind Protokollierungsdienste zu einem unverzichtbaren Modul für jede große Webanwendung geworden. Um verschiedene Anforderungen wie Fehlersuche und Leistungsüberwachung zu erfüllen, wird in diesem Artikel erläutert, wie Sie mit dem ThinkPHP6-Framework asynchrone Protokollierungsvorgänge durchführen.
In Webanwendungen kann die Protokollierung Entwicklern helfen, die Probleme und Fehler, auf die das System stößt, besser zu verstehen. Anhand der Protokollierung können Entwickler das Verhalten der Anwendung klar nachvollziehen und erkennen, wo und wann Fehler auftreten.
2. ThinkPHP6 asynchrone Protokollierung
Normalerweise protokollieren wir den Controller oder das Modell. Um dies zu erreichen, verwenden wir die injizierte PsrLogLoggerInterface
-Schnittstelle.
// Controller或Model中 use PsrLogLoggerInterface; public function index(LoggerInterface $logger){ $logger->info('hello world'); }
Einfach zu bedienen. Verwenden Sie die asynchrone Protokollierung, um einen asynchronen Logger zu definieren: PsrLogLoggerInterface
接口来实现。
use MonologLogger; use MonologHandlerStreamHandler; $logger=new Logger("AsyncLogger"); $logger->pushHandler(new StreamHandler('runtime/log/async.log'), Logger::INFO);
简单的使用方式。使用异步日志记录,定义一个异步日志记录器:
// Message类 namespace appcommon; class Message { /** * 记录日志 * @param $level * @param $message * @param array $context * @return bool */ public static function log($level,$message,array $context=[]){ $data=[ 'level'=>$level, 'message'=>$message, 'context'=>$context, 'channel'=>'AsyncLogger', 'datetime'=>date('Y-m-d H:i:s'), 'host'=>$_SERVER['SERVER_ADDR'] ?? '', 'uri'=>$_SERVER['REQUEST_URI'] ?? '', ]; $producer=Queue::getConnection('AsyncLogger',true); $producer->setExchangeOptions(['name'=>'async_logs','type'=>'topic','durable'=>true])->declareExchange(); try{ $producer->publish(json_encode($data),[ 'routing_key' =>'log', 'exchange' =>'async_logs', ]); return true; }catch (Exception $e){ return false; } } }
日志记录器定义好后,使用队列发送日志记录信息,这里我们选择使用 RabbitMQ 当做队列服务。
// Consumer类 use BunnyMessage; use PsrLogLoggerInterface; class Consumer { /** * @param Message $message * @param LoggerInterface $logger */ public function process(Message $message,LoggerInterface $logger){ $body=$message->content; $data= json_decode($body,true); $channel=$data['channel'] ?? 'default_logger'; $logger->notice($data['message'], $data); } }
其中,我们使用 appcommonQueue
类来提供 rabbitmq 的连接实例;data
中除了记录日志的信息外,还包含一些环境信息,比如时间、IP地址、请求的uri地址等。
队列处理程序:
// Queue类 namespace appcommon; use BunnyAsyncClient; use BunnyChannel; use BunnyMessage; use BunnyProtocolMethodBasicConsumeOkFrame; use BunnyProtocolMethodChannelCloseFrame; use BunnyProtocolMethodChannelCloseOkFrame; use BunnyProtocolMethodConnectionCloseFrame; use BunnyProtocolMethodConnectionCloseOkFrame; use BunnyProtocolMethodConnectionStartFrame; use BunnyClientStateEnum; use BunnyMessage as BunnyMessage; class Queue { /** * @param string $queueName * @return Client|null */ public static function getConnection(string $routingKey, bool $persistent=false):?Client { $config=config('rabbitmq.async_log'); $client=new Client([ 'host' => $config['host'], 'port' => $config['port'], 'user' => $config['user'], 'password' => $config['password'], 'vhost' => $config['vhost'],//注意此处改为需要的 VHOST 'concurrency' => 2, ]); try{ $client->connect(); $client->channel() ->then(function (Channel $channel) use($client,$routingKey,$persistent){ $channel->exchangeDeclare('async_logs','topic',true,true); $channel->queueDeclare($routingKey, $passive=false,$durable=true,$exclusive=false,$autoDelete=false,$nowait=false); $channel->queueBind($routingKey, 'async_logs', $routingKey); $channel->consume( function ($msg, Channel $channel, BunnyMessage $message) use($client,$routingKey){ $className=config('rabbitmq.async_log.consumer'); $consumer=new $className($client,$routingKey); $consumer->process($message,app('log.async_logger')); $channel->ack($msg);//处理消息 }, $routingKey,//队列Name '',//消费Tag false,//no_local false,//no_ack false,//exclusive $persistent ? ['delivery_mode'=>2] : [] ); }); }catch (Exception $e){ return null; }finally{ return $client; } } }
当然,我们还需要一个辅助处理日志的类。
rrreee上面这段代码中定义了队列连接的 host、port 等,通过 $client->channel()
创建了一个 channel 对象,通过 $channel->exchangeDeclare()
和 $channel->queueDeclare()
创建了 exchange 和 queue,并将它们进行了绑定。最后,使用 $channel->consume()
rrreee
appcommonQueue
, um Rabbitmq-Verbindungsinstanzen bereitzustellen. Zusätzlich zur Aufzeichnung von Protokollinformationen enthält data
auch einige Umgebungsinformationen wie Zeit und IP Adresse, angeforderte URI-Adresse usw. Warteschlangenhandler: $client->channel()
erstellt, und ein Kanalobjekt wird über $channel->exchangeDeclare ()
und $channel->queueDeclare()
erstellen Exchange und Warteschlange und binden sie. Verwenden Sie abschließend $channel->consume()
, um Nachrichten aus der Warteschlange asynchron zu konsumieren und an die Nachrichtenverarbeitungsklasse zu senden. Das obige ist der detaillierte Inhalt vonWie verwende ich ThinkPHP6 für asynchrone Protokollierungsvorgänge?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!