Maison  >  Article  >  cadre php  >  Comment utiliser ThinkPHP6 pour les opérations de journalisation asynchrone ?

Comment utiliser ThinkPHP6 pour les opérations de journalisation asynchrone ?

WBOY
WBOYoriginal
2023-06-12 09:57:112180parcourir

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.

1. Qu'est-ce que la journalisation

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.

2. Journalisation asynchrone ThinkPHP6

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

Facile à utiliser. Utilisez la journalisation asynchrone pour définir un enregistreur asynchrone :

rrreee

Une fois l'enregistreur défini, utilisez une file d'attente pour envoyer les informations de journalisation. Ici, nous choisissons d'utiliser RabbitMQ comme service de file d'attente.

rrreee

Parmi eux, nous utilisons la classe appcommonQueue 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.
  1. Gestionnaire de file d'attente :
  2. rrreee
  3. Bien sûr, nous avons également besoin d'une classe pour nous aider dans le traitement des journaux.
  4. rrreee
  5. Le code ci-dessus définit l'hôte, le port, etc. de la connexion à la file d'attente. Un objet canal est créé via $client->channel(), et un objet canal est créé via $channel->exchangeDeclare () et $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.
3. Résumé

Cet article explique comment utiliser le framework ThinkPHP6 pour effectuer des opérations de journalisation asynchrone afin que la journalisation n'affecte plus la vitesse de réponse de l'application. En général, voici les étapes : 🎜🎜🎜Développez votre propre enregistreur asynchrone 🎜🎜Utilisez RabbitMQ pour le traitement de la file d'attente des messages 🎜🎜Écrivez un gestionnaire de messages 🎜🎜🎜Dans les projets réels, nous devons optimiser le code en fonction des besoins spécifiques et l'ajuster la configuration de la file d'attente. Grâce à la journalisation asynchrone, l'efficacité opérationnelle des applications Web peut être efficacement améliorée, ainsi que la stabilité et la fiabilité du système. 🎜

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn