【问题标题】:Timestamping logs of programs managed by supervisordsupervisord 管理的程序的时间戳日志
【发布时间】:2013-07-21 22:18:06
【问题描述】:

我正在使用 supervisord 来管理一个需要在后台运行的 php 程序。该程序将事件记录到文件worker_log。在我正在使用的supervisord.conf 中配置它很简单:

stderr_logfile=/var/log/supervisord/worker_log;

但是,我希望写入日志的事件能够自行添加时间戳。我无法控制 php 程序,因此不能选择装饰它的日志。我想我要做的就是注释掉上面的日志配置,并通过主管命令配置中的命令行管道来装饰程序:

command=php /www/myapp/worker.php 2>&1 | sed "s/^/`date` /" > /var/log/supervisord/worker_log;

手动运行此命令时,它似乎工作正常。但是,supervisord 似乎以某种方式阻止它正常运行,我不知道如何。 worker.php 执行良好,但在此配置中,它的报告被抑制。而且,正因为如此,它当然不会添加时间戳。

是否有人对此有足够的了解以提供有关如何实现为工作人员的输出添加时间戳的目标的指导?

【问题讨论】:

  • 命令参数是否可能不支持管道?或者可能是run时释放终端的命令,哪个supervisord不支持?

标签: php bash supervisord


【解决方案1】:

您可以编写一个专用的包装脚本,在调用您的工作代码之前将过滤器附加到标准错误:

// filter to prepend date/time on all stderr output
class eventdata_filter extends php_user_filter
{
    function filter($in, $out, &$consumed, $closing)
    {
        while (($bucket = stream_bucket_make_writeable($in))) {
            $bucket->data = date('c') . ' ' . $bucket->data;
            $consumed += $bucket->datalen;
            stream_bucket_append($out, $bucket);
        }
        return PSFS_PASS_ON;
    }
}

// register our custom filter    
stream_filter_register('eventdata', 'eventdata_filter');

// keep a reference to the attached filter
$filter = stream_filter_append(STDERR, 'eventdata', STREAM_FILTER_WRITE);

// isolate the worker from any variables in this scope, such as $filter
function run()
{
    include 'worker.php';
}

// run the worker
run();

// remove the filter
stream_filter_remove($filter);

顺便说一句,如果您不删除过滤器,它会导致分段错误(至少,在 5.4 上测试过)。

【讨论】:

  • 我今天要试试这个!这是一个非常好的建议,尽管不可否认的是一层代码是不幸的。
  • 这不会为致命错误消息添加时间戳,这会跳过所有用户代码并直接进入“向 STDERR 输出消息并死掉”
  • @Stampy 是的,不幸的是,这是致命错误的本质,因为任何错误处理程序都无法捕获这些错误 =( 不过,也许关闭处理程序可以工作......
【解决方案2】:

先前的答案(来自 Jack)是正确的,因为您需要另一层代码来为每一行加上时间戳。 perl 中的这一行将达到相同的结果:

perl -ne '@timeparts=localtime(); printf("%04d/%02d/%02d %02d:%02d:%02d %s",$timeparts[5]+1900,$timeparts[4]+1,@timeparts[3,2,1,0], $_);'

使用它代替 sed 脚本。

您尝试的方法不起作用的一个问题是日期是在调用 sed 命令时由 shell 计算并替换的,因此所有行都具有相同的日志时间戳

【讨论】:

  • 为什么不只是 perl -ne 'print scalar(localtime)." ".$_' ?或者perl -mPOSIX=strftime -ne 'print strftime("%F %T ",localtime),$_;'
  • 这也可以。我更喜欢我提供的格式,但这取决于个人口味
【解决方案3】:

编辑:我想我会把它留在这里。确切地说,这种方法不起作用,因为 sed 命令只是永久使用其启动 date 输出,因此时间戳不正确。


实现这一点的另一种方法(非常接近您最初的尝试)是将您的原始命令放在 bash -c "command here" 的引号内,例如

command=bash -c 'php /www/myapp/worker.php 2>&1 | sed "s/^/`date` /" >> /var/log/supervisord/worker_log';

注意,我从> 切换到>>,因为我倾向于保留这些日志,并通过logrotate 规则管理日志文件。

对于更一般的情况,您可能还需要设置环境,这有点不合时宜,但至少在一个地方进行检查。玩具示例:bash -c "source ~/setup.bash && php /www/myapp/worker.php 2>&1 | sed ... >> /your/logfile/path.log"

(免责声明:鉴于我对这个答案尚不存在感到有点惊讶,如果得知这是一种糟糕的做事方式,我不会感到惊讶)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-06
    • 1970-01-01
    • 2012-09-10
    • 2023-04-10
    • 2015-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多