With the rapid development of the Internet, logging services have become an essential module for every large-scale web application. In order to facilitate various needs such as error troubleshooting and performance monitoring, this article will introduce how to use the ThinkPHP6 framework to perform asynchronous logging operations.
In the field of computer science, logging refers to recording events and information that occur in a computer system. Typically, these records are stored in files or databases. Logging helps to understand the operating status of the system, discover and solve problems in a timely manner, and thereby improve the reliability and stability of the system.
In web applications, logging can help developers better understand the problems and errors encountered by the system. Based on logging, developers can clearly understand the behavior of the application and where and when errors occur.
In the application development process, logging is an essential module. Moreover, logging is often a time-consuming operation that can affect system performance if performed synchronously. To this end, ThinkPHP6 introduces the function of asynchronous logging, so that logging no longer affects the response speed of the application.
Usually logging in the controller or model, we use the injected PsrLogLoggerInterface
interface to achieve this.
// Controller或Model中 use PsrLogLoggerInterface; public function index(LoggerInterface $logger){ $logger->info('hello world'); }
Easy to use. Use asynchronous logging to define an asynchronous logger:
use MonologLogger; use MonologHandlerStreamHandler; $logger=new Logger("AsyncLogger"); $logger->pushHandler(new StreamHandler('runtime/log/async.log'), Logger::INFO);
After the logger is defined, use a queue to send logging information. Here we choose to use RabbitMQ as the queue service.
// 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; } } }
Among them, we use the appcommonQueue
class to provide rabbitmq connection instance; data
in addition to recording log information, also contains some environmental information, such as time, IP address, requested URI address, etc.
Queue handler:
// 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); } }
Of course, we also need a class to assist in processing logs.
// 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; } } }
The above code defines the host, port, etc. of the queue connection. A channel object is created through $client->channel()
, and a channel object is created through $channel- >exchangeDeclare()
and $channel->queueDeclare()
create exchange and queue and bind them. Finally, use $channel->consume()
to asynchronously consume messages from the queue and send the messages to the message processing class.
This article introduces how to use the ThinkPHP6 framework to perform asynchronous logging operations so that logging no longer affects the response speed of the application. In general, the following are the steps:
In actual projects, we need to optimize the code and adjust the queue configuration according to specific needs. Through asynchronous logging, the operating efficiency of web applications can be effectively improved, and the stability and reliability of the system can be improved.
The above is the detailed content of How to use ThinkPHP6 for asynchronous logging operations?. For more information, please follow other related articles on the PHP Chinese website!