. * @since 2.0.0 */ namespace Decalog\Handler; use Decalog\System\Option; use DLMonolog\Logger; use DLMonolog\Handler\AbstractProcessingHandler; use DLMonolog\Formatter\FormatterInterface; use Decalog\Formatter\GenericFormatter; use Decalog\System\SharedMemory; use Decalog\System\Environment; use malkusch\lock\mutex\FlockMutex; use malkusch\lock\mutex\SemaphoreMutex; /** * Define the Monolog shared memory handler. * * Handles all features of shared memory handler for Monolog. * * @package Handlers * @author Pierre Lannoy . * @since 2.0.0 */ class SharedMemoryHandler extends AbstractProcessingHandler { /** * The buffer size. * * @since 2.0.0 * @var integer $buffer The number of messages in buffer. */ private $buffer = 4000; /** * The read index. * * @since 2.0.0 * @var string $index The index for data. */ private static $index = ''; /** * Get relevant ftok. * * @since 2.0.0 */ private static function ftok() { if ( 1 === Environment::exec_mode() ) { return ftok( __FILE__, 'c' ); } else { return ftok( __FILE__, 'w' ); } } /** * Initialize the class and set its properties. * * @param integer $level Optional. The min level to log. * @param boolean $bubble Optional. Has the record to bubble?. * @since 2.0.0 */ public function __construct( $level = Logger::INFO, bool $bubble = true ) { parent::__construct( $level, $bubble ); } /** * {@inheritDoc} */ protected function getDefaultFormatter(): FormatterInterface { return new GenericFormatter(); } /** * Write the record in memory. * * @param array $record The record to write. * @since 2.0.0 */ protected function write( array $record ): void { // phpcs:ignore $messages = unserialize( $record['formatted'] ); $mutex = new FlockMutex( fopen( __FILE__, 'r' ), 1 ); $ftok = self::ftok(); $mutex->synchronized(function () use ($messages, $ftok) { $sm = new SharedMemory( $ftok ); $data = $sm->read(); foreach ( $messages as $message ) { if ( is_array( $message ) ) { $date = new \DateTime(); $data[ $date->format( 'YmdHisu' ) ] = $message; } } $data = array_slice( $data, -$this->buffer ); if ( false === $sm->write( $data ) ) { //error_log( 'ERROR' ); } }); } /** * Read the current records. * * @return array The current records, ordered. * @since 2.0.0 */ public static function read(): array { try { $mutex = new FlockMutex( fopen( __FILE__, 'r' ), 1 ); $ftok = ftok( __FILE__, 'w' ); $data1 = $mutex->synchronized(function () use ($ftok) { $log = new SharedMemory( $ftok ); $data = $log->read(); return $data; }); $ftok = ftok( __FILE__, 'c' ); $data2 = $mutex->synchronized(function () use ($ftok) { $log = new SharedMemory( $ftok ); $data = $log->read(); return $data; }); $data = array_merge( $data1, $data2 ); uksort($data, 'strcmp' ); } catch ( \Throwable $e ) { $data = []; } $result = []; foreach ( $data as $key => $line ) { if ( 0 < strcmp( $key, self::$index ) ) { $result[$key] = $line; self::$index = $key; } } return $result; } }