cakephp PHP -将命令行输出发送到动态命名的文件

qyuhtwio  于 2022-11-11  发布在  PHP
关注(0)|答案(2)|浏览(127)

I have an application which is built in CakePHP 3.
It uses Console Commands to execute several intensive processes in the background using cron.
The application consists of 5 individual commands:

src/Command/Stage1Command.php
src/Command/Stage2Command.php
src/Command/Stage3Command.php
src/Command/Stage4Command.php
src/Command/Stage5Command.php

These can be executedmanuallyby running each one individually, e.g. to execute Stage1Command.php :

$ php bin/cake.php stage1

To make them run via Cron, I created a 6th command ( src/Command/RunAllCommand.php ) which goes through these in order.

// src/Command/RunAllCommand.php
 class RunAllCommand extends Command
 {
     public function execute(Arguments $args, ConsoleIo $io)
     {
         $stage1 = new Step1Command();
         $this->executeCommand($stage1);

         // ... 

         $stage5 = new Stage5Command();
         $this->executeCommand($stage5);
     }
 }

This works fine so I can now execute everything with 1 command, php bin/cake.php run_all , which will be added as a cron task to automate running the 5 processes.
The problem I'm having is that each of the 5 commands ( Stage1Command ... Stage5Command ) produces output which appears on standard output in the console.
I need to be able to write the output produced by each of the 5 commands individually into dynamically named files.
So I can't do something like this

$ php bin/cake.php run_all > output.log

Because

  1. output.log would contain everything , i.e. the output from all 5 commands.
  2. output.log isn't a dynamic filename, it has been entered manually on the command line (or as the output destination of the cron task).
    I looked at Redirecting PHP output to a text file and tried the following.
    Added ob_start(); to RunAllCommand.php :
namespace App\Command;
ob_start();

class RunAllCommand extends Command { ... }

After executing the first task ( Stage1Command ) capturing ob_get_clean() to a variable called $content :

$stage1 = new Step1Command();
$this->executeCommand($stage1);
$content = ob_get_clean();

When I var_dump($content); it comes out as an empty string:

string(0) ""

But the output is still produced on the command line when executing php bin/cake.php run_all (RunAllCommand.php).
My plan for the dynamic filename was to generate it with PHP inside RunAllCommand.php , e.g.

// $id is a dynamic ID generated from a database call.
// This $id is being generated inside a foreach() loop so is different on each iteration (hence the dynamic nature of the filename).
$id = 234343; 
$filename_stage1 = 'logs/stage1_' . $id . '.txt'; // e.g. "logs/stage1_234343.txt"

Then write $content to the above file, e.g.

file_put_contents($filename_stage1, $content);

So I have 2 problems:

  1. The output is being echoed to the console, and unavailable in $content .
  2. Assuming (1) is fixed, how to "reset" the output buffering such that I can use file_put_contents with 5 different filenames to capture the output for the relevant stage.
wbgh16ku

wbgh16ku1#

在每个命令文件上,您可以使用LogTrait,然后在任何命令之前输出文件输出内容,以区分记录的命令,或者设置具有不同范围的日志配置,以输出到不同的文件。输出到cli-debug.log文件的示例。

use Cake\Log\LogTrait;

class Stage1Command extends Command
{
    use LogTrait;

    public function execute(Arguments $args, ConsoleIo $io)
    {
        $this->log('Stage 1 Output: ', 'debug');

        //do stuff

        $this->log('output stage 1 stuff', 'debug');

    }
}
gkl3eglg

gkl3eglg2#

我有两个建议来解决你的问题。

选项1 -使用shell_exec

shell_exec返回输出的字符串,因此您可以直接将其写入日志文件。

public function execute(Arguments $args, ConsoleIo $io)
{
    $stage1_log = shell_exec('bin/cake stage1 arguments');
    file_put_contents('stage1_dynamic_log_file.txt', $stage1_log);

    $stage2_log = shell_exec('bin/cake stage2 arguments');
    file_put_contents('stage2_dynamic_log_file.txt', $stage2_log);
}

选项2 -覆盖控制台输出流

或者,一个更像CakePHP风格的方法是调用命令时稍有不同。如果您查看executeCommand()的内容,它会做一些检查,然后调用command->run($args, $io)
此外,如果您查看ConsoleIo的构造方式,我们可以覆盖输出方法,这样我们就可以使用文件来代替php://stdout,如果您查看ConsoleOutput的代码,它只是使用普通的fopenfwrite

use Cake\Console\ConsoleIo;
use Cake\Console\ConsoleOutput;

public function execute(Arguments $args, ConsoleIo $io)
{
    // File names
    $id = 234343; 
    $filename_stage1 = 'logs/stage1_' . $id . '.txt';

    // Create command object
    $stage1 = new Stage1Command();

    // Define output as this filename
    $output = new ConsoleOutput($filename_stage1);

    // Create a new ConsoleIo using this new output method
    $stage1_io = new ConsoleIo($output);

    // Execute passing in the ConsoleIo with text file for output
    $this->executeCommand($stage1, ['arguments'], $stage1_io);
}

相关问题