[GH-ISSUE #1347] Is Monolog 1.x (1.24) compatible with PHP 7.2? #563

Closed
opened 2026-03-04 02:16:00 +03:00 by kerem · 5 comments
Owner

Originally created by @bigtunacan on GitHub (Jul 10, 2019).
Original GitHub issue: https://github.com/Seldaek/monolog/issues/1347

I'm in progress of upgrading a PHP 5.3 application to PHP 7.2 that is using monolog. I'm trying to use the latest 1.x series (1.24) of Monolog which is working on the existing PHP 5.3 servers, but appears to have issues on PHP 7.2? It is unclear to me from the documentation if the 1.x series should be compatible with PHP 7.2.

Originally created by @bigtunacan on GitHub (Jul 10, 2019). Original GitHub issue: https://github.com/Seldaek/monolog/issues/1347 I'm in progress of upgrading a PHP 5.3 application to PHP 7.2 that is using monolog. I'm trying to use the latest 1.x series (1.24) of Monolog which is working on the existing PHP 5.3 servers, but appears to have issues on PHP 7.2? It is unclear to me from the documentation if the 1.x series should be compatible with PHP 7.2.
kerem closed this issue 2026-03-04 02:16:00 +03:00
Author
Owner

@xabbuh commented on GitHub (Jul 11, 2019):

I use Monolog 1 without any issue on PHP 7.2. What issues did you run into?

<!-- gh-comment-id:510465140 --> @xabbuh commented on GitHub (Jul 11, 2019): I use Monolog 1 without any issue on PHP 7.2. What issues did you run into?
Author
Owner

@bigtunacan commented on GitHub (Jul 11, 2019):

We have a logging class that extends Monolog\Logger to provide convenient formatted logging to syslog. It has worked for years with PHP 5.3. Now that we are on PHP 7.2 nothing writes to the logs and even we will get silent code failures. The app will stop running once it hits a call to log, but if you comment out the logging everything after it runs.

Here is what our log class looks like.

<?php
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
use Monolog\Logger;

class DefaultLogger extends Logger {

  /**
   * context
   *
   * Default Context for logger. Lets you set default context for logging.
   * If you add context in an ->info or ->error (etc) call it will be merged
   * with the default context.
   *
   * @var array $context Default Context for logging.
   */
  public $context = array();

  public $options = array(
      'dateFormat' => 'Y-m-d\\TH:i:sP',
      'userId' => null,
      'applicationID' => null,
      'syslog' => array(
          'enabled' => true,
          'host' => 'my.host.com',
          'facility' => 'local6',
          'format' => '[%datetime%] [%channel%] [%level_name%] %context% %message%',
          'level' => 100
      ),
      'tags' => array(
          'php',
          'generic'
      )
  );

  /**
   * DefaultLogger
   *
   * @param string $name       Name of logger. Should probably be class_name($this).
   * @param array  $handlers   Logger handlers. See Monolog Documentation.
   * @param array  $processors Logger processors. See Monolog Documentation.
   *
   * @throws \InvalidArgumentException   Throws error on config file load or parse error.
   */
  public function __construct(
    $name,
    array $handlers = array(),
    array $processors = array()
  ) {
    // Standard Monolog config
    $this->name = $name;
    $this->handlers = $handlers;
    $this->processors = $processors;

    // Throw an error if the logger is not enabled.
    if ( ! $this->options['syslog']['enabled'] ) {
        throw new \InvalidArgumentException('No log output defined.');
    }

    if ( $this->options['syslog']['enabled'] ) {
      $this->initializeSyslogLogger();
    }
  }

  /**
   * error_handler
   *
   * Transform errors into Exceptions.
   *
   * @param int    $errno   Error number if avialable.
   * @param string $errstr  Error message
   * @param string $errfile File error occured in
   * @param int    $errline Line number of error
   *
   * @throws \ErrorException
   *
   * @return null
   */
  private function error_handler($errno, $errstr, $errfile, $errline)
  {
    throw new \ErrorException(
      $errstr,
      0,
      $errno,
      $errfile,
      $errline
    );
  }

  /**
   * addRecord
   *
   * Add the record to monolog at the appropriate level.
   *
   * @param int    $level   Level of event to be logged
   * @param string $message Message text
   * @param array  $context Additional context to be logged.
   *
   * @return null
   */
  public function addRecord($level, $message, array $context = array())
  {
    if ( empty($context) ) {
      $context = $this->context;
    } else {
      $context = array_merge($context, $this->context);
    }

    if ( isset($this->options['userID']) ) {
      $context['userID']        = $this->options['userID'];
    }

    if ( isset($this->options['applicationID']) ) {
      $context['applicationID'] = $this->options['applicationID'];
    }

    if ( empty($context['tags']) ) {
      $context['tags'] = $this->options['tags'];
    } elseif ( is_array($context['tags']) ) {
      $context['tags'] = array_merge($context['tags'], $this->options['tags']);
    } elseif ( is_string($context['tags']) ) {
      $tempString = $context['tags'];
      $context['tags'] = array_push($this->options['tags'], $tempString);
    }

    parent::addRecord($level, $message, $context);
  }

  /**
   * initializeSyslogLogger
   *
   * Set up and initialize the syslogger.
   *
   * @return null
   */
  private function initializeSyslogLogger()
  {
    $syslog = new SyslogUdpHandler(
      $this->options['syslog']['host'],
      null,
      $this->options['syslog']['facility'],
      $this->options['syslog']['level']
    );

    $syslogFormatter = new LineFormatter(
      $this->options['syslog']['format'],
      $this->options['dateFormat']
    );

    $syslog->setFormatter($syslogFormatter);
    $this->pushHandler($syslog);
  }
}
<!-- gh-comment-id:510514783 --> @bigtunacan commented on GitHub (Jul 11, 2019): We have a logging class that extends Monolog\Logger to provide convenient formatted logging to syslog. It has worked for years with PHP 5.3. Now that we are on PHP 7.2 nothing writes to the logs and even we will get silent code failures. The app will stop running once it hits a call to log, but if you comment out the logging everything after it runs. Here is what our log class looks like. ```php <?php use Monolog\Formatter\LineFormatter; use Monolog\Handler\StreamHandler; use Monolog\Handler\SyslogUdpHandler; use Monolog\Logger; class DefaultLogger extends Logger { /** * context * * Default Context for logger. Lets you set default context for logging. * If you add context in an ->info or ->error (etc) call it will be merged * with the default context. * * @var array $context Default Context for logging. */ public $context = array(); public $options = array( 'dateFormat' => 'Y-m-d\\TH:i:sP', 'userId' => null, 'applicationID' => null, 'syslog' => array( 'enabled' => true, 'host' => 'my.host.com', 'facility' => 'local6', 'format' => '[%datetime%] [%channel%] [%level_name%] %context% %message%', 'level' => 100 ), 'tags' => array( 'php', 'generic' ) ); /** * DefaultLogger * * @param string $name Name of logger. Should probably be class_name($this). * @param array $handlers Logger handlers. See Monolog Documentation. * @param array $processors Logger processors. See Monolog Documentation. * * @throws \InvalidArgumentException Throws error on config file load or parse error. */ public function __construct( $name, array $handlers = array(), array $processors = array() ) { // Standard Monolog config $this->name = $name; $this->handlers = $handlers; $this->processors = $processors; // Throw an error if the logger is not enabled. if ( ! $this->options['syslog']['enabled'] ) { throw new \InvalidArgumentException('No log output defined.'); } if ( $this->options['syslog']['enabled'] ) { $this->initializeSyslogLogger(); } } /** * error_handler * * Transform errors into Exceptions. * * @param int $errno Error number if avialable. * @param string $errstr Error message * @param string $errfile File error occured in * @param int $errline Line number of error * * @throws \ErrorException * * @return null */ private function error_handler($errno, $errstr, $errfile, $errline) { throw new \ErrorException( $errstr, 0, $errno, $errfile, $errline ); } /** * addRecord * * Add the record to monolog at the appropriate level. * * @param int $level Level of event to be logged * @param string $message Message text * @param array $context Additional context to be logged. * * @return null */ public function addRecord($level, $message, array $context = array()) { if ( empty($context) ) { $context = $this->context; } else { $context = array_merge($context, $this->context); } if ( isset($this->options['userID']) ) { $context['userID'] = $this->options['userID']; } if ( isset($this->options['applicationID']) ) { $context['applicationID'] = $this->options['applicationID']; } if ( empty($context['tags']) ) { $context['tags'] = $this->options['tags']; } elseif ( is_array($context['tags']) ) { $context['tags'] = array_merge($context['tags'], $this->options['tags']); } elseif ( is_string($context['tags']) ) { $tempString = $context['tags']; $context['tags'] = array_push($this->options['tags'], $tempString); } parent::addRecord($level, $message, $context); } /** * initializeSyslogLogger * * Set up and initialize the syslogger. * * @return null */ private function initializeSyslogLogger() { $syslog = new SyslogUdpHandler( $this->options['syslog']['host'], null, $this->options['syslog']['facility'], $this->options['syslog']['level'] ); $syslogFormatter = new LineFormatter( $this->options['syslog']['format'], $this->options['dateFormat'] ); $syslog->setFormatter($syslogFormatter); $this->pushHandler($syslog); } } ```
Author
Owner

@xabbuh commented on GitHub (Jul 11, 2019):

Is it intended that you do not call the constructor of Monolog's Logger class?

<!-- gh-comment-id:510518475 --> @xabbuh commented on GitHub (Jul 11, 2019): Is it intended that you do not call the constructor of Monolog's `Logger` class?
Author
Owner

@bigtunacan commented on GitHub (Jul 11, 2019):

I didn't create this; just the unlucky maintainer..., but it appears to do essentially what happens in the parent constructor in these lines.

$this->name = $name;
$this->handlers = $handlers;
$this->processors = $processors;

I did try replacing that with a call to the parent constructor instead to see what would happen.

parent::__construct($name, $handlers, $processors);

The behavior is the same both ways.

<!-- gh-comment-id:510543204 --> @bigtunacan commented on GitHub (Jul 11, 2019): I didn't create this; just the unlucky maintainer..., but it appears to do essentially what happens in the parent constructor in these lines. ``` $this->name = $name; $this->handlers = $handlers; $this->processors = $processors; ``` I did try replacing that with a call to the parent constructor instead to see what would happen. ``` parent::__construct($name, $handlers, $processors); ``` The behavior is the same both ways.
Author
Owner

@xabbuh commented on GitHub (Jul 11, 2019):

I tried to reproduce that with this little script, but the code didn't error, but output the TEST string as expected:

<?php

require __DIR__.'/vendor/autoload.php';

use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
use Monolog\Logger;

class DefaultLogger extends Logger {

  /**
   * context
   *
   * Default Context for logger. Lets you set default context for logging.
   * If you add context in an ->info or ->error (etc) call it will be merged
   * with the default context.
   *
   * @var array $context Default Context for logging.
   */
  public $context = array();

  public $options = array(
      'dateFormat' => 'Y-m-d\\TH:i:sP',
      'userId' => null,
      'applicationID' => null,
      'syslog' => array(
          'enabled' => true,
          'host' => 'my.host.com',
          'facility' => 'local6',
          'format' => '[%datetime%] [%channel%] [%level_name%] %context% %message%',
          'level' => 100
      ),
      'tags' => array(
          'php',
          'generic'
      )
  );

  /**
   * DefaultLogger
   *
   * @param string $name       Name of logger. Should probably be class_name($this).
   * @param array  $handlers   Logger handlers. See Monolog Documentation.
   * @param array  $processors Logger processors. See Monolog Documentation.
   *
   * @throws \InvalidArgumentException   Throws error on config file load or parse error.
   */
  public function __construct(
    $name,
    array $handlers = array(),
    array $processors = array()
  ) {
    // Standard Monolog config
    $this->name = $name;
    $this->handlers = $handlers;
    $this->processors = $processors;

    // Throw an error if the logger is not enabled.
    if ( ! $this->options['syslog']['enabled'] ) {
        throw new \InvalidArgumentException('No log output defined.');
    }

    if ( $this->options['syslog']['enabled'] ) {
      $this->initializeSyslogLogger();
    }
  }

  /**
   * error_handler
   *
   * Transform errors into Exceptions.
   *
   * @param int    $errno   Error number if avialable.
   * @param string $errstr  Error message
   * @param string $errfile File error occured in
   * @param int    $errline Line number of error
   *
   * @throws \ErrorException
   *
   * @return null
   */
  private function error_handler($errno, $errstr, $errfile, $errline)
  {
    throw new \ErrorException(
      $errstr,
      0,
      $errno,
      $errfile,
      $errline
    );
  }

  /**
   * addRecord
   *
   * Add the record to monolog at the appropriate level.
   *
   * @param int    $level   Level of event to be logged
   * @param string $message Message text
   * @param array  $context Additional context to be logged.
   *
   * @return null
   */
  public function addRecord($level, $message, array $context = array())
  {
    if ( empty($context) ) {
      $context = $this->context;
    } else {
      $context = array_merge($context, $this->context);
    }

    if ( isset($this->options['userID']) ) {
      $context['userID']        = $this->options['userID'];
    }

    if ( isset($this->options['applicationID']) ) {
      $context['applicationID'] = $this->options['applicationID'];
    }

    if ( empty($context['tags']) ) {
      $context['tags'] = $this->options['tags'];
    } elseif ( is_array($context['tags']) ) {
      $context['tags'] = array_merge($context['tags'], $this->options['tags']);
    } elseif ( is_string($context['tags']) ) {
      $tempString = $context['tags'];
      $context['tags'] = array_push($this->options['tags'], $tempString);
    }

    parent::addRecord($level, $message, $context);
  }

  /**
   * initializeSyslogLogger
   *
   * Set up and initialize the syslogger.
   *
   * @return null
   */
  private function initializeSyslogLogger()
  {
    $syslog = new SyslogUdpHandler(
      $this->options['syslog']['host'],
      null,
      $this->options['syslog']['facility'],
      $this->options['syslog']['level']
    );

    $syslogFormatter = new LineFormatter(
      $this->options['syslog']['format'],
      $this->options['dateFormat']
    );

    $syslog->setFormatter($syslogFormatter);
    $this->pushHandler($syslog);
  }
}

$logger = new DefaultLogger('my_logger');
$logger->debug('foo');

var_dump('TEST');
<!-- gh-comment-id:510651332 --> @xabbuh commented on GitHub (Jul 11, 2019): I tried to reproduce that with this little script, but the code didn't error, but output the `TEST` string as expected: ```php <?php require __DIR__.'/vendor/autoload.php'; use Monolog\Formatter\LineFormatter; use Monolog\Handler\StreamHandler; use Monolog\Handler\SyslogUdpHandler; use Monolog\Logger; class DefaultLogger extends Logger { /** * context * * Default Context for logger. Lets you set default context for logging. * If you add context in an ->info or ->error (etc) call it will be merged * with the default context. * * @var array $context Default Context for logging. */ public $context = array(); public $options = array( 'dateFormat' => 'Y-m-d\\TH:i:sP', 'userId' => null, 'applicationID' => null, 'syslog' => array( 'enabled' => true, 'host' => 'my.host.com', 'facility' => 'local6', 'format' => '[%datetime%] [%channel%] [%level_name%] %context% %message%', 'level' => 100 ), 'tags' => array( 'php', 'generic' ) ); /** * DefaultLogger * * @param string $name Name of logger. Should probably be class_name($this). * @param array $handlers Logger handlers. See Monolog Documentation. * @param array $processors Logger processors. See Monolog Documentation. * * @throws \InvalidArgumentException Throws error on config file load or parse error. */ public function __construct( $name, array $handlers = array(), array $processors = array() ) { // Standard Monolog config $this->name = $name; $this->handlers = $handlers; $this->processors = $processors; // Throw an error if the logger is not enabled. if ( ! $this->options['syslog']['enabled'] ) { throw new \InvalidArgumentException('No log output defined.'); } if ( $this->options['syslog']['enabled'] ) { $this->initializeSyslogLogger(); } } /** * error_handler * * Transform errors into Exceptions. * * @param int $errno Error number if avialable. * @param string $errstr Error message * @param string $errfile File error occured in * @param int $errline Line number of error * * @throws \ErrorException * * @return null */ private function error_handler($errno, $errstr, $errfile, $errline) { throw new \ErrorException( $errstr, 0, $errno, $errfile, $errline ); } /** * addRecord * * Add the record to monolog at the appropriate level. * * @param int $level Level of event to be logged * @param string $message Message text * @param array $context Additional context to be logged. * * @return null */ public function addRecord($level, $message, array $context = array()) { if ( empty($context) ) { $context = $this->context; } else { $context = array_merge($context, $this->context); } if ( isset($this->options['userID']) ) { $context['userID'] = $this->options['userID']; } if ( isset($this->options['applicationID']) ) { $context['applicationID'] = $this->options['applicationID']; } if ( empty($context['tags']) ) { $context['tags'] = $this->options['tags']; } elseif ( is_array($context['tags']) ) { $context['tags'] = array_merge($context['tags'], $this->options['tags']); } elseif ( is_string($context['tags']) ) { $tempString = $context['tags']; $context['tags'] = array_push($this->options['tags'], $tempString); } parent::addRecord($level, $message, $context); } /** * initializeSyslogLogger * * Set up and initialize the syslogger. * * @return null */ private function initializeSyslogLogger() { $syslog = new SyslogUdpHandler( $this->options['syslog']['host'], null, $this->options['syslog']['facility'], $this->options['syslog']['level'] ); $syslogFormatter = new LineFormatter( $this->options['syslog']['format'], $this->options['dateFormat'] ); $syslog->setFormatter($syslogFormatter); $this->pushHandler($syslog); } } $logger = new DefaultLogger('my_logger'); $logger->debug('foo'); var_dump('TEST'); ```
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/monolog#563
No description provided.