Avec le développement rapide d'Internet, les services de journalisation sont devenus un module essentiel pour toute application Web à grande échelle. Afin de faciliter divers besoins tels que le dépannage des erreurs et la surveillance des performances, cet article explique comment utiliser le framework ThinkPHP6 pour effectuer des opérations de journalisation asynchrone.
Dans le domaine de l'informatique, la journalisation fait référence à l'enregistrement d'événements et d'informations qui se produisent dans un système informatique. Généralement, ces enregistrements sont stockés dans des fichiers ou des bases de données. La journalisation permet de comprendre l'état de fonctionnement du système, de découvrir et de résoudre les problèmes en temps opportun et d'améliorer ainsi la fiabilité et la stabilité du système.
Dans les applications Web, la journalisation peut aider les développeurs à mieux comprendre les problèmes et les erreurs rencontrés par le système. Grâce à la journalisation, les développeurs peuvent clairement comprendre le comportement de l'application ainsi que l'endroit et le moment où les erreurs se produisent.
Dans le processus de développement d'applications, la journalisation est un module essentiel. De plus, la journalisation est souvent une opération fastidieuse qui peut affecter les performances du système si elle est effectuée de manière synchrone. À cette fin, ThinkPHP6 introduit la fonction de journalisation asynchrone, afin que la journalisation n'affecte plus la vitesse de réponse de l'application.
En nous connectant généralement au contrôleur ou au modèle, nous utilisons l'interface PsrLogLoggerInterface
injectée pour y parvenir. PsrLogLoggerInterface
接口来实现。
// Controller或Model中 use PsrLogLoggerInterface; public function index(LoggerInterface $logger){ $logger->info('hello world'); }
简单的使用方式。使用异步日志记录,定义一个异步日志记录器:
use MonologLogger; use MonologHandlerStreamHandler; $logger=new Logger("AsyncLogger"); $logger->pushHandler(new StreamHandler('runtime/log/async.log'), Logger::INFO);
日志记录器定义好后,使用队列发送日志记录信息,这里我们选择使用 RabbitMQ 当做队列服务。
// 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; } } }
其中,我们使用 appcommonQueue
类来提供 rabbitmq 的连接实例;data
中除了记录日志的信息外,还包含一些环境信息,比如时间、IP地址、请求的uri地址等。
队列处理程序:
// 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); } }
当然,我们还需要一个辅助处理日志的类。
// 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; } } }
上面这段代码中定义了队列连接的 host、port 等,通过 $client->channel()
创建了一个 channel 对象,通过 $channel->exchangeDeclare()
和 $channel->queueDeclare()
创建了 exchange 和 queue,并将它们进行了绑定。最后,使用 $channel->consume()
rrreee
rrreee
Parmi eux, nous utilisons la classeappcommonQueue
pour fournir des instances de connexion Rabbitmq ; en plus de l'enregistrement des informations de journal, data
contient également des informations environnementales, telles que l'heure et l'adresse IP ; adresse, adresse uri demandée, etc. $client->channel()
, et un objet canal est créé via $channel->queueDeclare()
créent un échange et une file d'attente et les lient. Enfin, utilisez $channel->consume()
pour consommer de manière asynchrone les messages de la file d'attente et envoyer les messages à la classe de traitement des messages. Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!