Файловый менеджер - Редактировать - /var/www/xthruster/html/wp-content/uploads/flags/monolog.tar
Назад
monolog/src/Monolog/DateTimeImmutable.php 0000644 00000002415 14721613470 0014473 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog; use DateTimeZone; /** * Overrides default json encoding of date time objects * * @author Menno Holtkamp * @author Jordi Boggiano <j.boggiano@seld.be> */ class DateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable { /** * @var bool */ private $useMicroseconds; public function __construct(bool $useMicroseconds, ?\DateTimeZone $timezone = null) { $this->useMicroseconds = $useMicroseconds; // if you like to use a custom time to pass to Logger::addRecord directly, // call modify() or setTimestamp() on this instance to change the date after creating it parent::__construct('now', $timezone); } public function jsonSerialize() : string { if ($this->useMicroseconds) { return $this->format('Y-m-d\\TH:i:s.uP'); } return $this->format('Y-m-d\\TH:i:sP'); } public function __toString() : string { return $this->jsonSerialize(); } } monolog/src/Monolog/Handler/InsightOpsHandler.php 0000644 00000004042 14721613470 0016077 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Inspired on LogEntriesHandler. * * @author Robert Kaufmann III <rok3@rok3.me> * @author Gabriel Machado <gabriel.ms1@hotmail.com> */ class InsightOpsHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\SocketHandler { /** * @var string */ protected $logToken; /** * @param string $token Log token supplied by InsightOps * @param string $region Region where InsightOps account is hosted. Could be 'us' or 'eu'. * @param bool $useSSL Whether or not SSL encryption should be used * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ public function __construct(string $token, string $region = 'us', bool $useSSL = \true, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, bool $persistent = \false, float $timeout = 0.0, float $writingTimeout = 10.0, ?float $connectionTimeout = null, ?int $chunkSize = null) { if ($useSSL && !\extension_loaded('openssl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for InsightOpsHandler'); } $endpoint = $useSSL ? 'ssl://' . $region . '.data.logs.insight.rapid7.com:443' : $region . '.data.logs.insight.rapid7.com:80'; parent::__construct($endpoint, $level, $bubble, $persistent, $timeout, $writingTimeout, $connectionTimeout, $chunkSize); $this->logToken = $token; } /** * {@inheritDoc} */ protected function generateDataStream(array $record) : string { return $this->logToken . ' ' . $record['formatted']; } } monolog/src/Monolog/Handler/Handler.php 0000644 00000002446 14721613470 0014075 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; /** * Base Handler class providing basic close() support as well as handleBatch * * @author Jordi Boggiano <j.boggiano@seld.be> */ abstract class Handler implements \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { /** * {@inheritDoc} */ public function handleBatch(array $records) : void { foreach ($records as $record) { $this->handle($record); } } /** * {@inheritDoc} */ public function close() : void { } public function __destruct() { try { $this->close(); } catch (\Throwable $e) { // do nothing } } public function __sleep() { $this->close(); $reflClass = new \ReflectionClass($this); $keys = []; foreach ($reflClass->getProperties() as $reflProp) { if (!$reflProp->isStatic()) { $keys[] = $reflProp->getName(); } } return $keys; } } monolog/src/Monolog/Handler/NoopHandler.php 0000644 00000001676 14721613470 0014735 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; /** * No-op * * This handler handles anything, but does nothing, and does not stop bubbling to the rest of the stack. * This can be used for testing, or to disable a handler when overriding a configuration without * influencing the rest of the stack. * * @author Roel Harbers <roelharbers@gmail.com> */ class NoopHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\Handler { /** * {@inheritDoc} */ public function isHandling(array $record) : bool { return \true; } /** * {@inheritDoc} */ public function handle(array $record) : bool { return \false; } } monolog/src/Monolog/Handler/AmqpHandler.php 0000644 00000012367 14721613470 0014717 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\JsonFormatter; use Google\Site_Kit_Dependencies\PhpAmqpLib\Message\AMQPMessage; use Google\Site_Kit_Dependencies\PhpAmqpLib\Channel\AMQPChannel; use AMQPExchange; /** * @phpstan-import-type Record from \Monolog\Logger */ class AmqpHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** * @var AMQPExchange|AMQPChannel $exchange */ protected $exchange; /** @var array<string, mixed> */ private $extraAttributes = []; /** * @return array<string, mixed> */ public function getExtraAttributes() : array { return $this->extraAttributes; } /** * Configure extra attributes to pass to the AMQPExchange (if you are using the amqp extension) * * @param array<string, mixed> $extraAttributes One of content_type, content_encoding, * message_id, user_id, app_id, delivery_mode, * priority, timestamp, expiration, type * or reply_to, headers. * @return AmqpHandler */ public function setExtraAttributes(array $extraAttributes) : self { $this->extraAttributes = $extraAttributes; return $this; } /** * @var string */ protected $exchangeName; /** * @param AMQPExchange|AMQPChannel $exchange AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use * @param string|null $exchangeName Optional exchange name, for AMQPChannel (PhpAmqpLib) only */ public function __construct($exchange, ?string $exchangeName = null, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { if ($exchange instanceof \Google\Site_Kit_Dependencies\PhpAmqpLib\Channel\AMQPChannel) { $this->exchangeName = (string) $exchangeName; } elseif (!$exchange instanceof \AMQPExchange) { throw new \InvalidArgumentException('PhpAmqpLib\\Channel\\AMQPChannel or AMQPExchange instance required'); } elseif ($exchangeName) { @\trigger_error('The $exchangeName parameter can only be passed when using PhpAmqpLib, if using an AMQPExchange instance configure it beforehand', \E_USER_DEPRECATED); } $this->exchange = $exchange; parent::__construct($level, $bubble); } /** * {@inheritDoc} */ protected function write(array $record) : void { $data = $record["formatted"]; $routingKey = $this->getRoutingKey($record); if ($this->exchange instanceof \AMQPExchange) { $attributes = ['delivery_mode' => 2, 'content_type' => 'application/json']; if ($this->extraAttributes) { $attributes = \array_merge($attributes, $this->extraAttributes); } $this->exchange->publish($data, $routingKey, 0, $attributes); } else { $this->exchange->basic_publish($this->createAmqpMessage($data), $this->exchangeName, $routingKey); } } /** * {@inheritDoc} */ public function handleBatch(array $records) : void { if ($this->exchange instanceof \AMQPExchange) { parent::handleBatch($records); return; } foreach ($records as $record) { if (!$this->isHandling($record)) { continue; } /** @var Record $record */ $record = $this->processRecord($record); $data = $this->getFormatter()->format($record); $this->exchange->batch_basic_publish($this->createAmqpMessage($data), $this->exchangeName, $this->getRoutingKey($record)); } $this->exchange->publish_batch(); } /** * Gets the routing key for the AMQP exchange * * @phpstan-param Record $record */ protected function getRoutingKey(array $record) : string { $routingKey = \sprintf('%s.%s', $record['level_name'], $record['channel']); return \strtolower($routingKey); } private function createAmqpMessage(string $data) : \Google\Site_Kit_Dependencies\PhpAmqpLib\Message\AMQPMessage { $attributes = ['delivery_mode' => 2, 'content_type' => 'application/json']; if ($this->extraAttributes) { $attributes = \array_merge($attributes, $this->extraAttributes); } return new \Google\Site_Kit_Dependencies\PhpAmqpLib\Message\AMQPMessage($data, $attributes); } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\JsonFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\JsonFormatter::BATCH_MODE_JSON, \false); } } monolog/src/Monolog/Handler/GelfHandler.php 0000644 00000003335 14721613470 0014671 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Gelf\PublisherInterface; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Formatter\GelfMessageFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Handler to send messages to a Graylog2 (http://www.graylog2.org) server * * @author Matt Lehner <mlehner@gmail.com> * @author Benjamin Zikarsky <benjamin@zikarsky.de> */ class GelfHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** * @var PublisherInterface the publisher object that sends the message to the server */ protected $publisher; /** * @param PublisherInterface $publisher a gelf publisher object */ public function __construct(\Google\Site_Kit_Dependencies\Gelf\PublisherInterface $publisher, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { parent::__construct($level, $bubble); $this->publisher = $publisher; } /** * {@inheritDoc} */ protected function write(array $record) : void { $this->publisher->publish($record['formatted']); } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\GelfMessageFormatter(); } } monolog/src/Monolog/Handler/ProcessHandler.php 0000644 00000012263 14721613470 0015432 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Stores to STDIN of any process, specified by a command. * * Usage example: * <pre> * $log = new Logger('myLogger'); * $log->pushHandler(new ProcessHandler('/usr/bin/php /var/www/monolog/someScript.php')); * </pre> * * @author Kolja Zuelsdorf <koljaz@web.de> */ class ProcessHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** * Holds the process to receive data on its STDIN. * * @var resource|bool|null */ private $process; /** * @var string */ private $command; /** * @var string|null */ private $cwd; /** * @var resource[] */ private $pipes = []; /** * @var array<int, string[]> */ protected const DESCRIPTOR_SPEC = [ 0 => ['pipe', 'r'], // STDIN is a pipe that the child will read from 1 => ['pipe', 'w'], // STDOUT is a pipe that the child will write to 2 => ['pipe', 'w'], ]; /** * @param string $command Command for the process to start. Absolute paths are recommended, * especially if you do not use the $cwd parameter. * @param string|null $cwd "Current working directory" (CWD) for the process to be executed in. * @throws \InvalidArgumentException */ public function __construct(string $command, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, ?string $cwd = null) { if ($command === '') { throw new \InvalidArgumentException('The command argument must be a non-empty string.'); } if ($cwd === '') { throw new \InvalidArgumentException('The optional CWD argument must be a non-empty string or null.'); } parent::__construct($level, $bubble); $this->command = $command; $this->cwd = $cwd; } /** * Writes the record down to the log of the implementing handler * * @throws \UnexpectedValueException */ protected function write(array $record) : void { $this->ensureProcessIsStarted(); $this->writeProcessInput($record['formatted']); $errors = $this->readProcessErrors(); if (empty($errors) === \false) { throw new \UnexpectedValueException(\sprintf('Errors while writing to process: %s', $errors)); } } /** * Makes sure that the process is actually started, and if not, starts it, * assigns the stream pipes, and handles startup errors, if any. */ private function ensureProcessIsStarted() : void { if (\is_resource($this->process) === \false) { $this->startProcess(); $this->handleStartupErrors(); } } /** * Starts the actual process and sets all streams to non-blocking. */ private function startProcess() : void { $this->process = \proc_open($this->command, static::DESCRIPTOR_SPEC, $this->pipes, $this->cwd); foreach ($this->pipes as $pipe) { \stream_set_blocking($pipe, \false); } } /** * Selects the STDERR stream, handles upcoming startup errors, and throws an exception, if any. * * @throws \UnexpectedValueException */ private function handleStartupErrors() : void { $selected = $this->selectErrorStream(); if (\false === $selected) { throw new \UnexpectedValueException('Something went wrong while selecting a stream.'); } $errors = $this->readProcessErrors(); if (\is_resource($this->process) === \false || empty($errors) === \false) { throw new \UnexpectedValueException(\sprintf('The process "%s" could not be opened: ' . $errors, $this->command)); } } /** * Selects the STDERR stream. * * @return int|bool */ protected function selectErrorStream() { $empty = []; $errorPipes = [$this->pipes[2]]; return \stream_select($errorPipes, $empty, $empty, 1); } /** * Reads the errors of the process, if there are any. * * @codeCoverageIgnore * @return string Empty string if there are no errors. */ protected function readProcessErrors() : string { return (string) \stream_get_contents($this->pipes[2]); } /** * Writes to the input stream of the opened process. * * @codeCoverageIgnore */ protected function writeProcessInput(string $string) : void { \fwrite($this->pipes[0], $string); } /** * {@inheritDoc} */ public function close() : void { if (\is_resource($this->process)) { foreach ($this->pipes as $pipe) { \fclose($pipe); } \proc_close($this->process); $this->process = null; } } } monolog/src/Monolog/Handler/SymfonyMailerHandler.php 0000644 00000010052 14721613470 0016604 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; use Google\Site_Kit_Dependencies\Symfony\Component\Mailer\MailerInterface; use Google\Site_Kit_Dependencies\Symfony\Component\Mailer\Transport\TransportInterface; use Google\Site_Kit_Dependencies\Symfony\Component\Mime\Email; /** * SymfonyMailerHandler uses Symfony's Mailer component to send the emails * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Record from \Monolog\Logger */ class SymfonyMailerHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\MailHandler { /** @var MailerInterface|TransportInterface */ protected $mailer; /** @var Email|callable(string, Record[]): Email */ private $emailTemplate; /** * @psalm-param Email|callable(string, Record[]): Email $email * * @param MailerInterface|TransportInterface $mailer The mailer to use * @param callable|Email $email An email template, the subject/body will be replaced */ public function __construct($mailer, $email, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR, bool $bubble = \true) { parent::__construct($level, $bubble); $this->mailer = $mailer; $this->emailTemplate = $email; } /** * {@inheritDoc} */ protected function send(string $content, array $records) : void { $this->mailer->send($this->buildMessage($content, $records)); } /** * Gets the formatter for the Swift_Message subject. * * @param string|null $format The format of the subject */ protected function getSubjectFormatter(?string $format) : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter($format); } /** * Creates instance of Email to be sent * * @param string $content formatted email body to be sent * @param array $records Log records that formed the content * * @phpstan-param Record[] $records */ protected function buildMessage(string $content, array $records) : \Google\Site_Kit_Dependencies\Symfony\Component\Mime\Email { $message = null; if ($this->emailTemplate instanceof \Google\Site_Kit_Dependencies\Symfony\Component\Mime\Email) { $message = clone $this->emailTemplate; } elseif (\is_callable($this->emailTemplate)) { $message = ($this->emailTemplate)($content, $records); } if (!$message instanceof \Google\Site_Kit_Dependencies\Symfony\Component\Mime\Email) { $record = \reset($records); throw new \InvalidArgumentException('Could not resolve message as instance of Email or a callable returning it' . ($record ? \Google\Site_Kit_Dependencies\Monolog\Utils::getRecordMessageForException($record) : '')); } if ($records) { $subjectFormatter = $this->getSubjectFormatter($message->getSubject()); $message->subject($subjectFormatter->format($this->getHighestRecord($records))); } if ($this->isHtmlBody($content)) { if (null !== ($charset = $message->getHtmlCharset())) { $message->html($content, $charset); } else { $message->html($content); } } else { if (null !== ($charset = $message->getTextCharset())) { $message->text($content, $charset); } else { $message->text($content); } } return $message->date(new \DateTimeImmutable()); } } monolog/src/Monolog/Handler/FormattableHandlerInterface.php 0000644 00000002025 14721613470 0020070 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Interface to describe loggers that have a formatter * * @author Jordi Boggiano <j.boggiano@seld.be> */ interface FormattableHandlerInterface { /** * Sets the formatter. * * @param FormatterInterface $formatter * @return HandlerInterface self */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface; /** * Gets the formatter. * * @return FormatterInterface */ public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; } monolog/src/Monolog/Handler/TestHandler.php 0000644 00000015461 14721613470 0014736 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Used for testing purposes. * * It records all records and gives you access to them for verification. * * @author Jordi Boggiano <j.boggiano@seld.be> * * @method bool hasEmergency($record) * @method bool hasAlert($record) * @method bool hasCritical($record) * @method bool hasError($record) * @method bool hasWarning($record) * @method bool hasNotice($record) * @method bool hasInfo($record) * @method bool hasDebug($record) * * @method bool hasEmergencyRecords() * @method bool hasAlertRecords() * @method bool hasCriticalRecords() * @method bool hasErrorRecords() * @method bool hasWarningRecords() * @method bool hasNoticeRecords() * @method bool hasInfoRecords() * @method bool hasDebugRecords() * * @method bool hasEmergencyThatContains($message) * @method bool hasAlertThatContains($message) * @method bool hasCriticalThatContains($message) * @method bool hasErrorThatContains($message) * @method bool hasWarningThatContains($message) * @method bool hasNoticeThatContains($message) * @method bool hasInfoThatContains($message) * @method bool hasDebugThatContains($message) * * @method bool hasEmergencyThatMatches($message) * @method bool hasAlertThatMatches($message) * @method bool hasCriticalThatMatches($message) * @method bool hasErrorThatMatches($message) * @method bool hasWarningThatMatches($message) * @method bool hasNoticeThatMatches($message) * @method bool hasInfoThatMatches($message) * @method bool hasDebugThatMatches($message) * * @method bool hasEmergencyThatPasses($message) * @method bool hasAlertThatPasses($message) * @method bool hasCriticalThatPasses($message) * @method bool hasErrorThatPasses($message) * @method bool hasWarningThatPasses($message) * @method bool hasNoticeThatPasses($message) * @method bool hasInfoThatPasses($message) * @method bool hasDebugThatPasses($message) * * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ class TestHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var Record[] */ protected $records = []; /** @var array<Level, Record[]> */ protected $recordsByLevel = []; /** @var bool */ private $skipReset = \false; /** * @return array * * @phpstan-return Record[] */ public function getRecords() { return $this->records; } /** * @return void */ public function clear() { $this->records = []; $this->recordsByLevel = []; } /** * @return void */ public function reset() { if (!$this->skipReset) { $this->clear(); } } /** * @return void */ public function setSkipReset(bool $skipReset) { $this->skipReset = $skipReset; } /** * @param string|int $level Logging level value or name * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecords($level) : bool { return isset($this->recordsByLevel[\Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($level)]); } /** * @param string|array $record Either a message string or an array containing message and optionally context keys that will be checked against all records * @param string|int $level Logging level value or name * * @phpstan-param array{message: string, context?: mixed[]}|string $record * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecord($record, $level) : bool { if (\is_string($record)) { $record = array('message' => $record); } return $this->hasRecordThatPasses(function ($rec) use($record) { if ($rec['message'] !== $record['message']) { return \false; } if (isset($record['context']) && $rec['context'] !== $record['context']) { return \false; } return \true; }, $level); } /** * @param string|int $level Logging level value or name * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecordThatContains(string $message, $level) : bool { return $this->hasRecordThatPasses(function ($rec) use($message) { return \strpos($rec['message'], $message) !== \false; }, $level); } /** * @param string|int $level Logging level value or name * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecordThatMatches(string $regex, $level) : bool { return $this->hasRecordThatPasses(function (array $rec) use($regex) : bool { return \preg_match($regex, $rec['message']) > 0; }, $level); } /** * @param string|int $level Logging level value or name * @return bool * * @psalm-param callable(Record, int): mixed $predicate * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecordThatPasses(callable $predicate, $level) { $level = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($level); if (!isset($this->recordsByLevel[$level])) { return \false; } foreach ($this->recordsByLevel[$level] as $i => $rec) { if ($predicate($rec, $i)) { return \true; } } return \false; } /** * {@inheritDoc} */ protected function write(array $record) : void { $this->recordsByLevel[$record['level']][] = $record; $this->records[] = $record; } /** * @param string $method * @param mixed[] $args * @return bool */ public function __call($method, $args) { if (\preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; $level = \constant('Monolog\\Logger::' . \strtoupper($matches[2])); $callback = [$this, $genericMethod]; if (\is_callable($callback)) { $args[] = $level; return \call_user_func_array($callback, $args); } } throw new \BadMethodCallException('Call to undefined method ' . \get_class($this) . '::' . $method . '()'); } } monolog/src/Monolog/Handler/SwiftMailerHandler.php 0000644 00000010215 14721613470 0016235 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; use Google\Site_Kit_Dependencies\Swift_Message; use Google\Site_Kit_Dependencies\Swift; /** * SwiftMailerHandler uses Swift_Mailer to send the emails * * @author Gyula Sallai * * @phpstan-import-type Record from \Monolog\Logger * @deprecated Since Monolog 2.6. Use SymfonyMailerHandler instead. */ class SwiftMailerHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\MailHandler { /** @var \Swift_Mailer */ protected $mailer; /** @var Swift_Message|callable(string, Record[]): Swift_Message */ private $messageTemplate; /** * @psalm-param Swift_Message|callable(string, Record[]): Swift_Message $message * * @param \Swift_Mailer $mailer The mailer to use * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced */ public function __construct(\Google\Site_Kit_Dependencies\Swift_Mailer $mailer, $message, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR, bool $bubble = \true) { parent::__construct($level, $bubble); @\trigger_error('The SwiftMailerHandler is deprecated since Monolog 2.6. Use SymfonyMailerHandler instead.', \E_USER_DEPRECATED); $this->mailer = $mailer; $this->messageTemplate = $message; } /** * {@inheritDoc} */ protected function send(string $content, array $records) : void { $this->mailer->send($this->buildMessage($content, $records)); } /** * Gets the formatter for the Swift_Message subject. * * @param string|null $format The format of the subject */ protected function getSubjectFormatter(?string $format) : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter($format); } /** * Creates instance of Swift_Message to be sent * * @param string $content formatted email body to be sent * @param array $records Log records that formed the content * @return Swift_Message * * @phpstan-param Record[] $records */ protected function buildMessage(string $content, array $records) : \Google\Site_Kit_Dependencies\Swift_Message { $message = null; if ($this->messageTemplate instanceof \Google\Site_Kit_Dependencies\Swift_Message) { $message = clone $this->messageTemplate; $message->generateId(); } elseif (\is_callable($this->messageTemplate)) { $message = ($this->messageTemplate)($content, $records); } if (!$message instanceof \Google\Site_Kit_Dependencies\Swift_Message) { $record = \reset($records); throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it' . ($record ? \Google\Site_Kit_Dependencies\Monolog\Utils::getRecordMessageForException($record) : '')); } if ($records) { $subjectFormatter = $this->getSubjectFormatter($message->getSubject()); $message->setSubject($subjectFormatter->format($this->getHighestRecord($records))); } $mime = 'text/plain'; if ($this->isHtmlBody($content)) { $mime = 'text/html'; } $message->setBody($content, $mime); /** @phpstan-ignore-next-line */ if (\version_compare(\Google\Site_Kit_Dependencies\Swift::VERSION, '6.0.0', '>=')) { $message->setDate(new \DateTimeImmutable()); } else { /** @phpstan-ignore-next-line */ $message->setDate(\time()); } return $message; } } monolog/src/Monolog/Handler/PsrHandler.php 0000644 00000005457 14721613470 0014567 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Psr\Log\LoggerInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Proxies log messages to an existing PSR-3 compliant logger. * * If a formatter is configured, the formatter's output MUST be a string and the * formatted message will be fed to the wrapped PSR logger instead of the original * log record's message. * * @author Michael Moussa <michael.moussa@gmail.com> */ class PsrHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractHandler implements \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface { /** * PSR-3 compliant logger * * @var LoggerInterface */ protected $logger; /** * @var FormatterInterface|null */ protected $formatter; /** * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied */ public function __construct(\Google\Site_Kit_Dependencies\Psr\Log\LoggerInterface $logger, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { parent::__construct($level, $bubble); $this->logger = $logger; } /** * {@inheritDoc} */ public function handle(array $record) : bool { if (!$this->isHandling($record)) { return \false; } if ($this->formatter) { $formatted = $this->formatter->format($record); $this->logger->log(\strtolower($record['level_name']), (string) $formatted, $record['context']); } else { $this->logger->log(\strtolower($record['level_name']), $record['message'], $record['context']); } return \false === $this->bubble; } /** * Sets the formatter. * * @param FormatterInterface $formatter */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { $this->formatter = $formatter; return $this; } /** * Gets the formatter. * * @return FormatterInterface */ public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { if (!$this->formatter) { throw new \LogicException('No formatter has been set and this handler does not have a default formatter'); } return $this->formatter; } } monolog/src/Monolog/Handler/AbstractProcessingHandler.php 0000644 00000004035 14721613470 0017612 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; /** * Base Handler class providing the Handler structure, including processors and formatters * * Classes extending it should (in most cases) only implement write($record) * * @author Jordi Boggiano <j.boggiano@seld.be> * @author Christophe Coevoet <stof@notk.org> * * @phpstan-import-type LevelName from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type Record from \Monolog\Logger * @phpstan-type FormattedRecord array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[], formatted: mixed} */ abstract class AbstractProcessingHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractHandler implements \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface, \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface { use ProcessableHandlerTrait; use FormattableHandlerTrait; /** * {@inheritDoc} */ public function handle(array $record) : bool { if (!$this->isHandling($record)) { return \false; } if ($this->processors) { /** @var Record $record */ $record = $this->processRecord($record); } $record['formatted'] = $this->getFormatter()->format($record); $this->write($record); return \false === $this->bubble; } /** * Writes the record down to the log of the implementing handler * * @phpstan-param FormattedRecord $record */ protected abstract function write(array $record) : void; /** * @return void */ public function reset() { parent::reset(); $this->resetProcessors(); } } monolog/src/Monolog/Handler/DeduplicationHandler.php 0000644 00000014347 14721613470 0016605 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Simple handler wrapper that deduplicates log records across multiple requests * * It also includes the BufferHandler functionality and will buffer * all messages until the end of the request or flush() is called. * * This works by storing all log records' messages above $deduplicationLevel * to the file specified by $deduplicationStore. When further logs come in at the end of the * request (or when flush() is called), all those above $deduplicationLevel are checked * against the existing stored logs. If they match and the timestamps in the stored log is * not older than $time seconds, the new log record is discarded. If no log record is new, the * whole data set is discarded. * * This is mainly useful in combination with Mail handlers or things like Slack or HipChat handlers * that send messages to people, to avoid spamming with the same message over and over in case of * a major component failure like a database server being down which makes all requests fail in the * same way. * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger */ class DeduplicationHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\BufferHandler { /** * @var string */ protected $deduplicationStore; /** * @var Level */ protected $deduplicationLevel; /** * @var int */ protected $time; /** * @var bool */ private $gc = \false; /** * @param HandlerInterface $handler Handler. * @param string $deduplicationStore The file/path where the deduplication log should be kept * @param string|int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes * @param int $time The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * * @phpstan-param Level|LevelName|LogLevel::* $deduplicationLevel */ public function __construct(\Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface $handler, ?string $deduplicationStore = null, $deduplicationLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR, int $time = 60, bool $bubble = \true) { parent::__construct($handler, 0, \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, $bubble, \false); $this->deduplicationStore = $deduplicationStore === null ? \sys_get_temp_dir() . '/monolog-dedup-' . \substr(\md5(__FILE__), 0, 20) . '.log' : $deduplicationStore; $this->deduplicationLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($deduplicationLevel); $this->time = $time; } public function flush() : void { if ($this->bufferSize === 0) { return; } $passthru = null; foreach ($this->buffer as $record) { if ($record['level'] >= $this->deduplicationLevel) { $passthru = $passthru || !$this->isDuplicate($record); if ($passthru) { $this->appendRecord($record); } } } // default of null is valid as well as if no record matches duplicationLevel we just pass through if ($passthru === \true || $passthru === null) { $this->handler->handleBatch($this->buffer); } $this->clear(); if ($this->gc) { $this->collectLogs(); } } /** * @phpstan-param Record $record */ private function isDuplicate(array $record) : bool { if (!\file_exists($this->deduplicationStore)) { return \false; } $store = \file($this->deduplicationStore, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES); if (!\is_array($store)) { return \false; } $yesterday = \time() - 86400; $timestampValidity = $record['datetime']->getTimestamp() - $this->time; $expectedMessage = \preg_replace('{[\\r\\n].*}', '', $record['message']); for ($i = \count($store) - 1; $i >= 0; $i--) { list($timestamp, $level, $message) = \explode(':', $store[$i], 3); if ($level === $record['level_name'] && $message === $expectedMessage && $timestamp > $timestampValidity) { return \true; } if ($timestamp < $yesterday) { $this->gc = \true; } } return \false; } private function collectLogs() : void { if (!\file_exists($this->deduplicationStore)) { return; } $handle = \fopen($this->deduplicationStore, 'rw+'); if (!$handle) { throw new \RuntimeException('Failed to open file for reading and writing: ' . $this->deduplicationStore); } \flock($handle, \LOCK_EX); $validLogs = []; $timestampValidity = \time() - $this->time; while (!\feof($handle)) { $log = \fgets($handle); if ($log && \substr($log, 0, 10) >= $timestampValidity) { $validLogs[] = $log; } } \ftruncate($handle, 0); \rewind($handle); foreach ($validLogs as $log) { \fwrite($handle, $log); } \flock($handle, \LOCK_UN); \fclose($handle); $this->gc = \false; } /** * @phpstan-param Record $record */ private function appendRecord(array $record) : void { \file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . \preg_replace('{[\\r\\n].*}', '', $record['message']) . "\n", \FILE_APPEND); } } monolog/src/Monolog/Handler/SlackWebhookHandler.php 0000644 00000010277 14721613470 0016373 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; use Google\Site_Kit_Dependencies\Monolog\Handler\Slack\SlackRecord; /** * Sends notifications through Slack Webhooks * * @author Haralan Dobrev <hkdobrev@gmail.com> * @see https://api.slack.com/incoming-webhooks */ class SlackWebhookHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** * Slack Webhook token * @var string */ private $webhookUrl; /** * Instance of the SlackRecord util class preparing data for Slack API. * @var SlackRecord */ private $slackRecord; /** * @param string $webhookUrl Slack Webhook URL * @param string|null $channel Slack channel (encoded ID or name) * @param string|null $username Name of a bot * @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise) * @param string|null $iconEmoji The emoji name to use (or null) * @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style * @param bool $includeContextAndExtra Whether the attachment should include context and extra data * @param string[] $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] */ public function __construct(string $webhookUrl, ?string $channel = null, ?string $username = null, bool $useAttachment = \true, ?string $iconEmoji = null, bool $useShortAttachment = \false, bool $includeContextAndExtra = \false, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL, bool $bubble = \true, array $excludeFields = array()) { if (!\extension_loaded('curl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The curl extension is needed to use the SlackWebhookHandler'); } parent::__construct($level, $bubble); $this->webhookUrl = $webhookUrl; $this->slackRecord = new \Google\Site_Kit_Dependencies\Monolog\Handler\Slack\SlackRecord($channel, $username, $useAttachment, $iconEmoji, $useShortAttachment, $includeContextAndExtra, $excludeFields); } public function getSlackRecord() : \Google\Site_Kit_Dependencies\Monolog\Handler\Slack\SlackRecord { return $this->slackRecord; } public function getWebhookUrl() : string { return $this->webhookUrl; } /** * {@inheritDoc} */ protected function write(array $record) : void { $postData = $this->slackRecord->getSlackData($record); $postString = \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($postData); $ch = \curl_init(); $options = array(\CURLOPT_URL => $this->webhookUrl, \CURLOPT_POST => \true, \CURLOPT_RETURNTRANSFER => \true, \CURLOPT_HTTPHEADER => array('Content-type: application/json'), \CURLOPT_POSTFIELDS => $postString); if (\defined('CURLOPT_SAFE_UPLOAD')) { $options[\CURLOPT_SAFE_UPLOAD] = \true; } \curl_setopt_array($ch, $options); \Google\Site_Kit_Dependencies\Monolog\Handler\Curl\Util::execute($ch); } public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { parent::setFormatter($formatter); $this->slackRecord->setFormatter($formatter); return $this; } public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { $formatter = parent::getFormatter(); $this->slackRecord->setFormatter($formatter); return $formatter; } } monolog/src/Monolog/Handler/ProcessableHandlerTrait.php 0000644 00000003562 14721613470 0017264 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\ResettableInterface; use Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface; /** * Helper trait for implementing ProcessableInterface * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Record from \Monolog\Logger */ trait ProcessableHandlerTrait { /** * @var callable[] * @phpstan-var array<ProcessorInterface|callable(Record): Record> */ protected $processors = []; /** * {@inheritDoc} */ public function pushProcessor(callable $callback) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { \array_unshift($this->processors, $callback); return $this; } /** * {@inheritDoc} */ public function popProcessor() : callable { if (!$this->processors) { throw new \LogicException('You tried to pop from an empty processor stack.'); } return \array_shift($this->processors); } /** * Processes a record. * * @phpstan-param Record $record * @phpstan-return Record */ protected function processRecord(array $record) : array { foreach ($this->processors as $processor) { $record = $processor($record); } return $record; } protected function resetProcessors() : void { foreach ($this->processors as $processor) { if ($processor instanceof \Google\Site_Kit_Dependencies\Monolog\ResettableInterface) { $processor->reset(); } } } } monolog/src/Monolog/Handler/MissingExtensionException.php 0000644 00000000766 14721613470 0017710 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; /** * Exception can be thrown if an extension for a handler is missing * * @author Christian Bergau <cbergau86@gmail.com> */ class MissingExtensionException extends \Exception { } monolog/src/Monolog/Handler/SyslogUdpHandler.php 0000644 00000011241 14721613470 0015740 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use DateTimeInterface; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Handler\SyslogUdp\UdpSocket; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * A Handler for logging to a remote syslogd server. * * @author Jesper Skovgaard Nielsen <nulpunkt@gmail.com> * @author Dominik Kukacka <dominik.kukacka@gmail.com> */ class SyslogUdpHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractSyslogHandler { const RFC3164 = 0; const RFC5424 = 1; const RFC5424e = 2; /** @var array<self::RFC*, string> */ private $dateFormats = array(self::RFC3164 => 'M d H:i:s', self::RFC5424 => \DateTime::RFC3339, self::RFC5424e => \DateTime::RFC3339_EXTENDED); /** @var UdpSocket */ protected $socket; /** @var string */ protected $ident; /** @var self::RFC* */ protected $rfc; /** * @param string $host Either IP/hostname or a path to a unix socket (port must be 0 then) * @param int $port Port number, or 0 if $host is a unix socket * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param string $ident Program name or tag for each log message. * @param int $rfc RFC to format the message for. * @throws MissingExtensionException * * @phpstan-param self::RFC* $rfc */ public function __construct(string $host, int $port = 514, $facility = \LOG_USER, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, string $ident = 'php', int $rfc = self::RFC5424) { if (!\extension_loaded('sockets')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The sockets extension is required to use the SyslogUdpHandler'); } parent::__construct($facility, $level, $bubble); $this->ident = $ident; $this->rfc = $rfc; $this->socket = new \Google\Site_Kit_Dependencies\Monolog\Handler\SyslogUdp\UdpSocket($host, $port); } protected function write(array $record) : void { $lines = $this->splitMessageIntoLines($record['formatted']); $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']], $record['datetime']); foreach ($lines as $line) { $this->socket->write($line, $header); } } public function close() : void { $this->socket->close(); } /** * @param string|string[] $message * @return string[] */ private function splitMessageIntoLines($message) : array { if (\is_array($message)) { $message = \implode("\n", $message); } $lines = \preg_split('/$\\R?^/m', (string) $message, -1, \PREG_SPLIT_NO_EMPTY); if (\false === $lines) { $pcreErrorCode = \preg_last_error(); throw new \RuntimeException('Could not preg_split: ' . $pcreErrorCode . ' / ' . \Google\Site_Kit_Dependencies\Monolog\Utils::pcreLastErrorMessage($pcreErrorCode)); } return $lines; } /** * Make common syslog header (see rfc5424 or rfc3164) */ protected function makeCommonSyslogHeader(int $severity, \DateTimeInterface $datetime) : string { $priority = $severity + $this->facility; if (!($pid = \getmypid())) { $pid = '-'; } if (!($hostname = \gethostname())) { $hostname = '-'; } if ($this->rfc === self::RFC3164) { // see https://github.com/phpstan/phpstan/issues/5348 // @phpstan-ignore-next-line $dateNew = $datetime->setTimezone(new \DateTimeZone('UTC')); $date = $dateNew->format($this->dateFormats[$this->rfc]); return "<{$priority}>" . $date . " " . $hostname . " " . $this->ident . "[" . $pid . "]: "; } $date = $datetime->format($this->dateFormats[$this->rfc]); return "<{$priority}>1 " . $date . " " . $hostname . " " . $this->ident . " " . $pid . " - - "; } /** * Inject your own socket, mainly used for testing */ public function setSocket(\Google\Site_Kit_Dependencies\Monolog\Handler\SyslogUdp\UdpSocket $socket) : self { $this->socket = $socket; return $this; } } monolog/src/Monolog/Handler/LogEntriesHandler.php 0000644 00000003606 14721613470 0016070 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * @author Robert Kaufmann III <rok3@rok3.me> */ class LogEntriesHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\SocketHandler { /** * @var string */ protected $logToken; /** * @param string $token Log token supplied by LogEntries * @param bool $useSSL Whether or not SSL encryption should be used. * @param string $host Custom hostname to send the data to if needed * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ public function __construct(string $token, bool $useSSL = \true, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, string $host = 'data.logentries.com', bool $persistent = \false, float $timeout = 0.0, float $writingTimeout = 10.0, ?float $connectionTimeout = null, ?int $chunkSize = null) { if ($useSSL && !\extension_loaded('openssl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); } $endpoint = $useSSL ? 'ssl://' . $host . ':443' : $host . ':80'; parent::__construct($endpoint, $level, $bubble, $persistent, $timeout, $writingTimeout, $connectionTimeout, $chunkSize); $this->logToken = $token; } /** * {@inheritDoc} */ protected function generateDataStream(array $record) : string { return $this->logToken . ' ' . $record['formatted']; } } monolog/src/Monolog/Handler/SendGridHandler.php 0000644 00000006045 14721613470 0015514 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * SendGridrHandler uses the SendGrid API v2 function to send Log emails, more information in https://sendgrid.com/docs/API_Reference/Web_API/mail.html * * @author Ricardo Fontanelli <ricardo.fontanelli@hotmail.com> */ class SendGridHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\MailHandler { /** * The SendGrid API User * @var string */ protected $apiUser; /** * The SendGrid API Key * @var string */ protected $apiKey; /** * The email addresses to which the message will be sent * @var string */ protected $from; /** * The email addresses to which the message will be sent * @var string[] */ protected $to; /** * The subject of the email * @var string */ protected $subject; /** * @param string $apiUser The SendGrid API User * @param string $apiKey The SendGrid API Key * @param string $from The sender of the email * @param string|string[] $to The recipients of the email * @param string $subject The subject of the mail */ public function __construct(string $apiUser, string $apiKey, string $from, $to, string $subject, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR, bool $bubble = \true) { if (!\extension_loaded('curl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The curl extension is needed to use the SendGridHandler'); } parent::__construct($level, $bubble); $this->apiUser = $apiUser; $this->apiKey = $apiKey; $this->from = $from; $this->to = (array) $to; $this->subject = $subject; } /** * {@inheritDoc} */ protected function send(string $content, array $records) : void { $message = []; $message['api_user'] = $this->apiUser; $message['api_key'] = $this->apiKey; $message['from'] = $this->from; foreach ($this->to as $recipient) { $message['to[]'] = $recipient; } $message['subject'] = $this->subject; $message['date'] = \date('r'); if ($this->isHtmlBody($content)) { $message['html'] = $content; } else { $message['text'] = $content; } $ch = \curl_init(); \curl_setopt($ch, \CURLOPT_URL, 'https://api.sendgrid.com/api/mail.send.json'); \curl_setopt($ch, \CURLOPT_POST, 1); \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1); \curl_setopt($ch, \CURLOPT_POSTFIELDS, \http_build_query($message)); \Google\Site_Kit_Dependencies\Monolog\Handler\Curl\Util::execute($ch, 2); } } monolog/src/Monolog/Handler/ErrorLogHandler.php 0000644 00000005553 14721613470 0015553 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Stores to PHP error_log() handler. * * @author Elan Ruusamäe <glen@delfi.ee> */ class ErrorLogHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { public const OPERATING_SYSTEM = 0; public const SAPI = 4; /** @var int */ protected $messageType; /** @var bool */ protected $expandNewlines; /** * @param int $messageType Says where the error should go. * @param bool $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries */ public function __construct(int $messageType = self::OPERATING_SYSTEM, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, bool $expandNewlines = \false) { parent::__construct($level, $bubble); if (\false === \in_array($messageType, self::getAvailableTypes(), \true)) { $message = \sprintf('The given message type "%s" is not supported', \print_r($messageType, \true)); throw new \InvalidArgumentException($message); } $this->messageType = $messageType; $this->expandNewlines = $expandNewlines; } /** * @return int[] With all available types */ public static function getAvailableTypes() : array { return [self::OPERATING_SYSTEM, self::SAPI]; } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter('[%datetime%] %channel%.%level_name%: %message% %context% %extra%'); } /** * {@inheritDoc} */ protected function write(array $record) : void { if (!$this->expandNewlines) { \error_log((string) $record['formatted'], $this->messageType); return; } $lines = \preg_split('{[\\r\\n]+}', (string) $record['formatted']); if ($lines === \false) { $pcreErrorCode = \preg_last_error(); throw new \RuntimeException('Failed to preg_split formatted string: ' . $pcreErrorCode . ' / ' . \Google\Site_Kit_Dependencies\Monolog\Utils::pcreLastErrorMessage($pcreErrorCode)); } foreach ($lines as $line) { \error_log($line, $this->messageType); } } } monolog/src/Monolog/Handler/SamplingHandler.php 0000644 00000011463 14721613470 0015567 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Sampling handler * * A sampled event stream can be useful for logging high frequency events in * a production environment where you only need an idea of what is happening * and are not concerned with capturing every occurrence. Since the decision to * handle or not handle a particular event is determined randomly, the * resulting sampled log is not guaranteed to contain 1/N of the events that * occurred in the application, but based on the Law of large numbers, it will * tend to be close to this ratio with a large number of attempts. * * @author Bryan Davis <bd808@wikimedia.org> * @author Kunal Mehta <legoktm@gmail.com> * * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger */ class SamplingHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractHandler implements \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface, \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface { use ProcessableHandlerTrait; /** * @var HandlerInterface|callable * @phpstan-var HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface */ protected $handler; /** * @var int $factor */ protected $factor; /** * @psalm-param HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface $handler * * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler). * @param int $factor Sample factor (e.g. 10 means every ~10th record is sampled) */ public function __construct($handler, int $factor) { parent::__construct(); $this->handler = $handler; $this->factor = $factor; if (!$this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface && !\is_callable($this->handler)) { throw new \RuntimeException("The given handler (" . \json_encode($this->handler) . ") is not a callable nor a Monolog\\Handler\\HandlerInterface object"); } } public function isHandling(array $record) : bool { return $this->getHandler($record)->isHandling($record); } public function handle(array $record) : bool { if ($this->isHandling($record) && \mt_rand(1, $this->factor) === 1) { if ($this->processors) { /** @var Record $record */ $record = $this->processRecord($record); } $this->getHandler($record)->handle($record); } return \false === $this->bubble; } /** * Return the nested handler * * If the handler was provided as a factory callable, this will trigger the handler's instantiation. * * @phpstan-param Record|array{level: Level}|null $record * * @return HandlerInterface */ public function getHandler(?array $record = null) { if (!$this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface) { $this->handler = ($this->handler)($record, $this); if (!$this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } } return $this->handler; } /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { $handler = $this->getHandler(); if ($handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { $handler->setFormatter($formatter); return $this; } throw new \UnexpectedValueException('The nested handler of type ' . \get_class($handler) . ' does not support formatters.'); } /** * {@inheritDoc} */ public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { $handler = $this->getHandler(); if ($handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { return $handler->getFormatter(); } throw new \UnexpectedValueException('The nested handler of type ' . \get_class($handler) . ' does not support formatters.'); } } monolog/src/Monolog/Handler/RotatingFileHandler.php 0000644 00000014321 14721613470 0016400 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use InvalidArgumentException; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Stores logs to files that are rotated every day and a limited number of files are kept. * * This rotation is only intended to be used as a workaround. Using logrotate to * handle the rotation is strongly encouraged when you can use it. * * @author Christophe Coevoet <stof@notk.org> * @author Jordi Boggiano <j.boggiano@seld.be> */ class RotatingFileHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\StreamHandler { public const FILE_PER_DAY = 'Y-m-d'; public const FILE_PER_MONTH = 'Y-m'; public const FILE_PER_YEAR = 'Y'; /** @var string */ protected $filename; /** @var int */ protected $maxFiles; /** @var bool */ protected $mustRotate; /** @var \DateTimeImmutable */ protected $nextRotation; /** @var string */ protected $filenameFormat; /** @var string */ protected $dateFormat; /** * @param string $filename * @param int $maxFiles The maximal amount of files to keep (0 means unlimited) * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) * @param bool $useLocking Try to lock log file before doing any writes */ public function __construct(string $filename, int $maxFiles = 0, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, ?int $filePermission = null, bool $useLocking = \false) { $this->filename = \Google\Site_Kit_Dependencies\Monolog\Utils::canonicalizePath($filename); $this->maxFiles = $maxFiles; $this->nextRotation = new \DateTimeImmutable('tomorrow'); $this->filenameFormat = '{filename}-{date}'; $this->dateFormat = static::FILE_PER_DAY; parent::__construct($this->getTimedFilename(), $level, $bubble, $filePermission, $useLocking); } /** * {@inheritDoc} */ public function close() : void { parent::close(); if (\true === $this->mustRotate) { $this->rotate(); } } /** * {@inheritDoc} */ public function reset() { parent::reset(); if (\true === $this->mustRotate) { $this->rotate(); } } public function setFilenameFormat(string $filenameFormat, string $dateFormat) : self { if (!\preg_match('{^[Yy](([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { throw new \InvalidArgumentException('Invalid date format - format must be one of ' . 'RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), RotatingFileHandler::FILE_PER_MONTH ("Y-m") ' . 'or RotatingFileHandler::FILE_PER_YEAR ("Y"), or you can set one of the ' . 'date formats using slashes, underscores and/or dots instead of dashes.'); } if (\substr_count($filenameFormat, '{date}') === 0) { throw new \InvalidArgumentException('Invalid filename format - format must contain at least `{date}`, because otherwise rotating is impossible.'); } $this->filenameFormat = $filenameFormat; $this->dateFormat = $dateFormat; $this->url = $this->getTimedFilename(); $this->close(); return $this; } /** * {@inheritDoc} */ protected function write(array $record) : void { // on the first record written, if the log is new, we should rotate (once per day) if (null === $this->mustRotate) { $this->mustRotate = null === $this->url || !\file_exists($this->url); } if ($this->nextRotation <= $record['datetime']) { $this->mustRotate = \true; $this->close(); } parent::write($record); } /** * Rotates the files. */ protected function rotate() : void { // update filename $this->url = $this->getTimedFilename(); $this->nextRotation = new \DateTimeImmutable('tomorrow'); // skip GC of old logs if files are unlimited if (0 === $this->maxFiles) { return; } $logFiles = \glob($this->getGlobPattern()); if (\false === $logFiles) { // failed to glob return; } if ($this->maxFiles >= \count($logFiles)) { // no files to remove return; } // Sorting the files by name to remove the older ones \usort($logFiles, function ($a, $b) { return \strcmp($b, $a); }); foreach (\array_slice($logFiles, $this->maxFiles) as $file) { if (\is_writable($file)) { // suppress errors here as unlink() might fail if two processes // are cleaning up/rotating at the same time \set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) : bool { return \false; }); \unlink($file); \restore_error_handler(); } } $this->mustRotate = \false; } protected function getTimedFilename() : string { $fileInfo = \pathinfo($this->filename); $timedFilename = \str_replace(['{filename}', '{date}'], [$fileInfo['filename'], \date($this->dateFormat)], $fileInfo['dirname'] . '/' . $this->filenameFormat); if (isset($fileInfo['extension'])) { $timedFilename .= '.' . $fileInfo['extension']; } return $timedFilename; } protected function getGlobPattern() : string { $fileInfo = \pathinfo($this->filename); $glob = \str_replace(['{filename}', '{date}'], [$fileInfo['filename'], \str_replace(['Y', 'y', 'm', 'd'], ['[0-9][0-9][0-9][0-9]', '[0-9][0-9]', '[0-9][0-9]', '[0-9][0-9]'], $this->dateFormat)], $fileInfo['dirname'] . '/' . $this->filenameFormat); if (isset($fileInfo['extension'])) { $glob .= '.' . $fileInfo['extension']; } return $glob; } } monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php 0000644 00000005124 14721613470 0023541 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler\FingersCrossed; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Channel and Error level based monolog activation strategy. Allows to trigger activation * based on level per channel. e.g. trigger activation on level 'ERROR' by default, except * for records of the 'sql' channel; those should trigger activation on level 'WARN'. * * Example: * * <code> * $activationStrategy = new ChannelLevelActivationStrategy( * Logger::CRITICAL, * array( * 'request' => Logger::ALERT, * 'sensitive' => Logger::ERROR, * ) * ); * $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy); * </code> * * @author Mike Meessen <netmikey@gmail.com> * * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ class ChannelLevelActivationStrategy implements \Google\Site_Kit_Dependencies\Monolog\Handler\FingersCrossed\ActivationStrategyInterface { /** * @var Level */ private $defaultActionLevel; /** * @var array<string, Level> */ private $channelToActionLevel; /** * @param int|string $defaultActionLevel The default action level to be used if the record's category doesn't match any * @param array<string, int> $channelToActionLevel An array that maps channel names to action levels. * * @phpstan-param array<string, Level> $channelToActionLevel * @phpstan-param Level|LevelName|LogLevel::* $defaultActionLevel */ public function __construct($defaultActionLevel, array $channelToActionLevel = []) { $this->defaultActionLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($defaultActionLevel); $this->channelToActionLevel = \array_map('Monolog\\Logger::toMonologLevel', $channelToActionLevel); } /** * @phpstan-param Record $record */ public function isHandlerActivated(array $record) : bool { if (isset($this->channelToActionLevel[$record['channel']])) { return $record['level'] >= $this->channelToActionLevel[$record['channel']]; } return $record['level'] >= $this->defaultActionLevel; } } monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php 0000644 00000001356 14721613470 0023104 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler\FingersCrossed; /** * Interface for activation strategies for the FingersCrossedHandler. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> * * @phpstan-import-type Record from \Monolog\Logger */ interface ActivationStrategyInterface { /** * Returns whether the given record activates the handler. * * @phpstan-param Record $record */ public function isHandlerActivated(array $record) : bool; } monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php 0000644 00000002406 14721613470 0023262 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler\FingersCrossed; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Error level based activation strategy. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> * * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ class ErrorLevelActivationStrategy implements \Google\Site_Kit_Dependencies\Monolog\Handler\FingersCrossed\ActivationStrategyInterface { /** * @var Level */ private $actionLevel; /** * @param int|string $actionLevel Level or name or value * * @phpstan-param Level|LevelName|LogLevel::* $actionLevel */ public function __construct($actionLevel) { $this->actionLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($actionLevel); } public function isHandlerActivated(array $record) : bool { return $record['level'] >= $this->actionLevel; } } monolog/src/Monolog/Handler/MandrillHandler.php 0000644 00000005322 14721613470 0015554 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Swift; use Google\Site_Kit_Dependencies\Swift_Message; /** * MandrillHandler uses cURL to send the emails to the Mandrill API * * @author Adam Nicholson <adamnicholson10@gmail.com> */ class MandrillHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\MailHandler { /** @var Swift_Message */ protected $message; /** @var string */ protected $apiKey; /** * @psalm-param Swift_Message|callable(): Swift_Message $message * * @param string $apiKey A valid Mandrill API key * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced */ public function __construct(string $apiKey, $message, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR, bool $bubble = \true) { parent::__construct($level, $bubble); if (!$message instanceof \Google\Site_Kit_Dependencies\Swift_Message && \is_callable($message)) { $message = $message(); } if (!$message instanceof \Google\Site_Kit_Dependencies\Swift_Message) { throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it'); } $this->message = $message; $this->apiKey = $apiKey; } /** * {@inheritDoc} */ protected function send(string $content, array $records) : void { $mime = 'text/plain'; if ($this->isHtmlBody($content)) { $mime = 'text/html'; } $message = clone $this->message; $message->setBody($content, $mime); /** @phpstan-ignore-next-line */ if (\version_compare(\Google\Site_Kit_Dependencies\Swift::VERSION, '6.0.0', '>=')) { $message->setDate(new \DateTimeImmutable()); } else { /** @phpstan-ignore-next-line */ $message->setDate(\time()); } $ch = \curl_init(); \curl_setopt($ch, \CURLOPT_URL, 'https://mandrillapp.com/api/1.0/messages/send-raw.json'); \curl_setopt($ch, \CURLOPT_POST, 1); \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1); \curl_setopt($ch, \CURLOPT_POSTFIELDS, \http_build_query(['key' => $this->apiKey, 'raw_message' => (string) $message, 'async' => \false])); \Google\Site_Kit_Dependencies\Monolog\Handler\Curl\Util::execute($ch); } } monolog/src/Monolog/Handler/PushoverHandler.php 0000644 00000017660 14721613470 0015635 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Sends notifications through the pushover api to mobile phones * * @author Sebastian Göttschkes <sebastian.goettschkes@googlemail.com> * @see https://www.pushover.net/api * * @phpstan-import-type FormattedRecord from AbstractProcessingHandler * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ class PushoverHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\SocketHandler { /** @var string */ private $token; /** @var array<int|string> */ private $users; /** @var string */ private $title; /** @var string|int|null */ private $user = null; /** @var int */ private $retry; /** @var int */ private $expire; /** @var int */ private $highPriorityLevel; /** @var int */ private $emergencyLevel; /** @var bool */ private $useFormattedMessage = \false; /** * All parameters that can be sent to Pushover * @see https://pushover.net/api * @var array<string, bool> */ private $parameterNames = ['token' => \true, 'user' => \true, 'message' => \true, 'device' => \true, 'title' => \true, 'url' => \true, 'url_title' => \true, 'priority' => \true, 'timestamp' => \true, 'sound' => \true, 'retry' => \true, 'expire' => \true, 'callback' => \true]; /** * Sounds the api supports by default * @see https://pushover.net/api#sounds * @var string[] */ private $sounds = ['pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming', 'intermission', 'magic', 'mechanical', 'pianobar', 'siren', 'spacealarm', 'tugboat', 'alien', 'climb', 'persistent', 'echo', 'updown', 'none']; /** * @param string $token Pushover api token * @param string|array $users Pushover user id or array of ids the message will be sent to * @param string|null $title Title sent to the Pushover API * @param bool $useSSL Whether to connect via SSL. Required when pushing messages to users that are not * the pushover.net app owner. OpenSSL is required for this option. * @param string|int $highPriorityLevel The minimum logging level at which this handler will start * sending "high priority" requests to the Pushover API * @param string|int $emergencyLevel The minimum logging level at which this handler will start * sending "emergency" requests to the Pushover API * @param int $retry The retry parameter specifies how often (in seconds) the Pushover servers will * send the same notification to the user. * @param int $expire The expire parameter specifies how many seconds your notification will continue * to be retried for (every retry seconds). * * @phpstan-param string|array<int|string> $users * @phpstan-param Level|LevelName|LogLevel::* $highPriorityLevel * @phpstan-param Level|LevelName|LogLevel::* $emergencyLevel */ public function __construct(string $token, $users, ?string $title = null, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL, bool $bubble = \true, bool $useSSL = \true, $highPriorityLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL, $emergencyLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY, int $retry = 30, int $expire = 25200, bool $persistent = \false, float $timeout = 0.0, float $writingTimeout = 10.0, ?float $connectionTimeout = null, ?int $chunkSize = null) { $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80'; parent::__construct($connectionString, $level, $bubble, $persistent, $timeout, $writingTimeout, $connectionTimeout, $chunkSize); $this->token = $token; $this->users = (array) $users; $this->title = $title ?: (string) \gethostname(); $this->highPriorityLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($highPriorityLevel); $this->emergencyLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($emergencyLevel); $this->retry = $retry; $this->expire = $expire; } protected function generateDataStream(array $record) : string { $content = $this->buildContent($record); return $this->buildHeader($content) . $content; } /** * @phpstan-param FormattedRecord $record */ private function buildContent(array $record) : string { // Pushover has a limit of 512 characters on title and message combined. $maxMessageLength = 512 - \strlen($this->title); $message = $this->useFormattedMessage ? $record['formatted'] : $record['message']; $message = \Google\Site_Kit_Dependencies\Monolog\Utils::substr($message, 0, $maxMessageLength); $timestamp = $record['datetime']->getTimestamp(); $dataArray = ['token' => $this->token, 'user' => $this->user, 'message' => $message, 'title' => $this->title, 'timestamp' => $timestamp]; if (isset($record['level']) && $record['level'] >= $this->emergencyLevel) { $dataArray['priority'] = 2; $dataArray['retry'] = $this->retry; $dataArray['expire'] = $this->expire; } elseif (isset($record['level']) && $record['level'] >= $this->highPriorityLevel) { $dataArray['priority'] = 1; } // First determine the available parameters $context = \array_intersect_key($record['context'], $this->parameterNames); $extra = \array_intersect_key($record['extra'], $this->parameterNames); // Least important info should be merged with subsequent info $dataArray = \array_merge($extra, $context, $dataArray); // Only pass sounds that are supported by the API if (isset($dataArray['sound']) && !\in_array($dataArray['sound'], $this->sounds)) { unset($dataArray['sound']); } return \http_build_query($dataArray); } private function buildHeader(string $content) : string { $header = "POST /1/messages.json HTTP/1.1\r\n"; $header .= "Host: api.pushover.net\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: " . \strlen($content) . "\r\n"; $header .= "\r\n"; return $header; } protected function write(array $record) : void { foreach ($this->users as $user) { $this->user = $user; parent::write($record); $this->closeSocket(); } $this->user = null; } /** * @param int|string $value * * @phpstan-param Level|LevelName|LogLevel::* $value */ public function setHighPriorityLevel($value) : self { $this->highPriorityLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($value); return $this; } /** * @param int|string $value * * @phpstan-param Level|LevelName|LogLevel::* $value */ public function setEmergencyLevel($value) : self { $this->emergencyLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($value); return $this; } /** * Use the formatted message? */ public function useFormattedMessage(bool $value) : self { $this->useFormattedMessage = $value; return $this; } } monolog/src/Monolog/Handler/CubeHandler.php 0000644 00000013144 14721613470 0014671 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Logs to Cube. * * @link https://github.com/square/cube/wiki * @author Wan Chen <kami@kamisama.me> * @deprecated Since 2.8.0 and 3.2.0, Cube appears abandoned and thus we will drop this handler in Monolog 4 */ class CubeHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var resource|\Socket|null */ private $udpConnection = null; /** @var resource|\CurlHandle|null */ private $httpConnection = null; /** @var string */ private $scheme; /** @var string */ private $host; /** @var int */ private $port; /** @var string[] */ private $acceptedSchemes = ['http', 'udp']; /** * Create a Cube handler * * @throws \UnexpectedValueException when given url is not a valid url. * A valid url must consist of three parts : protocol://host:port * Only valid protocols used by Cube are http and udp */ public function __construct(string $url, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { $urlInfo = \parse_url($url); if ($urlInfo === \false || !isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) { throw new \UnexpectedValueException('URL "' . $url . '" is not valid'); } if (!\in_array($urlInfo['scheme'], $this->acceptedSchemes)) { throw new \UnexpectedValueException('Invalid protocol (' . $urlInfo['scheme'] . ').' . ' Valid options are ' . \implode(', ', $this->acceptedSchemes)); } $this->scheme = $urlInfo['scheme']; $this->host = $urlInfo['host']; $this->port = (int) $urlInfo['port']; parent::__construct($level, $bubble); } /** * Establish a connection to an UDP socket * * @throws \LogicException when unable to connect to the socket * @throws MissingExtensionException when there is no socket extension */ protected function connectUdp() : void { if (!\extension_loaded('sockets')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler'); } $udpConnection = \socket_create(\AF_INET, \SOCK_DGRAM, 0); if (\false === $udpConnection) { throw new \LogicException('Unable to create a socket'); } $this->udpConnection = $udpConnection; if (!\socket_connect($this->udpConnection, $this->host, $this->port)) { throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port); } } /** * Establish a connection to an http server * * @throws \LogicException when unable to connect to the socket * @throws MissingExtensionException when no curl extension */ protected function connectHttp() : void { if (!\extension_loaded('curl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The curl extension is required to use http URLs with the CubeHandler'); } $httpConnection = \curl_init('http://' . $this->host . ':' . $this->port . '/1.0/event/put'); if (\false === $httpConnection) { throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port); } $this->httpConnection = $httpConnection; \curl_setopt($this->httpConnection, \CURLOPT_CUSTOMREQUEST, "POST"); \curl_setopt($this->httpConnection, \CURLOPT_RETURNTRANSFER, \true); } /** * {@inheritDoc} */ protected function write(array $record) : void { $date = $record['datetime']; $data = ['time' => $date->format('Y-m-d\\TH:i:s.uO')]; unset($record['datetime']); if (isset($record['context']['type'])) { $data['type'] = $record['context']['type']; unset($record['context']['type']); } else { $data['type'] = $record['channel']; } $data['data'] = $record['context']; $data['data']['level'] = $record['level']; if ($this->scheme === 'http') { $this->writeHttp(\Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($data)); } else { $this->writeUdp(\Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($data)); } } private function writeUdp(string $data) : void { if (!$this->udpConnection) { $this->connectUdp(); } \socket_send($this->udpConnection, $data, \strlen($data), 0); } private function writeHttp(string $data) : void { if (!$this->httpConnection) { $this->connectHttp(); } if (null === $this->httpConnection) { throw new \LogicException('No connection could be established'); } \curl_setopt($this->httpConnection, \CURLOPT_POSTFIELDS, '[' . $data . ']'); \curl_setopt($this->httpConnection, \CURLOPT_HTTPHEADER, ['Content-Type: application/json', 'Content-Length: ' . \strlen('[' . $data . ']')]); \Google\Site_Kit_Dependencies\Monolog\Handler\Curl\Util::execute($this->httpConnection, 5, \false); } } monolog/src/Monolog/Handler/ZendMonitorHandler.php 0000644 00000007432 14721613470 0016266 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Handler sending logs to Zend Monitor * * @author Christian Bergau <cbergau86@gmail.com> * @author Jason Davis <happydude@jasondavis.net> * * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class ZendMonitorHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** * Monolog level / ZendMonitor Custom Event priority map * * @var array<int, int> */ protected $levelMap = []; /** * @throws MissingExtensionException */ public function __construct($level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { if (!\function_exists('Google\\Site_Kit_Dependencies\\zend_monitor_custom_event')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('You must have Zend Server installed with Zend Monitor enabled in order to use this handler'); } //zend monitor constants are not defined if zend monitor is not enabled. $this->levelMap = [\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG => \Google\Site_Kit_Dependencies\ZEND_MONITOR_EVENT_SEVERITY_INFO, \Google\Site_Kit_Dependencies\Monolog\Logger::INFO => \Google\Site_Kit_Dependencies\ZEND_MONITOR_EVENT_SEVERITY_INFO, \Google\Site_Kit_Dependencies\Monolog\Logger::NOTICE => \Google\Site_Kit_Dependencies\ZEND_MONITOR_EVENT_SEVERITY_INFO, \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING => \Google\Site_Kit_Dependencies\ZEND_MONITOR_EVENT_SEVERITY_WARNING, \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR => \Google\Site_Kit_Dependencies\ZEND_MONITOR_EVENT_SEVERITY_ERROR, \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL => \Google\Site_Kit_Dependencies\ZEND_MONITOR_EVENT_SEVERITY_ERROR, \Google\Site_Kit_Dependencies\Monolog\Logger::ALERT => \Google\Site_Kit_Dependencies\ZEND_MONITOR_EVENT_SEVERITY_ERROR, \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY => \Google\Site_Kit_Dependencies\ZEND_MONITOR_EVENT_SEVERITY_ERROR]; parent::__construct($level, $bubble); } /** * {@inheritDoc} */ protected function write(array $record) : void { $this->writeZendMonitorCustomEvent(\Google\Site_Kit_Dependencies\Monolog\Logger::getLevelName($record['level']), $record['message'], $record['formatted'], $this->levelMap[$record['level']]); } /** * Write to Zend Monitor Events * @param string $type Text displayed in "Class Name (custom)" field * @param string $message Text displayed in "Error String" * @param array $formatted Displayed in Custom Variables tab * @param int $severity Set the event severity level (-1,0,1) * * @phpstan-param FormattedRecord $formatted */ protected function writeZendMonitorCustomEvent(string $type, string $message, array $formatted, int $severity) : void { zend_monitor_custom_event($type, $message, $formatted, $severity); } /** * {@inheritDoc} */ public function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter(); } /** * @return array<int, int> */ public function getLevelMap() : array { return $this->levelMap; } } monolog/src/Monolog/Handler/HandlerInterface.php 0000644 00000005766 14721613470 0015726 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; /** * Interface that all Monolog Handlers must implement * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger */ interface HandlerInterface { /** * Checks whether the given record will be handled by this handler. * * This is mostly done for performance reasons, to avoid calling processors for nothing. * * Handlers should still check the record levels within handle(), returning false in isHandling() * is no guarantee that handle() will not be called, and isHandling() might not be called * for a given record. * * @param array $record Partial log record containing only a level key * * @return bool * * @phpstan-param array{level: Level} $record */ public function isHandling(array $record) : bool; /** * Handles a record. * * All records may be passed to this method, and the handler should discard * those that it does not want to handle. * * The return value of this function controls the bubbling process of the handler stack. * Unless the bubbling is interrupted (by returning true), the Logger class will keep on * calling further handlers in the stack with a given log record. * * @param array $record The record to handle * @return bool true means that this handler handled the record, and that bubbling is not permitted. * false means the record was either not processed or that this handler allows bubbling. * * @phpstan-param Record $record */ public function handle(array $record) : bool; /** * Handles a set of records at once. * * @param array $records The records to handle (an array of record arrays) * * @phpstan-param Record[] $records */ public function handleBatch(array $records) : void; /** * Closes the handler. * * Ends a log cycle and frees all resources used by the handler. * * Closing a Handler means flushing all buffers and freeing any open resources/handles. * * Implementations have to be idempotent (i.e. it should be possible to call close several times without breakage) * and ideally handlers should be able to reopen themselves on handle() after they have been closed. * * This is useful at the end of a request and will be called automatically when the object * is destroyed if you extend Monolog\Handler\Handler. * * If you are thinking of calling this method yourself, most likely you should be * calling ResettableInterface::reset instead. Have a look. */ public function close() : void; } monolog/src/Monolog/Handler/NativeMailerHandler.php 0000644 00000012112 14721613470 0016365 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; /** * NativeMailerHandler uses the mail() function to send the emails * * @author Christophe Coevoet <stof@notk.org> * @author Mark Garrett <mark@moderndeveloperllc.com> */ class NativeMailerHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\MailHandler { /** * The email addresses to which the message will be sent * @var string[] */ protected $to; /** * The subject of the email * @var string */ protected $subject; /** * Optional headers for the message * @var string[] */ protected $headers = []; /** * Optional parameters for the message * @var string[] */ protected $parameters = []; /** * The wordwrap length for the message * @var int */ protected $maxColumnWidth; /** * The Content-type for the message * @var string|null */ protected $contentType; /** * The encoding for the message * @var string */ protected $encoding = 'utf-8'; /** * @param string|string[] $to The receiver of the mail * @param string $subject The subject of the mail * @param string $from The sender of the mail * @param int $maxColumnWidth The maximum column width that the message lines will have */ public function __construct($to, string $subject, string $from, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR, bool $bubble = \true, int $maxColumnWidth = 70) { parent::__construct($level, $bubble); $this->to = (array) $to; $this->subject = $subject; $this->addHeader(\sprintf('From: %s', $from)); $this->maxColumnWidth = $maxColumnWidth; } /** * Add headers to the message * * @param string|string[] $headers Custom added headers */ public function addHeader($headers) : self { foreach ((array) $headers as $header) { if (\strpos($header, "\n") !== \false || \strpos($header, "\r") !== \false) { throw new \InvalidArgumentException('Headers can not contain newline characters for security reasons'); } $this->headers[] = $header; } return $this; } /** * Add parameters to the message * * @param string|string[] $parameters Custom added parameters */ public function addParameter($parameters) : self { $this->parameters = \array_merge($this->parameters, (array) $parameters); return $this; } /** * {@inheritDoc} */ protected function send(string $content, array $records) : void { $contentType = $this->getContentType() ?: ($this->isHtmlBody($content) ? 'text/html' : 'text/plain'); if ($contentType !== 'text/html') { $content = \wordwrap($content, $this->maxColumnWidth); } $headers = \ltrim(\implode("\r\n", $this->headers) . "\r\n", "\r\n"); $headers .= 'Content-type: ' . $contentType . '; charset=' . $this->getEncoding() . "\r\n"; if ($contentType === 'text/html' && \false === \strpos($headers, 'MIME-Version:')) { $headers .= 'MIME-Version: 1.0' . "\r\n"; } $subject = $this->subject; if ($records) { $subjectFormatter = new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter($this->subject); $subject = $subjectFormatter->format($this->getHighestRecord($records)); } $parameters = \implode(' ', $this->parameters); foreach ($this->to as $to) { \mail($to, $subject, $content, $headers, $parameters); } } public function getContentType() : ?string { return $this->contentType; } public function getEncoding() : string { return $this->encoding; } /** * @param string $contentType The content type of the email - Defaults to text/plain. Use text/html for HTML messages. */ public function setContentType(string $contentType) : self { if (\strpos($contentType, "\n") !== \false || \strpos($contentType, "\r") !== \false) { throw new \InvalidArgumentException('The content type can not contain newline characters to prevent email header injection'); } $this->contentType = $contentType; return $this; } public function setEncoding(string $encoding) : self { if (\strpos($encoding, "\n") !== \false || \strpos($encoding, "\r") !== \false) { throw new \InvalidArgumentException('The encoding can not contain newline characters to prevent email header injection'); } $this->encoding = $encoding; return $this; } } monolog/src/Monolog/Handler/FormattableHandlerTrait.php 0000644 00000003103 14721613470 0017251 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; /** * Helper trait for implementing FormattableInterface * * @author Jordi Boggiano <j.boggiano@seld.be> */ trait FormattableHandlerTrait { /** * @var ?FormatterInterface */ protected $formatter; /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { $this->formatter = $formatter; return $this; } /** * {@inheritDoc} */ public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { if (!$this->formatter) { $this->formatter = $this->getDefaultFormatter(); } return $this->formatter; } /** * Gets the default formatter. * * Overwrite this if the LineFormatter is not a good default for your handler. */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter(); } } monolog/src/Monolog/Handler/CouchDBHandler.php 0000644 00000004305 14721613470 0015261 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\JsonFormatter; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * CouchDB handler * * @author Markus Bachmann <markus.bachmann@bachi.biz> */ class CouchDBHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var mixed[] */ private $options; /** * @param mixed[] $options */ public function __construct(array $options = [], $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { $this->options = \array_merge(['host' => 'localhost', 'port' => 5984, 'dbname' => 'logger', 'username' => null, 'password' => null], $options); parent::__construct($level, $bubble); } /** * {@inheritDoc} */ protected function write(array $record) : void { $basicAuth = null; if ($this->options['username']) { $basicAuth = \sprintf('%s:%s@', $this->options['username'], $this->options['password']); } $url = 'http://' . $basicAuth . $this->options['host'] . ':' . $this->options['port'] . '/' . $this->options['dbname']; $context = \stream_context_create(['http' => ['method' => 'POST', 'content' => $record['formatted'], 'ignore_errors' => \true, 'max_redirects' => 0, 'header' => 'Content-type: application/json']]); if (\false === @\file_get_contents($url, \false, $context)) { throw new \RuntimeException(\sprintf('Could not connect to %s', $url)); } } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\JsonFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\JsonFormatter::BATCH_MODE_JSON, \false); } } monolog/src/Monolog/Handler/Curl/Util.php 0000644 00000003517 14721613470 0014342 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler\Curl; use CurlHandle; /** * This class is marked as internal and it is not under the BC promise of the package. * * @internal */ final class Util { /** @var array<int> */ private static $retriableErrorCodes = [\CURLE_COULDNT_RESOLVE_HOST, \CURLE_COULDNT_CONNECT, \CURLE_HTTP_NOT_FOUND, \CURLE_READ_ERROR, \CURLE_OPERATION_TIMEOUTED, \CURLE_HTTP_POST_ERROR, \CURLE_SSL_CONNECT_ERROR]; /** * Executes a CURL request with optional retries and exception on failure * * @param resource|CurlHandle $ch curl handler * @param int $retries * @param bool $closeAfterDone * @return bool|string @see curl_exec */ public static function execute($ch, int $retries = 5, bool $closeAfterDone = \true) { while ($retries--) { $curlResponse = \curl_exec($ch); if ($curlResponse === \false) { $curlErrno = \curl_errno($ch); if (\false === \in_array($curlErrno, self::$retriableErrorCodes, \true) || !$retries) { $curlError = \curl_error($ch); if ($closeAfterDone) { \curl_close($ch); } throw new \RuntimeException(\sprintf('Curl error (code %d): %s', $curlErrno, $curlError)); } continue; } if ($closeAfterDone) { \curl_close($ch); } return $curlResponse; } return \false; } } monolog/src/Monolog/Handler/GroupHandler.php 0000644 00000007123 14721613470 0015107 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\ResettableInterface; /** * Forwards records to multiple handlers * * @author Lenar Lõhmus <lenar@city.ee> * * @phpstan-import-type Record from \Monolog\Logger */ class GroupHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\Handler implements \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface, \Google\Site_Kit_Dependencies\Monolog\ResettableInterface { use ProcessableHandlerTrait; /** @var HandlerInterface[] */ protected $handlers; /** @var bool */ protected $bubble; /** * @param HandlerInterface[] $handlers Array of Handlers. * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(array $handlers, bool $bubble = \true) { foreach ($handlers as $handler) { if (!$handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface) { throw new \InvalidArgumentException('The first argument of the GroupHandler must be an array of HandlerInterface instances.'); } } $this->handlers = $handlers; $this->bubble = $bubble; } /** * {@inheritDoc} */ public function isHandling(array $record) : bool { foreach ($this->handlers as $handler) { if ($handler->isHandling($record)) { return \true; } } return \false; } /** * {@inheritDoc} */ public function handle(array $record) : bool { if ($this->processors) { /** @var Record $record */ $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { $handler->handle($record); } return \false === $this->bubble; } /** * {@inheritDoc} */ public function handleBatch(array $records) : void { if ($this->processors) { $processed = []; foreach ($records as $record) { $processed[] = $this->processRecord($record); } /** @var Record[] $records */ $records = $processed; } foreach ($this->handlers as $handler) { $handler->handleBatch($records); } } public function reset() { $this->resetProcessors(); foreach ($this->handlers as $handler) { if ($handler instanceof \Google\Site_Kit_Dependencies\Monolog\ResettableInterface) { $handler->reset(); } } } public function close() : void { parent::close(); foreach ($this->handlers as $handler) { $handler->close(); } } /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { foreach ($this->handlers as $handler) { if ($handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { $handler->setFormatter($formatter); } } return $this; } } monolog/src/Monolog/Handler/SyslogHandler.php 0000644 00000004117 14721613470 0015273 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Logs to syslog service. * * usage example: * * $log = new Logger('application'); * $syslog = new SyslogHandler('myfacility', 'local6'); * $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%"); * $syslog->setFormatter($formatter); * $log->pushHandler($syslog); * * @author Sven Paulus <sven@karlsruhe.org> */ class SyslogHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractSyslogHandler { /** @var string */ protected $ident; /** @var int */ protected $logopts; /** * @param string $ident * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID */ public function __construct(string $ident, $facility = \LOG_USER, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, int $logopts = \LOG_PID) { parent::__construct($facility, $level, $bubble); $this->ident = $ident; $this->logopts = $logopts; } /** * {@inheritDoc} */ public function close() : void { \closelog(); } /** * {@inheritDoc} */ protected function write(array $record) : void { if (!\openlog($this->ident, $this->logopts, $this->facility)) { throw new \LogicException('Can\'t open syslog for ident "' . $this->ident . '" and facility "' . $this->facility . '"' . \Google\Site_Kit_Dependencies\Monolog\Utils::getRecordMessageForException($record)); } \syslog($this->logLevels[$record['level']], (string) $record['formatted']); } } monolog/src/Monolog/Handler/Slack/SlackRecord.php 0000644 00000024653 14721613470 0015755 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler\Slack; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; use Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Slack record utility helping to log to Slack webhooks or API. * * @author Greg Kedzierski <greg@gregkedzierski.com> * @author Haralan Dobrev <hkdobrev@gmail.com> * @see https://api.slack.com/incoming-webhooks * @see https://api.slack.com/docs/message-attachments * * @phpstan-import-type FormattedRecord from \Monolog\Handler\AbstractProcessingHandler * @phpstan-import-type Record from \Monolog\Logger */ class SlackRecord { public const COLOR_DANGER = 'danger'; public const COLOR_WARNING = 'warning'; public const COLOR_GOOD = 'good'; public const COLOR_DEFAULT = '#e3e4e6'; /** * Slack channel (encoded ID or name) * @var string|null */ private $channel; /** * Name of a bot * @var string|null */ private $username; /** * User icon e.g. 'ghost', 'http://example.com/user.png' * @var string|null */ private $userIcon; /** * Whether the message should be added to Slack as attachment (plain text otherwise) * @var bool */ private $useAttachment; /** * Whether the the context/extra messages added to Slack as attachments are in a short style * @var bool */ private $useShortAttachment; /** * Whether the attachment should include context and extra data * @var bool */ private $includeContextAndExtra; /** * Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] * @var string[] */ private $excludeFields; /** * @var ?FormatterInterface */ private $formatter; /** * @var NormalizerFormatter */ private $normalizerFormatter; /** * @param string[] $excludeFields */ public function __construct(?string $channel = null, ?string $username = null, bool $useAttachment = \true, ?string $userIcon = null, bool $useShortAttachment = \false, bool $includeContextAndExtra = \false, array $excludeFields = array(), ?\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter = null) { $this->setChannel($channel)->setUsername($username)->useAttachment($useAttachment)->setUserIcon($userIcon)->useShortAttachment($useShortAttachment)->includeContextAndExtra($includeContextAndExtra)->excludeFields($excludeFields)->setFormatter($formatter); if ($this->includeContextAndExtra) { $this->normalizerFormatter = new \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter(); } } /** * Returns required data in format that Slack * is expecting. * * @phpstan-param FormattedRecord $record * @phpstan-return mixed[] */ public function getSlackData(array $record) : array { $dataArray = array(); $record = $this->removeExcludedFields($record); if ($this->username) { $dataArray['username'] = $this->username; } if ($this->channel) { $dataArray['channel'] = $this->channel; } if ($this->formatter && !$this->useAttachment) { /** @phpstan-ignore-next-line */ $message = $this->formatter->format($record); } else { $message = $record['message']; } if ($this->useAttachment) { $attachment = array('fallback' => $message, 'text' => $message, 'color' => $this->getAttachmentColor($record['level']), 'fields' => array(), 'mrkdwn_in' => array('fields'), 'ts' => $record['datetime']->getTimestamp(), 'footer' => $this->username, 'footer_icon' => $this->userIcon); if ($this->useShortAttachment) { $attachment['title'] = $record['level_name']; } else { $attachment['title'] = 'Message'; $attachment['fields'][] = $this->generateAttachmentField('Level', $record['level_name']); } if ($this->includeContextAndExtra) { foreach (array('extra', 'context') as $key) { if (empty($record[$key])) { continue; } if ($this->useShortAttachment) { $attachment['fields'][] = $this->generateAttachmentField((string) $key, $record[$key]); } else { // Add all extra fields as individual fields in attachment $attachment['fields'] = \array_merge($attachment['fields'], $this->generateAttachmentFields($record[$key])); } } } $dataArray['attachments'] = array($attachment); } else { $dataArray['text'] = $message; } if ($this->userIcon) { if (\filter_var($this->userIcon, \FILTER_VALIDATE_URL)) { $dataArray['icon_url'] = $this->userIcon; } else { $dataArray['icon_emoji'] = ":{$this->userIcon}:"; } } return $dataArray; } /** * Returns a Slack message attachment color associated with * provided level. */ public function getAttachmentColor(int $level) : string { switch (\true) { case $level >= \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR: return static::COLOR_DANGER; case $level >= \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING: return static::COLOR_WARNING; case $level >= \Google\Site_Kit_Dependencies\Monolog\Logger::INFO: return static::COLOR_GOOD; default: return static::COLOR_DEFAULT; } } /** * Stringifies an array of key/value pairs to be used in attachment fields * * @param mixed[] $fields */ public function stringify(array $fields) : string { /** @var Record $fields */ $normalized = $this->normalizerFormatter->format($fields); $hasSecondDimension = \count(\array_filter($normalized, 'is_array')); $hasNonNumericKeys = !\count(\array_filter(\array_keys($normalized), 'is_numeric')); return $hasSecondDimension || $hasNonNumericKeys ? \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($normalized, \JSON_PRETTY_PRINT | \Google\Site_Kit_Dependencies\Monolog\Utils::DEFAULT_JSON_FLAGS) : \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($normalized, \Google\Site_Kit_Dependencies\Monolog\Utils::DEFAULT_JSON_FLAGS); } /** * Channel used by the bot when posting * * @param ?string $channel * * @return static */ public function setChannel(?string $channel = null) : self { $this->channel = $channel; return $this; } /** * Username used by the bot when posting * * @param ?string $username * * @return static */ public function setUsername(?string $username = null) : self { $this->username = $username; return $this; } public function useAttachment(bool $useAttachment = \true) : self { $this->useAttachment = $useAttachment; return $this; } public function setUserIcon(?string $userIcon = null) : self { $this->userIcon = $userIcon; if (\is_string($userIcon)) { $this->userIcon = \trim($userIcon, ':'); } return $this; } public function useShortAttachment(bool $useShortAttachment = \false) : self { $this->useShortAttachment = $useShortAttachment; return $this; } public function includeContextAndExtra(bool $includeContextAndExtra = \false) : self { $this->includeContextAndExtra = $includeContextAndExtra; if ($this->includeContextAndExtra) { $this->normalizerFormatter = new \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter(); } return $this; } /** * @param string[] $excludeFields */ public function excludeFields(array $excludeFields = []) : self { $this->excludeFields = $excludeFields; return $this; } public function setFormatter(?\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter = null) : self { $this->formatter = $formatter; return $this; } /** * Generates attachment field * * @param string|mixed[] $value * * @return array{title: string, value: string, short: false} */ private function generateAttachmentField(string $title, $value) : array { $value = \is_array($value) ? \sprintf('```%s```', \substr($this->stringify($value), 0, 1990)) : $value; return array('title' => \ucfirst($title), 'value' => $value, 'short' => \false); } /** * Generates a collection of attachment fields from array * * @param mixed[] $data * * @return array<array{title: string, value: string, short: false}> */ private function generateAttachmentFields(array $data) : array { /** @var Record $data */ $normalized = $this->normalizerFormatter->format($data); $fields = array(); foreach ($normalized as $key => $value) { $fields[] = $this->generateAttachmentField((string) $key, $value); } return $fields; } /** * Get a copy of record with fields excluded according to $this->excludeFields * * @phpstan-param FormattedRecord $record * * @return mixed[] */ private function removeExcludedFields(array $record) : array { foreach ($this->excludeFields as $field) { $keys = \explode('.', $field); $node =& $record; $lastKey = \end($keys); foreach ($keys as $key) { if (!isset($node[$key])) { break; } if ($lastKey === $key) { unset($node[$key]); break; } $node =& $node[$key]; } } return $record; } } monolog/src/Monolog/Handler/RedisHandler.php 0000644 00000006331 14721613470 0015061 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Logs to a Redis key using rpush * * usage example: * * $log = new Logger('application'); * $redis = new RedisHandler(new Predis\Client("tcp://localhost:6379"), "logs", "prod"); * $log->pushHandler($redis); * * @author Thomas Tourlourat <thomas@tourlourat.com> * * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class RedisHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; /** @var string */ private $redisKey; /** @var int */ protected $capSize; /** * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance * @param string $key The key name to push records to * @param int $capSize Number of entries to limit list size to, 0 = unlimited */ public function __construct($redis, string $key, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, int $capSize = 0) { if (!($redis instanceof \Google\Site_Kit_Dependencies\Predis\Client || $redis instanceof \Redis)) { throw new \InvalidArgumentException('Predis\\Client or Redis instance required'); } $this->redisClient = $redis; $this->redisKey = $key; $this->capSize = $capSize; parent::__construct($level, $bubble); } /** * {@inheritDoc} */ protected function write(array $record) : void { if ($this->capSize) { $this->writeCapped($record); } else { $this->redisClient->rpush($this->redisKey, $record["formatted"]); } } /** * Write and cap the collection * Writes the record to the redis list and caps its * * @phpstan-param FormattedRecord $record */ protected function writeCapped(array $record) : void { if ($this->redisClient instanceof \Redis) { $mode = \defined('\\Redis::MULTI') ? \Redis::MULTI : 1; $this->redisClient->multi($mode)->rpush($this->redisKey, $record["formatted"])->ltrim($this->redisKey, -$this->capSize, -1)->exec(); } else { $redisKey = $this->redisKey; $capSize = $this->capSize; $this->redisClient->transaction(function ($tx) use($record, $redisKey, $capSize) { $tx->rpush($redisKey, $record["formatted"]); $tx->ltrim($redisKey, -$capSize, -1); }); } } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter(); } } monolog/src/Monolog/Handler/StreamHandler.php 0000644 00000016441 14721613470 0015251 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Stores to any stream resource * * Can be used to store into php://stderr, remote and local files, etc. * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class StreamHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @const int */ protected const MAX_CHUNK_SIZE = 2147483647; /** @const int 10MB */ protected const DEFAULT_CHUNK_SIZE = 10 * 1024 * 1024; /** @var int */ protected $streamChunkSize; /** @var resource|null */ protected $stream; /** @var ?string */ protected $url = null; /** @var ?string */ private $errorMessage = null; /** @var ?int */ protected $filePermission; /** @var bool */ protected $useLocking; /** @var true|null */ private $dirCreated = null; /** * @param resource|string $stream If a missing path can't be created, an UnexpectedValueException will be thrown on first write * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) * @param bool $useLocking Try to lock log file before doing any writes * * @throws \InvalidArgumentException If stream is not a resource or string */ public function __construct($stream, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, ?int $filePermission = null, bool $useLocking = \false) { parent::__construct($level, $bubble); if (($phpMemoryLimit = \Google\Site_Kit_Dependencies\Monolog\Utils::expandIniShorthandBytes(\ini_get('memory_limit'))) !== \false) { if ($phpMemoryLimit > 0) { // use max 10% of allowed memory for the chunk size, and at least 100KB $this->streamChunkSize = \min(static::MAX_CHUNK_SIZE, \max((int) ($phpMemoryLimit / 10), 100 * 1024)); } else { // memory is unlimited, set to the default 10MB $this->streamChunkSize = static::DEFAULT_CHUNK_SIZE; } } else { // no memory limit information, set to the default 10MB $this->streamChunkSize = static::DEFAULT_CHUNK_SIZE; } if (\is_resource($stream)) { $this->stream = $stream; \stream_set_chunk_size($this->stream, $this->streamChunkSize); } elseif (\is_string($stream)) { $this->url = \Google\Site_Kit_Dependencies\Monolog\Utils::canonicalizePath($stream); } else { throw new \InvalidArgumentException('A stream must either be a resource or a string.'); } $this->filePermission = $filePermission; $this->useLocking = $useLocking; } /** * {@inheritDoc} */ public function close() : void { if ($this->url && \is_resource($this->stream)) { \fclose($this->stream); } $this->stream = null; $this->dirCreated = null; } /** * Return the currently active stream if it is open * * @return resource|null */ public function getStream() { return $this->stream; } /** * Return the stream URL if it was configured with a URL and not an active resource * * @return string|null */ public function getUrl() : ?string { return $this->url; } /** * @return int */ public function getStreamChunkSize() : int { return $this->streamChunkSize; } /** * {@inheritDoc} */ protected function write(array $record) : void { if (!\is_resource($this->stream)) { $url = $this->url; if (null === $url || '' === $url) { throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().' . \Google\Site_Kit_Dependencies\Monolog\Utils::getRecordMessageForException($record)); } $this->createDir($url); $this->errorMessage = null; \set_error_handler([$this, 'customErrorHandler']); try { $stream = \fopen($url, 'a'); if ($this->filePermission !== null) { @\chmod($url, $this->filePermission); } } finally { \restore_error_handler(); } if (!\is_resource($stream)) { $this->stream = null; throw new \UnexpectedValueException(\sprintf('The stream or file "%s" could not be opened in append mode: ' . $this->errorMessage, $url) . \Google\Site_Kit_Dependencies\Monolog\Utils::getRecordMessageForException($record)); } \stream_set_chunk_size($stream, $this->streamChunkSize); $this->stream = $stream; } $stream = $this->stream; if (!\is_resource($stream)) { throw new \LogicException('No stream was opened yet' . \Google\Site_Kit_Dependencies\Monolog\Utils::getRecordMessageForException($record)); } if ($this->useLocking) { // ignoring errors here, there's not much we can do about them \flock($stream, \LOCK_EX); } $this->streamWrite($stream, $record); if ($this->useLocking) { \flock($stream, \LOCK_UN); } } /** * Write to stream * @param resource $stream * @param array $record * * @phpstan-param FormattedRecord $record */ protected function streamWrite($stream, array $record) : void { \fwrite($stream, (string) $record['formatted']); } private function customErrorHandler(int $code, string $msg) : bool { $this->errorMessage = \preg_replace('{^(fopen|mkdir)\\(.*?\\): }', '', $msg); return \true; } private function getDirFromStream(string $stream) : ?string { $pos = \strpos($stream, '://'); if ($pos === \false) { return \dirname($stream); } if ('file://' === \substr($stream, 0, 7)) { return \dirname(\substr($stream, 7)); } return null; } private function createDir(string $url) : void { // Do not try to create dir if it has already been tried. if ($this->dirCreated) { return; } $dir = $this->getDirFromStream($url); if (null !== $dir && !\is_dir($dir)) { $this->errorMessage = null; \set_error_handler([$this, 'customErrorHandler']); $status = \mkdir($dir, 0777, \true); \restore_error_handler(); if (\false === $status && !\is_dir($dir) && \strpos((string) $this->errorMessage, 'File exists') === \false) { throw new \UnexpectedValueException(\sprintf('There is no existing directory at "%s" and it could not be created: ' . $this->errorMessage, $dir)); } } $this->dirCreated = \true; } } monolog/src/Monolog/Handler/NewRelicHandler.php 0000644 00000014657 14721613470 0015535 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; use Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Class to record a log on a NewRelic application. * Enabling New Relic High Security mode may prevent capture of useful information. * * This handler requires a NormalizerFormatter to function and expects an array in $record['formatted'] * * @see https://docs.newrelic.com/docs/agents/php-agent * @see https://docs.newrelic.com/docs/accounts-partnerships/accounts/security/high-security */ class NewRelicHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** * Name of the New Relic application that will receive logs from this handler. * * @var ?string */ protected $appName; /** * Name of the current transaction * * @var ?string */ protected $transactionName; /** * Some context and extra data is passed into the handler as arrays of values. Do we send them as is * (useful if we are using the API), or explode them for display on the NewRelic RPM website? * * @var bool */ protected $explodeArrays; /** * {@inheritDoc} * * @param string|null $appName * @param bool $explodeArrays * @param string|null $transactionName */ public function __construct($level = \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR, bool $bubble = \true, ?string $appName = null, bool $explodeArrays = \false, ?string $transactionName = null) { parent::__construct($level, $bubble); $this->appName = $appName; $this->explodeArrays = $explodeArrays; $this->transactionName = $transactionName; } /** * {@inheritDoc} */ protected function write(array $record) : void { if (!$this->isNewRelicEnabled()) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler'); } if ($appName = $this->getAppName($record['context'])) { $this->setNewRelicAppName($appName); } if ($transactionName = $this->getTransactionName($record['context'])) { $this->setNewRelicTransactionName($transactionName); unset($record['formatted']['context']['transaction_name']); } if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { \newrelic_notice_error($record['message'], $record['context']['exception']); unset($record['formatted']['context']['exception']); } else { \newrelic_notice_error($record['message']); } if (isset($record['formatted']['context']) && \is_array($record['formatted']['context'])) { foreach ($record['formatted']['context'] as $key => $parameter) { if (\is_array($parameter) && $this->explodeArrays) { foreach ($parameter as $paramKey => $paramValue) { $this->setNewRelicParameter('context_' . $key . '_' . $paramKey, $paramValue); } } else { $this->setNewRelicParameter('context_' . $key, $parameter); } } } if (isset($record['formatted']['extra']) && \is_array($record['formatted']['extra'])) { foreach ($record['formatted']['extra'] as $key => $parameter) { if (\is_array($parameter) && $this->explodeArrays) { foreach ($parameter as $paramKey => $paramValue) { $this->setNewRelicParameter('extra_' . $key . '_' . $paramKey, $paramValue); } } else { $this->setNewRelicParameter('extra_' . $key, $parameter); } } } } /** * Checks whether the NewRelic extension is enabled in the system. * * @return bool */ protected function isNewRelicEnabled() : bool { return \extension_loaded('newrelic'); } /** * Returns the appname where this log should be sent. Each log can override the default appname, set in this * handler's constructor, by providing the appname in it's context. * * @param mixed[] $context */ protected function getAppName(array $context) : ?string { if (isset($context['appname'])) { return $context['appname']; } return $this->appName; } /** * Returns the name of the current transaction. Each log can override the default transaction name, set in this * handler's constructor, by providing the transaction_name in it's context * * @param mixed[] $context */ protected function getTransactionName(array $context) : ?string { if (isset($context['transaction_name'])) { return $context['transaction_name']; } return $this->transactionName; } /** * Sets the NewRelic application that should receive this log. */ protected function setNewRelicAppName(string $appName) : void { \newrelic_set_appname($appName); } /** * Overwrites the name of the current transaction */ protected function setNewRelicTransactionName(string $transactionName) : void { \newrelic_name_transaction($transactionName); } /** * @param string $key * @param mixed $value */ protected function setNewRelicParameter(string $key, $value) : void { if (null === $value || \is_scalar($value)) { \newrelic_add_custom_parameter($key, $value); } else { \newrelic_add_custom_parameter($key, \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($value, null, \true)); } } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter(); } } monolog/src/Monolog/Handler/WebRequestRecognizerTrait.php 0000644 00000001052 14721613470 0017632 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; trait WebRequestRecognizerTrait { /** * Checks if PHP's serving a web request * @return bool */ protected function isWebRequest() : bool { return 'cli' !== \PHP_SAPI && 'phpdbg' !== \PHP_SAPI; } } monolog/src/Monolog/Handler/IFTTTHandler.php 0000644 00000004567 14721613470 0014716 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * IFTTTHandler uses cURL to trigger IFTTT Maker actions * * Register a secret key and trigger/event name at https://ifttt.com/maker * * value1 will be the channel from monolog's Logger constructor, * value2 will be the level name (ERROR, WARNING, ..) * value3 will be the log record's message * * @author Nehal Patel <nehal@nehalpatel.me> */ class IFTTTHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var string */ private $eventName; /** @var string */ private $secretKey; /** * @param string $eventName The name of the IFTTT Maker event that should be triggered * @param string $secretKey A valid IFTTT secret key */ public function __construct(string $eventName, string $secretKey, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR, bool $bubble = \true) { if (!\extension_loaded('curl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The curl extension is needed to use the IFTTTHandler'); } $this->eventName = $eventName; $this->secretKey = $secretKey; parent::__construct($level, $bubble); } /** * {@inheritDoc} */ public function write(array $record) : void { $postData = ["value1" => $record["channel"], "value2" => $record["level_name"], "value3" => $record["message"]]; $postString = \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($postData); $ch = \curl_init(); \curl_setopt($ch, \CURLOPT_URL, "https://maker.ifttt.com/trigger/" . $this->eventName . "/with/key/" . $this->secretKey); \curl_setopt($ch, \CURLOPT_POST, \true); \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, \true); \curl_setopt($ch, \CURLOPT_POSTFIELDS, $postString); \curl_setopt($ch, \CURLOPT_HTTPHEADER, ["Content-Type: application/json"]); \Google\Site_Kit_Dependencies\Monolog\Handler\Curl\Util::execute($ch); } } monolog/src/Monolog/Handler/FleepHookHandler.php 0000644 00000007232 14721613470 0015670 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Sends logs to Fleep.io using Webhook integrations * * You'll need a Fleep.io account to use this handler. * * @see https://fleep.io/integrations/webhooks/ Fleep Webhooks Documentation * @author Ando Roots <ando@sqroot.eu> * * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FleepHookHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\SocketHandler { protected const FLEEP_HOST = 'fleep.io'; protected const FLEEP_HOOK_URI = '/hook/'; /** * @var string Webhook token (specifies the conversation where logs are sent) */ protected $token; /** * Construct a new Fleep.io Handler. * * For instructions on how to create a new web hook in your conversations * see https://fleep.io/integrations/webhooks/ * * @param string $token Webhook token * @throws MissingExtensionException */ public function __construct(string $token, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, bool $persistent = \false, float $timeout = 0.0, float $writingTimeout = 10.0, ?float $connectionTimeout = null, ?int $chunkSize = null) { if (!\extension_loaded('openssl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The OpenSSL PHP extension is required to use the FleepHookHandler'); } $this->token = $token; $connectionString = 'ssl://' . static::FLEEP_HOST . ':443'; parent::__construct($connectionString, $level, $bubble, $persistent, $timeout, $writingTimeout, $connectionTimeout, $chunkSize); } /** * Returns the default formatter to use with this handler * * Overloaded to remove empty context and extra arrays from the end of the log message. * * @return LineFormatter */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter(null, null, \true, \true); } /** * Handles a log record */ public function write(array $record) : void { parent::write($record); $this->closeSocket(); } /** * {@inheritDoc} */ protected function generateDataStream(array $record) : string { $content = $this->buildContent($record); return $this->buildHeader($content) . $content; } /** * Builds the header of the API Call */ private function buildHeader(string $content) : string { $header = "POST " . static::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n"; $header .= "Host: " . static::FLEEP_HOST . "\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: " . \strlen($content) . "\r\n"; $header .= "\r\n"; return $header; } /** * Builds the body of API call * * @phpstan-param FormattedRecord $record */ private function buildContent(array $record) : string { $dataArray = ['message' => $record['formatted']]; return \http_build_query($dataArray); } } monolog/src/Monolog/Handler/HandlerWrapper.php 0000644 00000010234 14721613470 0015430 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\ResettableInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * This simple wrapper class can be used to extend handlers functionality. * * Example: A custom filtering that can be applied to any handler. * * Inherit from this class and override handle() like this: * * public function handle(array $record) * { * if ($record meets certain conditions) { * return false; * } * return $this->handler->handle($record); * } * * @author Alexey Karapetov <alexey@karapetov.com> */ class HandlerWrapper implements \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface, \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface, \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface, \Google\Site_Kit_Dependencies\Monolog\ResettableInterface { /** * @var HandlerInterface */ protected $handler; public function __construct(\Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface $handler) { $this->handler = $handler; } /** * {@inheritDoc} */ public function isHandling(array $record) : bool { return $this->handler->isHandling($record); } /** * {@inheritDoc} */ public function handle(array $record) : bool { return $this->handler->handle($record); } /** * {@inheritDoc} */ public function handleBatch(array $records) : void { $this->handler->handleBatch($records); } /** * {@inheritDoc} */ public function close() : void { $this->handler->close(); } /** * {@inheritDoc} */ public function pushProcessor(callable $callback) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { if ($this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface) { $this->handler->pushProcessor($callback); return $this; } throw new \LogicException('The wrapped handler does not implement ' . \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface::class); } /** * {@inheritDoc} */ public function popProcessor() : callable { if ($this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface) { return $this->handler->popProcessor(); } throw new \LogicException('The wrapped handler does not implement ' . \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface::class); } /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { if ($this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { $this->handler->setFormatter($formatter); return $this; } throw new \LogicException('The wrapped handler does not implement ' . \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface::class); } /** * {@inheritDoc} */ public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { if ($this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { return $this->handler->getFormatter(); } throw new \LogicException('The wrapped handler does not implement ' . \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface::class); } public function reset() { if ($this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\ResettableInterface) { $this->handler->reset(); } } } monolog/src/Monolog/Handler/RedisPubSubHandler.php 0000644 00000004133 14721613470 0016200 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Sends the message to a Redis Pub/Sub channel using PUBLISH * * usage example: * * $log = new Logger('application'); * $redis = new RedisPubSubHandler(new Predis\Client("tcp://localhost:6379"), "logs", Logger::WARNING); * $log->pushHandler($redis); * * @author Gaëtan Faugère <gaetan@fauge.re> */ class RedisPubSubHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; /** @var string */ private $channelKey; /** * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance * @param string $key The channel key to publish records to */ public function __construct($redis, string $key, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { if (!($redis instanceof \Google\Site_Kit_Dependencies\Predis\Client || $redis instanceof \Redis)) { throw new \InvalidArgumentException('Predis\\Client or Redis instance required'); } $this->redisClient = $redis; $this->channelKey = $key; parent::__construct($level, $bubble); } /** * {@inheritDoc} */ protected function write(array $record) : void { $this->redisClient->publish($this->channelKey, $record["formatted"]); } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter(); } } monolog/src/Monolog/Handler/PHPConsoleHandler.php 0000644 00000026215 14721613470 0015770 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; use Google\Site_Kit_Dependencies\PhpConsole\Connector; use Google\Site_Kit_Dependencies\PhpConsole\Handler as VendorPhpConsoleHandler; use Google\Site_Kit_Dependencies\PhpConsole\Helper; /** * Monolog handler for Google Chrome extension "PHP Console" * * Display PHP error/debug log messages in Google Chrome console and notification popups, executes PHP code remotely * * Usage: * 1. Install Google Chrome extension [now dead and removed from the chrome store] * 2. See overview https://github.com/barbushin/php-console#overview * 3. Install PHP Console library https://github.com/barbushin/php-console#installation * 4. Example (result will looks like http://i.hizliresim.com/vg3Pz4.png) * * $logger = new \Monolog\Logger('all', array(new \Monolog\Handler\PHPConsoleHandler())); * \Monolog\ErrorHandler::register($logger); * echo $undefinedVar; * $logger->debug('SELECT * FROM users', array('db', 'time' => 0.012)); * PC::debug($_SERVER); // PHP Console debugger for any type of vars * * @author Sergey Barbushin https://www.linkedin.com/in/barbushin * * @phpstan-import-type Record from \Monolog\Logger * @deprecated Since 2.8.0 and 3.2.0, PHPConsole is abandoned and thus we will drop this handler in Monolog 4 */ class PHPConsoleHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var array<string, mixed> */ private $options = [ 'enabled' => \true, // bool Is PHP Console server enabled 'classesPartialsTraceIgnore' => ['Monolog\\'], // array Hide calls of classes started with... 'debugTagsKeysInContext' => [0, 'tag'], // bool Is PHP Console server enabled 'useOwnErrorsHandler' => \false, // bool Enable errors handling 'useOwnExceptionsHandler' => \false, // bool Enable exceptions handling 'sourcesBasePath' => null, // string Base path of all project sources to strip in errors source paths 'registerHelper' => \true, // bool Register PhpConsole\Helper that allows short debug calls like PC::debug($var, 'ta.g.s') 'serverEncoding' => null, // string|null Server internal encoding 'headersLimit' => null, // int|null Set headers size limit for your web-server 'password' => null, // string|null Protect PHP Console connection by password 'enableSslOnlyMode' => \false, // bool Force connection by SSL for clients with PHP Console installed 'ipMasks' => [], // array Set IP masks of clients that will be allowed to connect to PHP Console: array('192.168.*.*', '127.0.0.1') 'enableEvalListener' => \false, // bool Enable eval request to be handled by eval dispatcher(if enabled, 'password' option is also required) 'dumperDetectCallbacks' => \false, // bool Convert callback items in dumper vars to (callback SomeClass::someMethod) strings 'dumperLevelLimit' => 5, // int Maximum dumped vars array or object nested dump level 'dumperItemsCountLimit' => 100, // int Maximum dumped var same level array items or object properties number 'dumperItemSizeLimit' => 5000, // int Maximum length of any string or dumped array item 'dumperDumpSizeLimit' => 500000, // int Maximum approximate size of dumped vars result formatted in JSON 'detectDumpTraceAndSource' => \false, // bool Autodetect and append trace data to debug 'dataStorage' => null, ]; /** @var Connector */ private $connector; /** * @param array<string, mixed> $options See \Monolog\Handler\PHPConsoleHandler::$options for more details * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) * @throws \RuntimeException */ public function __construct(array $options = [], ?\Google\Site_Kit_Dependencies\PhpConsole\Connector $connector = null, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { if (!\class_exists('Google\\Site_Kit_Dependencies\\PhpConsole\\Connector')) { throw new \RuntimeException('PHP Console library not found. See https://github.com/barbushin/php-console#installation'); } parent::__construct($level, $bubble); $this->options = $this->initOptions($options); $this->connector = $this->initConnector($connector); } /** * @param array<string, mixed> $options * * @return array<string, mixed> */ private function initOptions(array $options) : array { $wrongOptions = \array_diff(\array_keys($options), \array_keys($this->options)); if ($wrongOptions) { throw new \RuntimeException('Unknown options: ' . \implode(', ', $wrongOptions)); } return \array_replace($this->options, $options); } private function initConnector(?\Google\Site_Kit_Dependencies\PhpConsole\Connector $connector = null) : \Google\Site_Kit_Dependencies\PhpConsole\Connector { if (!$connector) { if ($this->options['dataStorage']) { \Google\Site_Kit_Dependencies\PhpConsole\Connector::setPostponeStorage($this->options['dataStorage']); } $connector = \Google\Site_Kit_Dependencies\PhpConsole\Connector::getInstance(); } if ($this->options['registerHelper'] && !\Google\Site_Kit_Dependencies\PhpConsole\Helper::isRegistered()) { \Google\Site_Kit_Dependencies\PhpConsole\Helper::register(); } if ($this->options['enabled'] && $connector->isActiveClient()) { if ($this->options['useOwnErrorsHandler'] || $this->options['useOwnExceptionsHandler']) { $handler = \Google\Site_Kit_Dependencies\PhpConsole\Handler::getInstance(); $handler->setHandleErrors($this->options['useOwnErrorsHandler']); $handler->setHandleExceptions($this->options['useOwnExceptionsHandler']); $handler->start(); } if ($this->options['sourcesBasePath']) { $connector->setSourcesBasePath($this->options['sourcesBasePath']); } if ($this->options['serverEncoding']) { $connector->setServerEncoding($this->options['serverEncoding']); } if ($this->options['password']) { $connector->setPassword($this->options['password']); } if ($this->options['enableSslOnlyMode']) { $connector->enableSslOnlyMode(); } if ($this->options['ipMasks']) { $connector->setAllowedIpMasks($this->options['ipMasks']); } if ($this->options['headersLimit']) { $connector->setHeadersLimit($this->options['headersLimit']); } if ($this->options['detectDumpTraceAndSource']) { $connector->getDebugDispatcher()->detectTraceAndSource = \true; } $dumper = $connector->getDumper(); $dumper->levelLimit = $this->options['dumperLevelLimit']; $dumper->itemsCountLimit = $this->options['dumperItemsCountLimit']; $dumper->itemSizeLimit = $this->options['dumperItemSizeLimit']; $dumper->dumpSizeLimit = $this->options['dumperDumpSizeLimit']; $dumper->detectCallbacks = $this->options['dumperDetectCallbacks']; if ($this->options['enableEvalListener']) { $connector->startEvalRequestsListener(); } } return $connector; } public function getConnector() : \Google\Site_Kit_Dependencies\PhpConsole\Connector { return $this->connector; } /** * @return array<string, mixed> */ public function getOptions() : array { return $this->options; } public function handle(array $record) : bool { if ($this->options['enabled'] && $this->connector->isActiveClient()) { return parent::handle($record); } return !$this->bubble; } /** * Writes the record down to the log of the implementing handler */ protected function write(array $record) : void { if ($record['level'] < \Google\Site_Kit_Dependencies\Monolog\Logger::NOTICE) { $this->handleDebugRecord($record); } elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { $this->handleExceptionRecord($record); } else { $this->handleErrorRecord($record); } } /** * @phpstan-param Record $record */ private function handleDebugRecord(array $record) : void { $tags = $this->getRecordTags($record); $message = $record['message']; if ($record['context']) { $message .= ' ' . \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($this->connector->getDumper()->dump(\array_filter($record['context'])), null, \true); } $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); } /** * @phpstan-param Record $record */ private function handleExceptionRecord(array $record) : void { $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']); } /** * @phpstan-param Record $record */ private function handleErrorRecord(array $record) : void { $context = $record['context']; $this->connector->getErrorsDispatcher()->dispatchError($context['code'] ?? null, $context['message'] ?? $record['message'], $context['file'] ?? null, $context['line'] ?? null, $this->options['classesPartialsTraceIgnore']); } /** * @phpstan-param Record $record * @return string */ private function getRecordTags(array &$record) { $tags = null; if (!empty($record['context'])) { $context =& $record['context']; foreach ($this->options['debugTagsKeysInContext'] as $key) { if (!empty($context[$key])) { $tags = $context[$key]; if ($key === 0) { \array_shift($context); } else { unset($context[$key]); } break; } } } return $tags ?: \strtolower($record['level_name']); } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter('%message%'); } } monolog/src/Monolog/Handler/SlackHandler.php 0000644 00000016117 14721613470 0015053 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; use Google\Site_Kit_Dependencies\Monolog\Handler\Slack\SlackRecord; /** * Sends notifications through Slack API * * @author Greg Kedzierski <greg@gregkedzierski.com> * @see https://api.slack.com/ * * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class SlackHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\SocketHandler { /** * Slack API token * @var string */ private $token; /** * Instance of the SlackRecord util class preparing data for Slack API. * @var SlackRecord */ private $slackRecord; /** * @param string $token Slack API token * @param string $channel Slack channel (encoded ID or name) * @param string|null $username Name of a bot * @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise) * @param string|null $iconEmoji The emoji name to use (or null) * @param bool $useShortAttachment Whether the context/extra messages added to Slack as attachments are in a short style * @param bool $includeContextAndExtra Whether the attachment should include context and extra data * @param string[] $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] * @throws MissingExtensionException If no OpenSSL PHP extension configured */ public function __construct(string $token, string $channel, ?string $username = null, bool $useAttachment = \true, ?string $iconEmoji = null, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL, bool $bubble = \true, bool $useShortAttachment = \false, bool $includeContextAndExtra = \false, array $excludeFields = array(), bool $persistent = \false, float $timeout = 0.0, float $writingTimeout = 10.0, ?float $connectionTimeout = null, ?int $chunkSize = null) { if (!\extension_loaded('openssl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The OpenSSL PHP extension is required to use the SlackHandler'); } parent::__construct('ssl://slack.com:443', $level, $bubble, $persistent, $timeout, $writingTimeout, $connectionTimeout, $chunkSize); $this->slackRecord = new \Google\Site_Kit_Dependencies\Monolog\Handler\Slack\SlackRecord($channel, $username, $useAttachment, $iconEmoji, $useShortAttachment, $includeContextAndExtra, $excludeFields); $this->token = $token; } public function getSlackRecord() : \Google\Site_Kit_Dependencies\Monolog\Handler\Slack\SlackRecord { return $this->slackRecord; } public function getToken() : string { return $this->token; } /** * {@inheritDoc} */ protected function generateDataStream(array $record) : string { $content = $this->buildContent($record); return $this->buildHeader($content) . $content; } /** * Builds the body of API call * * @phpstan-param FormattedRecord $record */ private function buildContent(array $record) : string { $dataArray = $this->prepareContentData($record); return \http_build_query($dataArray); } /** * @phpstan-param FormattedRecord $record * @return string[] */ protected function prepareContentData(array $record) : array { $dataArray = $this->slackRecord->getSlackData($record); $dataArray['token'] = $this->token; if (!empty($dataArray['attachments'])) { $dataArray['attachments'] = \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($dataArray['attachments']); } return $dataArray; } /** * Builds the header of the API Call */ private function buildHeader(string $content) : string { $header = "POST /api/chat.postMessage HTTP/1.1\r\n"; $header .= "Host: slack.com\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: " . \strlen($content) . "\r\n"; $header .= "\r\n"; return $header; } /** * {@inheritDoc} */ protected function write(array $record) : void { parent::write($record); $this->finalizeWrite(); } /** * Finalizes the request by reading some bytes and then closing the socket * * If we do not read some but close the socket too early, slack sometimes * drops the request entirely. */ protected function finalizeWrite() : void { $res = $this->getResource(); if (\is_resource($res)) { @\fread($res, 2048); } $this->closeSocket(); } public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { parent::setFormatter($formatter); $this->slackRecord->setFormatter($formatter); return $this; } public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { $formatter = parent::getFormatter(); $this->slackRecord->setFormatter($formatter); return $formatter; } /** * Channel used by the bot when posting */ public function setChannel(string $channel) : self { $this->slackRecord->setChannel($channel); return $this; } /** * Username used by the bot when posting */ public function setUsername(string $username) : self { $this->slackRecord->setUsername($username); return $this; } public function useAttachment(bool $useAttachment) : self { $this->slackRecord->useAttachment($useAttachment); return $this; } public function setIconEmoji(string $iconEmoji) : self { $this->slackRecord->setUserIcon($iconEmoji); return $this; } public function useShortAttachment(bool $useShortAttachment) : self { $this->slackRecord->useShortAttachment($useShortAttachment); return $this; } public function includeContextAndExtra(bool $includeContextAndExtra) : self { $this->slackRecord->includeContextAndExtra($includeContextAndExtra); return $this; } /** * @param string[] $excludeFields */ public function excludeFields(array $excludeFields) : self { $this->slackRecord->excludeFields($excludeFields); return $this; } } monolog/src/Monolog/Handler/FallbackGroupHandler.php 0000644 00000003455 14721613470 0016533 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Throwable; /** * Forwards records to at most one handler * * If a handler fails, the exception is suppressed and the record is forwarded to the next handler. * * As soon as one handler handles a record successfully, the handling stops there. * * @phpstan-import-type Record from \Monolog\Logger */ class FallbackGroupHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\GroupHandler { /** * {@inheritDoc} */ public function handle(array $record) : bool { if ($this->processors) { /** @var Record $record */ $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { try { $handler->handle($record); break; } catch (\Throwable $e) { // What throwable? } } return \false === $this->bubble; } /** * {@inheritDoc} */ public function handleBatch(array $records) : void { if ($this->processors) { $processed = []; foreach ($records as $record) { $processed[] = $this->processRecord($record); } /** @var Record[] $records */ $records = $processed; } foreach ($this->handlers as $handler) { try { $handler->handleBatch($records); break; } catch (\Throwable $e) { // What throwable? } } } } monolog/src/Monolog/Handler/BrowserConsoleHandler.php 0000644 00000023423 14721613470 0016762 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; use Google\Site_Kit_Dependencies\Monolog\Utils; use Google\Site_Kit_Dependencies\Monolog\Logger; use function count; use function headers_list; use function stripos; use function trigger_error; use const E_USER_DEPRECATED; /** * Handler sending logs to browser's javascript console with no browser extension required * * @author Olivier Poitrey <rs@dailymotion.com> * * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class BrowserConsoleHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var bool */ protected static $initialized = \false; /** @var FormattedRecord[] */ protected static $records = []; protected const FORMAT_HTML = 'html'; protected const FORMAT_JS = 'js'; protected const FORMAT_UNKNOWN = 'unknown'; /** * {@inheritDoc} * * Formatted output may contain some formatting markers to be transferred to `console.log` using the %c format. * * Example of formatted string: * * You can do [[blue text]]{color: blue} or [[green background]]{background-color: green; color: white} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter('[[%channel%]]{macro: autolabel} [[%level_name%]]{font-weight: bold} %message%'); } /** * {@inheritDoc} */ protected function write(array $record) : void { // Accumulate records static::$records[] = $record; // Register shutdown handler if not already done if (!static::$initialized) { static::$initialized = \true; $this->registerShutdownFunction(); } } /** * Convert records to javascript console commands and send it to the browser. * This method is automatically called on PHP shutdown if output is HTML or Javascript. */ public static function send() : void { $format = static::getResponseFormat(); if ($format === self::FORMAT_UNKNOWN) { return; } if (\count(static::$records)) { if ($format === self::FORMAT_HTML) { static::writeOutput('<script>' . static::generateScript() . '</script>'); } elseif ($format === self::FORMAT_JS) { static::writeOutput(static::generateScript()); } static::resetStatic(); } } public function close() : void { self::resetStatic(); } public function reset() { parent::reset(); self::resetStatic(); } /** * Forget all logged records */ public static function resetStatic() : void { static::$records = []; } /** * Wrapper for register_shutdown_function to allow overriding */ protected function registerShutdownFunction() : void { if (\PHP_SAPI !== 'cli') { \register_shutdown_function(['Monolog\\Handler\\BrowserConsoleHandler', 'send']); } } /** * Wrapper for echo to allow overriding */ protected static function writeOutput(string $str) : void { echo $str; } /** * Checks the format of the response * * If Content-Type is set to application/javascript or text/javascript -> js * If Content-Type is set to text/html, or is unset -> html * If Content-Type is anything else -> unknown * * @return string One of 'js', 'html' or 'unknown' * @phpstan-return self::FORMAT_* */ protected static function getResponseFormat() : string { // Check content type foreach (\headers_list() as $header) { if (\stripos($header, 'content-type:') === 0) { return static::getResponseFormatFromContentType($header); } } return self::FORMAT_HTML; } /** * @return string One of 'js', 'html' or 'unknown' * @phpstan-return self::FORMAT_* */ protected static function getResponseFormatFromContentType(string $contentType) : string { // This handler only works with HTML and javascript outputs // text/javascript is obsolete in favour of application/javascript, but still used if (\stripos($contentType, 'application/javascript') !== \false || \stripos($contentType, 'text/javascript') !== \false) { return self::FORMAT_JS; } if (\stripos($contentType, 'text/html') !== \false) { return self::FORMAT_HTML; } return self::FORMAT_UNKNOWN; } private static function generateScript() : string { $script = []; foreach (static::$records as $record) { $context = static::dump('Context', $record['context']); $extra = static::dump('Extra', $record['extra']); if (empty($context) && empty($extra)) { $script[] = static::call_array(static::getConsoleMethodForLevel($record['level']), static::handleStyles($record['formatted'])); } else { $script = \array_merge($script, [static::call_array('groupCollapsed', static::handleStyles($record['formatted']))], $context, $extra, [static::call('groupEnd')]); } } return "(function (c) {if (c && c.groupCollapsed) {\n" . \implode("\n", $script) . "\n}})(console);"; } private static function getConsoleMethodForLevel(int $level) : string { return [\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG => 'debug', \Google\Site_Kit_Dependencies\Monolog\Logger::INFO => 'info', \Google\Site_Kit_Dependencies\Monolog\Logger::NOTICE => 'info', \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING => 'warn', \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR => 'error', \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL => 'error', \Google\Site_Kit_Dependencies\Monolog\Logger::ALERT => 'error', \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY => 'error'][$level] ?? 'log'; } /** * @return string[] */ private static function handleStyles(string $formatted) : array { $args = []; $format = '%c' . $formatted; \preg_match_all('/\\[\\[(.*?)\\]\\]\\{([^}]*)\\}/s', $format, $matches, \PREG_OFFSET_CAPTURE | \PREG_SET_ORDER); foreach (\array_reverse($matches) as $match) { $args[] = '"font-weight: normal"'; $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0])); $pos = $match[0][1]; $format = \Google\Site_Kit_Dependencies\Monolog\Utils::substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . \Google\Site_Kit_Dependencies\Monolog\Utils::substr($format, $pos + \strlen($match[0][0])); } $args[] = static::quote('font-weight: normal'); $args[] = static::quote($format); return \array_reverse($args); } private static function handleCustomStyles(string $style, string $string) : string { static $colors = ['blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey']; static $labels = []; $style = \preg_replace_callback('/macro\\s*:(.*?)(?:;|$)/', function (array $m) use($string, &$colors, &$labels) { if (\trim($m[1]) === 'autolabel') { // Format the string as a label with consistent auto assigned background color if (!isset($labels[$string])) { $labels[$string] = $colors[\count($labels) % \count($colors)]; } $color = $labels[$string]; return "background-color: {$color}; color: white; border-radius: 3px; padding: 0 2px 0 2px"; } return $m[1]; }, $style); if (null === $style) { $pcreErrorCode = \preg_last_error(); throw new \RuntimeException('Failed to run preg_replace_callback: ' . $pcreErrorCode . ' / ' . \Google\Site_Kit_Dependencies\Monolog\Utils::pcreLastErrorMessage($pcreErrorCode)); } return $style; } /** * @param mixed[] $dict * @return mixed[] */ private static function dump(string $title, array $dict) : array { $script = []; $dict = \array_filter($dict); if (empty($dict)) { return $script; } $script[] = static::call('log', static::quote('%c%s'), static::quote('font-weight: bold'), static::quote($title)); foreach ($dict as $key => $value) { $value = \json_encode($value); if (empty($value)) { $value = static::quote(''); } $script[] = static::call('log', static::quote('%s: %o'), static::quote((string) $key), $value); } return $script; } private static function quote(string $arg) : string { return '"' . \addcslashes($arg, "\"\n\\") . '"'; } /** * @param mixed $args */ private static function call(...$args) : string { $method = \array_shift($args); if (!\is_string($method)) { throw new \UnexpectedValueException('Expected the first arg to be a string, got: ' . \var_export($method, \true)); } return static::call_array($method, $args); } /** * @param mixed[] $args */ private static function call_array(string $method, array $args) : string { return 'c.' . $method . '(' . \implode(', ', $args) . ');'; } } monolog/src/Monolog/Handler/LogmaticHandler.php 0000644 00000005450 14721613470 0015553 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\LogmaticFormatter; /** * @author Julien Breux <julien.breux@gmail.com> */ class LogmaticHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\SocketHandler { /** * @var string */ private $logToken; /** * @var string */ private $hostname; /** * @var string */ private $appname; /** * @param string $token Log token supplied by Logmatic. * @param string $hostname Host name supplied by Logmatic. * @param string $appname Application name supplied by Logmatic. * @param bool $useSSL Whether or not SSL encryption should be used. * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ public function __construct(string $token, string $hostname = '', string $appname = '', bool $useSSL = \true, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, bool $persistent = \false, float $timeout = 0.0, float $writingTimeout = 10.0, ?float $connectionTimeout = null, ?int $chunkSize = null) { if ($useSSL && !\extension_loaded('openssl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The OpenSSL PHP extension is required to use SSL encrypted connection for LogmaticHandler'); } $endpoint = $useSSL ? 'ssl://api.logmatic.io:10515' : 'api.logmatic.io:10514'; $endpoint .= '/v1/'; parent::__construct($endpoint, $level, $bubble, $persistent, $timeout, $writingTimeout, $connectionTimeout, $chunkSize); $this->logToken = $token; $this->hostname = $hostname; $this->appname = $appname; } /** * {@inheritDoc} */ protected function generateDataStream(array $record) : string { return $this->logToken . ' ' . $record['formatted']; } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { $formatter = new \Google\Site_Kit_Dependencies\Monolog\Formatter\LogmaticFormatter(); if (!empty($this->hostname)) { $formatter->setHostname($this->hostname); } if (!empty($this->appname)) { $formatter->setAppname($this->appname); } return $formatter; } } monolog/src/Monolog/Handler/ProcessableHandlerInterface.php 0000644 00000002425 14721613470 0020076 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface; /** * Interface to describe loggers that have processors * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Record from \Monolog\Logger */ interface ProcessableHandlerInterface { /** * Adds a processor in the stack. * * @psalm-param ProcessorInterface|callable(Record): Record $callback * * @param ProcessorInterface|callable $callback * @return HandlerInterface self */ public function pushProcessor(callable $callback) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface; /** * Removes the processor on top of the stack and returns it. * * @psalm-return ProcessorInterface|callable(Record): Record $callback * * @throws \LogicException In case the processor stack is empty * @return callable|ProcessorInterface */ public function popProcessor() : callable; } monolog/src/Monolog/Handler/DynamoDbHandler.php 0000644 00000005606 14721613470 0015514 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Aws\Sdk; use Google\Site_Kit_Dependencies\Aws\DynamoDb\DynamoDbClient; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Aws\DynamoDb\Marshaler; use Google\Site_Kit_Dependencies\Monolog\Formatter\ScalarFormatter; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Amazon DynamoDB handler (http://aws.amazon.com/dynamodb/) * * @link https://github.com/aws/aws-sdk-php/ * @author Andrew Lawson <adlawson@gmail.com> */ class DynamoDbHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { public const DATE_FORMAT = 'Y-m-d\\TH:i:s.uO'; /** * @var DynamoDbClient */ protected $client; /** * @var string */ protected $table; /** * @var int */ protected $version; /** * @var Marshaler */ protected $marshaler; public function __construct(\Google\Site_Kit_Dependencies\Aws\DynamoDb\DynamoDbClient $client, string $table, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { /** @phpstan-ignore-next-line */ if (\defined('Aws\\Sdk::VERSION') && \version_compare(\Google\Site_Kit_Dependencies\Aws\Sdk::VERSION, '3.0', '>=')) { $this->version = 3; $this->marshaler = new \Google\Site_Kit_Dependencies\Aws\DynamoDb\Marshaler(); } else { $this->version = 2; } $this->client = $client; $this->table = $table; parent::__construct($level, $bubble); } /** * {@inheritDoc} */ protected function write(array $record) : void { $filtered = $this->filterEmptyFields($record['formatted']); if ($this->version === 3) { $formatted = $this->marshaler->marshalItem($filtered); } else { /** @phpstan-ignore-next-line */ $formatted = $this->client->formatAttributes($filtered); } $this->client->putItem(['TableName' => $this->table, 'Item' => $formatted]); } /** * @param mixed[] $record * @return mixed[] */ protected function filterEmptyFields(array $record) : array { return \array_filter($record, function ($value) { return !empty($value) || \false === $value || 0 === $value; }); } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\ScalarFormatter(self::DATE_FORMAT); } } monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php 0000644 00000004343 14721613470 0016350 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler\SyslogUdp; use Google\Site_Kit_Dependencies\Monolog\Utils; use Socket; class UdpSocket { protected const DATAGRAM_MAX_LENGTH = 65023; /** @var string */ protected $ip; /** @var int */ protected $port; /** @var resource|Socket|null */ protected $socket = null; public function __construct(string $ip, int $port = 514) { $this->ip = $ip; $this->port = $port; } /** * @param string $line * @param string $header * @return void */ public function write($line, $header = "") { $this->send($this->assembleMessage($line, $header)); } public function close() : void { if (\is_resource($this->socket) || $this->socket instanceof \Socket) { \socket_close($this->socket); $this->socket = null; } } /** * @return resource|Socket */ protected function getSocket() { if (null !== $this->socket) { return $this->socket; } $domain = \AF_INET; $protocol = \SOL_UDP; // Check if we are using unix sockets. if ($this->port === 0) { $domain = \AF_UNIX; $protocol = \IPPROTO_IP; } $this->socket = \socket_create($domain, \SOCK_DGRAM, $protocol) ?: null; if (null === $this->socket) { throw new \RuntimeException('The UdpSocket to ' . $this->ip . ':' . $this->port . ' could not be opened via socket_create'); } return $this->socket; } protected function send(string $chunk) : void { \socket_sendto($this->getSocket(), $chunk, \strlen($chunk), $flags = 0, $this->ip, $this->port); } protected function assembleMessage(string $line, string $header) : string { $chunkSize = static::DATAGRAM_MAX_LENGTH - \strlen($header); return $header . \Google\Site_Kit_Dependencies\Monolog\Utils::substr($line, 0, $chunkSize); } } monolog/src/Monolog/Handler/FilterHandler.php 0000644 00000017275 14721613470 0015251 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\ResettableInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Simple handler wrapper that filters records based on a list of levels * * It can be configured with an exact list of levels to allow, or a min/max level. * * @author Hennadiy Verkh * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ class FilterHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\Handler implements \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface, \Google\Site_Kit_Dependencies\Monolog\ResettableInterface, \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface { use ProcessableHandlerTrait; /** * Handler or factory callable($record, $this) * * @var callable|HandlerInterface * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface */ protected $handler; /** * Minimum level for logs that are passed to handler * * @var int[] * @phpstan-var array<Level, int> */ protected $acceptedLevels; /** * Whether the messages that are handled can bubble up the stack or not * * @var bool */ protected $bubble; /** * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler * * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler). * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided * @param int|string $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * * @phpstan-param Level|LevelName|LogLevel::*|array<Level|LevelName|LogLevel::*> $minLevelOrList * @phpstan-param Level|LevelName|LogLevel::* $maxLevel */ public function __construct($handler, $minLevelOrList = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, $maxLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY, bool $bubble = \true) { $this->handler = $handler; $this->bubble = $bubble; $this->setAcceptedLevels($minLevelOrList, $maxLevel); if (!$this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface && !\is_callable($this->handler)) { throw new \RuntimeException("The given handler (" . \json_encode($this->handler) . ") is not a callable nor a Monolog\\Handler\\HandlerInterface object"); } } /** * @phpstan-return array<int, Level> */ public function getAcceptedLevels() : array { return \array_flip($this->acceptedLevels); } /** * @param int|string|array $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided * @param int|string $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array * * @phpstan-param Level|LevelName|LogLevel::*|array<Level|LevelName|LogLevel::*> $minLevelOrList * @phpstan-param Level|LevelName|LogLevel::* $maxLevel */ public function setAcceptedLevels($minLevelOrList = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, $maxLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY) : self { if (\is_array($minLevelOrList)) { $acceptedLevels = \array_map('Monolog\\Logger::toMonologLevel', $minLevelOrList); } else { $minLevelOrList = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($minLevelOrList); $maxLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($maxLevel); $acceptedLevels = \array_values(\array_filter(\Google\Site_Kit_Dependencies\Monolog\Logger::getLevels(), function ($level) use($minLevelOrList, $maxLevel) { return $level >= $minLevelOrList && $level <= $maxLevel; })); } $this->acceptedLevels = \array_flip($acceptedLevels); return $this; } /** * {@inheritDoc} */ public function isHandling(array $record) : bool { return isset($this->acceptedLevels[$record['level']]); } /** * {@inheritDoc} */ public function handle(array $record) : bool { if (!$this->isHandling($record)) { return \false; } if ($this->processors) { /** @var Record $record */ $record = $this->processRecord($record); } $this->getHandler($record)->handle($record); return \false === $this->bubble; } /** * {@inheritDoc} */ public function handleBatch(array $records) : void { $filtered = []; foreach ($records as $record) { if ($this->isHandling($record)) { $filtered[] = $record; } } if (\count($filtered) > 0) { $this->getHandler($filtered[\count($filtered) - 1])->handleBatch($filtered); } } /** * Return the nested handler * * If the handler was provided as a factory callable, this will trigger the handler's instantiation. * * @return HandlerInterface * * @phpstan-param Record $record */ public function getHandler(?array $record = null) { if (!$this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface) { $this->handler = ($this->handler)($record, $this); if (!$this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } } return $this->handler; } /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { $handler = $this->getHandler(); if ($handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { $handler->setFormatter($formatter); return $this; } throw new \UnexpectedValueException('The nested handler of type ' . \get_class($handler) . ' does not support formatters.'); } /** * {@inheritDoc} */ public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { $handler = $this->getHandler(); if ($handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { return $handler->getFormatter(); } throw new \UnexpectedValueException('The nested handler of type ' . \get_class($handler) . ' does not support formatters.'); } public function reset() { $this->resetProcessors(); if ($this->getHandler() instanceof \Google\Site_Kit_Dependencies\Monolog\ResettableInterface) { $this->getHandler()->reset(); } } } monolog/src/Monolog/Handler/AbstractHandler.php 0000644 00000005622 14721613470 0015560 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\ResettableInterface; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Base Handler class providing basic level/bubble support * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ abstract class AbstractHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\Handler implements \Google\Site_Kit_Dependencies\Monolog\ResettableInterface { /** * @var int * @phpstan-var Level */ protected $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG; /** @var bool */ protected $bubble = \true; /** * @param int|string $level The minimum logging level at which this handler will be triggered * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function __construct($level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { $this->setLevel($level); $this->bubble = $bubble; } /** * {@inheritDoc} */ public function isHandling(array $record) : bool { return $record['level'] >= $this->level; } /** * Sets minimum logging level at which this handler will be triggered. * * @param Level|LevelName|LogLevel::* $level Level or level name * @return self */ public function setLevel($level) : self { $this->level = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($level); return $this; } /** * Gets minimum logging level at which this handler will be triggered. * * @return int * * @phpstan-return Level */ public function getLevel() : int { return $this->level; } /** * Sets the bubbling behavior. * * @param bool $bubble true means that this handler allows bubbling. * false means that bubbling is not permitted. * @return self */ public function setBubble(bool $bubble) : self { $this->bubble = $bubble; return $this; } /** * Gets the bubbling behavior. * * @return bool true means that this handler allows bubbling. * false means that bubbling is not permitted. */ public function getBubble() : bool { return $this->bubble; } /** * {@inheritDoc} */ public function reset() { } } monolog/src/Monolog/Handler/NullHandler.php 0000644 00000003010 14721613470 0014714 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Blackhole * * Any record it can handle will be thrown away. This can be used * to put on top of an existing stack to override it temporarily. * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ class NullHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\Handler { /** * @var int */ private $level; /** * @param string|int $level The minimum logging level at which this handler will be triggered * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function __construct($level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG) { $this->level = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($level); } /** * {@inheritDoc} */ public function isHandling(array $record) : bool { return $record['level'] >= $this->level; } /** * {@inheritDoc} */ public function handle(array $record) : bool { return $record['level'] >= $this->level; } } monolog/src/Monolog/Handler/RollbarHandler.php 0000644 00000007271 14721613470 0015414 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Rollbar\RollbarLogger; use Throwable; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Sends errors to Rollbar * * If the context data contains a `payload` key, that is used as an array * of payload options to RollbarLogger's log method. * * Rollbar's context info will contain the context + extra keys from the log record * merged, and then on top of that a few keys: * * - level (rollbar level name) * - monolog_level (monolog level name, raw level, as rollbar only has 5 but monolog 8) * - channel * - datetime (unix timestamp) * * @author Paul Statezny <paulstatezny@gmail.com> */ class RollbarHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** * @var RollbarLogger */ protected $rollbarLogger; /** @var string[] */ protected $levelMap = [\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG => 'debug', \Google\Site_Kit_Dependencies\Monolog\Logger::INFO => 'info', \Google\Site_Kit_Dependencies\Monolog\Logger::NOTICE => 'info', \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING => 'warning', \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR => 'error', \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL => 'critical', \Google\Site_Kit_Dependencies\Monolog\Logger::ALERT => 'critical', \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY => 'critical']; /** * Records whether any log records have been added since the last flush of the rollbar notifier * * @var bool */ private $hasRecords = \false; /** @var bool */ protected $initialized = \false; /** * @param RollbarLogger $rollbarLogger RollbarLogger object constructed with valid token */ public function __construct(\Google\Site_Kit_Dependencies\Rollbar\RollbarLogger $rollbarLogger, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR, bool $bubble = \true) { $this->rollbarLogger = $rollbarLogger; parent::__construct($level, $bubble); } /** * {@inheritDoc} */ protected function write(array $record) : void { if (!$this->initialized) { // __destructor() doesn't get called on Fatal errors \register_shutdown_function(array($this, 'close')); $this->initialized = \true; } $context = $record['context']; $context = \array_merge($context, $record['extra'], ['level' => $this->levelMap[$record['level']], 'monolog_level' => $record['level_name'], 'channel' => $record['channel'], 'datetime' => $record['datetime']->format('U')]); if (isset($context['exception']) && $context['exception'] instanceof \Throwable) { $exception = $context['exception']; unset($context['exception']); $toLog = $exception; } else { $toLog = $record['message']; } // @phpstan-ignore-next-line $this->rollbarLogger->log($context['level'], $toLog, $context); $this->hasRecords = \true; } public function flush() : void { if ($this->hasRecords) { $this->rollbarLogger->flush(); $this->hasRecords = \false; } } /** * {@inheritDoc} */ public function close() : void { $this->flush(); } /** * {@inheritDoc} */ public function reset() { $this->flush(); parent::reset(); } } monolog/src/Monolog/Handler/FlowdockHandler.php 0000644 00000007562 14721613470 0015572 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; use Google\Site_Kit_Dependencies\Monolog\Formatter\FlowdockFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Sends notifications through the Flowdock push API * * This must be configured with a FlowdockFormatter instance via setFormatter() * * Notes: * API token - Flowdock API token * * @author Dominik Liebler <liebler.dominik@gmail.com> * @see https://www.flowdock.com/api/push * * @phpstan-import-type FormattedRecord from AbstractProcessingHandler * @deprecated Since 2.9.0 and 3.3.0, Flowdock was shutdown we will thus drop this handler in Monolog 4 */ class FlowdockHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\SocketHandler { /** * @var string */ protected $apiToken; /** * @throws MissingExtensionException if OpenSSL is missing */ public function __construct(string $apiToken, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, bool $persistent = \false, float $timeout = 0.0, float $writingTimeout = 10.0, ?float $connectionTimeout = null, ?int $chunkSize = null) { if (!\extension_loaded('openssl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler'); } parent::__construct('ssl://api.flowdock.com:443', $level, $bubble, $persistent, $timeout, $writingTimeout, $connectionTimeout, $chunkSize); $this->apiToken = $apiToken; } /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { if (!$formatter instanceof \Google\Site_Kit_Dependencies\Monolog\Formatter\FlowdockFormatter) { throw new \InvalidArgumentException('The FlowdockHandler requires an instance of Monolog\\Formatter\\FlowdockFormatter to function correctly'); } return parent::setFormatter($formatter); } /** * Gets the default formatter. */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { throw new \InvalidArgumentException('The FlowdockHandler must be configured (via setFormatter) with an instance of Monolog\\Formatter\\FlowdockFormatter to function correctly'); } /** * {@inheritDoc} */ protected function write(array $record) : void { parent::write($record); $this->closeSocket(); } /** * {@inheritDoc} */ protected function generateDataStream(array $record) : string { $content = $this->buildContent($record); return $this->buildHeader($content) . $content; } /** * Builds the body of API call * * @phpstan-param FormattedRecord $record */ private function buildContent(array $record) : string { return \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($record['formatted']['flowdock']); } /** * Builds the header of the API Call */ private function buildHeader(string $content) : string { $header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n"; $header .= "Host: api.flowdock.com\r\n"; $header .= "Content-Type: application/json\r\n"; $header .= "Content-Length: " . \strlen($content) . "\r\n"; $header .= "\r\n"; return $header; } } monolog/src/Monolog/Handler/ChromePHPHandler.php 0000644 00000013075 14721613470 0015603 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\ChromePHPFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) * * This also works out of the box with Firefox 43+ * * @author Christophe Coevoet <stof@notk.org> * * @phpstan-import-type Record from \Monolog\Logger */ class ChromePHPHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { use WebRequestRecognizerTrait; /** * Version of the extension */ protected const VERSION = '4.0'; /** * Header name */ protected const HEADER_NAME = 'X-ChromeLogger-Data'; /** * Regular expression to detect supported browsers (matches any Chrome, or Firefox 43+) */ protected const USER_AGENT_REGEX = '{\\b(?:Chrome/\\d+(?:\\.\\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\\d|\\d{3,})(?:\\.\\d)*)\\b}'; /** @var bool */ protected static $initialized = \false; /** * Tracks whether we sent too much data * * Chrome limits the headers to 4KB, so when we sent 3KB we stop sending * * @var bool */ protected static $overflowed = \false; /** @var mixed[] */ protected static $json = ['version' => self::VERSION, 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => []]; /** @var bool */ protected static $sendHeaders = \true; public function __construct($level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { parent::__construct($level, $bubble); if (!\function_exists('json_encode')) { throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s ChromePHPHandler'); } } /** * {@inheritDoc} */ public function handleBatch(array $records) : void { if (!$this->isWebRequest()) { return; } $messages = []; foreach ($records as $record) { if ($record['level'] < $this->level) { continue; } /** @var Record $message */ $message = $this->processRecord($record); $messages[] = $message; } if (!empty($messages)) { $messages = $this->getFormatter()->formatBatch($messages); self::$json['rows'] = \array_merge(self::$json['rows'], $messages); $this->send(); } } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\ChromePHPFormatter(); } /** * Creates & sends header for a record * * @see sendHeader() * @see send() */ protected function write(array $record) : void { if (!$this->isWebRequest()) { return; } self::$json['rows'][] = $record['formatted']; $this->send(); } /** * Sends the log header * * @see sendHeader() */ protected function send() : void { if (self::$overflowed || !self::$sendHeaders) { return; } if (!self::$initialized) { self::$initialized = \true; self::$sendHeaders = $this->headersAccepted(); if (!self::$sendHeaders) { return; } self::$json['request_uri'] = $_SERVER['REQUEST_URI'] ?? ''; } $json = \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode(self::$json, \Google\Site_Kit_Dependencies\Monolog\Utils::DEFAULT_JSON_FLAGS & ~\JSON_UNESCAPED_UNICODE, \true); $data = \base64_encode($json); if (\strlen($data) > 3 * 1024) { self::$overflowed = \true; $record = ['message' => 'Incomplete logs, chrome header size limit reached', 'context' => [], 'level' => \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING, 'level_name' => \Google\Site_Kit_Dependencies\Monolog\Logger::getLevelName(\Google\Site_Kit_Dependencies\Monolog\Logger::WARNING), 'channel' => 'monolog', 'datetime' => new \DateTimeImmutable(), 'extra' => []]; self::$json['rows'][\count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); $json = \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode(self::$json, \Google\Site_Kit_Dependencies\Monolog\Utils::DEFAULT_JSON_FLAGS & ~\JSON_UNESCAPED_UNICODE, \true); $data = \base64_encode($json); } if (\trim($data) !== '') { $this->sendHeader(static::HEADER_NAME, $data); } } /** * Send header string to the client */ protected function sendHeader(string $header, string $content) : void { if (!\headers_sent() && self::$sendHeaders) { \header(\sprintf('%s: %s', $header, $content)); } } /** * Verifies if the headers are accepted by the current user agent */ protected function headersAccepted() : bool { if (empty($_SERVER['HTTP_USER_AGENT'])) { return \false; } return \preg_match(static::USER_AGENT_REGEX, $_SERVER['HTTP_USER_AGENT']) === 1; } } monolog/src/Monolog/Handler/LogglyHandler.php 0000644 00000010610 14721613470 0015243 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\LogglyFormatter; use function array_key_exists; use CurlHandle; /** * Sends errors to Loggly. * * @author Przemek Sobstel <przemek@sobstel.org> * @author Adam Pancutt <adam@pancutt.com> * @author Gregory Barchard <gregory@barchard.net> */ class LogglyHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { protected const HOST = 'logs-01.loggly.com'; protected const ENDPOINT_SINGLE = 'inputs'; protected const ENDPOINT_BATCH = 'bulk'; /** * Caches the curl handlers for every given endpoint. * * @var resource[]|CurlHandle[] */ protected $curlHandlers = []; /** @var string */ protected $token; /** @var string[] */ protected $tag = []; /** * @param string $token API token supplied by Loggly * * @throws MissingExtensionException If the curl extension is missing */ public function __construct(string $token, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { if (!\extension_loaded('curl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The curl extension is needed to use the LogglyHandler'); } $this->token = $token; parent::__construct($level, $bubble); } /** * Loads and returns the shared curl handler for the given endpoint. * * @param string $endpoint * * @return resource|CurlHandle */ protected function getCurlHandler(string $endpoint) { if (!\array_key_exists($endpoint, $this->curlHandlers)) { $this->curlHandlers[$endpoint] = $this->loadCurlHandle($endpoint); } return $this->curlHandlers[$endpoint]; } /** * Starts a fresh curl session for the given endpoint and returns its handler. * * @param string $endpoint * * @return resource|CurlHandle */ private function loadCurlHandle(string $endpoint) { $url = \sprintf("https://%s/%s/%s/", static::HOST, $endpoint, $this->token); $ch = \curl_init(); \curl_setopt($ch, \CURLOPT_URL, $url); \curl_setopt($ch, \CURLOPT_POST, \true); \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, \true); return $ch; } /** * @param string[]|string $tag */ public function setTag($tag) : self { $tag = !empty($tag) ? $tag : []; $this->tag = \is_array($tag) ? $tag : [$tag]; return $this; } /** * @param string[]|string $tag */ public function addTag($tag) : self { if (!empty($tag)) { $tag = \is_array($tag) ? $tag : [$tag]; $this->tag = \array_unique(\array_merge($this->tag, $tag)); } return $this; } protected function write(array $record) : void { $this->send($record["formatted"], static::ENDPOINT_SINGLE); } public function handleBatch(array $records) : void { $level = $this->level; $records = \array_filter($records, function ($record) use($level) { return $record['level'] >= $level; }); if ($records) { $this->send($this->getFormatter()->formatBatch($records), static::ENDPOINT_BATCH); } } protected function send(string $data, string $endpoint) : void { $ch = $this->getCurlHandler($endpoint); $headers = ['Content-Type: application/json']; if (!empty($this->tag)) { $headers[] = 'X-LOGGLY-TAG: ' . \implode(',', $this->tag); } \curl_setopt($ch, \CURLOPT_POSTFIELDS, $data); \curl_setopt($ch, \CURLOPT_HTTPHEADER, $headers); \Google\Site_Kit_Dependencies\Monolog\Handler\Curl\Util::execute($ch, 5, \false); } protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LogglyFormatter(); } } monolog/src/Monolog/Handler/TelegramBotHandler.php 0000644 00000020404 14721613470 0016215 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use RuntimeException; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Handler send logs to Telegram using Telegram Bot API. * * How to use: * 1) Create telegram bot with https://telegram.me/BotFather * 2) Create a telegram channel where logs will be recorded. * 3) Add created bot from step 1 to the created channel from step 2. * * Use telegram bot API key from step 1 and channel name with '@' prefix from step 2 to create instance of TelegramBotHandler * * @link https://core.telegram.org/bots/api * * @author Mazur Alexandr <alexandrmazur96@gmail.com> * * @phpstan-import-type Record from \Monolog\Logger */ class TelegramBotHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { private const BOT_API = 'https://api.telegram.org/bot'; /** * The available values of parseMode according to the Telegram api documentation */ private const AVAILABLE_PARSE_MODES = ['HTML', 'MarkdownV2', 'Markdown']; /** * The maximum number of characters allowed in a message according to the Telegram api documentation */ private const MAX_MESSAGE_LENGTH = 4096; /** * Telegram bot access token provided by BotFather. * Create telegram bot with https://telegram.me/BotFather and use access token from it. * @var string */ private $apiKey; /** * Telegram channel name. * Since to start with '@' symbol as prefix. * @var string */ private $channel; /** * The kind of formatting that is used for the message. * See available options at https://core.telegram.org/bots/api#formatting-options * or in AVAILABLE_PARSE_MODES * @var ?string */ private $parseMode; /** * Disables link previews for links in the message. * @var ?bool */ private $disableWebPagePreview; /** * Sends the message silently. Users will receive a notification with no sound. * @var ?bool */ private $disableNotification; /** * True - split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages. * False - truncates a message that is too long. * @var bool */ private $splitLongMessages; /** * Adds 1-second delay between sending a split message (according to Telegram API to avoid 429 Too Many Requests). * @var bool */ private $delayBetweenMessages; /** * @param string $apiKey Telegram bot access token provided by BotFather * @param string $channel Telegram channel name * @param bool $splitLongMessages Split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages * @param bool $delayBetweenMessages Adds delay between sending a split message according to Telegram API * @throws MissingExtensionException */ public function __construct(string $apiKey, string $channel, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, ?string $parseMode = null, ?bool $disableWebPagePreview = null, ?bool $disableNotification = null, bool $splitLongMessages = \false, bool $delayBetweenMessages = \false) { if (!\extension_loaded('curl')) { throw new \Google\Site_Kit_Dependencies\Monolog\Handler\MissingExtensionException('The curl extension is needed to use the TelegramBotHandler'); } parent::__construct($level, $bubble); $this->apiKey = $apiKey; $this->channel = $channel; $this->setParseMode($parseMode); $this->disableWebPagePreview($disableWebPagePreview); $this->disableNotification($disableNotification); $this->splitLongMessages($splitLongMessages); $this->delayBetweenMessages($delayBetweenMessages); } public function setParseMode(?string $parseMode = null) : self { if ($parseMode !== null && !\in_array($parseMode, self::AVAILABLE_PARSE_MODES)) { throw new \InvalidArgumentException('Unknown parseMode, use one of these: ' . \implode(', ', self::AVAILABLE_PARSE_MODES) . '.'); } $this->parseMode = $parseMode; return $this; } public function disableWebPagePreview(?bool $disableWebPagePreview = null) : self { $this->disableWebPagePreview = $disableWebPagePreview; return $this; } public function disableNotification(?bool $disableNotification = null) : self { $this->disableNotification = $disableNotification; return $this; } /** * True - split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages. * False - truncates a message that is too long. * @param bool $splitLongMessages * @return $this */ public function splitLongMessages(bool $splitLongMessages = \false) : self { $this->splitLongMessages = $splitLongMessages; return $this; } /** * Adds 1-second delay between sending a split message (according to Telegram API to avoid 429 Too Many Requests). * @param bool $delayBetweenMessages * @return $this */ public function delayBetweenMessages(bool $delayBetweenMessages = \false) : self { $this->delayBetweenMessages = $delayBetweenMessages; return $this; } /** * {@inheritDoc} */ public function handleBatch(array $records) : void { /** @var Record[] $messages */ $messages = []; foreach ($records as $record) { if (!$this->isHandling($record)) { continue; } if ($this->processors) { /** @var Record $record */ $record = $this->processRecord($record); } $messages[] = $record; } if (!empty($messages)) { $this->send((string) $this->getFormatter()->formatBatch($messages)); } } /** * @inheritDoc */ protected function write(array $record) : void { $this->send($record['formatted']); } /** * Send request to @link https://api.telegram.org/bot on SendMessage action. * @param string $message */ protected function send(string $message) : void { $messages = $this->handleMessageLength($message); foreach ($messages as $key => $msg) { if ($this->delayBetweenMessages && $key > 0) { \sleep(1); } $this->sendCurl($msg); } } protected function sendCurl(string $message) : void { $ch = \curl_init(); $url = self::BOT_API . $this->apiKey . '/SendMessage'; \curl_setopt($ch, \CURLOPT_URL, $url); \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, \true); \curl_setopt($ch, \CURLOPT_SSL_VERIFYPEER, \true); \curl_setopt($ch, \CURLOPT_POSTFIELDS, \http_build_query(['text' => $message, 'chat_id' => $this->channel, 'parse_mode' => $this->parseMode, 'disable_web_page_preview' => $this->disableWebPagePreview, 'disable_notification' => $this->disableNotification])); $result = \Google\Site_Kit_Dependencies\Monolog\Handler\Curl\Util::execute($ch); if (!\is_string($result)) { throw new \RuntimeException('Telegram API error. Description: No response'); } $result = \json_decode($result, \true); if ($result['ok'] === \false) { throw new \RuntimeException('Telegram API error. Description: ' . $result['description']); } } /** * Handle a message that is too long: truncates or splits into several * @param string $message * @return string[] */ private function handleMessageLength(string $message) : array { $truncatedMarker = ' (...truncated)'; if (!$this->splitLongMessages && \strlen($message) > self::MAX_MESSAGE_LENGTH) { return [\Google\Site_Kit_Dependencies\Monolog\Utils::substr($message, 0, self::MAX_MESSAGE_LENGTH - \strlen($truncatedMarker)) . $truncatedMarker]; } return \str_split($message, self::MAX_MESSAGE_LENGTH); } } monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php 0000644 00000002735 14721613470 0016756 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Doctrine\CouchDB\CouchDBClient; /** * CouchDB handler for Doctrine CouchDB ODM * * @author Markus Bachmann <markus.bachmann@bachi.biz> */ class DoctrineCouchDBHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var CouchDBClient */ private $client; public function __construct(\Google\Site_Kit_Dependencies\Doctrine\CouchDB\CouchDBClient $client, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { $this->client = $client; parent::__construct($level, $bubble); } /** * {@inheritDoc} */ protected function write(array $record) : void { $this->client->postDocument($record['formatted']); } protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter(); } } monolog/src/Monolog/Handler/ElasticaHandler.php 0000644 00000007401 14721613470 0015537 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Elastica\Document; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\ElasticaFormatter; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Elastica\Client; use Google\Site_Kit_Dependencies\Elastica\Exception\ExceptionInterface; /** * Elastic Search handler * * Usage example: * * $client = new \Elastica\Client(); * $options = array( * 'index' => 'elastic_index_name', * 'type' => 'elastic_doc_type', Types have been removed in Elastica 7 * ); * $handler = new ElasticaHandler($client, $options); * $log = new Logger('application'); * $log->pushHandler($handler); * * @author Jelle Vink <jelle.vink@gmail.com> */ class ElasticaHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** * @var Client */ protected $client; /** * @var mixed[] Handler config options */ protected $options = []; /** * @param Client $client Elastica Client object * @param mixed[] $options Handler configuration */ public function __construct(\Google\Site_Kit_Dependencies\Elastica\Client $client, array $options = [], $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { parent::__construct($level, $bubble); $this->client = $client; $this->options = \array_merge([ 'index' => 'monolog', // Elastic index name 'type' => 'record', // Elastic document type 'ignore_error' => \false, ], $options); } /** * {@inheritDoc} */ protected function write(array $record) : void { $this->bulkSend([$record['formatted']]); } /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { if ($formatter instanceof \Google\Site_Kit_Dependencies\Monolog\Formatter\ElasticaFormatter) { return parent::setFormatter($formatter); } throw new \InvalidArgumentException('ElasticaHandler is only compatible with ElasticaFormatter'); } /** * @return mixed[] */ public function getOptions() : array { return $this->options; } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\ElasticaFormatter($this->options['index'], $this->options['type']); } /** * {@inheritDoc} */ public function handleBatch(array $records) : void { $documents = $this->getFormatter()->formatBatch($records); $this->bulkSend($documents); } /** * Use Elasticsearch bulk API to send list of documents * * @param Document[] $documents * * @throws \RuntimeException */ protected function bulkSend(array $documents) : void { try { $this->client->addDocuments($documents); } catch (\Google\Site_Kit_Dependencies\Elastica\Exception\ExceptionInterface $e) { if (!$this->options['ignore_error']) { throw new \RuntimeException("Error sending messages to Elasticsearch", 0, $e); } } } } monolog/src/Monolog/Handler/FingersCrossedHandler.php 0000644 00000022470 14721613470 0016735 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; use Google\Site_Kit_Dependencies\Monolog\Handler\FingersCrossed\ActivationStrategyInterface; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\ResettableInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Buffers all records until a certain level is reached * * The advantage of this approach is that you don't get any clutter in your log files. * Only requests which actually trigger an error (or whatever your actionLevel is) will be * in the logs, but they will contain all records, not only those above the level threshold. * * You can then have a passthruLevel as well which means that at the end of the request, * even if it did not get activated, it will still send through log records of e.g. at least a * warning level. * * You can find the various activation strategies in the * Monolog\Handler\FingersCrossed\ namespace. * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ class FingersCrossedHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\Handler implements \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface, \Google\Site_Kit_Dependencies\Monolog\ResettableInterface, \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface { use ProcessableHandlerTrait; /** * @var callable|HandlerInterface * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface */ protected $handler; /** @var ActivationStrategyInterface */ protected $activationStrategy; /** @var bool */ protected $buffering = \true; /** @var int */ protected $bufferSize; /** @var Record[] */ protected $buffer = []; /** @var bool */ protected $stopBuffering; /** * @var ?int * @phpstan-var ?Level */ protected $passthruLevel; /** @var bool */ protected $bubble; /** * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler * * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler). * @param int|string|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action, or a level name/value at which the handler is activated * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $stopBuffering Whether the handler should stop buffering after being triggered (default true) * @param int|string $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered * * @phpstan-param Level|LevelName|LogLevel::* $passthruLevel * @phpstan-param Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy */ public function __construct($handler, $activationStrategy = null, int $bufferSize = 0, bool $bubble = \true, bool $stopBuffering = \true, $passthruLevel = null) { if (null === $activationStrategy) { $activationStrategy = new \Google\Site_Kit_Dependencies\Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy(\Google\Site_Kit_Dependencies\Monolog\Logger::WARNING); } // convert simple int activationStrategy to an object if (!$activationStrategy instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FingersCrossed\ActivationStrategyInterface) { $activationStrategy = new \Google\Site_Kit_Dependencies\Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy($activationStrategy); } $this->handler = $handler; $this->activationStrategy = $activationStrategy; $this->bufferSize = $bufferSize; $this->bubble = $bubble; $this->stopBuffering = $stopBuffering; if ($passthruLevel !== null) { $this->passthruLevel = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($passthruLevel); } if (!$this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface && !\is_callable($this->handler)) { throw new \RuntimeException("The given handler (" . \json_encode($this->handler) . ") is not a callable nor a Monolog\\Handler\\HandlerInterface object"); } } /** * {@inheritDoc} */ public function isHandling(array $record) : bool { return \true; } /** * Manually activate this logger regardless of the activation strategy */ public function activate() : void { if ($this->stopBuffering) { $this->buffering = \false; } $this->getHandler(\end($this->buffer) ?: null)->handleBatch($this->buffer); $this->buffer = []; } /** * {@inheritDoc} */ public function handle(array $record) : bool { if ($this->processors) { /** @var Record $record */ $record = $this->processRecord($record); } if ($this->buffering) { $this->buffer[] = $record; if ($this->bufferSize > 0 && \count($this->buffer) > $this->bufferSize) { \array_shift($this->buffer); } if ($this->activationStrategy->isHandlerActivated($record)) { $this->activate(); } } else { $this->getHandler($record)->handle($record); } return \false === $this->bubble; } /** * {@inheritDoc} */ public function close() : void { $this->flushBuffer(); $this->getHandler()->close(); } public function reset() { $this->flushBuffer(); $this->resetProcessors(); if ($this->getHandler() instanceof \Google\Site_Kit_Dependencies\Monolog\ResettableInterface) { $this->getHandler()->reset(); } } /** * Clears the buffer without flushing any messages down to the wrapped handler. * * It also resets the handler to its initial buffering state. */ public function clear() : void { $this->buffer = []; $this->reset(); } /** * Resets the state of the handler. Stops forwarding records to the wrapped handler. */ private function flushBuffer() : void { if (null !== $this->passthruLevel) { $level = $this->passthruLevel; $this->buffer = \array_filter($this->buffer, function ($record) use($level) { return $record['level'] >= $level; }); if (\count($this->buffer) > 0) { $this->getHandler(\end($this->buffer))->handleBatch($this->buffer); } } $this->buffer = []; $this->buffering = \true; } /** * Return the nested handler * * If the handler was provided as a factory callable, this will trigger the handler's instantiation. * * @return HandlerInterface * * @phpstan-param Record $record */ public function getHandler(?array $record = null) { if (!$this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface) { $this->handler = ($this->handler)($record, $this); if (!$this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } } return $this->handler; } /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { $handler = $this->getHandler(); if ($handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { $handler->setFormatter($formatter); return $this; } throw new \UnexpectedValueException('The nested handler of type ' . \get_class($handler) . ' does not support formatters.'); } /** * {@inheritDoc} */ public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { $handler = $this->getHandler(); if ($handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { return $handler->getFormatter(); } throw new \UnexpectedValueException('The nested handler of type ' . \get_class($handler) . ' does not support formatters.'); } } monolog/src/Monolog/Handler/BufferHandler.php 0000644 00000012206 14721613470 0015222 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\ResettableInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Buffers all records until closing the handler and then pass them as batch. * * This is useful for a MailHandler to send only one mail per request instead of * sending one per log message. * * @author Christophe Coevoet <stof@notk.org> * * @phpstan-import-type Record from \Monolog\Logger */ class BufferHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractHandler implements \Google\Site_Kit_Dependencies\Monolog\Handler\ProcessableHandlerInterface, \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface { use ProcessableHandlerTrait; /** @var HandlerInterface */ protected $handler; /** @var int */ protected $bufferSize = 0; /** @var int */ protected $bufferLimit; /** @var bool */ protected $flushOnOverflow; /** @var Record[] */ protected $buffer = []; /** @var bool */ protected $initialized = \false; /** * @param HandlerInterface $handler Handler. * @param int $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. * @param bool $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded */ public function __construct(\Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface $handler, int $bufferLimit = 0, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, bool $flushOnOverflow = \false) { parent::__construct($level, $bubble); $this->handler = $handler; $this->bufferLimit = $bufferLimit; $this->flushOnOverflow = $flushOnOverflow; } /** * {@inheritDoc} */ public function handle(array $record) : bool { if ($record['level'] < $this->level) { return \false; } if (!$this->initialized) { // __destructor() doesn't get called on Fatal errors \register_shutdown_function([$this, 'close']); $this->initialized = \true; } if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) { if ($this->flushOnOverflow) { $this->flush(); } else { \array_shift($this->buffer); $this->bufferSize--; } } if ($this->processors) { /** @var Record $record */ $record = $this->processRecord($record); } $this->buffer[] = $record; $this->bufferSize++; return \false === $this->bubble; } public function flush() : void { if ($this->bufferSize === 0) { return; } $this->handler->handleBatch($this->buffer); $this->clear(); } public function __destruct() { // suppress the parent behavior since we already have register_shutdown_function() // to call close(), and the reference contained there will prevent this from being // GC'd until the end of the request } /** * {@inheritDoc} */ public function close() : void { $this->flush(); $this->handler->close(); } /** * Clears the buffer without flushing any messages down to the wrapped handler. */ public function clear() : void { $this->bufferSize = 0; $this->buffer = []; } public function reset() { $this->flush(); parent::reset(); $this->resetProcessors(); if ($this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\ResettableInterface) { $this->handler->reset(); } } /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { if ($this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { $this->handler->setFormatter($formatter); return $this; } throw new \UnexpectedValueException('The nested handler of type ' . \get_class($this->handler) . ' does not support formatters.'); } /** * {@inheritDoc} */ public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { if ($this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { return $this->handler->getFormatter(); } throw new \UnexpectedValueException('The nested handler of type ' . \get_class($this->handler) . ' does not support formatters.'); } } monolog/src/Monolog/Handler/AbstractSyslogHandler.php 0000644 00000007714 14721613470 0016765 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter; /** * Common syslog functionality * * @phpstan-import-type Level from \Monolog\Logger */ abstract class AbstractSyslogHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var int */ protected $facility; /** * Translates Monolog log levels to syslog log priorities. * @var array * @phpstan-var array<Level, int> */ protected $logLevels = [\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG => \LOG_DEBUG, \Google\Site_Kit_Dependencies\Monolog\Logger::INFO => \LOG_INFO, \Google\Site_Kit_Dependencies\Monolog\Logger::NOTICE => \LOG_NOTICE, \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING => \LOG_WARNING, \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR => \LOG_ERR, \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL => \LOG_CRIT, \Google\Site_Kit_Dependencies\Monolog\Logger::ALERT => \LOG_ALERT, \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY => \LOG_EMERG]; /** * List of valid log facility names. * @var array<string, int> */ protected $facilities = ['auth' => \LOG_AUTH, 'authpriv' => \LOG_AUTHPRIV, 'cron' => \LOG_CRON, 'daemon' => \LOG_DAEMON, 'kern' => \LOG_KERN, 'lpr' => \LOG_LPR, 'mail' => \LOG_MAIL, 'news' => \LOG_NEWS, 'syslog' => \LOG_SYSLOG, 'user' => \LOG_USER, 'uucp' => \LOG_UUCP]; /** * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant */ public function __construct($facility = \LOG_USER, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { parent::__construct($level, $bubble); if (!\defined('PHP_WINDOWS_VERSION_BUILD')) { $this->facilities['local0'] = \LOG_LOCAL0; $this->facilities['local1'] = \LOG_LOCAL1; $this->facilities['local2'] = \LOG_LOCAL2; $this->facilities['local3'] = \LOG_LOCAL3; $this->facilities['local4'] = \LOG_LOCAL4; $this->facilities['local5'] = \LOG_LOCAL5; $this->facilities['local6'] = \LOG_LOCAL6; $this->facilities['local7'] = \LOG_LOCAL7; } else { $this->facilities['local0'] = 128; // LOG_LOCAL0 $this->facilities['local1'] = 136; // LOG_LOCAL1 $this->facilities['local2'] = 144; // LOG_LOCAL2 $this->facilities['local3'] = 152; // LOG_LOCAL3 $this->facilities['local4'] = 160; // LOG_LOCAL4 $this->facilities['local5'] = 168; // LOG_LOCAL5 $this->facilities['local6'] = 176; // LOG_LOCAL6 $this->facilities['local7'] = 184; // LOG_LOCAL7 } // convert textual description of facility to syslog constant if (\is_string($facility) && \array_key_exists(\strtolower($facility), $this->facilities)) { $facility = $this->facilities[\strtolower($facility)]; } elseif (!\in_array($facility, \array_values($this->facilities), \true)) { throw new \UnexpectedValueException('Unknown facility value "' . $facility . '" given'); } $this->facility = $facility; } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\LineFormatter('%channel%.%level_name%: %message% %context% %extra%'); } } monolog/src/Monolog/Handler/ElasticsearchHandler.php 0000644 00000016164 14721613470 0016572 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Elastic\Elasticsearch\Response\Elasticsearch; use Throwable; use RuntimeException; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\ElasticsearchFormatter; use InvalidArgumentException; use Google\Site_Kit_Dependencies\Elasticsearch\Common\Exceptions\RuntimeException as ElasticsearchRuntimeException; use Google\Site_Kit_Dependencies\Elasticsearch\Client; use Google\Site_Kit_Dependencies\Elastic\Elasticsearch\Exception\InvalidArgumentException as ElasticInvalidArgumentException; use Google\Site_Kit_Dependencies\Elastic\Elasticsearch\Client as Client8; /** * Elasticsearch handler * * @link https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html * * Simple usage example: * * $client = \Elasticsearch\ClientBuilder::create() * ->setHosts($hosts) * ->build(); * * $options = array( * 'index' => 'elastic_index_name', * 'type' => 'elastic_doc_type', * ); * $handler = new ElasticsearchHandler($client, $options); * $log = new Logger('application'); * $log->pushHandler($handler); * * @author Avtandil Kikabidze <akalongman@gmail.com> */ class ElasticsearchHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** * @var Client|Client8 */ protected $client; /** * @var mixed[] Handler config options */ protected $options = []; /** * @var bool */ private $needsType; /** * @param Client|Client8 $client Elasticsearch Client object * @param mixed[] $options Handler configuration */ public function __construct($client, array $options = [], $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { if (!$client instanceof \Google\Site_Kit_Dependencies\Elasticsearch\Client && !$client instanceof \Google\Site_Kit_Dependencies\Elastic\Elasticsearch\Client) { throw new \TypeError('Elasticsearch\\Client or Elastic\\Elasticsearch\\Client instance required'); } parent::__construct($level, $bubble); $this->client = $client; $this->options = \array_merge([ 'index' => 'monolog', // Elastic index name 'type' => '_doc', // Elastic document type 'ignore_error' => \false, ], $options); if ($client instanceof \Google\Site_Kit_Dependencies\Elastic\Elasticsearch\Client || $client::VERSION[0] === '7') { $this->needsType = \false; // force the type to _doc for ES8/ES7 $this->options['type'] = '_doc'; } else { $this->needsType = \true; } } /** * {@inheritDoc} */ protected function write(array $record) : void { $this->bulkSend([$record['formatted']]); } /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { if ($formatter instanceof \Google\Site_Kit_Dependencies\Monolog\Formatter\ElasticsearchFormatter) { return parent::setFormatter($formatter); } throw new \InvalidArgumentException('ElasticsearchHandler is only compatible with ElasticsearchFormatter'); } /** * Getter options * * @return mixed[] */ public function getOptions() : array { return $this->options; } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\ElasticsearchFormatter($this->options['index'], $this->options['type']); } /** * {@inheritDoc} */ public function handleBatch(array $records) : void { $documents = $this->getFormatter()->formatBatch($records); $this->bulkSend($documents); } /** * Use Elasticsearch bulk API to send list of documents * * @param array[] $records Records + _index/_type keys * @throws \RuntimeException */ protected function bulkSend(array $records) : void { try { $params = ['body' => []]; foreach ($records as $record) { $params['body'][] = ['index' => $this->needsType ? ['_index' => $record['_index'], '_type' => $record['_type']] : ['_index' => $record['_index']]]; unset($record['_index'], $record['_type']); $params['body'][] = $record; } /** @var Elasticsearch */ $responses = $this->client->bulk($params); if ($responses['errors'] === \true) { throw $this->createExceptionFromResponses($responses); } } catch (\Throwable $e) { if (!$this->options['ignore_error']) { throw new \RuntimeException('Error sending messages to Elasticsearch', 0, $e); } } } /** * Creates elasticsearch exception from responses array * * Only the first error is converted into an exception. * * @param mixed[]|Elasticsearch $responses returned by $this->client->bulk() */ protected function createExceptionFromResponses($responses) : \Throwable { foreach ($responses['items'] ?? [] as $item) { if (isset($item['index']['error'])) { return $this->createExceptionFromError($item['index']['error']); } } if (\class_exists(\Google\Site_Kit_Dependencies\Elastic\Elasticsearch\Exception\InvalidArgumentException::class)) { return new \Google\Site_Kit_Dependencies\Elastic\Elasticsearch\Exception\InvalidArgumentException('Elasticsearch failed to index one or more records.'); } return new \Google\Site_Kit_Dependencies\Elasticsearch\Common\Exceptions\RuntimeException('Elasticsearch failed to index one or more records.'); } /** * Creates elasticsearch exception from error array * * @param mixed[] $error */ protected function createExceptionFromError(array $error) : \Throwable { $previous = isset($error['caused_by']) ? $this->createExceptionFromError($error['caused_by']) : null; if (\class_exists(\Google\Site_Kit_Dependencies\Elastic\Elasticsearch\Exception\InvalidArgumentException::class)) { return new \Google\Site_Kit_Dependencies\Elastic\Elasticsearch\Exception\InvalidArgumentException($error['type'] . ': ' . $error['reason'], 0, $previous); } return new \Google\Site_Kit_Dependencies\Elasticsearch\Common\Exceptions\RuntimeException($error['type'] . ': ' . $error['reason'], 0, $previous); } } monolog/src/Monolog/Handler/SqsHandler.php 0000644 00000003746 14721613470 0014570 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Aws\Sqs\SqsClient; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Writes to any sqs queue. * * @author Martijn van Calker <git@amvc.nl> */ class SqsHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** 256 KB in bytes - maximum message size in SQS */ protected const MAX_MESSAGE_SIZE = 262144; /** 100 KB in bytes - head message size for new error log */ protected const HEAD_MESSAGE_SIZE = 102400; /** @var SqsClient */ private $client; /** @var string */ private $queueUrl; public function __construct(\Google\Site_Kit_Dependencies\Aws\Sqs\SqsClient $sqsClient, string $queueUrl, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { parent::__construct($level, $bubble); $this->client = $sqsClient; $this->queueUrl = $queueUrl; } /** * {@inheritDoc} */ protected function write(array $record) : void { if (!isset($record['formatted']) || 'string' !== \gettype($record['formatted'])) { throw new \InvalidArgumentException('SqsHandler accepts only formatted records as a string' . \Google\Site_Kit_Dependencies\Monolog\Utils::getRecordMessageForException($record)); } $messageBody = $record['formatted']; if (\strlen($messageBody) >= static::MAX_MESSAGE_SIZE) { $messageBody = \Google\Site_Kit_Dependencies\Monolog\Utils::substr($messageBody, 0, static::HEAD_MESSAGE_SIZE); } $this->client->sendMessage(['QueueUrl' => $this->queueUrl, 'MessageBody' => $messageBody]); } } monolog/src/Monolog/Handler/OverflowHandler.php 0000644 00000012155 14721613470 0015617 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Handler to only pass log messages when a certain threshold of number of messages is reached. * * This can be useful in cases of processing a batch of data, but you're for example only interested * in case it fails catastrophically instead of a warning for 1 or 2 events. Worse things can happen, right? * * Usage example: * * ``` * $log = new Logger('application'); * $handler = new SomeHandler(...) * * // Pass all warnings to the handler when more than 10 & all error messages when more then 5 * $overflow = new OverflowHandler($handler, [Logger::WARNING => 10, Logger::ERROR => 5]); * * $log->pushHandler($overflow); *``` * * @author Kris Buist <krisbuist@gmail.com> */ class OverflowHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractHandler implements \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface { /** @var HandlerInterface */ private $handler; /** @var int[] */ private $thresholdMap = [\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG => 0, \Google\Site_Kit_Dependencies\Monolog\Logger::INFO => 0, \Google\Site_Kit_Dependencies\Monolog\Logger::NOTICE => 0, \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING => 0, \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR => 0, \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL => 0, \Google\Site_Kit_Dependencies\Monolog\Logger::ALERT => 0, \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY => 0]; /** * Buffer of all messages passed to the handler before the threshold was reached * * @var mixed[][] */ private $buffer = []; /** * @param HandlerInterface $handler * @param int[] $thresholdMap Dictionary of logger level => threshold */ public function __construct(\Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface $handler, array $thresholdMap = [], $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { $this->handler = $handler; foreach ($thresholdMap as $thresholdLevel => $threshold) { $this->thresholdMap[$thresholdLevel] = $threshold; } parent::__construct($level, $bubble); } /** * Handles a record. * * All records may be passed to this method, and the handler should discard * those that it does not want to handle. * * The return value of this function controls the bubbling process of the handler stack. * Unless the bubbling is interrupted (by returning true), the Logger class will keep on * calling further handlers in the stack with a given log record. * * {@inheritDoc} */ public function handle(array $record) : bool { if ($record['level'] < $this->level) { return \false; } $level = $record['level']; if (!isset($this->thresholdMap[$level])) { $this->thresholdMap[$level] = 0; } if ($this->thresholdMap[$level] > 0) { // The overflow threshold is not yet reached, so we're buffering the record and lowering the threshold by 1 $this->thresholdMap[$level]--; $this->buffer[$level][] = $record; return \false === $this->bubble; } if ($this->thresholdMap[$level] == 0) { // This current message is breaking the threshold. Flush the buffer and continue handling the current record foreach ($this->buffer[$level] ?? [] as $buffered) { $this->handler->handle($buffered); } $this->thresholdMap[$level]--; unset($this->buffer[$level]); } $this->handler->handle($record); return \false === $this->bubble; } /** * {@inheritDoc} */ public function setFormatter(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface $formatter) : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { if ($this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { $this->handler->setFormatter($formatter); return $this; } throw new \UnexpectedValueException('The nested handler of type ' . \get_class($this->handler) . ' does not support formatters.'); } /** * {@inheritDoc} */ public function getFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { if ($this->handler instanceof \Google\Site_Kit_Dependencies\Monolog\Handler\FormattableHandlerInterface) { return $this->handler->getFormatter(); } throw new \UnexpectedValueException('The nested handler of type ' . \get_class($this->handler) . ' does not support formatters.'); } } monolog/src/Monolog/Handler/FirePHPHandler.php 0000644 00000012503 14721613470 0015246 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\WildfireFormatter; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol. * * @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com> * * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FirePHPHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { use WebRequestRecognizerTrait; /** * WildFire JSON header message format */ protected const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'; /** * FirePHP structure for parsing messages & their presentation */ protected const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'; /** * Must reference a "known" plugin, otherwise headers won't display in FirePHP */ protected const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3'; /** * Header prefix for Wildfire to recognize & parse headers */ protected const HEADER_PREFIX = 'X-Wf'; /** * Whether or not Wildfire vendor-specific headers have been generated & sent yet * @var bool */ protected static $initialized = \false; /** * Shared static message index between potentially multiple handlers * @var int */ protected static $messageIndex = 1; /** @var bool */ protected static $sendHeaders = \true; /** * Base header creation function used by init headers & record headers * * @param array<int|string> $meta Wildfire Plugin, Protocol & Structure Indexes * @param string $message Log message * * @return array<string, string> Complete header string ready for the client as key and message as value * * @phpstan-return non-empty-array<string, string> */ protected function createHeader(array $meta, string $message) : array { $header = \sprintf('%s-%s', static::HEADER_PREFIX, \join('-', $meta)); return [$header => $message]; } /** * Creates message header from record * * @return array<string, string> * * @phpstan-return non-empty-array<string, string> * * @see createHeader() * * @phpstan-param FormattedRecord $record */ protected function createRecordHeader(array $record) : array { // Wildfire is extensible to support multiple protocols & plugins in a single request, // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake. return $this->createHeader([1, 1, 1, self::$messageIndex++], $record['formatted']); } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\WildfireFormatter(); } /** * Wildfire initialization headers to enable message parsing * * @see createHeader() * @see sendHeader() * * @return array<string, string> */ protected function getInitHeaders() : array { // Initial payload consists of required headers for Wildfire return \array_merge($this->createHeader(['Protocol', 1], static::PROTOCOL_URI), $this->createHeader([1, 'Structure', 1], static::STRUCTURE_URI), $this->createHeader([1, 'Plugin', 1], static::PLUGIN_URI)); } /** * Send header string to the client */ protected function sendHeader(string $header, string $content) : void { if (!\headers_sent() && self::$sendHeaders) { \header(\sprintf('%s: %s', $header, $content)); } } /** * Creates & sends header for a record, ensuring init headers have been sent prior * * @see sendHeader() * @see sendInitHeaders() */ protected function write(array $record) : void { if (!self::$sendHeaders || !$this->isWebRequest()) { return; } // WildFire-specific headers must be sent prior to any messages if (!self::$initialized) { self::$initialized = \true; self::$sendHeaders = $this->headersAccepted(); if (!self::$sendHeaders) { return; } foreach ($this->getInitHeaders() as $header => $content) { $this->sendHeader($header, $content); } } $header = $this->createRecordHeader($record); if (\trim(\current($header)) !== '') { $this->sendHeader(\key($header), \current($header)); } } /** * Verifies if the headers are accepted by the current user agent */ protected function headersAccepted() : bool { if (!empty($_SERVER['HTTP_USER_AGENT']) && \preg_match('{\\bFirePHP/\\d+\\.\\d+\\b}', $_SERVER['HTTP_USER_AGENT'])) { return \true; } return isset($_SERVER['HTTP_X_FIREPHP_VERSION']); } } monolog/src/Monolog/Handler/MailHandler.php 0000644 00000005007 14721613470 0014674 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\HtmlFormatter; /** * Base class for all mail handlers * * @author Gyula Sallai * * @phpstan-import-type Record from \Monolog\Logger */ abstract class MailHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** * {@inheritDoc} */ public function handleBatch(array $records) : void { $messages = []; foreach ($records as $record) { if ($record['level'] < $this->level) { continue; } /** @var Record $message */ $message = $this->processRecord($record); $messages[] = $message; } if (!empty($messages)) { $this->send((string) $this->getFormatter()->formatBatch($messages), $messages); } } /** * Send a mail with the given content * * @param string $content formatted email body to be sent * @param array $records the array of log records that formed this content * * @phpstan-param Record[] $records */ protected abstract function send(string $content, array $records) : void; /** * {@inheritDoc} */ protected function write(array $record) : void { $this->send((string) $record['formatted'], [$record]); } /** * @phpstan-param non-empty-array<Record> $records * @phpstan-return Record */ protected function getHighestRecord(array $records) : array { $highestRecord = null; foreach ($records as $record) { if ($highestRecord === null || $highestRecord['level'] < $record['level']) { $highestRecord = $record; } } return $highestRecord; } protected function isHtmlBody(string $body) : bool { return ($body[0] ?? null) === '<'; } /** * Gets the default formatter. * * @return FormatterInterface */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\HtmlFormatter(); } } monolog/src/Monolog/Handler/SocketHandler.php 0000644 00000030133 14721613470 0015240 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Stores to any socket - uses fsockopen() or pfsockopen(). * * @author Pablo de Leon Belloc <pablolb@gmail.com> * @see http://php.net/manual/en/function.fsockopen.php * * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class SocketHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var string */ private $connectionString; /** @var float */ private $connectionTimeout; /** @var resource|null */ private $resource; /** @var float */ private $timeout; /** @var float */ private $writingTimeout; /** @var ?int */ private $lastSentBytes = null; /** @var ?int */ private $chunkSize; /** @var bool */ private $persistent; /** @var ?int */ private $errno = null; /** @var ?string */ private $errstr = null; /** @var ?float */ private $lastWritingAt = null; /** * @param string $connectionString Socket connection string * @param bool $persistent Flag to enable/disable persistent connections * @param float $timeout Socket timeout to wait until the request is being aborted * @param float $writingTimeout Socket timeout to wait until the request should've been sent/written * @param float|null $connectionTimeout Socket connect timeout to wait until the connection should've been * established * @param int|null $chunkSize Sets the chunk size. Only has effect during connection in the writing cycle * * @throws \InvalidArgumentException If an invalid timeout value (less than 0) is passed. */ public function __construct(string $connectionString, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true, bool $persistent = \false, float $timeout = 0.0, float $writingTimeout = 10.0, ?float $connectionTimeout = null, ?int $chunkSize = null) { parent::__construct($level, $bubble); $this->connectionString = $connectionString; if ($connectionTimeout !== null) { $this->validateTimeout($connectionTimeout); } $this->connectionTimeout = $connectionTimeout ?? (float) \ini_get('default_socket_timeout'); $this->persistent = $persistent; $this->validateTimeout($timeout); $this->timeout = $timeout; $this->validateTimeout($writingTimeout); $this->writingTimeout = $writingTimeout; $this->chunkSize = $chunkSize; } /** * Connect (if necessary) and write to the socket * * {@inheritDoc} * * @throws \UnexpectedValueException * @throws \RuntimeException */ protected function write(array $record) : void { $this->connectIfNotConnected(); $data = $this->generateDataStream($record); $this->writeToSocket($data); } /** * We will not close a PersistentSocket instance so it can be reused in other requests. */ public function close() : void { if (!$this->isPersistent()) { $this->closeSocket(); } } /** * Close socket, if open */ public function closeSocket() : void { if (\is_resource($this->resource)) { \fclose($this->resource); $this->resource = null; } } /** * Set socket connection to be persistent. It only has effect before the connection is initiated. */ public function setPersistent(bool $persistent) : self { $this->persistent = $persistent; return $this; } /** * Set connection timeout. Only has effect before we connect. * * @see http://php.net/manual/en/function.fsockopen.php */ public function setConnectionTimeout(float $seconds) : self { $this->validateTimeout($seconds); $this->connectionTimeout = $seconds; return $this; } /** * Set write timeout. Only has effect before we connect. * * @see http://php.net/manual/en/function.stream-set-timeout.php */ public function setTimeout(float $seconds) : self { $this->validateTimeout($seconds); $this->timeout = $seconds; return $this; } /** * Set writing timeout. Only has effect during connection in the writing cycle. * * @param float $seconds 0 for no timeout */ public function setWritingTimeout(float $seconds) : self { $this->validateTimeout($seconds); $this->writingTimeout = $seconds; return $this; } /** * Set chunk size. Only has effect during connection in the writing cycle. */ public function setChunkSize(int $bytes) : self { $this->chunkSize = $bytes; return $this; } /** * Get current connection string */ public function getConnectionString() : string { return $this->connectionString; } /** * Get persistent setting */ public function isPersistent() : bool { return $this->persistent; } /** * Get current connection timeout setting */ public function getConnectionTimeout() : float { return $this->connectionTimeout; } /** * Get current in-transfer timeout */ public function getTimeout() : float { return $this->timeout; } /** * Get current local writing timeout * * @return float */ public function getWritingTimeout() : float { return $this->writingTimeout; } /** * Get current chunk size */ public function getChunkSize() : ?int { return $this->chunkSize; } /** * Check to see if the socket is currently available. * * UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details. */ public function isConnected() : bool { return \is_resource($this->resource) && !\feof($this->resource); // on TCP - other party can close connection. } /** * Wrapper to allow mocking * * @return resource|false */ protected function pfsockopen() { return @\pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout); } /** * Wrapper to allow mocking * * @return resource|false */ protected function fsockopen() { return @\fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout); } /** * Wrapper to allow mocking * * @see http://php.net/manual/en/function.stream-set-timeout.php * * @return bool */ protected function streamSetTimeout() { $seconds = \floor($this->timeout); $microseconds = \round(($this->timeout - $seconds) * 1000000.0); if (!\is_resource($this->resource)) { throw new \LogicException('streamSetTimeout called but $this->resource is not a resource'); } return \stream_set_timeout($this->resource, (int) $seconds, (int) $microseconds); } /** * Wrapper to allow mocking * * @see http://php.net/manual/en/function.stream-set-chunk-size.php * * @return int|bool */ protected function streamSetChunkSize() { if (!\is_resource($this->resource)) { throw new \LogicException('streamSetChunkSize called but $this->resource is not a resource'); } if (null === $this->chunkSize) { throw new \LogicException('streamSetChunkSize called but $this->chunkSize is not set'); } return \stream_set_chunk_size($this->resource, $this->chunkSize); } /** * Wrapper to allow mocking * * @return int|bool */ protected function fwrite(string $data) { if (!\is_resource($this->resource)) { throw new \LogicException('fwrite called but $this->resource is not a resource'); } return @\fwrite($this->resource, $data); } /** * Wrapper to allow mocking * * @return mixed[]|bool */ protected function streamGetMetadata() { if (!\is_resource($this->resource)) { throw new \LogicException('streamGetMetadata called but $this->resource is not a resource'); } return \stream_get_meta_data($this->resource); } private function validateTimeout(float $value) : void { if ($value < 0) { throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got {$value})"); } } private function connectIfNotConnected() : void { if ($this->isConnected()) { return; } $this->connect(); } /** * @phpstan-param FormattedRecord $record */ protected function generateDataStream(array $record) : string { return (string) $record['formatted']; } /** * @return resource|null */ protected function getResource() { return $this->resource; } private function connect() : void { $this->createSocketResource(); $this->setSocketTimeout(); $this->setStreamChunkSize(); } private function createSocketResource() : void { if ($this->isPersistent()) { $resource = $this->pfsockopen(); } else { $resource = $this->fsockopen(); } if (\is_bool($resource)) { throw new \UnexpectedValueException("Failed connecting to {$this->connectionString} ({$this->errno}: {$this->errstr})"); } $this->resource = $resource; } private function setSocketTimeout() : void { if (!$this->streamSetTimeout()) { throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()"); } } private function setStreamChunkSize() : void { if ($this->chunkSize && !$this->streamSetChunkSize()) { throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()"); } } private function writeToSocket(string $data) : void { $length = \strlen($data); $sent = 0; $this->lastSentBytes = $sent; while ($this->isConnected() && $sent < $length) { if (0 == $sent) { $chunk = $this->fwrite($data); } else { $chunk = $this->fwrite(\substr($data, $sent)); } if ($chunk === \false) { throw new \RuntimeException("Could not write to socket"); } $sent += $chunk; $socketInfo = $this->streamGetMetadata(); if (\is_array($socketInfo) && $socketInfo['timed_out']) { throw new \RuntimeException("Write timed-out"); } if ($this->writingIsTimedOut($sent)) { throw new \RuntimeException("Write timed-out, no data sent for `{$this->writingTimeout}` seconds, probably we got disconnected (sent {$sent} of {$length})"); } } if (!$this->isConnected() && $sent < $length) { throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent {$sent} of {$length})"); } } private function writingIsTimedOut(int $sent) : bool { // convert to ms if (0.0 == $this->writingTimeout) { return \false; } if ($sent !== $this->lastSentBytes) { $this->lastWritingAt = \microtime(\true); $this->lastSentBytes = $sent; return \false; } else { \usleep(100); } if (\microtime(\true) - $this->lastWritingAt >= $this->writingTimeout) { $this->closeSocket(); return \true; } return \false; } } monolog/src/Monolog/Handler/MongoDBHandler.php 0000644 00000005645 14721613470 0015307 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; use MongoDB\Driver\BulkWrite; use MongoDB\Driver\Manager; use Google\Site_Kit_Dependencies\MongoDB\Client; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; use Google\Site_Kit_Dependencies\Monolog\Formatter\MongoDBFormatter; /** * Logs to a MongoDB database. * * Usage example: * * $log = new \Monolog\Logger('application'); * $client = new \MongoDB\Client('mongodb://localhost:27017'); * $mongodb = new \Monolog\Handler\MongoDBHandler($client, 'logs', 'prod'); * $log->pushHandler($mongodb); * * The above examples uses the MongoDB PHP library's client class; however, the * MongoDB\Driver\Manager class from ext-mongodb is also supported. */ class MongoDBHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\AbstractProcessingHandler { /** @var \MongoDB\Collection */ private $collection; /** @var Client|Manager */ private $manager; /** @var string */ private $namespace; /** * Constructor. * * @param Client|Manager $mongodb MongoDB library or driver client * @param string $database Database name * @param string $collection Collection name */ public function __construct($mongodb, string $database, string $collection, $level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, bool $bubble = \true) { if (!($mongodb instanceof \Google\Site_Kit_Dependencies\MongoDB\Client || $mongodb instanceof \MongoDB\Driver\Manager)) { throw new \InvalidArgumentException('MongoDB\\Client or MongoDB\\Driver\\Manager instance required'); } if ($mongodb instanceof \Google\Site_Kit_Dependencies\MongoDB\Client) { $this->collection = $mongodb->selectCollection($database, $collection); } else { $this->manager = $mongodb; $this->namespace = $database . '.' . $collection; } parent::__construct($level, $bubble); } protected function write(array $record) : void { if (isset($this->collection)) { $this->collection->insertOne($record['formatted']); } if (isset($this->manager, $this->namespace)) { $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert($record["formatted"]); $this->manager->executeBulkWrite($this->namespace, $bulk); } } /** * {@inheritDoc} */ protected function getDefaultFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { return new \Google\Site_Kit_Dependencies\Monolog\Formatter\MongoDBFormatter(); } } monolog/src/Monolog/Handler/WhatFailureGroupHandler.php 0000644 00000003747 14721613470 0017253 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Handler; /** * Forwards records to multiple handlers suppressing failures of each handler * and continuing through to give every handler a chance to succeed. * * @author Craig D'Amelio <craig@damelio.ca> * * @phpstan-import-type Record from \Monolog\Logger */ class WhatFailureGroupHandler extends \Google\Site_Kit_Dependencies\Monolog\Handler\GroupHandler { /** * {@inheritDoc} */ public function handle(array $record) : bool { if ($this->processors) { /** @var Record $record */ $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { try { $handler->handle($record); } catch (\Throwable $e) { // What failure? } } return \false === $this->bubble; } /** * {@inheritDoc} */ public function handleBatch(array $records) : void { if ($this->processors) { $processed = array(); foreach ($records as $record) { $processed[] = $this->processRecord($record); } /** @var Record[] $records */ $records = $processed; } foreach ($this->handlers as $handler) { try { $handler->handleBatch($records); } catch (\Throwable $e) { // What failure? } } } /** * {@inheritDoc} */ public function close() : void { foreach ($this->handlers as $handler) { try { $handler->close(); } catch (\Throwable $e) { // What failure? } } } } monolog/src/Monolog/Test/TestCase.php 0000644 00000005306 14721613470 0013573 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Test; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\DateTimeImmutable; use Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface; /** * Lets you easily generate log records and a dummy formatter for testing purposes * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger * * @internal feel free to reuse this to test your own handlers, this is marked internal to avoid issues with PHPStorm https://github.com/Seldaek/monolog/issues/1677 */ class TestCase extends \Google\Site_Kit_Dependencies\PHPUnit\Framework\TestCase { public function tearDown() : void { parent::tearDown(); if (isset($this->handler)) { unset($this->handler); } } /** * @param mixed[] $context * * @return array Record * * @phpstan-param Level $level * @phpstan-return Record */ protected function getRecord(int $level = \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING, string $message = 'test', array $context = []) : array { return ['message' => (string) $message, 'context' => $context, 'level' => $level, 'level_name' => \Google\Site_Kit_Dependencies\Monolog\Logger::getLevelName($level), 'channel' => 'test', 'datetime' => new \Google\Site_Kit_Dependencies\Monolog\DateTimeImmutable(\true), 'extra' => []]; } /** * @phpstan-return Record[] */ protected function getMultipleRecords() : array { return [$this->getRecord(\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, 'debug message 1'), $this->getRecord(\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, 'debug message 2'), $this->getRecord(\Google\Site_Kit_Dependencies\Monolog\Logger::INFO, 'information'), $this->getRecord(\Google\Site_Kit_Dependencies\Monolog\Logger::WARNING, 'warning'), $this->getRecord(\Google\Site_Kit_Dependencies\Monolog\Logger::ERROR, 'error')]; } protected function getIdentityFormatter() : \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { $formatter = $this->createMock(\Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface::class); $formatter->expects($this->any())->method('format')->will($this->returnCallback(function ($record) { return $record['message']; })); return $formatter; } } monolog/src/Monolog/Logger.php 0000644 00000055101 14721613470 0012356 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog; use DateTimeZone; use Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface; use Google\Site_Kit_Dependencies\Psr\Log\LoggerInterface; use Google\Site_Kit_Dependencies\Psr\Log\InvalidArgumentException; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; use Throwable; use Stringable; /** * Monolog log channel * * It contains a stack of Handlers and a stack of Processors, * and uses them to store records that are added to it. * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-type Level Logger::DEBUG|Logger::INFO|Logger::NOTICE|Logger::WARNING|Logger::ERROR|Logger::CRITICAL|Logger::ALERT|Logger::EMERGENCY * @phpstan-type LevelName 'DEBUG'|'INFO'|'NOTICE'|'WARNING'|'ERROR'|'CRITICAL'|'ALERT'|'EMERGENCY' * @phpstan-type Record array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[]} */ class Logger implements \Google\Site_Kit_Dependencies\Psr\Log\LoggerInterface, \Google\Site_Kit_Dependencies\Monolog\ResettableInterface { /** * Detailed debug information */ public const DEBUG = 100; /** * Interesting events * * Examples: User logs in, SQL logs. */ public const INFO = 200; /** * Uncommon events */ public const NOTICE = 250; /** * Exceptional occurrences that are not errors * * Examples: Use of deprecated APIs, poor use of an API, * undesirable things that are not necessarily wrong. */ public const WARNING = 300; /** * Runtime errors */ public const ERROR = 400; /** * Critical conditions * * Example: Application component unavailable, unexpected exception. */ public const CRITICAL = 500; /** * Action must be taken immediately * * Example: Entire website down, database unavailable, etc. * This should trigger the SMS alerts and wake you up. */ public const ALERT = 550; /** * Urgent alert. */ public const EMERGENCY = 600; /** * Monolog API version * * This is only bumped when API breaks are done and should * follow the major version of the library * * @var int */ public const API = 2; /** * This is a static variable and not a constant to serve as an extension point for custom levels * * @var array<int, string> $levels Logging levels with the levels as key * * @phpstan-var array<Level, LevelName> $levels Logging levels with the levels as key */ protected static $levels = [self::DEBUG => 'DEBUG', self::INFO => 'INFO', self::NOTICE => 'NOTICE', self::WARNING => 'WARNING', self::ERROR => 'ERROR', self::CRITICAL => 'CRITICAL', self::ALERT => 'ALERT', self::EMERGENCY => 'EMERGENCY']; /** * Mapping between levels numbers defined in RFC 5424 and Monolog ones * * @phpstan-var array<int, Level> $rfc_5424_levels */ private const RFC_5424_LEVELS = [7 => self::DEBUG, 6 => self::INFO, 5 => self::NOTICE, 4 => self::WARNING, 3 => self::ERROR, 2 => self::CRITICAL, 1 => self::ALERT, 0 => self::EMERGENCY]; /** * @var string */ protected $name; /** * The handler stack * * @var HandlerInterface[] */ protected $handlers; /** * Processors that will process all log records * * To process records of a single handler instead, add the processor on that specific handler * * @var callable[] */ protected $processors; /** * @var bool */ protected $microsecondTimestamps = \true; /** * @var DateTimeZone */ protected $timezone; /** * @var callable|null */ protected $exceptionHandler; /** * @var int Keeps track of depth to prevent infinite logging loops */ private $logDepth = 0; /** * @var \WeakMap<\Fiber, int>|null Keeps track of depth inside fibers to prevent infinite logging loops */ private $fiberLogDepth; /** * @var bool Whether to detect infinite logging loops * * This can be disabled via {@see useLoggingLoopDetection} if you have async handlers that do not play well with this */ private $detectCycles = \true; /** * @psalm-param array<callable(array): array> $processors * * @param string $name The logging channel, a simple descriptive name that is attached to all log records * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc. * @param callable[] $processors Optional array of processors * @param DateTimeZone|null $timezone Optional timezone, if not provided date_default_timezone_get() will be used */ public function __construct(string $name, array $handlers = [], array $processors = [], ?\DateTimeZone $timezone = null) { $this->name = $name; $this->setHandlers($handlers); $this->processors = $processors; $this->timezone = $timezone ?: new \DateTimeZone(\date_default_timezone_get() ?: 'UTC'); if (\PHP_VERSION_ID >= 80100) { // Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412 /** @var \WeakMap<\Fiber, int> $fiberLogDepth */ $fiberLogDepth = new \WeakMap(); $this->fiberLogDepth = $fiberLogDepth; } } public function getName() : string { return $this->name; } /** * Return a new cloned instance with the name changed */ public function withName(string $name) : self { $new = clone $this; $new->name = $name; return $new; } /** * Pushes a handler on to the stack. */ public function pushHandler(\Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface $handler) : self { \array_unshift($this->handlers, $handler); return $this; } /** * Pops a handler from the stack * * @throws \LogicException If empty handler stack */ public function popHandler() : \Google\Site_Kit_Dependencies\Monolog\Handler\HandlerInterface { if (!$this->handlers) { throw new \LogicException('You tried to pop from an empty handler stack.'); } return \array_shift($this->handlers); } /** * Set handlers, replacing all existing ones. * * If a map is passed, keys will be ignored. * * @param HandlerInterface[] $handlers */ public function setHandlers(array $handlers) : self { $this->handlers = []; foreach (\array_reverse($handlers) as $handler) { $this->pushHandler($handler); } return $this; } /** * @return HandlerInterface[] */ public function getHandlers() : array { return $this->handlers; } /** * Adds a processor on to the stack. */ public function pushProcessor(callable $callback) : self { \array_unshift($this->processors, $callback); return $this; } /** * Removes the processor on top of the stack and returns it. * * @throws \LogicException If empty processor stack * @return callable */ public function popProcessor() : callable { if (!$this->processors) { throw new \LogicException('You tried to pop from an empty processor stack.'); } return \array_shift($this->processors); } /** * @return callable[] */ public function getProcessors() : array { return $this->processors; } /** * Control the use of microsecond resolution timestamps in the 'datetime' * member of new records. * * As of PHP7.1 microseconds are always included by the engine, so * there is no performance penalty and Monolog 2 enabled microseconds * by default. This function lets you disable them though in case you want * to suppress microseconds from the output. * * @param bool $micro True to use microtime() to create timestamps */ public function useMicrosecondTimestamps(bool $micro) : self { $this->microsecondTimestamps = $micro; return $this; } public function useLoggingLoopDetection(bool $detectCycles) : self { $this->detectCycles = $detectCycles; return $this; } /** * Adds a log record. * * @param int $level The logging level (a Monolog or RFC 5424 level) * @param string $message The log message * @param mixed[] $context The log context * @param DateTimeImmutable $datetime Optional log date to log into the past or future * @return bool Whether the record has been processed * * @phpstan-param Level $level */ public function addRecord(int $level, string $message, array $context = [], ?\Google\Site_Kit_Dependencies\Monolog\DateTimeImmutable $datetime = null) : bool { if (isset(self::RFC_5424_LEVELS[$level])) { $level = self::RFC_5424_LEVELS[$level]; } if ($this->detectCycles) { if (\PHP_VERSION_ID >= 80100 && ($fiber = \Fiber::getCurrent())) { $this->fiberLogDepth[$fiber] = $this->fiberLogDepth[$fiber] ?? 0; $logDepth = ++$this->fiberLogDepth[$fiber]; } else { $logDepth = ++$this->logDepth; } } else { $logDepth = 0; } if ($logDepth === 3) { $this->warning('A possible infinite logging loop was detected and aborted. It appears some of your handler code is triggering logging, see the previous log record for a hint as to what may be the cause.'); return \false; } elseif ($logDepth >= 5) { // log depth 4 is let through, so we can log the warning above return \false; } try { $record = null; foreach ($this->handlers as $handler) { if (null === $record) { // skip creating the record as long as no handler is going to handle it if (!$handler->isHandling(['level' => $level])) { continue; } $levelName = static::getLevelName($level); $record = ['message' => $message, 'context' => $context, 'level' => $level, 'level_name' => $levelName, 'channel' => $this->name, 'datetime' => $datetime ?? new \Google\Site_Kit_Dependencies\Monolog\DateTimeImmutable($this->microsecondTimestamps, $this->timezone), 'extra' => []]; try { foreach ($this->processors as $processor) { $record = $processor($record); } } catch (\Throwable $e) { $this->handleException($e, $record); return \true; } } // once the record exists, send it to all handlers as long as the bubbling chain is not interrupted try { if (\true === $handler->handle($record)) { break; } } catch (\Throwable $e) { $this->handleException($e, $record); return \true; } } } finally { if ($this->detectCycles) { if (isset($fiber)) { $this->fiberLogDepth[$fiber]--; } else { $this->logDepth--; } } } return null !== $record; } /** * Ends a log cycle and frees all resources used by handlers. * * Closing a Handler means flushing all buffers and freeing any open resources/handles. * Handlers that have been closed should be able to accept log records again and re-open * themselves on demand, but this may not always be possible depending on implementation. * * This is useful at the end of a request and will be called automatically on every handler * when they get destructed. */ public function close() : void { foreach ($this->handlers as $handler) { $handler->close(); } } /** * Ends a log cycle and resets all handlers and processors to their initial state. * * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal * state, and getting it back to a state in which it can receive log records again. * * This is useful in case you want to avoid logs leaking between two requests or jobs when you * have a long running process like a worker or an application server serving multiple requests * in one process. */ public function reset() : void { foreach ($this->handlers as $handler) { if ($handler instanceof \Google\Site_Kit_Dependencies\Monolog\ResettableInterface) { $handler->reset(); } } foreach ($this->processors as $processor) { if ($processor instanceof \Google\Site_Kit_Dependencies\Monolog\ResettableInterface) { $processor->reset(); } } } /** * Gets all supported logging levels. * * @return array<string, int> Assoc array with human-readable level names => level codes. * @phpstan-return array<LevelName, Level> */ public static function getLevels() : array { return \array_flip(static::$levels); } /** * Gets the name of the logging level. * * @throws \Psr\Log\InvalidArgumentException If level is not defined * * @phpstan-param Level $level * @phpstan-return LevelName */ public static function getLevelName(int $level) : string { if (!isset(static::$levels[$level])) { throw new \Google\Site_Kit_Dependencies\Psr\Log\InvalidArgumentException('Level "' . $level . '" is not defined, use one of: ' . \implode(', ', \array_keys(static::$levels))); } return static::$levels[$level]; } /** * Converts PSR-3 levels to Monolog ones if necessary * * @param string|int $level Level number (monolog) or name (PSR-3) * @throws \Psr\Log\InvalidArgumentException If level is not defined * * @phpstan-param Level|LevelName|LogLevel::* $level * @phpstan-return Level */ public static function toMonologLevel($level) : int { if (\is_string($level)) { if (\is_numeric($level)) { /** @phpstan-ignore-next-line */ return \intval($level); } // Contains chars of all log levels and avoids using strtoupper() which may have // strange results depending on locale (for example, "i" will become "İ" in Turkish locale) $upper = \strtr($level, 'abcdefgilmnortuwy', 'ABCDEFGILMNORTUWY'); if (\defined(__CLASS__ . '::' . $upper)) { return \constant(__CLASS__ . '::' . $upper); } throw new \Google\Site_Kit_Dependencies\Psr\Log\InvalidArgumentException('Level "' . $level . '" is not defined, use one of: ' . \implode(', ', \array_keys(static::$levels) + static::$levels)); } if (!\is_int($level)) { throw new \Google\Site_Kit_Dependencies\Psr\Log\InvalidArgumentException('Level "' . \var_export($level, \true) . '" is not defined, use one of: ' . \implode(', ', \array_keys(static::$levels) + static::$levels)); } return $level; } /** * Checks whether the Logger has a handler that listens on the given level * * @phpstan-param Level $level */ public function isHandling(int $level) : bool { $record = ['level' => $level]; foreach ($this->handlers as $handler) { if ($handler->isHandling($record)) { return \true; } } return \false; } /** * Set a custom exception handler that will be called if adding a new record fails * * The callable will receive an exception object and the record that failed to be logged */ public function setExceptionHandler(?callable $callback) : self { $this->exceptionHandler = $callback; return $this; } public function getExceptionHandler() : ?callable { return $this->exceptionHandler; } /** * Adds a log record at an arbitrary level. * * This method allows for compatibility with common interfaces. * * @param mixed $level The log level (a Monolog, PSR-3 or RFC 5424 level) * @param string|Stringable $message The log message * @param mixed[] $context The log context * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function log($level, $message, array $context = []) : void { if (!\is_int($level) && !\is_string($level)) { throw new \InvalidArgumentException('$level is expected to be a string or int'); } if (isset(self::RFC_5424_LEVELS[$level])) { $level = self::RFC_5424_LEVELS[$level]; } $level = static::toMonologLevel($level); $this->addRecord($level, (string) $message, $context); } /** * Adds a log record at the DEBUG level. * * This method allows for compatibility with common interfaces. * * @param string|Stringable $message The log message * @param mixed[] $context The log context */ public function debug($message, array $context = []) : void { $this->addRecord(static::DEBUG, (string) $message, $context); } /** * Adds a log record at the INFO level. * * This method allows for compatibility with common interfaces. * * @param string|Stringable $message The log message * @param mixed[] $context The log context */ public function info($message, array $context = []) : void { $this->addRecord(static::INFO, (string) $message, $context); } /** * Adds a log record at the NOTICE level. * * This method allows for compatibility with common interfaces. * * @param string|Stringable $message The log message * @param mixed[] $context The log context */ public function notice($message, array $context = []) : void { $this->addRecord(static::NOTICE, (string) $message, $context); } /** * Adds a log record at the WARNING level. * * This method allows for compatibility with common interfaces. * * @param string|Stringable $message The log message * @param mixed[] $context The log context */ public function warning($message, array $context = []) : void { $this->addRecord(static::WARNING, (string) $message, $context); } /** * Adds a log record at the ERROR level. * * This method allows for compatibility with common interfaces. * * @param string|Stringable $message The log message * @param mixed[] $context The log context */ public function error($message, array $context = []) : void { $this->addRecord(static::ERROR, (string) $message, $context); } /** * Adds a log record at the CRITICAL level. * * This method allows for compatibility with common interfaces. * * @param string|Stringable $message The log message * @param mixed[] $context The log context */ public function critical($message, array $context = []) : void { $this->addRecord(static::CRITICAL, (string) $message, $context); } /** * Adds a log record at the ALERT level. * * This method allows for compatibility with common interfaces. * * @param string|Stringable $message The log message * @param mixed[] $context The log context */ public function alert($message, array $context = []) : void { $this->addRecord(static::ALERT, (string) $message, $context); } /** * Adds a log record at the EMERGENCY level. * * This method allows for compatibility with common interfaces. * * @param string|Stringable $message The log message * @param mixed[] $context The log context */ public function emergency($message, array $context = []) : void { $this->addRecord(static::EMERGENCY, (string) $message, $context); } /** * Sets the timezone to be used for the timestamp of log records. */ public function setTimezone(\DateTimeZone $tz) : self { $this->timezone = $tz; return $this; } /** * Returns the timezone to be used for the timestamp of log records. */ public function getTimezone() : \DateTimeZone { return $this->timezone; } /** * Delegates exception management to the custom exception handler, * or throws the exception if no custom handler is set. * * @param array $record * @phpstan-param Record $record */ protected function handleException(\Throwable $e, array $record) : void { if (!$this->exceptionHandler) { throw $e; } ($this->exceptionHandler)($e, $record); } /** * @return array<string, mixed> */ public function __serialize() : array { return ['name' => $this->name, 'handlers' => $this->handlers, 'processors' => $this->processors, 'microsecondTimestamps' => $this->microsecondTimestamps, 'timezone' => $this->timezone, 'exceptionHandler' => $this->exceptionHandler, 'logDepth' => $this->logDepth, 'detectCycles' => $this->detectCycles]; } /** * @param array<string, mixed> $data */ public function __unserialize(array $data) : void { foreach (['name', 'handlers', 'processors', 'microsecondTimestamps', 'timezone', 'exceptionHandler', 'logDepth', 'detectCycles'] as $property) { if (isset($data[$property])) { $this->{$property} = $data[$property]; } } if (\PHP_VERSION_ID >= 80100) { // Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412 /** @var \WeakMap<\Fiber, int> $fiberLogDepth */ $fiberLogDepth = new \WeakMap(); $this->fiberLogDepth = $fiberLogDepth; } } } monolog/src/Monolog/Utils.php 0000644 00000022416 14721613470 0012242 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog; final class Utils { const DEFAULT_JSON_FLAGS = \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_PRESERVE_ZERO_FRACTION | \JSON_INVALID_UTF8_SUBSTITUTE | \JSON_PARTIAL_OUTPUT_ON_ERROR; public static function getClass(object $object) : string { $class = \get_class($object); if (\false === ($pos = \strpos($class, "@anonymous\x00"))) { return $class; } if (\false === ($parent = \get_parent_class($class))) { return \substr($class, 0, $pos + 10); } return $parent . '@anonymous'; } public static function substr(string $string, int $start, ?int $length = null) : string { if (\extension_loaded('mbstring')) { return \mb_strcut($string, $start, $length); } return \substr($string, $start, null === $length ? \strlen($string) : $length); } /** * Makes sure if a relative path is passed in it is turned into an absolute path * * @param string $streamUrl stream URL or path without protocol */ public static function canonicalizePath(string $streamUrl) : string { $prefix = ''; if ('file://' === \substr($streamUrl, 0, 7)) { $streamUrl = \substr($streamUrl, 7); $prefix = 'file://'; } // other type of stream, not supported if (\false !== \strpos($streamUrl, '://')) { return $streamUrl; } // already absolute if (\substr($streamUrl, 0, 1) === '/' || \substr($streamUrl, 1, 1) === ':' || \substr($streamUrl, 0, 2) === '\\\\') { return $prefix . $streamUrl; } $streamUrl = \getcwd() . '/' . $streamUrl; return $prefix . $streamUrl; } /** * Return the JSON representation of a value * * @param mixed $data * @param int $encodeFlags flags to pass to json encode, defaults to DEFAULT_JSON_FLAGS * @param bool $ignoreErrors whether to ignore encoding errors or to throw on error, when ignored and the encoding fails, "null" is returned which is valid json for null * @throws \RuntimeException if encoding fails and errors are not ignored * @return string when errors are ignored and the encoding fails, "null" is returned which is valid json for null */ public static function jsonEncode($data, ?int $encodeFlags = null, bool $ignoreErrors = \false) : string { if (null === $encodeFlags) { $encodeFlags = self::DEFAULT_JSON_FLAGS; } if ($ignoreErrors) { $json = @\json_encode($data, $encodeFlags); if (\false === $json) { return 'null'; } return $json; } $json = \json_encode($data, $encodeFlags); if (\false === $json) { $json = self::handleJsonError(\json_last_error(), $data); } return $json; } /** * Handle a json_encode failure. * * If the failure is due to invalid string encoding, try to clean the * input and encode again. If the second encoding attempt fails, the * initial error is not encoding related or the input can't be cleaned then * raise a descriptive exception. * * @param int $code return code of json_last_error function * @param mixed $data data that was meant to be encoded * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION * @throws \RuntimeException if failure can't be corrected * @return string JSON encoded data after error correction */ public static function handleJsonError(int $code, $data, ?int $encodeFlags = null) : string { if ($code !== \JSON_ERROR_UTF8) { self::throwEncodeError($code, $data); } if (\is_string($data)) { self::detectAndCleanUtf8($data); } elseif (\is_array($data)) { \array_walk_recursive($data, array('Monolog\\Utils', 'detectAndCleanUtf8')); } else { self::throwEncodeError($code, $data); } if (null === $encodeFlags) { $encodeFlags = self::DEFAULT_JSON_FLAGS; } $json = \json_encode($data, $encodeFlags); if ($json === \false) { self::throwEncodeError(\json_last_error(), $data); } return $json; } /** * @internal */ public static function pcreLastErrorMessage(int $code) : string { if (\PHP_VERSION_ID >= 80000) { return \preg_last_error_msg(); } $constants = \get_defined_constants(\true)['pcre']; $constants = \array_filter($constants, function ($key) { return \substr($key, -6) == '_ERROR'; }, \ARRAY_FILTER_USE_KEY); $constants = \array_flip($constants); return $constants[$code] ?? 'UNDEFINED_ERROR'; } /** * Throws an exception according to a given code with a customized message * * @param int $code return code of json_last_error function * @param mixed $data data that was meant to be encoded * @throws \RuntimeException * * @return never */ private static function throwEncodeError(int $code, $data) : void { switch ($code) { case \JSON_ERROR_DEPTH: $msg = 'Maximum stack depth exceeded'; break; case \JSON_ERROR_STATE_MISMATCH: $msg = 'Underflow or the modes mismatch'; break; case \JSON_ERROR_CTRL_CHAR: $msg = 'Unexpected control character found'; break; case \JSON_ERROR_UTF8: $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded'; break; default: $msg = 'Unknown error'; } throw new \RuntimeException('JSON encoding failed: ' . $msg . '. Encoding: ' . \var_export($data, \true)); } /** * Detect invalid UTF-8 string characters and convert to valid UTF-8. * * Valid UTF-8 input will be left unmodified, but strings containing * invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed * original encoding of ISO-8859-15. This conversion may result in * incorrect output if the actual encoding was not ISO-8859-15, but it * will be clean UTF-8 output and will not rely on expensive and fragile * detection algorithms. * * Function converts the input in place in the passed variable so that it * can be used as a callback for array_walk_recursive. * * @param mixed $data Input to check and convert if needed, passed by ref */ private static function detectAndCleanUtf8(&$data) : void { if (\is_string($data) && !\preg_match('//u', $data)) { $data = \preg_replace_callback('/[\\x80-\\xFF]+/', function ($m) { return \function_exists('mb_convert_encoding') ? \mb_convert_encoding($m[0], 'UTF-8', 'ISO-8859-1') : \utf8_encode($m[0]); }, $data); if (!\is_string($data)) { $pcreErrorCode = \preg_last_error(); throw new \RuntimeException('Failed to preg_replace_callback: ' . $pcreErrorCode . ' / ' . self::pcreLastErrorMessage($pcreErrorCode)); } $data = \str_replace(['¤', '¦', '¨', '´', '¸', '¼', '½', '¾'], ['€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'], $data); } } /** * Converts a string with a valid 'memory_limit' format, to bytes. * * @param string|false $val * @return int|false Returns an integer representing bytes. Returns FALSE in case of error. */ public static function expandIniShorthandBytes($val) { if (!\is_string($val)) { return \false; } // support -1 if ((int) $val < 0) { return (int) $val; } if (!\preg_match('/^\\s*(?<val>\\d+)(?:\\.\\d+)?\\s*(?<unit>[gmk]?)\\s*$/i', $val, $match)) { return \false; } $val = (int) $match['val']; switch (\strtolower($match['unit'] ?? '')) { case 'g': $val *= 1024; case 'm': $val *= 1024; case 'k': $val *= 1024; } return $val; } /** * @param array<mixed> $record */ public static function getRecordMessageForException(array $record) : string { $context = ''; $extra = ''; try { if ($record['context']) { $context = "\nContext: " . \json_encode($record['context']); } if ($record['extra']) { $extra = "\nExtra: " . \json_encode($record['extra']); } } catch (\Throwable $e) { // noop } return "\nThe exception occurred while attempting to log: " . $record['message'] . $context . $extra; } } monolog/src/Monolog/Processor/ProcessIdProcessor.php 0000644 00000001255 14721613470 0016712 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; /** * Adds value of getmypid into records * * @author Andreas Hörnicke */ class ProcessIdProcessor implements \Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface { /** * {@inheritDoc} */ public function __invoke(array $record) : array { $record['extra']['process_id'] = \getmypid(); return $record; } } monolog/src/Monolog/Processor/HostnameProcessor.php 0000644 00000001440 14721613470 0016571 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; /** * Injects value of gethostname in all records */ class HostnameProcessor implements \Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface { /** @var string */ private static $host; public function __construct() { self::$host = (string) \gethostname(); } /** * {@inheritDoc} */ public function __invoke(array $record) : array { $record['extra']['hostname'] = self::$host; return $record; } } monolog/src/Monolog/Processor/MemoryUsageProcessor.php 0000644 00000001575 14721613470 0017261 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; /** * Injects memory_get_usage in all records * * @see Monolog\Processor\MemoryProcessor::__construct() for options * @author Rob Jensen */ class MemoryUsageProcessor extends \Google\Site_Kit_Dependencies\Monolog\Processor\MemoryProcessor { /** * {@inheritDoc} */ public function __invoke(array $record) : array { $usage = \memory_get_usage($this->realUsage); if ($this->useFormatting) { $usage = $this->formatBytes($usage); } $record['extra']['memory_usage'] = $usage; return $record; } } monolog/src/Monolog/Processor/UidProcessor.php 0000644 00000002651 14721613470 0015541 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; use Google\Site_Kit_Dependencies\Monolog\ResettableInterface; /** * Adds a unique identifier into records * * @author Simon Mönch <sm@webfactory.de> */ class UidProcessor implements \Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface, \Google\Site_Kit_Dependencies\Monolog\ResettableInterface { /** @var string */ private $uid; public function __construct(int $length = 7) { if ($length > 32 || $length < 1) { throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32'); } $this->uid = $this->generateUid($length); } /** * {@inheritDoc} */ public function __invoke(array $record) : array { $record['extra']['uid'] = $this->uid; return $record; } public function getUid() : string { return $this->uid; } public function reset() { $this->uid = $this->generateUid(\strlen($this->uid)); } private function generateUid(int $length) : string { return \substr(\bin2hex(\random_bytes((int) \ceil($length / 2))), 0, $length); } } monolog/src/Monolog/Processor/GitProcessor.php 0000644 00000004067 14721613470 0015546 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Injects Git branch and Git commit SHA in all records * * @author Nick Otter * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ class GitProcessor implements \Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface { /** @var int */ private $level; /** @var array{branch: string, commit: string}|array<never>|null */ private static $cache = null; /** * @param string|int $level The minimum logging level at which this Processor will be triggered * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function __construct($level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG) { $this->level = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($level); } /** * {@inheritDoc} */ public function __invoke(array $record) : array { // return if the level is not high enough if ($record['level'] < $this->level) { return $record; } $record['extra']['git'] = self::getGitInfo(); return $record; } /** * @return array{branch: string, commit: string}|array<never> */ private static function getGitInfo() : array { if (self::$cache) { return self::$cache; } $branches = `git branch -v --no-abbrev`; if ($branches && \preg_match('{^\\* (.+?)\\s+([a-f0-9]{40})(?:\\s|$)}m', $branches, $matches)) { return self::$cache = ['branch' => $matches[1], 'commit' => $matches[2]]; } return self::$cache = []; } } monolog/src/Monolog/Processor/IntrospectionProcessor.php 0000644 00000007505 14721613470 0017663 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Injects line/file:class/function where the log message came from * * Warning: This only works if the handler processes the logs directly. * If you put the processor on a handler that is behind a FingersCrossedHandler * for example, the processor will only be called once the trigger level is reached, * and all the log records will have the same file/line/.. data from the call that * triggered the FingersCrossedHandler. * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ class IntrospectionProcessor implements \Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface { /** @var int */ private $level; /** @var string[] */ private $skipClassesPartials; /** @var int */ private $skipStackFramesCount; /** @var string[] */ private $skipFunctions = ['call_user_func', 'call_user_func_array']; /** * @param string|int $level The minimum logging level at which this Processor will be triggered * @param string[] $skipClassesPartials * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function __construct($level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0) { $this->level = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($level); $this->skipClassesPartials = \array_merge(['Monolog\\'], $skipClassesPartials); $this->skipStackFramesCount = $skipStackFramesCount; } /** * {@inheritDoc} */ public function __invoke(array $record) : array { // return if the level is not high enough if ($record['level'] < $this->level) { return $record; } $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); // skip first since it's always the current method \array_shift($trace); // the call_user_func call is also skipped \array_shift($trace); $i = 0; while ($this->isTraceClassOrSkippedFunction($trace, $i)) { if (isset($trace[$i]['class'])) { foreach ($this->skipClassesPartials as $part) { if (\strpos($trace[$i]['class'], $part) !== \false) { $i++; continue 2; } } } elseif (\in_array($trace[$i]['function'], $this->skipFunctions)) { $i++; continue; } break; } $i += $this->skipStackFramesCount; // we should have the call source now $record['extra'] = \array_merge($record['extra'], ['file' => isset($trace[$i - 1]['file']) ? $trace[$i - 1]['file'] : null, 'line' => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null, 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null, 'callType' => isset($trace[$i]['type']) ? $trace[$i]['type'] : null, 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null]); return $record; } /** * @param array[] $trace */ private function isTraceClassOrSkippedFunction(array $trace, int $index) : bool { if (!isset($trace[$index])) { return \false; } return isset($trace[$index]['class']) || \in_array($trace[$index]['function'], $this->skipFunctions); } } monolog/src/Monolog/Processor/TagProcessor.php 0000644 00000002254 14721613470 0015532 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; /** * Adds a tags array into record * * @author Martijn Riemers */ class TagProcessor implements \Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface { /** @var string[] */ private $tags; /** * @param string[] $tags */ public function __construct(array $tags = []) { $this->setTags($tags); } /** * @param string[] $tags */ public function addTags(array $tags = []) : self { $this->tags = \array_merge($this->tags, $tags); return $this; } /** * @param string[] $tags */ public function setTags(array $tags = []) : self { $this->tags = $tags; return $this; } /** * {@inheritDoc} */ public function __invoke(array $record) : array { $record['extra']['tags'] = $this->tags; return $record; } } monolog/src/Monolog/Processor/MemoryProcessor.php 0000644 00000003563 14721613470 0016273 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; /** * Some methods that are common for all memory processors * * @author Rob Jensen */ abstract class MemoryProcessor implements \Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface { /** * @var bool If true, get the real size of memory allocated from system. Else, only the memory used by emalloc() is reported. */ protected $realUsage; /** * @var bool If true, then format memory size to human readable string (MB, KB, B depending on size) */ protected $useFormatting; /** * @param bool $realUsage Set this to true to get the real size of memory allocated from system. * @param bool $useFormatting If true, then format memory size to human readable string (MB, KB, B depending on size) */ public function __construct(bool $realUsage = \true, bool $useFormatting = \true) { $this->realUsage = $realUsage; $this->useFormatting = $useFormatting; } /** * Formats bytes into a human readable string if $this->useFormatting is true, otherwise return $bytes as is * * @param int $bytes * @return string|int Formatted string if $this->useFormatting is true, otherwise return $bytes as int */ protected function formatBytes(int $bytes) { if (!$this->useFormatting) { return $bytes; } if ($bytes > 1024 * 1024) { return \round($bytes / 1024 / 1024, 2) . ' MB'; } elseif ($bytes > 1024) { return \round($bytes / 1024, 2) . ' KB'; } return $bytes . ' B'; } } monolog/src/Monolog/Processor/WebProcessor.php 0000644 00000006706 14721613470 0015542 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; /** * Injects url/method and remote IP of the current web request in all records * * @author Jordi Boggiano <j.boggiano@seld.be> */ class WebProcessor implements \Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface { /** * @var array<string, mixed>|\ArrayAccess<string, mixed> */ protected $serverData; /** * Default fields * * Array is structured as [key in record.extra => key in $serverData] * * @var array<string, string> */ protected $extraFields = ['url' => 'REQUEST_URI', 'ip' => 'REMOTE_ADDR', 'http_method' => 'REQUEST_METHOD', 'server' => 'SERVER_NAME', 'referrer' => 'HTTP_REFERER', 'user_agent' => 'HTTP_USER_AGENT']; /** * @param array<string, mixed>|\ArrayAccess<string, mixed>|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data * @param array<string, string>|array<string>|null $extraFields Field names and the related key inside $serverData to be added (or just a list of field names to use the default configured $serverData mapping). If not provided it defaults to: [url, ip, http_method, server, referrer] + unique_id if present in server data */ public function __construct($serverData = null, ?array $extraFields = null) { if (null === $serverData) { $this->serverData =& $_SERVER; } elseif (\is_array($serverData) || $serverData instanceof \ArrayAccess) { $this->serverData = $serverData; } else { throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.'); } $defaultEnabled = ['url', 'ip', 'http_method', 'server', 'referrer']; if (isset($this->serverData['UNIQUE_ID'])) { $this->extraFields['unique_id'] = 'UNIQUE_ID'; $defaultEnabled[] = 'unique_id'; } if (null === $extraFields) { $extraFields = $defaultEnabled; } if (isset($extraFields[0])) { foreach (\array_keys($this->extraFields) as $fieldName) { if (!\in_array($fieldName, $extraFields)) { unset($this->extraFields[$fieldName]); } } } else { $this->extraFields = $extraFields; } } /** * {@inheritDoc} */ public function __invoke(array $record) : array { // skip processing if for some reason request data // is not present (CLI or wonky SAPIs) if (!isset($this->serverData['REQUEST_URI'])) { return $record; } $record['extra'] = $this->appendExtraFields($record['extra']); return $record; } public function addExtraField(string $extraName, string $serverName) : self { $this->extraFields[$extraName] = $serverName; return $this; } /** * @param mixed[] $extra * @return mixed[] */ private function appendExtraFields(array $extra) : array { foreach ($this->extraFields as $extraName => $serverName) { $extra[$extraName] = $this->serverData[$serverName] ?? null; } return $extra; } } monolog/src/Monolog/Processor/MercurialProcessor.php 0000644 00000004010 14721613470 0016732 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Injects Hg branch and Hg revision number in all records * * @author Jonathan A. Schweder <jonathanschweder@gmail.com> * * @phpstan-import-type LevelName from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger */ class MercurialProcessor implements \Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface { /** @var Level */ private $level; /** @var array{branch: string, revision: string}|array<never>|null */ private static $cache = null; /** * @param int|string $level The minimum logging level at which this Processor will be triggered * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function __construct($level = \Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG) { $this->level = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($level); } /** * {@inheritDoc} */ public function __invoke(array $record) : array { // return if the level is not high enough if ($record['level'] < $this->level) { return $record; } $record['extra']['hg'] = self::getMercurialInfo(); return $record; } /** * @return array{branch: string, revision: string}|array<never> */ private static function getMercurialInfo() : array { if (self::$cache) { return self::$cache; } $result = \explode(' ', \trim(`hg id -nb`)); if (\count($result) >= 3) { return self::$cache = ['branch' => $result[1], 'revision' => $result[2]]; } return self::$cache = []; } } monolog/src/Monolog/Processor/PsrLogMessageProcessor.php 0000644 00000006300 14721613470 0017526 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Processes a record's message according to PSR-3 rules * * It replaces {foo} with the value from $context['foo'] * * @author Jordi Boggiano <j.boggiano@seld.be> */ class PsrLogMessageProcessor implements \Google\Site_Kit_Dependencies\Monolog\Processor\ProcessorInterface { public const SIMPLE_DATE = "Y-m-d\\TH:i:s.uP"; /** @var string|null */ private $dateFormat; /** @var bool */ private $removeUsedContextFields; /** * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format * @param bool $removeUsedContextFields If set to true the fields interpolated into message gets unset */ public function __construct(?string $dateFormat = null, bool $removeUsedContextFields = \false) { $this->dateFormat = $dateFormat; $this->removeUsedContextFields = $removeUsedContextFields; } /** * {@inheritDoc} */ public function __invoke(array $record) : array { if (\false === \strpos($record['message'], '{')) { return $record; } $replacements = []; foreach ($record['context'] as $key => $val) { $placeholder = '{' . $key . '}'; if (\strpos($record['message'], $placeholder) === \false) { continue; } if (\is_null($val) || \is_scalar($val) || \is_object($val) && \method_exists($val, "__toString")) { $replacements[$placeholder] = $val; } elseif ($val instanceof \DateTimeInterface) { if (!$this->dateFormat && $val instanceof \Google\Site_Kit_Dependencies\Monolog\DateTimeImmutable) { // handle monolog dates using __toString if no specific dateFormat was asked for // so that it follows the useMicroseconds flag $replacements[$placeholder] = (string) $val; } else { $replacements[$placeholder] = $val->format($this->dateFormat ?: static::SIMPLE_DATE); } } elseif ($val instanceof \UnitEnum) { $replacements[$placeholder] = $val instanceof \BackedEnum ? $val->value : $val->name; } elseif (\is_object($val)) { $replacements[$placeholder] = '[object ' . \Google\Site_Kit_Dependencies\Monolog\Utils::getClass($val) . ']'; } elseif (\is_array($val)) { $replacements[$placeholder] = 'array' . \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($val, null, \true); } else { $replacements[$placeholder] = '[' . \gettype($val) . ']'; } if ($this->removeUsedContextFields) { unset($record['context'][$key]); } } $record['message'] = \strtr($record['message'], $replacements); return $record; } } monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php 0000644 00000001620 14721613470 0020051 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; /** * Injects memory_get_peak_usage in all records * * @see Monolog\Processor\MemoryProcessor::__construct() for options * @author Rob Jensen */ class MemoryPeakUsageProcessor extends \Google\Site_Kit_Dependencies\Monolog\Processor\MemoryProcessor { /** * {@inheritDoc} */ public function __invoke(array $record) : array { $usage = \memory_get_peak_usage($this->realUsage); if ($this->useFormatting) { $usage = $this->formatBytes($usage); } $record['extra']['memory_peak_usage'] = $usage; return $record; } } monolog/src/Monolog/Processor/ProcessorInterface.php 0000644 00000001277 14721613470 0016723 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Processor; /** * An optional interface to allow labelling Monolog processors. * * @author Nicolas Grekas <p@tchwork.com> * * @phpstan-import-type Record from \Monolog\Logger */ interface ProcessorInterface { /** * @return array The processed record * * @phpstan-param Record $record * @phpstan-return Record */ public function __invoke(array $record); } monolog/src/Monolog/SignalHandler.php 0000644 00000010307 14721613470 0013651 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog; use Google\Site_Kit_Dependencies\Psr\Log\LoggerInterface; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; use ReflectionExtension; /** * Monolog POSIX signal handler * * @author Robert Gust-Bardon <robert@gust-bardon.org> * * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ class SignalHandler { /** @var LoggerInterface */ private $logger; /** @var array<int, callable|string|int> SIG_DFL, SIG_IGN or previous callable */ private $previousSignalHandler = []; /** @var array<int, int> */ private $signalLevelMap = []; /** @var array<int, bool> */ private $signalRestartSyscalls = []; public function __construct(\Google\Site_Kit_Dependencies\Psr\Log\LoggerInterface $logger) { $this->logger = $logger; } /** * @param int|string $level Level or level name * @param bool $callPrevious * @param bool $restartSyscalls * @param bool|null $async * @return $this * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function registerSignalHandler(int $signo, $level = \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::CRITICAL, bool $callPrevious = \true, bool $restartSyscalls = \true, ?bool $async = \true) : self { if (!\extension_loaded('pcntl') || !\function_exists('pcntl_signal')) { return $this; } $level = \Google\Site_Kit_Dependencies\Monolog\Logger::toMonologLevel($level); if ($callPrevious) { $handler = \pcntl_signal_get_handler($signo); $this->previousSignalHandler[$signo] = $handler; } else { unset($this->previousSignalHandler[$signo]); } $this->signalLevelMap[$signo] = $level; $this->signalRestartSyscalls[$signo] = $restartSyscalls; if ($async !== null) { \pcntl_async_signals($async); } \pcntl_signal($signo, [$this, 'handleSignal'], $restartSyscalls); return $this; } /** * @param mixed $siginfo */ public function handleSignal(int $signo, $siginfo = null) : void { static $signals = []; if (!$signals && \extension_loaded('pcntl')) { $pcntl = new \ReflectionExtension('pcntl'); // HHVM 3.24.2 returns an empty array. foreach ($pcntl->getConstants() ?: \get_defined_constants(\true)['Core'] as $name => $value) { if (\substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && \is_int($value)) { $signals[$value] = $name; } } } $level = $this->signalLevelMap[$signo] ?? \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::CRITICAL; $signal = $signals[$signo] ?? $signo; $context = $siginfo ?? []; $this->logger->log($level, \sprintf('Program received signal %s', $signal), $context); if (!isset($this->previousSignalHandler[$signo])) { return; } if ($this->previousSignalHandler[$signo] === \SIG_DFL) { if (\extension_loaded('pcntl') && \function_exists('pcntl_signal') && \function_exists('pcntl_sigprocmask') && \function_exists('pcntl_signal_dispatch') && \extension_loaded('posix') && \function_exists('posix_getpid') && \function_exists('posix_kill')) { $restartSyscalls = $this->signalRestartSyscalls[$signo] ?? \true; \pcntl_signal($signo, \SIG_DFL, $restartSyscalls); \pcntl_sigprocmask(\SIG_UNBLOCK, [$signo], $oldset); \posix_kill(\posix_getpid(), $signo); \pcntl_signal_dispatch(); \pcntl_sigprocmask(\SIG_SETMASK, $oldset); \pcntl_signal($signo, [$this, 'handleSignal'], $restartSyscalls); } } elseif (\is_callable($this->previousSignalHandler[$signo])) { $this->previousSignalHandler[$signo]($signo, $siginfo); } } } monolog/src/Monolog/ResettableInterface.php 0000644 00000002011 14721613470 0015042 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog; /** * Handler or Processor implementing this interface will be reset when Logger::reset() is called. * * Resetting ends a log cycle gets them back to their initial state. * * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal * state, and getting it back to a state in which it can receive log records again. * * This is useful in case you want to avoid logs leaking between two requests or jobs when you * have a long running process like a worker or an application server serving multiple requests * in one process. * * @author Grégoire Pineau <lyrixx@lyrixx.info> */ interface ResettableInterface { /** * @return void */ public function reset(); } monolog/src/Monolog/Attribute/AsMonologProcessor.php 0000644 00000002766 14721613470 0016711 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Attribute; /** * A reusable attribute to help configure a class or a method as a processor. * * Using it offers no guarantee: it needs to be leveraged by a Monolog third-party consumer. * * Using it with the Monolog library only has no effect at all: processors should still be turned into a callable if * needed and manually pushed to the loggers and to the processable handlers. */ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class AsMonologProcessor { /** @var string|null */ public $channel = null; /** @var string|null */ public $handler = null; /** @var string|null */ public $method = null; /** * @param string|null $channel The logging channel the processor should be pushed to. * @param string|null $handler The handler the processor should be pushed to. * @param string|null $method The method that processes the records (if the attribute is used at the class level). */ public function __construct(?string $channel = null, ?string $handler = null, ?string $method = null) { $this->channel = $channel; $this->handler = $handler; $this->method = $method; } } monolog/src/Monolog/LogRecord.php 0000644 00000001764 14721613470 0013025 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog; use ArrayAccess; /** * Monolog log record interface for forward compatibility with Monolog 3.0 * * This is just present in Monolog 2.4+ to allow interoperable code to be written against * both versions by type-hinting arguments as `array|\Monolog\LogRecord $record` * * Do not rely on this interface for other purposes, and do not implement it. * * @author Jordi Boggiano <j.boggiano@seld.be> * @template-extends \ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra'|'formatted', mixed> * @phpstan-import-type Record from Logger */ interface LogRecord extends \ArrayAccess { /** * @phpstan-return Record */ public function toArray() : array; } monolog/src/Monolog/Registry.php 0000644 00000010131 14721613470 0012741 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog; use InvalidArgumentException; /** * Monolog log registry * * Allows to get `Logger` instances in the global scope * via static method calls on this class. * * <code> * $application = new Monolog\Logger('application'); * $api = new Monolog\Logger('api'); * * Monolog\Registry::addLogger($application); * Monolog\Registry::addLogger($api); * * function testLogger() * { * Monolog\Registry::api()->error('Sent to $api Logger instance'); * Monolog\Registry::application()->error('Sent to $application Logger instance'); * } * </code> * * @author Tomas Tatarko <tomas@tatarko.sk> */ class Registry { /** * List of all loggers in the registry (by named indexes) * * @var Logger[] */ private static $loggers = []; /** * Adds new logging channel to the registry * * @param Logger $logger Instance of the logging channel * @param string|null $name Name of the logging channel ($logger->getName() by default) * @param bool $overwrite Overwrite instance in the registry if the given name already exists? * @throws \InvalidArgumentException If $overwrite set to false and named Logger instance already exists * @return void */ public static function addLogger(\Google\Site_Kit_Dependencies\Monolog\Logger $logger, ?string $name = null, bool $overwrite = \false) { $name = $name ?: $logger->getName(); if (isset(self::$loggers[$name]) && !$overwrite) { throw new \InvalidArgumentException('Logger with the given name already exists'); } self::$loggers[$name] = $logger; } /** * Checks if such logging channel exists by name or instance * * @param string|Logger $logger Name or logger instance */ public static function hasLogger($logger) : bool { if ($logger instanceof \Google\Site_Kit_Dependencies\Monolog\Logger) { $index = \array_search($logger, self::$loggers, \true); return \false !== $index; } return isset(self::$loggers[$logger]); } /** * Removes instance from registry by name or instance * * @param string|Logger $logger Name or logger instance */ public static function removeLogger($logger) : void { if ($logger instanceof \Google\Site_Kit_Dependencies\Monolog\Logger) { if (\false !== ($idx = \array_search($logger, self::$loggers, \true))) { unset(self::$loggers[$idx]); } } else { unset(self::$loggers[$logger]); } } /** * Clears the registry */ public static function clear() : void { self::$loggers = []; } /** * Gets Logger instance from the registry * * @param string $name Name of the requested Logger instance * @throws \InvalidArgumentException If named Logger instance is not in the registry */ public static function getInstance($name) : \Google\Site_Kit_Dependencies\Monolog\Logger { if (!isset(self::$loggers[$name])) { throw new \InvalidArgumentException(\sprintf('Requested "%s" logger instance is not in the registry', $name)); } return self::$loggers[$name]; } /** * Gets Logger instance from the registry via static method call * * @param string $name Name of the requested Logger instance * @param mixed[] $arguments Arguments passed to static method call * @throws \InvalidArgumentException If named Logger instance is not in the registry * @return Logger Requested instance of Logger */ public static function __callStatic($name, $arguments) { return self::getInstance($name); } } monolog/src/Monolog/Formatter/ChromePHPFormatter.php 0000644 00000004540 14721613470 0016554 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Formats a log message according to the ChromePHP array format * * @author Christophe Coevoet <stof@notk.org> */ class ChromePHPFormatter implements \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { /** * Translates Monolog log levels to Wildfire levels. * * @var array<int, 'log'|'info'|'warn'|'error'> */ private $logLevels = [\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG => 'log', \Google\Site_Kit_Dependencies\Monolog\Logger::INFO => 'info', \Google\Site_Kit_Dependencies\Monolog\Logger::NOTICE => 'info', \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING => 'warn', \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR => 'error', \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL => 'error', \Google\Site_Kit_Dependencies\Monolog\Logger::ALERT => 'error', \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY => 'error']; /** * {@inheritDoc} */ public function format(array $record) { // Retrieve the line and file if set and remove them from the formatted extra $backtrace = 'unknown'; if (isset($record['extra']['file'], $record['extra']['line'])) { $backtrace = $record['extra']['file'] . ' : ' . $record['extra']['line']; unset($record['extra']['file'], $record['extra']['line']); } $message = ['message' => $record['message']]; if ($record['context']) { $message['context'] = $record['context']; } if ($record['extra']) { $message['extra'] = $record['extra']; } if (\count($message) === 1) { $message = \reset($message); } return [$record['channel'], $message, $backtrace, $this->logLevels[$record['level']]]; } /** * {@inheritDoc} */ public function formatBatch(array $records) { $formatted = []; foreach ($records as $record) { $formatted[] = $this->format($record); } return $formatted; } } monolog/src/Monolog/Formatter/LogglyFormatter.php 0000644 00000002545 14721613470 0016227 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; /** * Encodes message information into JSON in a format compatible with Loggly. * * @author Adam Pancutt <adam@pancutt.com> */ class LogglyFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\JsonFormatter { /** * Overrides the default batch mode to new lines for compatibility with the * Loggly bulk API. */ public function __construct(int $batchMode = self::BATCH_MODE_NEWLINES, bool $appendNewline = \false) { parent::__construct($batchMode, $appendNewline); } /** * Appends the 'timestamp' parameter for indexing by Loggly. * * @see https://www.loggly.com/docs/automated-parsing/#json * @see \Monolog\Formatter\JsonFormatter::format() */ public function format(array $record) : string { if (isset($record["datetime"]) && $record["datetime"] instanceof \DateTimeInterface) { $record["timestamp"] = $record["datetime"]->format("Y-m-d\\TH:i:s.uO"); unset($record["datetime"]); } return parent::format($record); } } monolog/src/Monolog/Formatter/LineFormatter.php 0000644 00000017412 14721613470 0015660 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Formats incoming records into a one-line string * * This is especially useful for logging to files * * @author Jordi Boggiano <j.boggiano@seld.be> * @author Christophe Coevoet <stof@notk.org> */ class LineFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter { public const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; /** @var string */ protected $format; /** @var bool */ protected $allowInlineLineBreaks; /** @var bool */ protected $ignoreEmptyContextAndExtra; /** @var bool */ protected $includeStacktraces; /** @var ?callable */ protected $stacktracesParser; /** * @param string|null $format The format of the message * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format * @param bool $allowInlineLineBreaks Whether to allow inline line breaks in log entries * @param bool $ignoreEmptyContextAndExtra */ public function __construct(?string $format = null, ?string $dateFormat = null, bool $allowInlineLineBreaks = \false, bool $ignoreEmptyContextAndExtra = \false, bool $includeStacktraces = \false) { $this->format = $format === null ? static::SIMPLE_FORMAT : $format; $this->allowInlineLineBreaks = $allowInlineLineBreaks; $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra; $this->includeStacktraces($includeStacktraces); parent::__construct($dateFormat); } public function includeStacktraces(bool $include = \true, ?callable $parser = null) : self { $this->includeStacktraces = $include; if ($this->includeStacktraces) { $this->allowInlineLineBreaks = \true; $this->stacktracesParser = $parser; } return $this; } public function allowInlineLineBreaks(bool $allow = \true) : self { $this->allowInlineLineBreaks = $allow; return $this; } public function ignoreEmptyContextAndExtra(bool $ignore = \true) : self { $this->ignoreEmptyContextAndExtra = $ignore; return $this; } /** * {@inheritDoc} */ public function format(array $record) : string { $vars = parent::format($record); $output = $this->format; foreach ($vars['extra'] as $var => $val) { if (\false !== \strpos($output, '%extra.' . $var . '%')) { $output = \str_replace('%extra.' . $var . '%', $this->stringify($val), $output); unset($vars['extra'][$var]); } } foreach ($vars['context'] as $var => $val) { if (\false !== \strpos($output, '%context.' . $var . '%')) { $output = \str_replace('%context.' . $var . '%', $this->stringify($val), $output); unset($vars['context'][$var]); } } if ($this->ignoreEmptyContextAndExtra) { if (empty($vars['context'])) { unset($vars['context']); $output = \str_replace('%context%', '', $output); } if (empty($vars['extra'])) { unset($vars['extra']); $output = \str_replace('%extra%', '', $output); } } foreach ($vars as $var => $val) { if (\false !== \strpos($output, '%' . $var . '%')) { $output = \str_replace('%' . $var . '%', $this->stringify($val), $output); } } // remove leftover %extra.xxx% and %context.xxx% if any if (\false !== \strpos($output, '%')) { $output = \preg_replace('/%(?:extra|context)\\..+?%/', '', $output); if (null === $output) { $pcreErrorCode = \preg_last_error(); throw new \RuntimeException('Failed to run preg_replace: ' . $pcreErrorCode . ' / ' . \Google\Site_Kit_Dependencies\Monolog\Utils::pcreLastErrorMessage($pcreErrorCode)); } } return $output; } public function formatBatch(array $records) : string { $message = ''; foreach ($records as $record) { $message .= $this->format($record); } return $message; } /** * @param mixed $value */ public function stringify($value) : string { return $this->replaceNewlines($this->convertToString($value)); } protected function normalizeException(\Throwable $e, int $depth = 0) : string { $str = $this->formatException($e); if ($previous = $e->getPrevious()) { do { $depth++; if ($depth > $this->maxNormalizeDepth) { $str .= "\n[previous exception] Over " . $this->maxNormalizeDepth . ' levels deep, aborting normalization'; break; } $str .= "\n[previous exception] " . $this->formatException($previous); } while ($previous = $previous->getPrevious()); } return $str; } /** * @param mixed $data */ protected function convertToString($data) : string { if (null === $data || \is_bool($data)) { return \var_export($data, \true); } if (\is_scalar($data)) { return (string) $data; } return $this->toJson($data, \true); } protected function replaceNewlines(string $str) : string { if ($this->allowInlineLineBreaks) { if (0 === \strpos($str, '{')) { $str = \preg_replace('/(?<!\\\\)\\\\[rn]/', "\n", $str); if (null === $str) { $pcreErrorCode = \preg_last_error(); throw new \RuntimeException('Failed to run preg_replace: ' . $pcreErrorCode . ' / ' . \Google\Site_Kit_Dependencies\Monolog\Utils::pcreLastErrorMessage($pcreErrorCode)); } } return $str; } return \str_replace(["\r\n", "\r", "\n"], ' ', $str); } private function formatException(\Throwable $e) : string { $str = '[object] (' . \Google\Site_Kit_Dependencies\Monolog\Utils::getClass($e) . '(code: ' . $e->getCode(); if ($e instanceof \SoapFault) { if (isset($e->faultcode)) { $str .= ' faultcode: ' . $e->faultcode; } if (isset($e->faultactor)) { $str .= ' faultactor: ' . $e->faultactor; } if (isset($e->detail)) { if (\is_string($e->detail)) { $str .= ' detail: ' . $e->detail; } elseif (\is_object($e->detail) || \is_array($e->detail)) { $str .= ' detail: ' . $this->toJson($e->detail, \true); } } } $str .= '): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine() . ')'; if ($this->includeStacktraces) { $str .= $this->stacktracesParser($e); } return $str; } private function stacktracesParser(\Throwable $e) : string { $trace = $e->getTraceAsString(); if ($this->stacktracesParser) { $trace = $this->stacktracesParserCustom($trace); } return "\n[stacktrace]\n" . $trace . "\n"; } private function stacktracesParserCustom(string $trace) : string { return \implode("\n", \array_filter(\array_map($this->stacktracesParser, \explode("\n", $trace)))); } } monolog/src/Monolog/Formatter/NormalizerFormatter.php 0000644 00000020476 14721613470 0017117 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use Google\Site_Kit_Dependencies\Monolog\DateTimeImmutable; use Google\Site_Kit_Dependencies\Monolog\Utils; use Throwable; /** * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets * * @author Jordi Boggiano <j.boggiano@seld.be> */ class NormalizerFormatter implements \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { public const SIMPLE_DATE = "Y-m-d\\TH:i:sP"; /** @var string */ protected $dateFormat; /** @var int */ protected $maxNormalizeDepth = 9; /** @var int */ protected $maxNormalizeItemCount = 1000; /** @var int */ private $jsonEncodeOptions = \Google\Site_Kit_Dependencies\Monolog\Utils::DEFAULT_JSON_FLAGS; /** * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format */ public function __construct(?string $dateFormat = null) { $this->dateFormat = null === $dateFormat ? static::SIMPLE_DATE : $dateFormat; if (!\function_exists('json_encode')) { throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter'); } } /** * {@inheritDoc} * * @param mixed[] $record */ public function format(array $record) { return $this->normalize($record); } /** * {@inheritDoc} */ public function formatBatch(array $records) { foreach ($records as $key => $record) { $records[$key] = $this->format($record); } return $records; } public function getDateFormat() : string { return $this->dateFormat; } public function setDateFormat(string $dateFormat) : self { $this->dateFormat = $dateFormat; return $this; } /** * The maximum number of normalization levels to go through */ public function getMaxNormalizeDepth() : int { return $this->maxNormalizeDepth; } public function setMaxNormalizeDepth(int $maxNormalizeDepth) : self { $this->maxNormalizeDepth = $maxNormalizeDepth; return $this; } /** * The maximum number of items to normalize per level */ public function getMaxNormalizeItemCount() : int { return $this->maxNormalizeItemCount; } public function setMaxNormalizeItemCount(int $maxNormalizeItemCount) : self { $this->maxNormalizeItemCount = $maxNormalizeItemCount; return $this; } /** * Enables `json_encode` pretty print. */ public function setJsonPrettyPrint(bool $enable) : self { if ($enable) { $this->jsonEncodeOptions |= \JSON_PRETTY_PRINT; } else { $this->jsonEncodeOptions &= ~\JSON_PRETTY_PRINT; } return $this; } /** * @param mixed $data * @return null|scalar|array<array|scalar|null> */ protected function normalize($data, int $depth = 0) { if ($depth > $this->maxNormalizeDepth) { return 'Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization'; } if (null === $data || \is_scalar($data)) { if (\is_float($data)) { if (\is_infinite($data)) { return ($data > 0 ? '' : '-') . 'INF'; } if (\is_nan($data)) { return 'NaN'; } } return $data; } if (\is_array($data)) { $normalized = []; $count = 1; foreach ($data as $key => $value) { if ($count++ > $this->maxNormalizeItemCount) { $normalized['...'] = 'Over ' . $this->maxNormalizeItemCount . ' items (' . \count($data) . ' total), aborting normalization'; break; } $normalized[$key] = $this->normalize($value, $depth + 1); } return $normalized; } if ($data instanceof \DateTimeInterface) { return $this->formatDate($data); } if (\is_object($data)) { if ($data instanceof \Throwable) { return $this->normalizeException($data, $depth); } if ($data instanceof \JsonSerializable) { /** @var null|scalar|array<array|scalar|null> $value */ $value = $data->jsonSerialize(); } elseif (\get_class($data) === '__PHP_Incomplete_Class') { $accessor = new \ArrayObject($data); $value = (string) $accessor['__PHP_Incomplete_Class_Name']; } elseif (\method_exists($data, '__toString')) { /** @var string $value */ $value = $data->__toString(); } else { // the rest is normalized by json encoding and decoding it /** @var null|scalar|array<array|scalar|null> $value */ $value = \json_decode($this->toJson($data, \true), \true); } return [\Google\Site_Kit_Dependencies\Monolog\Utils::getClass($data) => $value]; } if (\is_resource($data)) { return \sprintf('[resource(%s)]', \get_resource_type($data)); } return '[unknown(' . \gettype($data) . ')]'; } /** * @return mixed[] */ protected function normalizeException(\Throwable $e, int $depth = 0) { if ($depth > $this->maxNormalizeDepth) { return ['Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization']; } if ($e instanceof \JsonSerializable) { return (array) $e->jsonSerialize(); } $data = ['class' => \Google\Site_Kit_Dependencies\Monolog\Utils::getClass($e), 'message' => $e->getMessage(), 'code' => (int) $e->getCode(), 'file' => $e->getFile() . ':' . $e->getLine()]; if ($e instanceof \SoapFault) { if (isset($e->faultcode)) { $data['faultcode'] = $e->faultcode; } if (isset($e->faultactor)) { $data['faultactor'] = $e->faultactor; } if (isset($e->detail)) { if (\is_string($e->detail)) { $data['detail'] = $e->detail; } elseif (\is_object($e->detail) || \is_array($e->detail)) { $data['detail'] = $this->toJson($e->detail, \true); } } } $trace = $e->getTrace(); foreach ($trace as $frame) { if (isset($frame['file'])) { $data['trace'][] = $frame['file'] . ':' . $frame['line']; } } if ($previous = $e->getPrevious()) { $data['previous'] = $this->normalizeException($previous, $depth + 1); } return $data; } /** * Return the JSON representation of a value * * @param mixed $data * @throws \RuntimeException if encoding fails and errors are not ignored * @return string if encoding fails and ignoreErrors is true 'null' is returned */ protected function toJson($data, bool $ignoreErrors = \false) : string { return \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($data, $this->jsonEncodeOptions, $ignoreErrors); } /** * @return string */ protected function formatDate(\DateTimeInterface $date) { // in case the date format isn't custom then we defer to the custom DateTimeImmutable // formatting logic, which will pick the right format based on whether useMicroseconds is on if ($this->dateFormat === self::SIMPLE_DATE && $date instanceof \Google\Site_Kit_Dependencies\Monolog\DateTimeImmutable) { return (string) $date; } return $date->format($this->dateFormat); } public function addJsonEncodeOption(int $option) : self { $this->jsonEncodeOptions |= $option; return $this; } public function removeJsonEncodeOption(int $option) : self { $this->jsonEncodeOptions &= ~$option; return $this; } } monolog/src/Monolog/Formatter/FormatterInterface.php 0000644 00000001732 14721613470 0016667 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; /** * Interface for formatters * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Record from \Monolog\Logger */ interface FormatterInterface { /** * Formats a log record. * * @param array $record A record to format * @return mixed The formatted record * * @phpstan-param Record $record */ public function format(array $record); /** * Formats a set of log records. * * @param array $records A set of records to format * @return mixed The formatted set of records * * @phpstan-param Record[] $records */ public function formatBatch(array $records); } monolog/src/Monolog/Formatter/MongoDBFormatter.php 0000644 00000012014 14721613470 0016247 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use MongoDB\BSON\Type; use MongoDB\BSON\UTCDateTime; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Formats a record for use with the MongoDBHandler. * * @author Florian Plattner <me@florianplattner.de> */ class MongoDBFormatter implements \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { /** @var bool */ private $exceptionTraceAsString; /** @var int */ private $maxNestingLevel; /** @var bool */ private $isLegacyMongoExt; /** * @param int $maxNestingLevel 0 means infinite nesting, the $record itself is level 1, $record['context'] is 2 * @param bool $exceptionTraceAsString set to false to log exception traces as a sub documents instead of strings */ public function __construct(int $maxNestingLevel = 3, bool $exceptionTraceAsString = \true) { $this->maxNestingLevel = \max($maxNestingLevel, 0); $this->exceptionTraceAsString = $exceptionTraceAsString; $this->isLegacyMongoExt = \extension_loaded('mongodb') && \version_compare((string) \phpversion('mongodb'), '1.1.9', '<='); } /** * {@inheritDoc} * * @return mixed[] */ public function format(array $record) : array { /** @var mixed[] $res */ $res = $this->formatArray($record); return $res; } /** * {@inheritDoc} * * @return array<mixed[]> */ public function formatBatch(array $records) : array { $formatted = []; foreach ($records as $key => $record) { $formatted[$key] = $this->format($record); } return $formatted; } /** * @param mixed[] $array * @return mixed[]|string Array except when max nesting level is reached then a string "[...]" */ protected function formatArray(array $array, int $nestingLevel = 0) { if ($this->maxNestingLevel > 0 && $nestingLevel > $this->maxNestingLevel) { return '[...]'; } foreach ($array as $name => $value) { if ($value instanceof \DateTimeInterface) { $array[$name] = $this->formatDate($value, $nestingLevel + 1); } elseif ($value instanceof \Throwable) { $array[$name] = $this->formatException($value, $nestingLevel + 1); } elseif (\is_array($value)) { $array[$name] = $this->formatArray($value, $nestingLevel + 1); } elseif (\is_object($value) && !$value instanceof \MongoDB\BSON\Type) { $array[$name] = $this->formatObject($value, $nestingLevel + 1); } } return $array; } /** * @param mixed $value * @return mixed[]|string */ protected function formatObject($value, int $nestingLevel) { $objectVars = \get_object_vars($value); $objectVars['class'] = \Google\Site_Kit_Dependencies\Monolog\Utils::getClass($value); return $this->formatArray($objectVars, $nestingLevel); } /** * @return mixed[]|string */ protected function formatException(\Throwable $exception, int $nestingLevel) { $formattedException = ['class' => \Google\Site_Kit_Dependencies\Monolog\Utils::getClass($exception), 'message' => $exception->getMessage(), 'code' => (int) $exception->getCode(), 'file' => $exception->getFile() . ':' . $exception->getLine()]; if ($this->exceptionTraceAsString === \true) { $formattedException['trace'] = $exception->getTraceAsString(); } else { $formattedException['trace'] = $exception->getTrace(); } return $this->formatArray($formattedException, $nestingLevel); } protected function formatDate(\DateTimeInterface $value, int $nestingLevel) : \MongoDB\BSON\UTCDateTime { if ($this->isLegacyMongoExt) { return $this->legacyGetMongoDbDateTime($value); } return $this->getMongoDbDateTime($value); } private function getMongoDbDateTime(\DateTimeInterface $value) : \MongoDB\BSON\UTCDateTime { return new \MongoDB\BSON\UTCDateTime((int) \floor((float) $value->format('U.u') * 1000)); } /** * This is needed to support MongoDB Driver v1.19 and below * * See https://github.com/mongodb/mongo-php-driver/issues/426 * * It can probably be removed in 2.1 or later once MongoDB's 1.2 is released and widely adopted */ private function legacyGetMongoDbDateTime(\DateTimeInterface $value) : \MongoDB\BSON\UTCDateTime { $milliseconds = \floor((float) $value->format('U.u') * 1000); $milliseconds = \PHP_INT_SIZE == 8 ? (int) $milliseconds : (string) $milliseconds; // @phpstan-ignore-next-line return new \MongoDB\BSON\UTCDateTime($milliseconds); } } monolog/src/Monolog/Formatter/JsonFormatter.php 0000644 00000014106 14721613470 0015677 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use Throwable; /** * Encodes whatever record data is passed to it as json * * This can be useful to log to databases or remote APIs * * @author Jordi Boggiano <j.boggiano@seld.be> * * @phpstan-import-type Record from \Monolog\Logger */ class JsonFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter { public const BATCH_MODE_JSON = 1; public const BATCH_MODE_NEWLINES = 2; /** @var self::BATCH_MODE_* */ protected $batchMode; /** @var bool */ protected $appendNewline; /** @var bool */ protected $ignoreEmptyContextAndExtra; /** @var bool */ protected $includeStacktraces = \false; /** * @param self::BATCH_MODE_* $batchMode */ public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $appendNewline = \true, bool $ignoreEmptyContextAndExtra = \false, bool $includeStacktraces = \false) { $this->batchMode = $batchMode; $this->appendNewline = $appendNewline; $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra; $this->includeStacktraces = $includeStacktraces; parent::__construct(); } /** * The batch mode option configures the formatting style for * multiple records. By default, multiple records will be * formatted as a JSON-encoded array. However, for * compatibility with some API endpoints, alternative styles * are available. */ public function getBatchMode() : int { return $this->batchMode; } /** * True if newlines are appended to every formatted record */ public function isAppendingNewlines() : bool { return $this->appendNewline; } /** * {@inheritDoc} */ public function format(array $record) : string { $normalized = $this->normalize($record); if (isset($normalized['context']) && $normalized['context'] === []) { if ($this->ignoreEmptyContextAndExtra) { unset($normalized['context']); } else { $normalized['context'] = new \stdClass(); } } if (isset($normalized['extra']) && $normalized['extra'] === []) { if ($this->ignoreEmptyContextAndExtra) { unset($normalized['extra']); } else { $normalized['extra'] = new \stdClass(); } } return $this->toJson($normalized, \true) . ($this->appendNewline ? "\n" : ''); } /** * {@inheritDoc} */ public function formatBatch(array $records) : string { switch ($this->batchMode) { case static::BATCH_MODE_NEWLINES: return $this->formatBatchNewlines($records); case static::BATCH_MODE_JSON: default: return $this->formatBatchJson($records); } } /** * @return self */ public function includeStacktraces(bool $include = \true) : self { $this->includeStacktraces = $include; return $this; } /** * Return a JSON-encoded array of records. * * @phpstan-param Record[] $records */ protected function formatBatchJson(array $records) : string { return $this->toJson($this->normalize($records), \true); } /** * Use new lines to separate records instead of a * JSON-encoded array. * * @phpstan-param Record[] $records */ protected function formatBatchNewlines(array $records) : string { $instance = $this; $oldNewline = $this->appendNewline; $this->appendNewline = \false; \array_walk($records, function (&$value, $key) use($instance) { $value = $instance->format($value); }); $this->appendNewline = $oldNewline; return \implode("\n", $records); } /** * Normalizes given $data. * * @param mixed $data * * @return mixed */ protected function normalize($data, int $depth = 0) { if ($depth > $this->maxNormalizeDepth) { return 'Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization'; } if (\is_array($data)) { $normalized = []; $count = 1; foreach ($data as $key => $value) { if ($count++ > $this->maxNormalizeItemCount) { $normalized['...'] = 'Over ' . $this->maxNormalizeItemCount . ' items (' . \count($data) . ' total), aborting normalization'; break; } $normalized[$key] = $this->normalize($value, $depth + 1); } return $normalized; } if (\is_object($data)) { if ($data instanceof \DateTimeInterface) { return $this->formatDate($data); } if ($data instanceof \Throwable) { return $this->normalizeException($data, $depth); } // if the object has specific json serializability we want to make sure we skip the __toString treatment below if ($data instanceof \JsonSerializable) { return $data; } if (\method_exists($data, '__toString')) { return $data->__toString(); } return $data; } if (\is_resource($data)) { return parent::normalize($data); } return $data; } /** * Normalizes given exception with or without its own stack trace based on * `includeStacktraces` property. * * {@inheritDoc} */ protected function normalizeException(\Throwable $e, int $depth = 0) : array { $data = parent::normalizeException($e, $depth); if (!$this->includeStacktraces) { unset($data['trace']); } return $data; } } monolog/src/Monolog/Formatter/HtmlFormatter.php 0000644 00000011535 14721613470 0015675 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Formats incoming records into an HTML table * * This is especially useful for html email logging * * @author Tiago Brito <tlfbrito@gmail.com> */ class HtmlFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter { /** * Translates Monolog log levels to html color priorities. * * @var array<int, string> */ protected $logLevels = [\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG => '#CCCCCC', \Google\Site_Kit_Dependencies\Monolog\Logger::INFO => '#28A745', \Google\Site_Kit_Dependencies\Monolog\Logger::NOTICE => '#17A2B8', \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING => '#FFC107', \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR => '#FD7E14', \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL => '#DC3545', \Google\Site_Kit_Dependencies\Monolog\Logger::ALERT => '#821722', \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY => '#000000']; /** * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format */ public function __construct(?string $dateFormat = null) { parent::__construct($dateFormat); } /** * Creates an HTML table row * * @param string $th Row header content * @param string $td Row standard cell content * @param bool $escapeTd false if td content must not be html escaped */ protected function addRow(string $th, string $td = ' ', bool $escapeTd = \true) : string { $th = \htmlspecialchars($th, \ENT_NOQUOTES, 'UTF-8'); if ($escapeTd) { $td = '<pre>' . \htmlspecialchars($td, \ENT_NOQUOTES, 'UTF-8') . '</pre>'; } return "<tr style=\"padding: 4px;text-align: left;\">\n<th style=\"vertical-align: top;background: #ccc;color: #000\" width=\"100\">{$th}:</th>\n<td style=\"padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000\">" . $td . "</td>\n</tr>"; } /** * Create a HTML h1 tag * * @param string $title Text to be in the h1 * @param int $level Error level * @return string */ protected function addTitle(string $title, int $level) : string { $title = \htmlspecialchars($title, \ENT_NOQUOTES, 'UTF-8'); return '<h1 style="background: ' . $this->logLevels[$level] . ';color: #ffffff;padding: 5px;" class="monolog-output">' . $title . '</h1>'; } /** * Formats a log record. * * @return string The formatted record */ public function format(array $record) : string { $output = $this->addTitle($record['level_name'], $record['level']); $output .= '<table cellspacing="1" width="100%" class="monolog-output">'; $output .= $this->addRow('Message', (string) $record['message']); $output .= $this->addRow('Time', $this->formatDate($record['datetime'])); $output .= $this->addRow('Channel', $record['channel']); if ($record['context']) { $embeddedTable = '<table cellspacing="1" width="100%">'; foreach ($record['context'] as $key => $value) { $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value)); } $embeddedTable .= '</table>'; $output .= $this->addRow('Context', $embeddedTable, \false); } if ($record['extra']) { $embeddedTable = '<table cellspacing="1" width="100%">'; foreach ($record['extra'] as $key => $value) { $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value)); } $embeddedTable .= '</table>'; $output .= $this->addRow('Extra', $embeddedTable, \false); } return $output . '</table>'; } /** * Formats a set of log records. * * @return string The formatted set of records */ public function formatBatch(array $records) : string { $message = ''; foreach ($records as $record) { $message .= $this->format($record); } return $message; } /** * @param mixed $data */ protected function convertToString($data) : string { if (null === $data || \is_scalar($data)) { return (string) $data; } $data = $this->normalize($data); return \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode($data, \JSON_PRETTY_PRINT | \Google\Site_Kit_Dependencies\Monolog\Utils::DEFAULT_JSON_FLAGS, \true); } } monolog/src/Monolog/Formatter/WildfireFormatter.php 0000644 00000007771 14721613470 0016545 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use Google\Site_Kit_Dependencies\Monolog\Logger; /** * Serializes a log message according to Wildfire's header requirements * * @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com> * @author Christophe Coevoet <stof@notk.org> * @author Kirill chEbba Chebunin <iam@chebba.org> * * @phpstan-import-type Level from \Monolog\Logger */ class WildfireFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter { /** * Translates Monolog log levels to Wildfire levels. * * @var array<Level, string> */ private $logLevels = [\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG => 'LOG', \Google\Site_Kit_Dependencies\Monolog\Logger::INFO => 'INFO', \Google\Site_Kit_Dependencies\Monolog\Logger::NOTICE => 'INFO', \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING => 'WARN', \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR => 'ERROR', \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL => 'ERROR', \Google\Site_Kit_Dependencies\Monolog\Logger::ALERT => 'ERROR', \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY => 'ERROR']; /** * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format */ public function __construct(?string $dateFormat = null) { parent::__construct($dateFormat); // http headers do not like non-ISO-8559-1 characters $this->removeJsonEncodeOption(\JSON_UNESCAPED_UNICODE); } /** * {@inheritDoc} * * @return string */ public function format(array $record) : string { // Retrieve the line and file if set and remove them from the formatted extra $file = $line = ''; if (isset($record['extra']['file'])) { $file = $record['extra']['file']; unset($record['extra']['file']); } if (isset($record['extra']['line'])) { $line = $record['extra']['line']; unset($record['extra']['line']); } /** @var mixed[] $record */ $record = $this->normalize($record); $message = ['message' => $record['message']]; $handleError = \false; if ($record['context']) { $message['context'] = $record['context']; $handleError = \true; } if ($record['extra']) { $message['extra'] = $record['extra']; $handleError = \true; } if (\count($message) === 1) { $message = \reset($message); } if (isset($record['context']['table'])) { $type = 'TABLE'; $label = $record['channel'] . ': ' . $record['message']; $message = $record['context']['table']; } else { $type = $this->logLevels[$record['level']]; $label = $record['channel']; } // Create JSON object describing the appearance of the message in the console $json = $this->toJson([['Type' => $type, 'File' => $file, 'Line' => $line, 'Label' => $label], $message], $handleError); // The message itself is a serialization of the above JSON object + it's length return \sprintf('%d|%s|', \strlen($json), $json); } /** * {@inheritDoc} * * @phpstan-return never */ public function formatBatch(array $records) { throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter'); } /** * {@inheritDoc} * * @return null|scalar|array<array|scalar|null>|object */ protected function normalize($data, int $depth = 0) { if (\is_object($data) && !$data instanceof \DateTimeInterface) { return $data; } return parent::normalize($data, $depth); } } monolog/src/Monolog/Formatter/ScalarFormatter.php 0000644 00000002324 14721613470 0016172 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; /** * Formats data into an associative array of scalar values. * Objects and arrays will be JSON encoded. * * @author Andrew Lawson <adlawson@gmail.com> */ class ScalarFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter { /** * {@inheritDoc} * * @phpstan-return array<string, scalar|null> $record */ public function format(array $record) : array { $result = []; foreach ($record as $key => $value) { $result[$key] = $this->normalizeValue($value); } return $result; } /** * @param mixed $value * @return scalar|null */ protected function normalizeValue($value) { $normalized = $this->normalize($value); if (\is_array($normalized)) { return $this->toJson($normalized, \true); } return $normalized; } } monolog/src/Monolog/Formatter/GelfMessageFormatter.php 0000644 00000014054 14721613470 0017152 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use Google\Site_Kit_Dependencies\Monolog\Logger; use Google\Site_Kit_Dependencies\Gelf\Message; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Serializes a log message to GELF * @see http://docs.graylog.org/en/latest/pages/gelf.html * * @author Matt Lehner <mlehner@gmail.com> * * @phpstan-import-type Level from \Monolog\Logger */ class GelfMessageFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter { protected const DEFAULT_MAX_LENGTH = 32766; /** * @var string the name of the system for the Gelf log message */ protected $systemName; /** * @var string a prefix for 'extra' fields from the Monolog record (optional) */ protected $extraPrefix; /** * @var string a prefix for 'context' fields from the Monolog record (optional) */ protected $contextPrefix; /** * @var int max length per field */ protected $maxLength; /** * @var int */ private $gelfVersion = 2; /** * Translates Monolog log levels to Graylog2 log priorities. * * @var array<int, int> * * @phpstan-var array<Level, int> */ private $logLevels = [\Google\Site_Kit_Dependencies\Monolog\Logger::DEBUG => 7, \Google\Site_Kit_Dependencies\Monolog\Logger::INFO => 6, \Google\Site_Kit_Dependencies\Monolog\Logger::NOTICE => 5, \Google\Site_Kit_Dependencies\Monolog\Logger::WARNING => 4, \Google\Site_Kit_Dependencies\Monolog\Logger::ERROR => 3, \Google\Site_Kit_Dependencies\Monolog\Logger::CRITICAL => 2, \Google\Site_Kit_Dependencies\Monolog\Logger::ALERT => 1, \Google\Site_Kit_Dependencies\Monolog\Logger::EMERGENCY => 0]; public function __construct(?string $systemName = null, ?string $extraPrefix = null, string $contextPrefix = 'ctxt_', ?int $maxLength = null) { if (!\class_exists(\Google\Site_Kit_Dependencies\Gelf\Message::class)) { throw new \RuntimeException('Composer package graylog2/gelf-php is required to use Monolog\'s GelfMessageFormatter'); } parent::__construct('U.u'); $this->systemName = \is_null($systemName) || $systemName === '' ? (string) \gethostname() : $systemName; $this->extraPrefix = \is_null($extraPrefix) ? '' : $extraPrefix; $this->contextPrefix = $contextPrefix; $this->maxLength = \is_null($maxLength) ? self::DEFAULT_MAX_LENGTH : $maxLength; if (\method_exists(\Google\Site_Kit_Dependencies\Gelf\Message::class, 'setFacility')) { $this->gelfVersion = 1; } } /** * {@inheritDoc} */ public function format(array $record) : \Google\Site_Kit_Dependencies\Gelf\Message { $context = $extra = []; if (isset($record['context'])) { /** @var mixed[] $context */ $context = parent::normalize($record['context']); } if (isset($record['extra'])) { /** @var mixed[] $extra */ $extra = parent::normalize($record['extra']); } if (!isset($record['datetime'], $record['message'], $record['level'])) { throw new \InvalidArgumentException('The record should at least contain datetime, message and level keys, ' . \var_export($record, \true) . ' given'); } $message = new \Google\Site_Kit_Dependencies\Gelf\Message(); $message->setTimestamp($record['datetime'])->setShortMessage((string) $record['message'])->setHost($this->systemName)->setLevel($this->logLevels[$record['level']]); // message length + system name length + 200 for padding / metadata $len = 200 + \strlen((string) $record['message']) + \strlen($this->systemName); if ($len > $this->maxLength) { $message->setShortMessage(\Google\Site_Kit_Dependencies\Monolog\Utils::substr($record['message'], 0, $this->maxLength)); } if ($this->gelfVersion === 1) { if (isset($record['channel'])) { $message->setFacility($record['channel']); } if (isset($extra['line'])) { $message->setLine($extra['line']); unset($extra['line']); } if (isset($extra['file'])) { $message->setFile($extra['file']); unset($extra['file']); } } else { $message->setAdditional('facility', $record['channel']); } foreach ($extra as $key => $val) { $val = \is_scalar($val) || null === $val ? $val : $this->toJson($val); $len = \strlen($this->extraPrefix . $key . $val); if ($len > $this->maxLength) { $message->setAdditional($this->extraPrefix . $key, \Google\Site_Kit_Dependencies\Monolog\Utils::substr((string) $val, 0, $this->maxLength)); continue; } $message->setAdditional($this->extraPrefix . $key, $val); } foreach ($context as $key => $val) { $val = \is_scalar($val) || null === $val ? $val : $this->toJson($val); $len = \strlen($this->contextPrefix . $key . $val); if ($len > $this->maxLength) { $message->setAdditional($this->contextPrefix . $key, \Google\Site_Kit_Dependencies\Monolog\Utils::substr((string) $val, 0, $this->maxLength)); continue; } $message->setAdditional($this->contextPrefix . $key, $val); } if ($this->gelfVersion === 1) { /** @phpstan-ignore-next-line */ if (null === $message->getFile() && isset($context['exception']['file'])) { if (\preg_match("/^(.+):([0-9]+)\$/", $context['exception']['file'], $matches)) { $message->setFile($matches[1]); $message->setLine($matches[2]); } } } return $message; } } monolog/src/Monolog/Formatter/ElasticaFormatter.php 0000644 00000004313 14721613470 0016512 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use Google\Site_Kit_Dependencies\Elastica\Document; /** * Format a log message into an Elastica Document * * @author Jelle Vink <jelle.vink@gmail.com> * * @phpstan-import-type Record from \Monolog\Logger */ class ElasticaFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter { /** * @var string Elastic search index name */ protected $index; /** * @var ?string Elastic search document type */ protected $type; /** * @param string $index Elastic Search index name * @param ?string $type Elastic Search document type, deprecated as of Elastica 7 */ public function __construct(string $index, ?string $type) { // elasticsearch requires a ISO 8601 format date with optional millisecond precision. parent::__construct('Y-m-d\\TH:i:s.uP'); $this->index = $index; $this->type = $type; } /** * {@inheritDoc} */ public function format(array $record) { $record = parent::format($record); return $this->getDocument($record); } public function getIndex() : string { return $this->index; } /** * @deprecated since Elastica 7 type has no effect */ public function getType() : string { /** @phpstan-ignore-next-line */ return $this->type; } /** * Convert a log message into an Elastica Document * * @phpstan-param Record $record */ protected function getDocument(array $record) : \Google\Site_Kit_Dependencies\Elastica\Document { $document = new \Google\Site_Kit_Dependencies\Elastica\Document(); $document->setData($record); if (\method_exists($document, 'setType')) { /** @phpstan-ignore-next-line */ $document->setType($this->type); } $document->setIndex($this->index); return $document; } } monolog/src/Monolog/Formatter/LogstashFormatter.php 0000644 00000006544 14721613470 0016561 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; /** * Serializes a log message to Logstash Event Format * * @see https://www.elastic.co/products/logstash * @see https://github.com/elastic/logstash/blob/master/logstash-core/src/main/java/org/logstash/Event.java * * @author Tim Mower <timothy.mower@gmail.com> */ class LogstashFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter { /** * @var string the name of the system for the Logstash log message, used to fill the @source field */ protected $systemName; /** * @var string an application name for the Logstash log message, used to fill the @type field */ protected $applicationName; /** * @var string the key for 'extra' fields from the Monolog record */ protected $extraKey; /** * @var string the key for 'context' fields from the Monolog record */ protected $contextKey; /** * @param string $applicationName The application that sends the data, used as the "type" field of logstash * @param string|null $systemName The system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine * @param string $extraKey The key for extra keys inside logstash "fields", defaults to extra * @param string $contextKey The key for context keys inside logstash "fields", defaults to context */ public function __construct(string $applicationName, ?string $systemName = null, string $extraKey = 'extra', string $contextKey = 'context') { // logstash requires a ISO 8601 format date with optional millisecond precision. parent::__construct('Y-m-d\\TH:i:s.uP'); $this->systemName = $systemName === null ? (string) \gethostname() : $systemName; $this->applicationName = $applicationName; $this->extraKey = $extraKey; $this->contextKey = $contextKey; } /** * {@inheritDoc} */ public function format(array $record) : string { $record = parent::format($record); if (empty($record['datetime'])) { $record['datetime'] = \gmdate('c'); } $message = ['@timestamp' => $record['datetime'], '@version' => 1, 'host' => $this->systemName]; if (isset($record['message'])) { $message['message'] = $record['message']; } if (isset($record['channel'])) { $message['type'] = $record['channel']; $message['channel'] = $record['channel']; } if (isset($record['level_name'])) { $message['level'] = $record['level_name']; } if (isset($record['level'])) { $message['monolog_level'] = $record['level']; } if ($this->applicationName) { $message['type'] = $this->applicationName; } if (!empty($record['extra'])) { $message[$this->extraKey] = $record['extra']; } if (!empty($record['context'])) { $message[$this->contextKey] = $record['context']; } return $this->toJson($message) . "\n"; } } monolog/src/Monolog/Formatter/FlowdockFormatter.php 0000644 00000004701 14721613470 0016536 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; /** * formats the record to be used in the FlowdockHandler * * @author Dominik Liebler <liebler.dominik@gmail.com> * @deprecated Since 2.9.0 and 3.3.0, Flowdock was shutdown we will thus drop this handler in Monolog 4 */ class FlowdockFormatter implements \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { /** * @var string */ private $source; /** * @var string */ private $sourceEmail; public function __construct(string $source, string $sourceEmail) { $this->source = $source; $this->sourceEmail = $sourceEmail; } /** * {@inheritDoc} * * @return mixed[] */ public function format(array $record) : array { $tags = ['#logs', '#' . \strtolower($record['level_name']), '#' . $record['channel']]; foreach ($record['extra'] as $value) { $tags[] = '#' . $value; } $subject = \sprintf('in %s: %s - %s', $this->source, $record['level_name'], $this->getShortMessage($record['message'])); $record['flowdock'] = ['source' => $this->source, 'from_address' => $this->sourceEmail, 'subject' => $subject, 'content' => $record['message'], 'tags' => $tags, 'project' => $this->source]; return $record; } /** * {@inheritDoc} * * @return mixed[][] */ public function formatBatch(array $records) : array { $formatted = []; foreach ($records as $record) { $formatted[] = $this->format($record); } return $formatted; } public function getShortMessage(string $message) : string { static $hasMbString; if (null === $hasMbString) { $hasMbString = \function_exists('mb_strlen'); } $maxLength = 45; if ($hasMbString) { if (\mb_strlen($message, 'UTF-8') > $maxLength) { $message = \mb_substr($message, 0, $maxLength - 4, 'UTF-8') . ' ...'; } } else { if (\strlen($message) > $maxLength) { $message = \substr($message, 0, $maxLength - 4) . ' ...'; } } return $message; } } monolog/src/Monolog/Formatter/LogmaticFormatter.php 0000644 00000003023 14721613470 0016521 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; /** * Encodes message information into JSON in a format compatible with Logmatic. * * @author Julien Breux <julien.breux@gmail.com> */ class LogmaticFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\JsonFormatter { protected const MARKERS = ["sourcecode", "php"]; /** * @var string */ protected $hostname = ''; /** * @var string */ protected $appname = ''; public function setHostname(string $hostname) : self { $this->hostname = $hostname; return $this; } public function setAppname(string $appname) : self { $this->appname = $appname; return $this; } /** * Appends the 'hostname' and 'appname' parameter for indexing by Logmatic. * * @see http://doc.logmatic.io/docs/basics-to-send-data * @see \Monolog\Formatter\JsonFormatter::format() */ public function format(array $record) : string { if (!empty($this->hostname)) { $record["hostname"] = $this->hostname; } if (!empty($this->appname)) { $record["appname"] = $this->appname; } $record["@marker"] = static::MARKERS; return parent::format($record); } } monolog/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php 0000644 00000002322 14721613470 0020475 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use DateTimeInterface; use Google\Site_Kit_Dependencies\Monolog\LogRecord; /** * Encodes message information into JSON in a format compatible with Cloud logging. * * @see https://cloud.google.com/logging/docs/structured-logging * @see https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry * * @author Luís Cobucci <lcobucci@gmail.com> */ final class GoogleCloudLoggingFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\JsonFormatter { /** {@inheritdoc} **/ public function format(array $record) : string { // Re-key level for GCP logging $record['severity'] = $record['level_name']; $record['time'] = $record['datetime']->format(\DateTimeInterface::RFC3339_EXTENDED); // Remove keys that are not used by GCP unset($record['level'], $record['level_name'], $record['datetime']); return parent::format($record); } } monolog/src/Monolog/Formatter/ElasticsearchFormatter.php 0000644 00000003614 14721613470 0017542 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use DateTimeInterface; /** * Format a log message into an Elasticsearch record * * @author Avtandil Kikabidze <akalongman@gmail.com> */ class ElasticsearchFormatter extends \Google\Site_Kit_Dependencies\Monolog\Formatter\NormalizerFormatter { /** * @var string Elasticsearch index name */ protected $index; /** * @var string Elasticsearch record type */ protected $type; /** * @param string $index Elasticsearch index name * @param string $type Elasticsearch record type */ public function __construct(string $index, string $type) { // Elasticsearch requires an ISO 8601 format date with optional millisecond precision. parent::__construct(\DateTimeInterface::ISO8601); $this->index = $index; $this->type = $type; } /** * {@inheritDoc} */ public function format(array $record) { $record = parent::format($record); return $this->getDocument($record); } /** * Getter index * * @return string */ public function getIndex() : string { return $this->index; } /** * Getter type * * @return string */ public function getType() : string { return $this->type; } /** * Convert a log message into an Elasticsearch record * * @param mixed[] $record Log message * @return mixed[] */ protected function getDocument(array $record) : array { $record['_index'] = $this->index; $record['_type'] = $this->type; return $record; } } monolog/src/Monolog/Formatter/FluentdFormatter.php 0000644 00000004416 14721613470 0016372 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog\Formatter; use Google\Site_Kit_Dependencies\Monolog\Utils; /** * Class FluentdFormatter * * Serializes a log message to Fluentd unix socket protocol * * Fluentd config: * * <source> * type unix * path /var/run/td-agent/td-agent.sock * </source> * * Monolog setup: * * $logger = new Monolog\Logger('fluent.tag'); * $fluentHandler = new Monolog\Handler\SocketHandler('unix:///var/run/td-agent/td-agent.sock'); * $fluentHandler->setFormatter(new Monolog\Formatter\FluentdFormatter()); * $logger->pushHandler($fluentHandler); * * @author Andrius Putna <fordnox@gmail.com> */ class FluentdFormatter implements \Google\Site_Kit_Dependencies\Monolog\Formatter\FormatterInterface { /** * @var bool $levelTag should message level be a part of the fluentd tag */ protected $levelTag = \false; public function __construct(bool $levelTag = \false) { if (!\function_exists('json_encode')) { throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s FluentdUnixFormatter'); } $this->levelTag = $levelTag; } public function isUsingLevelsInTag() : bool { return $this->levelTag; } public function format(array $record) : string { $tag = $record['channel']; if ($this->levelTag) { $tag .= '.' . \strtolower($record['level_name']); } $message = ['message' => $record['message'], 'context' => $record['context'], 'extra' => $record['extra']]; if (!$this->levelTag) { $message['level'] = $record['level']; $message['level_name'] = $record['level_name']; } return \Google\Site_Kit_Dependencies\Monolog\Utils::jsonEncode([$tag, $record['datetime']->getTimestamp(), $message]); } public function formatBatch(array $records) : string { $message = ''; foreach ($records as $record) { $message .= $this->format($record); } return $message; } } monolog/src/Monolog/ErrorHandler.php 0000644 00000026431 14721613470 0013532 0 ustar 00 <?php declare (strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Google\Site_Kit_Dependencies\Monolog; use Google\Site_Kit_Dependencies\Psr\Log\LoggerInterface; use Google\Site_Kit_Dependencies\Psr\Log\LogLevel; /** * Monolog error handler * * A facility to enable logging of runtime errors, exceptions and fatal errors. * * Quick setup: <code>ErrorHandler::register($logger);</code> * * @author Jordi Boggiano <j.boggiano@seld.be> */ class ErrorHandler { /** @var LoggerInterface */ private $logger; /** @var ?callable */ private $previousExceptionHandler = null; /** @var array<class-string, LogLevel::*> an array of class name to LogLevel::* constant mapping */ private $uncaughtExceptionLevelMap = []; /** @var callable|true|null */ private $previousErrorHandler = null; /** @var array<int, LogLevel::*> an array of E_* constant to LogLevel::* constant mapping */ private $errorLevelMap = []; /** @var bool */ private $handleOnlyReportedErrors = \true; /** @var bool */ private $hasFatalErrorHandler = \false; /** @var LogLevel::* */ private $fatalLevel = \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::ALERT; /** @var ?string */ private $reservedMemory = null; /** @var ?array{type: int, message: string, file: string, line: int, trace: mixed} */ private $lastFatalData = null; /** @var int[] */ private static $fatalErrors = [\E_ERROR, \E_PARSE, \E_CORE_ERROR, \E_COMPILE_ERROR, \E_USER_ERROR]; public function __construct(\Google\Site_Kit_Dependencies\Psr\Log\LoggerInterface $logger) { $this->logger = $logger; } /** * Registers a new ErrorHandler for a given Logger * * By default it will handle errors, exceptions and fatal errors * * @param LoggerInterface $logger * @param array<int, LogLevel::*>|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling * @param array<class-string, LogLevel::*>|false $exceptionLevelMap an array of class name to LogLevel::* constant mapping, or false to disable exception handling * @param LogLevel::*|null|false $fatalLevel a LogLevel::* constant, null to use the default LogLevel::ALERT or false to disable fatal error handling * @return ErrorHandler */ public static function register(\Google\Site_Kit_Dependencies\Psr\Log\LoggerInterface $logger, $errorLevelMap = [], $exceptionLevelMap = [], $fatalLevel = null) : self { /** @phpstan-ignore-next-line */ $handler = new static($logger); if ($errorLevelMap !== \false) { $handler->registerErrorHandler($errorLevelMap); } if ($exceptionLevelMap !== \false) { $handler->registerExceptionHandler($exceptionLevelMap); } if ($fatalLevel !== \false) { $handler->registerFatalHandler($fatalLevel); } return $handler; } /** * @param array<class-string, LogLevel::*> $levelMap an array of class name to LogLevel::* constant mapping * @return $this */ public function registerExceptionHandler(array $levelMap = [], bool $callPrevious = \true) : self { $prev = \set_exception_handler(function (\Throwable $e) : void { $this->handleException($e); }); $this->uncaughtExceptionLevelMap = $levelMap; foreach ($this->defaultExceptionLevelMap() as $class => $level) { if (!isset($this->uncaughtExceptionLevelMap[$class])) { $this->uncaughtExceptionLevelMap[$class] = $level; } } if ($callPrevious && $prev) { $this->previousExceptionHandler = $prev; } return $this; } /** * @param array<int, LogLevel::*> $levelMap an array of E_* constant to LogLevel::* constant mapping * @return $this */ public function registerErrorHandler(array $levelMap = [], bool $callPrevious = \true, int $errorTypes = -1, bool $handleOnlyReportedErrors = \true) : self { $prev = \set_error_handler([$this, 'handleError'], $errorTypes); $this->errorLevelMap = \array_replace($this->defaultErrorLevelMap(), $levelMap); if ($callPrevious) { $this->previousErrorHandler = $prev ?: \true; } else { $this->previousErrorHandler = null; } $this->handleOnlyReportedErrors = $handleOnlyReportedErrors; return $this; } /** * @param LogLevel::*|null $level a LogLevel::* constant, null to use the default LogLevel::ALERT * @param int $reservedMemorySize Amount of KBs to reserve in memory so that it can be freed when handling fatal errors giving Monolog some room in memory to get its job done */ public function registerFatalHandler($level = null, int $reservedMemorySize = 20) : self { \register_shutdown_function([$this, 'handleFatalError']); $this->reservedMemory = \str_repeat(' ', 1024 * $reservedMemorySize); $this->fatalLevel = null === $level ? \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::ALERT : $level; $this->hasFatalErrorHandler = \true; return $this; } /** * @return array<class-string, LogLevel::*> */ protected function defaultExceptionLevelMap() : array { return ['ParseError' => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::CRITICAL, 'Throwable' => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::ERROR]; } /** * @return array<int, LogLevel::*> */ protected function defaultErrorLevelMap() : array { return [\E_ERROR => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::CRITICAL, \E_WARNING => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::WARNING, \E_PARSE => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::ALERT, \E_NOTICE => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::NOTICE, \E_CORE_ERROR => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::CRITICAL, \E_CORE_WARNING => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::WARNING, \E_COMPILE_ERROR => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::ALERT, \E_COMPILE_WARNING => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::WARNING, \E_USER_ERROR => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::ERROR, \E_USER_WARNING => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::WARNING, \E_USER_NOTICE => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::NOTICE, \E_STRICT => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::NOTICE, \E_RECOVERABLE_ERROR => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::ERROR, \E_DEPRECATED => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::NOTICE, \E_USER_DEPRECATED => \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::NOTICE]; } /** * @phpstan-return never */ private function handleException(\Throwable $e) : void { $level = \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::ERROR; foreach ($this->uncaughtExceptionLevelMap as $class => $candidate) { if ($e instanceof $class) { $level = $candidate; break; } } $this->logger->log($level, \sprintf('Uncaught Exception %s: "%s" at %s line %s', \Google\Site_Kit_Dependencies\Monolog\Utils::getClass($e), $e->getMessage(), $e->getFile(), $e->getLine()), ['exception' => $e]); if ($this->previousExceptionHandler) { ($this->previousExceptionHandler)($e); } if (!\headers_sent() && \in_array(\strtolower((string) \ini_get('display_errors')), ['0', '', 'false', 'off', 'none', 'no'], \true)) { \http_response_code(500); } exit(255); } /** * @private * * @param mixed[] $context */ public function handleError(int $code, string $message, string $file = '', int $line = 0, ?array $context = []) : bool { if ($this->handleOnlyReportedErrors && !(\error_reporting() & $code)) { return \false; } // fatal error codes are ignored if a fatal error handler is present as well to avoid duplicate log entries if (!$this->hasFatalErrorHandler || !\in_array($code, self::$fatalErrors, \true)) { $level = $this->errorLevelMap[$code] ?? \Google\Site_Kit_Dependencies\Psr\Log\LogLevel::CRITICAL; $this->logger->log($level, self::codeToString($code) . ': ' . $message, ['code' => $code, 'message' => $message, 'file' => $file, 'line' => $line]); } else { $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); \array_shift($trace); // Exclude handleError from trace $this->lastFatalData = ['type' => $code, 'message' => $message, 'file' => $file, 'line' => $line, 'trace' => $trace]; } if ($this->previousErrorHandler === \true) { return \false; } elseif ($this->previousErrorHandler) { return (bool) ($this->previousErrorHandler)($code, $message, $file, $line, $context); } return \true; } /** * @private */ public function handleFatalError() : void { $this->reservedMemory = ''; if (\is_array($this->lastFatalData)) { $lastError = $this->lastFatalData; } else { $lastError = \error_get_last(); } if ($lastError && \in_array($lastError['type'], self::$fatalErrors, \true)) { $trace = $lastError['trace'] ?? null; $this->logger->log($this->fatalLevel, 'Fatal Error (' . self::codeToString($lastError['type']) . '): ' . $lastError['message'], ['code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $trace]); if ($this->logger instanceof \Google\Site_Kit_Dependencies\Monolog\Logger) { foreach ($this->logger->getHandlers() as $handler) { $handler->close(); } } } } /** * @param int $code */ private static function codeToString($code) : string { switch ($code) { case \E_ERROR: return 'E_ERROR'; case \E_WARNING: return 'E_WARNING'; case \E_PARSE: return 'E_PARSE'; case \E_NOTICE: return 'E_NOTICE'; case \E_CORE_ERROR: return 'E_CORE_ERROR'; case \E_CORE_WARNING: return 'E_CORE_WARNING'; case \E_COMPILE_ERROR: return 'E_COMPILE_ERROR'; case \E_COMPILE_WARNING: return 'E_COMPILE_WARNING'; case \E_USER_ERROR: return 'E_USER_ERROR'; case \E_USER_WARNING: return 'E_USER_WARNING'; case \E_USER_NOTICE: return 'E_USER_NOTICE'; case \E_STRICT: return 'E_STRICT'; case \E_RECOVERABLE_ERROR: return 'E_RECOVERABLE_ERROR'; case \E_DEPRECATED: return 'E_DEPRECATED'; case \E_USER_DEPRECATED: return 'E_USER_DEPRECATED'; } return 'Unknown PHP error'; } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.3-4ubuntu2.24 | Генерация страницы: 0.02 |
proxy
|
phpinfo
|
Настройка