5
votes

On a project i am working we use Symfony2 console commands to run image converting (using LaTeX and some imagick). Due to the nature of project, not all conditions may be met during the console command run so the execution will fail, to be later restarted with a cron job, only if attempts count is not higher that predefined limit.

We already hove logging in our project, we use Monolog logger. What i basically want is to somehow duplicate everything that goes to the main log file in another log file, created specifically for that console command execution and only if attempts limit is reached.

So, if we run command once and it fails - it's ok and nothing should be created. But if we run command for the 10th time, which is attempt limit, i want to have a separate log file named, say '/logs/failed_commands//fail.log'. That log file should only have messages for the last failed attempt, but not for all the previous ones.

How to do that? Do i need some combination of special logger handler (like FingersCrossed) and proper exceptions handling? Should i rather create additional instance of logger (if so, how can i pass it over to dependent services?)

This is simplified and cleaned piece of command that runs images converting. The attempts limit is checked withing the $this->checkProcessLimit() method

public function execute(InputInterface $input, OutputInterface $output)
{
    try {
        set_time_limit(0); //loose any time restrictions
        $this->checkingDirectories();
        $this->checkProcessLimit();
        $this->isBuildRunning();
        $this->checkingFiles();

        try {
            $this->startPdfBuilding();
        } catch (InternalProjectException $e) {
            throw PdfBuildingException::failedStartBuilding($this->pressSheet->getId());
        }

    } catch (PdfBuildingException $e) {
        $this->printError($output, $e);

        return;
    }

    try {
        $this->logger->info('Building Image.');
        $this->instantiatePdfBuilder();

        $buildingResult = $this->pdfBuilder->outputPdf();
        $this->generatePreview($buildingResult);
        $this->movePDFs($buildingResult);

        $this->unlinkLockFile();
        $output->writeln('<info>Image successfully built</info>');
    } catch (LaTeXException $e) {
        $this->unlinkLockFile();
        $this->abortPdfBuilding($e->getMessage());
        $this->printError($output, $e);

        return;
    }
}

UPD: It seems that for dumping a bunch of log entries i need to use BufferHandler bundled with Monolog Logger. But i still need to figure out the way to set it up to get dumps only when errors limit (not error level) reached.

UPD2: I've managed to make it work, but i don't like the solution. Since in Symfony2 you have to define loggers in config.yml and have to rebuild cache for any changes in configuration, i had to resort to dynamically adding a handler to a logger. But the logger itself is considered to be of Psr\Log\LoggerInterface interface, which does not have any means to add handlers. The solution i had to use actually checks if used logger is an instance of Monolog\Logger and then manually adding a BufferHandler to it in Symfony2 Console command's initialize() method. Then, when it comes to the point where I check for attempts limit, i close buffer handler and delete actual log file (since BufferHandler has no means to removing/closing itself without flushing all it's contents) if limit is not yet reached. If it is, i just let the log file to stay. This way it works, but it always writes the log, and i have to remove logs if condition (reached attempt limit) is not met.

1

1 Answers

0
votes

i think you must create a custom handler.

With Monolog, you can log in a database (see for example https://github.com/Seldaek/monolog/blob/master/doc/04-extending.md)

Thus, it's easy to know how many times an error was raised since x days. (something like : "select count(*) from monolog where channel='...' and time>...")