如何使用ThinkPHP6进行异步日志记录操作?

来源:undefined 2024-12-28 02:35:55 1046

随着互联网的高速发展,日志记录服务成为了每个大型 web 应用必不可少的模块。为了方便错误排查、性能监控等各种需求,本文将介绍如何使用 thinkphp6 框架进行异步日志记录操作。

1. 什么是日志记录

在计算机科学领域,日志记录是指将计算机系统中发生的事件和信息记录下来。通常,这些记录都以文件或数据库的形式存储。日志记录有助于了解系统运行状况,及时发现和解决问题,进而提高系统的可靠性和稳定性。

在 web 应用中,日志记录可以帮助开发者更好地了解系统的遇到的问题和错误。依据日志记录,开发者可以清楚地了解应用的行为以及错误发生的位置和时机。

2. ThinkPHP6 异步日志记录

在应用开发过程中,日志记录是一个必不可少的模块。而且,日志记录经常是一个耗时的操作,如果同步执行的话会影响系统的性能。为此,ThinkPHP6 引入了异步日志记录的功能,让日志记录不再影响应用的响应速度。

通常在控制器或模型中记录日志,我们使用注入 PsrLogLoggerInterface 接口来实现。

1

2

3

4

5

6

// Controller或Model中

use PsrLogLoggerInterface;

public function index(LoggerInterface $logger){

$logger->info(hello world);

}

登录后复制

简单的使用方式。使用异步日志记录,定义一个异步日志记录器:

1

2

3

4

5

use MonologLogger;

use MonologHandlerStreamHandler;

$logger=new Logger("AsyncLogger");

$logger->pushHandler(new StreamHandler(runtime/log/async.log), Logger::INFO);

登录后复制

日志记录器定义好后,使用队列发送日志记录信息,这里我们选择使用 RabbitMQ 当做队列服务。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

// 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地址等。

队列处理程序:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

// 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);

}

}

登录后复制

当然,我们还需要一个辅助处理日志的类。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

// 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() 异步消费队列的消息,并将消息发送到消息处理类中。

3. 总结

本文介绍了如何使用 ThinkPHP6 框架进行异步日志记录操作,使日志记录不再影响应用的响应速度。总体来说,以下是操作步骤:

开发自己的异步日志记录器 使用 RabbitMQ 进行消息队列处理 编写消息处理程序

在实际项目中,我们需要根据具体的需求来优化代码和调整队列的配置。通过异步记录日志,可以有效提高 web 应用的运行效率,并提高系统的稳定性与可靠性。

以上就是如何使用ThinkPHP6进行异步日志记录操作?的详细内容,更多请关注php中文网其它相关文章!

最新文章