11

Is there any way to log an entire array using Monolog? I have been reading several docs but didn't find a way to log the entire array in a readable format, any advice?

Docs I've read:

Community
  • 1
  • 1
ReynierPM
  • 17,594
  • 53
  • 193
  • 363
  • Not sure why StackOverflow decided to close this question! Here's the answer: just use the LineFormatter with these options: `$formatter = new LineFormatter(null, null, true, true);` then set `$formatter->setJsonPrettyPrint(true);` then define your handler as usual `$handler = new StreamHandler( $path, $level );` and finally apply the formatter to the handler: `$handler->setFormatter($formatter);`. If you invoke the logger with the context argument `$logger->info("Short message", $anyArray);` you'll get `$anyArray` in the log in human-readable form :-) – coccoinomane Jun 02 '20 at 15:51

1 Answers1

15

If you check the logger interface (https://github.com/php-fig/log/blob/master/Psr/Log/LoggerInterface.php) you will see all of the logging methods gets message as a string, thus you get a warning when you try to log with a variable type other than string.

I tried to use a processor to format the array in a custom manner, but as expected the processor is triggered after you send the variable to logger interface.

The dirtiest way of logging an array may be any of those for your choice;

$logger->info(json_encode($array));
$logger->info(print_r($array, true));
$logger->info(var_export($array, true));

On the other hand you may want to format your array in a single proccessor to centralize your formatting logic with DRY principles.

Json encode array -> Send as Json String -> json decode to array -> format -> json encode again

CustomRequestProcessor.php

<?php
namespace Acme\WebBundle;


class CustomRequestProcessor
{


    public function __construct()
    {
    }

    public function processRecord(array $record)
    { 
        try {
            //parse json as object and cast to array
            $array = (array)json_decode($record['message']);
            if(!is_null($array)) {
                //format your message with your desired logic
                ksort($array);
                $record['message'] = json_encode($array);
            }
        } catch(\Exception $e) {
            echo $e->getMessage();
        }
        return $record;
    }
}

Register request processor in your config.yml or services.yml, see the tags node for registering the processor for a custom channel.

services:
monolog.formatter.session_request:
    class: Monolog\Formatter\LineFormatter
    arguments:
        - "[%%datetime%%] %%channel%%.%%level_name%%: %%message%%\n"

monolog.processor.session_request:
    class: Acme\WebBundle\CustomRequestProcessor
    arguments:  []
    tags:
        - { name: monolog.processor, method: processRecord, channel: testchannel }

And in the controller log your array as a json string,

<?php

namespace Acme\WebBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
    public function indexAction()
    {

        $logger = $this->get('monolog.logger.testchannel');
        $array = array(3=>"hello" , 1=>"world", 2=>"sf2");
        $logger->info(json_encode($array));

        return $this->render('AcmeWebBundle:Default:index.html.twig');
    }
}

Now you can format and log your array as your desire in a central request processor without sorting/formating/walking on the array in your every controller.

Ugur
  • 1,679
  • 14
  • 20
  • 2
    I've just spent 2 days trying to figure out how to do this. Thanks. Seems to me a better solution is to NOT use monolog at all. – ochitos May 18 '16 at 16:55
  • I was able to get mined to work with $logger->info(var_export($arrayName, true)); . Although json_encode is genius :) – frostshoxx Sep 21 '16 at 20:11
  • 8
    You guys are missing the point. Monolog is designed with *structured* logging in mind. The first parameter of any Monolog logger method is supposed to be a simple message string - in fact, Monolog explicitly [casts it as such](https://github.com/Seldaek/monolog/blob/master/src/Monolog/Logger.php#L427). However, the logger methods **do** support an extra `$context` parameter, which it will print *after* the message. So, try for example `$logger->info("My array", $array);` – alexw Oct 19 '16 at 22:23
  • 1
    @fuximusfoe I agree. I've just switch from monolog to using good old `file_get_contents()` with the `FILE_APPEND` flag. – kjdion84 Jan 11 '17 at 01:28
  • @alexw That makes sense... do you know how to format how the `$context` is printed? By default, it is a JSON in a single-line string, which is not very readable. – coccoinomane Jun 02 '20 at 15:30