【问题标题】:Monolog implementation with common class使用公共类的 Monolog 实现
【发布时间】:2018-11-17 22:58:22
【问题描述】:

我成功地实现了一个用于测试目的的 Monolog 记录器。现在我正试图在一个项目中使用它。该项目不使用任何 MVC 框架。

我正在尝试编写一个通用类文件来包装对 Monolog 实例的访问。

通用类文件:文件:app_log.php

require 'autoload.php';
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Processor\UidProcessor;
use Monolog\Processor\WebProcessor;
use Monolog\Processor\MemoryUsageProcessor;
use Monolog\Processor\ProcessIdProcessor;
use Monolog\Formatter\LineFormatter;

class app_log {
  public function info(){
    $logger = new Logger('applog');
    $handler = new RotatingFileHandler('useractivity.log', 0, Logger::INFO);
    $handler->setFormatter(new LineFormatter("[%datetime%] %extra.process_id% %channel%.%level_name%: %message% %extra% %context% \n"));
    $logger->pushHandler($handler);
    $logger->pushProcessor(new WebProcessor);
  }  
}

其他文件:users.php

include_once 'app_log.php';
class users extends dbconnector{
    function login(){
      // Some project code. 
      $logger = new app_log();
      $logger->info('User logged successfully');
    }
}

到目前为止效果很好,我想包括文件名、方法名、请求参数。但我在日志中得到app_log.php 文件名而不是users.php 和方法名称是'info' 而不是'login'

例子:

[2018-06-07 20:55:50] 4410 applog.INFO: User logged successfully {"file":"/var/www/portal/lib/app_log.php","line":59,"class":"app_log","function":"info"} []

你们能帮忙吗?

【问题讨论】:

  • 为什么不在app_log 类中使用singleton 模式,它会让您的日志记录更加轻松。

标签: php oop logging monolog


【解决方案1】:

恐怕你的整个设计完全是错误的。

不是每次需要登录时都实例化一个新的Logger,而应该创建一个$logger 以用作应用程序周围的服务。

如果不了解您的应用程序的更多信息(并且无论如何必须重写您的应用程序会使问题过于宽泛),很难猜测如何在此处实现依赖注入

但一种简单而幼稚的方法是:

class users extends dbconnector {

    protected $logger;

    public function _construct(Logger $logger) {
       $this->logger = $logger;
    }

    function login() {
      $this->logger->info('User logged successfully');
    }
}

然后:

$logger  = new Logger('applog');
$handler = new RotatingFileHandler('useractivity.log', 0, Logger::INFO);
$handler->setFormatter(new LineFormatter("[%datetime%] %extra.process_id% %channel%.%level_name%: %message% %extra% %context% \n"));
$logger->pushHandler($handler);
$logger->pushProcessor(new WebProcessor);
$logger->pushProcessor(new IntrospectionProcessor);

$users = new users($logger);

如果您在需要它的对象中注入 Logger 实例,您可以直接使用它,而无需创建自己的“包装器”(在您的示例中设计不佳),并且日志文件中的输出将符合您的期望。

请注意,您没有使用IntrospectionProcessor,您需要捕获文件名和文件行号。在上面的示例中,我还将它推送到 $loggerLogger 实例中。

(另外请注意,简单地将这个处理器添加到您的代码中并不能解决您的问题,因为对Logger::info() 的调用总是在app_log::info() 中发生)。

请记住,您需要添加相应的 use 语句:use Monolog\Processor\IntrospectionProcessor;

我不知道你系统的所有细节,无论如何也不能为你构建它,但如果依赖注入对你来说仍然太多,你可以暂时用全局状态的方法作弊。

例如:

function get_logger() {
   static $logger;

   if ($logger !== null) {
      return $logger;
   }

   $logger  = new Logger('applog');
   $handler = new RotatingFileHandler('useractivity.log', 0, Logger::INFO);
   $handler->setFormatter(new LineFormatter("[%datetime%] %extra.process_id% %channel%.%level_name%: %message% %extra% %context% \n"));
   $logger->pushHandler($handler);
   $logger->pushProcessor(new WebProcessor);
   $logger->pushProcessor(new IntrospectionProcessor);

   return $logger;
}

您可以将其放在您require_once 的文件中,并且在您需要访问记录器的每个地方都可以简单地执行以下操作:

 get_logger()->info('write to the log!');

这不是我赞同的事情,而是一个糟糕的解决方法,让您开始行动,直到您对其他 OOP 主题的理解有所提高。这只不过是一个穷人singleton,这通常是一种无论如何都要避免的模式;但这现在可以帮助你..

【讨论】:

  • 感谢您的回答。那么如何使第二部分可重用,因为我有很多像“用户”这样的类文件?而且我不能在每个文件中都使用 $logger。你能建议我吗?
  • 与本例完全相同。您的其他类“依赖” Logger 服务,因此您应该在每个此类中“注入”该服务。一种常用的方法是在实例化时注入对象:更改构造函数以接收额外的 $logger 参数并设置私有 logger 属性。然后在这些类中的每一个上,您都可以简单地调用$this->logger->info()
  • 完美!我现在明白了。感谢您的大力帮助。
【解决方案2】:

WebProcessor 不会添加你需要的数据,我的意思是文件和行。

IntrospectionProcessor 做你需要的,试试

$logger->pushProcessor(new IntrospectionProcessor());

【讨论】:

  • 这是错误的。由于在 OP 代码中调用源自 app_log::info(),因此它们将得到完全相同的结果。
  • @yivi 您的方法也不会产生所需的结果。但是如果作者结合了两种方法,他会得到他想要的
  • 由于 OP 已经打印了一个包含此信息的日志文件,我认为他们已经 那个 部分弄清楚了。但你是对的,他们在 $logger 实例中缺少这个处理器。
猜你喜欢
  • 2016-08-02
  • 1970-01-01
  • 2013-11-29
  • 1970-01-01
  • 2011-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多