php 如何在Kubernetes-cluster中从Symfony应用程序向Graylog发送错误消息

qlzsbp2j  于 2023-09-29  发布在  PHP
关注(0)|答案(2)|浏览(97)

bounty还有3天到期。回答此问题可获得+300声望奖励。Zeth希望引起更多的注意这个问题。

几个docker-container,在Kubernetes集群中运行:

PHP
Nginx
MySQL
Redis

有一个Graylog-instance(版本3),它监听来自这些容器的stdoutstderr
在PHP容器中,有一个Symfony应用程序,它使用Monolog来记录错误,信息,警告和通知等等。Monolog通常记录到一个文件,在/config/packages/prod/monolog.yaml中定义如下:

monolog:
    handlers:
        main:
            type: fingers_crossed
            action_level: error
            handler: nested
            excluded_http_codes: [404, 405]
        nested:
            type: rotating_file
            path: "%kernel.logs_dir%/%kernel.environment%.log"   # <-- Here
            level: debug

我的运营部门说:
Graylog看不到容器中的任何文件。就是这样

* 我的问题 *

我如何设置它,所以我所有的错误,警告,通知,信息等,是在Graylog中找到?

解决方案尝试1:获取Monolog-logger以打印到控制台

我尝试在/config/packages/prod/monolog.yaml中执行各种后空翻,以获得如下代码:

// src/Controller/YourController.php
namespace App\Controller;

use Psr\Log\LoggerInterface;
...

class YourController extends AbstractController
{
    public function yourAction(LoggerInterface $logger): Response
    {
        $logger->info('This is an informational log');
        return new Response('Check the logs!');
    }
}

将日志写入stdoutstderr。但是在标准输出中没有任何输出。
我的(最佳)尝试:

console:
            type:   console
            process_psr_3_messages: false
            channels: ['!event', '!doctrine', '!console']

        syslog_handler:
            type: syslog
            level: debug

解决方案二:使用error_log()

error_log('my message')-函数将输出到控制台。耶!虽然感觉很傻,我有这个巨大的日志库(Monolog),但我最终还是使用了error_log()
另外,我希望所有的错误和警告都是caught并发送到Graylog -而不仅仅是我自己插入的error_log-语句。
另一部分是,这是我使用error_log()时的输出示例:

projectname-php-1         | NOTICE: PHP message: ZZZ ErrorLogStatement: Error.log().
projectname-nginx-1       | 2023/09/22 12:56:17 [error] 10#10: *20 FastCGI sent in stderr: "PHP message: ZZZ ErrorLogStatement: Error.log()" while reading response header from upstream, client: 172.20.0.1, server: symfony.local, request: "GET /my-custom-endpoint?test_case=all_logs HTTP/1.1", upstream: "fastcgi://172.20.0.5:9000", host: "127.0.0.1:8200"
projectname-nginx-1       | 172.20.0.1 - - [22/Sep/2023:12:56:17 +0000] "GET /my-custom-endpoint?test_case=all_logs HTTP/1.1" 200 35 "-" "PostmanRuntime/7.32.3" "-"
projectname-php-1         | 172.20.0.6 -  22/Sep/2023:12:56:02 +0000 "GET /index.php" 200

这意味着我的Nginx容器和PHP容器都输出了错误,这在我的Graylog中增加了很多冗余行。我可以过滤这些,但仍然!太乱了

解决方案三:将我的错误日志“链接”到stdout

我在这里找到了这个建议:Make a Docker application write to stdout
也就是将循环错误日志文件“链接”到stdout(然后可能删除该文件的循环)。
所以我试着运行这个:

ln -sf /dev/stdout /var/www/docroot/var/log/my-log-file.log

但我犯了这个错误:
流或文件:无法在追加模式下打开“/var/www/docroot/var/log/prod-2023-09-22.log”:无法打开流:没有这样的文件或目录。
即使我成功了...这看起来很古怪,不像是正确的方法。所以我就不想让这件事继续下去了。

解决方案4:通过它的API将错误从Monolog发送到Graylog

这将是理想的解决方案。我只是希望有一个更简单的解决方案。
但这就是我现在在摆弄的东西。

fivyi3re

fivyi3re1#

为了将日志消息从运行在Kubernetes集群内Docker容器中的Symfony应用程序发送到Graylog示例,您可以通过Monolog library的GELF(Graylog Extended Log Format)消息格式测试对Graylog的支持。
通过在Monolog中使用GELF处理程序,您应该能够直接将日志消息发送到Graylog示例。
在Symfony应用程序的代码库中添加所需的软件包:

composer require graylog2/gelf-php

这将更新您的composer.jsoncomposer.lock文件,添加新的依赖项。
我假设你的Dockerfile包含像RUN composer install --no-progress --no-interaction --optimize-autoloader这样的行:当Docker镜像被重建时,composer install命令将安装graylog2/gelf-php包沿着其他依赖项。
然后,修改Symfony monolog.yaml配置文件以包含Gelf处理程序:

monolog:
    handlers:
        main:
            type: fingers_crossed
            action_level: error
            handler: gelf
            excluded_http_codes: [404, 405]
        gelf:
            type: gelf
            publisher:
                hostname: "%env(GRAYLOG_HOSTNAME)%"
                port: "%env(GRAYLOG_PORT)%"
            level: debug

.env或Kubernetes ConfigMap中,您可以指定GRAYLOG_HOSTNAMEGRAYLOG_PORT值:

GRAYLOG_HOSTNAME=graylog.example.com
GRAYLOG_PORT=12201

Symfony应用程序使用Monolog和GELF处理程序将日志直接发送到Graylog示例的组件和数据流如下所示:

+----------------+             +-----------------+              +--------------+
|  Kubernetes    |             |   Docker        |              |  Graylog     |
|  Cluster       |             |  Container      |              |  Instance    |
|                |             |  (PHP/Symfony)  |              |              |
|  +----------+  |  HTTP Req.  |  +-----------+  |  Logs (GELF) |  +-------+   |
|  |          |------------------>|           |------------------->|        |  |
|  |  User    |  |             |  |  Symfony  |  |              |  |        |  |
|  |          |<------------------|           |<-------------------|        |  |
|  +----------+  |  HTTP Resp. |  +-----------+  |              |  +--------+  |
|                |             |                 |              |              |
+----------------+             +-----------------+              +--------------+
  • 用户与托管在Kubernetes集群中Docker容器内的Symfony应用程序交互。
  • 收到HTTP请求后,Symfony应用程序会处理它。当需要记录的事件发生时,Monolog会将日志直接发送给Graylog。
  • 日志消息采用GELF格式,并使用GELF处理程序发送到指定的Graylog示例。
  • Graylog摄取并处理日志消息,使其可用于搜索和分析。

在这个设置中,Monolog直接与Graylog通信,避免了将日志写入Docker容器内的文件或控制台的需要。这应该解决了操作部门提到的限制,因为Graylog不需要访问容器内的文件。

yftpprvb

yftpprvb2#

根据你的问题,PHP SAPI容器(PHP-FPM)已经配置了基于Graylog的监听器,正如你用error_log()演示的那样,默认情况下,它会进入PHP SAPI错误日志通道,这就是你想要的地方(特别是对于容器化的Symfony应用程序)。
要使Monolog使用该配置,请使用标准处理程序之一**ErrorLogHandler**。

monolog:
   handlers:
       main:
           type:  error_log
           level: debug

也就是说,您不会用error_log()调用来粘贴代码,而是使用更多的PSR-3 Logger Interface专用等价物,这些等价物在方法名称中附带日志级别,并在Symfony-App中提供更多专用配置选项,同时保留最后的error_log()退出舱口,仍然集成并(相对地)开箱即用(即在Graylog中)。
我无法想象为什么你想在一个容器中旋转日志,但是因为这是Monolog,你有所有的选择,包括使用多个目标等。.

相关问题