| Current Path : /home/w/u/e/wuectly/www/03cbe/ |
| Current File : /home/w/u/e/wuectly/www/03cbe/Log.tar |
LogEntry.php 0000604 00000005535 15245540366 0007036 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Date\Date;
use Joomla\CMS\Filesystem\Path;
/**
* Joomla! Log Entry class
*
* This class is designed to hold log entries for either writing to an engine, or for
* supported engines, retrieving lists and building in memory (PHP based) search operations.
*
* @since 1.7.0
*/
class LogEntry
{
/**
* Application responsible for log entry.
* @var string
* @since 1.7.0
*/
public $category;
/**
* The message context.
*
* @var array
* @since 3.8.0
*/
public $context;
/**
* The date the message was logged.
* @var Date
* @since 1.7.0
*/
public $date;
/**
* Message to be logged.
* @var string
* @since 1.7.0
*/
public $message;
/**
* The priority of the message to be logged.
* @var string
* @since 1.7.0
* @see LogEntry::$priorities
*/
public $priority = Log::INFO;
/**
* List of available log priority levels [Based on the Syslog default levels].
* @var array
* @since 1.7.0
*/
protected $priorities = array(
Log::EMERGENCY,
Log::ALERT,
Log::CRITICAL,
Log::ERROR,
Log::WARNING,
Log::NOTICE,
Log::INFO,
Log::DEBUG,
);
/**
* Call stack and back trace of the logged call.
* @var array
* @since 3.1.4
*/
public $callStack = array();
/**
* Constructor
*
* @param string $message The message to log.
* @param int $priority Message priority based on {$this->priorities}.
* @param string $category Type of entry
* @param string $date Date of entry (defaults to now if not specified or blank)
* @param array $context An optional array with additional message context.
*
* @since 1.7.0
* @change 3.10.7 If the message containes a full path, the root path (JPATH_ROOT) is removed from it
* to avoid any full path disclosure. Before 3.10.7, the path was propagated as provided.
*/
public function __construct($message, $priority = Log::INFO, $category = '', $date = null, array $context = array())
{
$this->message = Path::removeRoot((string) $message);
// Sanitize the priority.
if (!in_array($priority, $this->priorities, true))
{
$priority = Log::INFO;
}
$this->priority = $priority;
$this->context = $context;
// Sanitize category if it exists.
if (!empty($category))
{
$this->category = (string) strtolower(preg_replace('/[^A-Z0-9_\.-]/i', '', $category));
}
// Get the current call stack and back trace (without args to save memory).
$this->callStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// Get the date as a Date object.
$this->date = new Date($date ? $date : 'now');
}
}
Logger/FormattedtextLogger.php 0000604 00000016520 15245540366 0012500 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log\Logger;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;
use Joomla\Utilities\IpHelper;
\JLoader::import('joomla.filesystem.file');
\JLoader::import('joomla.filesystem.folder');
/**
* Joomla! Formatted Text File Log class
*
* This class is designed to use as a base for building formatted text files for output. By
* default it emulates the Syslog style format output. This is a disk based output format.
*
* @since 1.7.0
*/
class FormattedtextLogger extends Logger
{
/**
* The format which each entry follows in the log file.
*
* All fields must be named in all caps and be within curly brackets eg. {FOOBAR}.
*
* @var string
* @since 1.7.0
*/
protected $format = '{DATETIME} {PRIORITY} {CLIENTIP} {CATEGORY} {MESSAGE}';
/**
* The parsed fields from the format string.
*
* @var array
* @since 1.7.0
*/
protected $fields = array();
/**
* The full filesystem path for the log file.
*
* @var string
* @since 1.7.0
*/
protected $path;
/**
* If true, all writes will be deferred as long as possible.
* NOTE: Deferred logs may never be written if the application encounters a fatal error.
*
* @var boolean
* @since 3.9.0
*/
protected $defer = false;
/**
* If deferring, entries will be stored here prior to writing.
*
* @var array
* @since 3.9.0
*/
protected $deferredEntries = array();
/**
* Constructor.
*
* @param array &$options Log object options.
*
* @since 1.7.0
*/
public function __construct(array &$options)
{
// Call the parent constructor.
parent::__construct($options);
// The name of the text file defaults to 'error.php' if not explicitly given.
if (empty($this->options['text_file']))
{
$this->options['text_file'] = 'error.php';
}
// The name of the text file path defaults to that which is set in configuration if not explicitly given.
if (empty($this->options['text_file_path']))
{
$this->options['text_file_path'] = \JFactory::getConfig()->get('log_path');
}
// False to treat the log file as a php file.
if (empty($this->options['text_file_no_php']))
{
$this->options['text_file_no_php'] = false;
}
// Build the full path to the log file.
$this->path = $this->options['text_file_path'] . '/' . $this->options['text_file'];
// Use the default entry format unless explicitly set otherwise.
if (!empty($this->options['text_entry_format']))
{
$this->format = (string) $this->options['text_entry_format'];
}
// Wait as long as possible before writing logs
if (!empty($this->options['defer']))
{
$this->defer = (boolean) $this->options['defer'];
}
// Build the fields array based on the format string.
$this->parseFields();
}
/**
* If deferred, write all pending logs.
*
* @since 3.9.0
*/
public function __destruct()
{
// Nothing to do
if (!$this->defer || empty($this->deferredEntries))
{
return;
}
// Initialise the file if not already done.
$this->initFile();
// Format all lines and write to file.
$lines = array_map(array($this, 'formatLine'), $this->deferredEntries);
if (!\JFile::append($this->path, implode("\n", $lines) . "\n"))
{
throw new \RuntimeException('Cannot write to log file.');
}
}
/**
* Method to add an entry to the log.
*
* @param LogEntry $entry The log entry object to add to the log.
*
* @return void
*
* @since 1.7.0
* @throws \RuntimeException
*/
public function addEntry(LogEntry $entry)
{
// Store the entry to be written later.
if ($this->defer)
{
$this->deferredEntries[] = $entry;
}
// Write it immediately.
else
{
// Initialise the file if not already done.
$this->initFile();
// Write the new entry to the file.
$line = $this->formatLine($entry);
$line .= "\n";
if (!\JFile::append($this->path, $line))
{
throw new \RuntimeException('Cannot write to log file.');
}
}
}
/**
* Format a line for the log file.
*
* @param JLogEntry $entry The log entry to format as a string.
*
* @return String
*
* @since 3.9.0
*/
protected function formatLine(LogEntry $entry)
{
// Set some default field values if not already set.
if (!isset($entry->clientIP))
{
$ip = IpHelper::getIp();
if ($ip !== '')
{
$entry->clientIP = $ip;
}
}
// If the time field is missing or the date field isn't only the date we need to rework it.
if ((strlen($entry->date) != 10) || !isset($entry->time))
{
// Get the date and time strings in GMT.
$entry->datetime = $entry->date->toISO8601();
$entry->time = $entry->date->format('H:i:s', false);
$entry->date = $entry->date->format('Y-m-d', false);
}
// Get a list of all the entry keys and make sure they are upper case.
$tmp = array_change_key_case(get_object_vars($entry), CASE_UPPER);
// Decode the entry priority into an English string.
$tmp['PRIORITY'] = $this->priorities[$entry->priority];
// Fill in field data for the line.
$line = $this->format;
foreach ($this->fields as $field)
{
$line = str_replace('{' . $field . '}', (isset($tmp[$field])) ? $tmp[$field] : '-', $line);
}
return $line;
}
/**
* Method to generate the log file header.
*
* @return string The log file header
*
* @since 1.7.0
*/
protected function generateFileHeader()
{
$head = array();
// Build the log file header.
// If the no php flag is not set add the php die statement.
if (empty($this->options['text_file_no_php']))
{
// Blank line to prevent information disclose: https://bugs.php.net/bug.php?id=60677
$head[] = '#';
$head[] = '#<?php die(\'Forbidden.\'); ?>';
}
$head[] = '#Date: ' . gmdate('Y-m-d H:i:s') . ' UTC';
$head[] = '#Software: ' . \JPlatform::getLongVersion();
$head[] = '';
// Prepare the fields string
$head[] = '#Fields: ' . strtolower(str_replace('}', '', str_replace('{', '', $this->format)));
$head[] = '';
return implode("\n", $head);
}
/**
* Method to initialise the log file. This will create the folder path to the file if it doesn't already
* exist and also get a new file header if the file doesn't already exist. If the file already exists it
* will simply open it for writing.
*
* @return void
*
* @since 1.7.0
* @throws \RuntimeException
*/
protected function initFile()
{
// We only need to make sure the file exists
if (\JFile::exists($this->path))
{
return;
}
// Make sure the folder exists in which to create the log file.
\JFolder::create(dirname($this->path));
// Build the log file header.
$head = $this->generateFileHeader();
if (!\JFile::write($this->path, $head))
{
throw new \RuntimeException('Cannot write to log file.');
}
}
/**
* Method to parse the format string into an array of fields.
*
* @return void
*
* @since 1.7.0
*/
protected function parseFields()
{
$this->fields = array();
$matches = array();
// Get all of the available fields in the format string.
preg_match_all('/{(.*?)}/i', $this->format, $matches);
// Build the parsed fields list based on the found fields.
foreach ($matches[1] as $match)
{
$this->fields[] = strtoupper($match);
}
}
}
Logger/CallbackLogger.php 0000604 00000003106 15245540366 0011336 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log\Logger;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;
/**
* Joomla! Callback Log class
*
* This class allows logging to be handled by a callback function.
* This allows unprecedented flexibility in the way logging can be handled.
*
* @since 3.0.1
*/
class CallbackLogger extends Logger
{
/**
* The function to call when an entry is added
*
* @var callable
* @since 3.0.1
*/
protected $callback;
/**
* Constructor.
*
* @param array &$options Log object options.
*
* @since 3.0.1
* @throws \RuntimeException
*/
public function __construct(array &$options)
{
// Call the parent constructor.
parent::__construct($options);
// Throw an exception if there is not a valid callback
if (!isset($this->options['callback']) || !is_callable($this->options['callback']))
{
throw new \RuntimeException(sprintf('%s created without valid callback function.', get_class($this)));
}
$this->callback = $this->options['callback'];
}
/**
* Method to add an entry to the log.
*
* @param LogEntry $entry The log entry object to add to the log.
*
* @return void
*
* @since 3.0.1
* @throws \RuntimeException
*/
public function addEntry(LogEntry $entry)
{
// Pass the log entry to the callback function
call_user_func($this->callback, $entry);
}
}
Logger/MessagequeueLogger.php 0000604 00000002706 15245540366 0012300 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log\Logger;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;
/**
* Joomla MessageQueue logger class.
*
* This class is designed to output logs to a specific MySQL database table. Fields in this
* table are based on the Syslog style of log output. This is designed to allow quick and
* easy searching.
*
* @since 1.7.0
*/
class MessagequeueLogger extends Logger
{
/**
* Method to add an entry to the log.
*
* @param LogEntry $entry The log entry object to add to the log.
*
* @return void
*
* @since 1.7.0
*/
public function addEntry(LogEntry $entry)
{
switch ($entry->priority)
{
case Log::EMERGENCY:
case Log::ALERT:
case Log::CRITICAL:
case Log::ERROR:
\JFactory::getApplication()->enqueueMessage($entry->message, 'error');
break;
case Log::WARNING:
\JFactory::getApplication()->enqueueMessage($entry->message, 'warning');
break;
case Log::NOTICE:
\JFactory::getApplication()->enqueueMessage($entry->message, 'notice');
break;
case Log::INFO:
\JFactory::getApplication()->enqueueMessage($entry->message, 'message');
break;
default:
// Ignore other priorities.
break;
}
}
}
Logger/EchoLogger.php 0000604 00000002373 15245540366 0010525 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log\Logger;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;
/**
* Joomla Echo logger class.
*
* @since 1.7.0
*/
class EchoLogger extends Logger
{
/**
* Value to use at the end of an echoed log entry to separate lines.
*
* @var string
* @since 1.7.0
*/
protected $line_separator = "\n";
/**
* Constructor.
*
* @param array &$options Log object options.
*
* @since 3.0.0
*/
public function __construct(array &$options)
{
parent::__construct($options);
if (!empty($this->options['line_separator']))
{
$this->line_separator = $this->options['line_separator'];
}
}
/**
* Method to add an entry to the log.
*
* @param LogEntry $entry The log entry object to add to the log.
*
* @return void
*
* @since 1.7.0
*/
public function addEntry(LogEntry $entry)
{
echo $this->priorities[$entry->priority] . ': '
. $entry->message . (empty($entry->category) ? '' : ' [' . $entry->category . ']')
. $this->line_separator;
}
}
Logger/W3cLogger.php 0000604 00000002242 15245540366 0010276 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log\Logger;
defined('JPATH_PLATFORM') or die;
/**
* Joomla! W3C Logging class
*
* This class is designed to build log files based on the W3C specification.
*
* @link https://www.w3.org/TR/WD-logfile.html
* @since 1.7.0
*/
class W3cLogger extends FormattedtextLogger
{
/**
* The format which each entry follows in the log file.
*
* All fields must be named in all caps and be within curly brackets eg. {FOOBAR}.
*
* @var string
* @since 1.7.0
*/
protected $format = '{DATE} {TIME} {PRIORITY} {CLIENTIP} {CATEGORY} {MESSAGE}';
/**
* Constructor.
*
* @param array &$options Log object options.
*
* @since 1.7.0
*/
public function __construct(array &$options)
{
// The name of the text file defaults to 'error.w3c.php' if not explicitly given.
if (empty($options['text_file']))
{
$options['text_file'] = 'error.w3c.php';
}
// Call the parent constructor.
parent::__construct($options);
}
}
Logger/SyslogLogger.php 0000604 00000006431 15245540366 0011126 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log\Logger;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;
/**
* Joomla! Syslog Log class
*
* This class is designed to call the PHP Syslog function call which is then sent to the
* system wide log system. For Linux/Unix based systems this is the syslog subsystem, for
* the Windows based implementations this can be found in the Event Log. For Windows,
* permissions may prevent PHP from properly outputting messages.
*
* @since 1.7.0
*/
class SyslogLogger extends Logger
{
/**
* Translation array for LogEntry priorities to SysLog priority names.
*
* @var array
* @since 1.7.0
*/
protected $priorities = array(
Log::EMERGENCY => 'EMERG',
Log::ALERT => 'ALERT',
Log::CRITICAL => 'CRIT',
Log::ERROR => 'ERR',
Log::WARNING => 'WARNING',
Log::NOTICE => 'NOTICE',
Log::INFO => 'INFO',
Log::DEBUG => 'DEBUG',
);
/**
* Constructor.
*
* @param array &$options Log object options.
*
* @since 1.7.0
*/
public function __construct(array &$options)
{
// Call the parent constructor.
parent::__construct($options);
// Ensure that we have an identity string for the Syslog entries.
if (empty($this->options['sys_ident']))
{
$this->options['sys_ident'] = 'Joomla Platform';
}
// If the option to add the process id to Syslog entries is set use it, otherwise default to true.
if (isset($this->options['sys_add_pid']))
{
$this->options['sys_add_pid'] = (bool) $this->options['sys_add_pid'];
}
else
{
$this->options['sys_add_pid'] = true;
}
// If the option to also send Syslog entries to STDERR is set use it, otherwise default to false.
if (isset($this->options['sys_use_stderr']))
{
$this->options['sys_use_stderr'] = (bool) $this->options['sys_use_stderr'];
}
else
{
$this->options['sys_use_stderr'] = false;
}
// Build the Syslog options from our log object options.
$sysOptions = 0;
if ($this->options['sys_add_pid'])
{
$sysOptions = $sysOptions | LOG_PID;
}
if ($this->options['sys_use_stderr'])
{
$sysOptions = $sysOptions | LOG_PERROR;
}
// Default logging facility is LOG_USER for Windows compatibility.
$sysFacility = LOG_USER;
// If we have a facility passed in and we're not on Windows, reset it.
if (isset($this->options['sys_facility']) && !IS_WIN)
{
$sysFacility = $this->options['sys_facility'];
}
// Open the Syslog connection.
openlog((string) $this->options['sys_ident'], $sysOptions, $sysFacility);
}
/**
* Destructor.
*
* @since 1.7.0
*/
public function __destruct()
{
closelog();
}
/**
* Method to add an entry to the log.
*
* @param LogEntry $entry The log entry object to add to the log.
*
* @return void
*
* @since 1.7.0
*/
public function addEntry(LogEntry $entry)
{
// Generate the value for the priority based on predefined constants.
$priority = constant(strtoupper('LOG_' . $this->priorities[$entry->priority]));
// Send the entry to Syslog.
syslog($priority, '[' . $entry->category . '] ' . $entry->message);
}
}
Logger/DatabaseLogger.php 0000604 00000007645 15245540366 0011362 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log\Logger;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;
/**
* Joomla! MySQL Database Log class
*
* This class is designed to output logs to a specific MySQL database table. Fields in this
* table are based on the Syslog style of log output. This is designed to allow quick and
* easy searching.
*
* @since 1.7.0
*/
class DatabaseLogger extends Logger
{
/**
* The name of the database driver to use for connecting to the database.
*
* @var string
* @since 1.7.0
*/
protected $driver = 'mysqli';
/**
* The host name (or IP) of the server with which to connect for the logger.
*
* @var string
* @since 1.7.0
*/
protected $host = '127.0.0.1';
/**
* The database server user to connect as for the logger.
*
* @var string
* @since 1.7.0
*/
protected $user = 'root';
/**
* The password to use for connecting to the database server.
*
* @var string
* @since 1.7.0
*/
protected $password = '';
/**
* The name of the database table to use for the logger.
*
* @var string
* @since 1.7.0
*/
protected $database = 'logging';
/**
* The database table to use for logging entries.
*
* @var string
* @since 1.7.0
*/
protected $table = 'jos_';
/**
* The database driver object for the logger.
*
* @var \JDatabaseDriver
* @since 1.7.0
*/
protected $db;
/**
* Constructor.
*
* @param array &$options Log object options.
*
* @since 1.7.0
*/
public function __construct(array &$options)
{
// Call the parent constructor.
parent::__construct($options);
// If both the database object and driver options are empty we want to use the system database connection.
if (empty($this->options['db_driver']))
{
$this->db = \JFactory::getDbo();
$this->driver = null;
$this->host = null;
$this->user = null;
$this->password = null;
$this->database = null;
$this->prefix = null;
}
else
{
$this->db = null;
$this->driver = (empty($this->options['db_driver'])) ? 'mysqli' : $this->options['db_driver'];
$this->host = (empty($this->options['db_host'])) ? '127.0.0.1' : $this->options['db_host'];
$this->user = (empty($this->options['db_user'])) ? 'root' : $this->options['db_user'];
$this->password = (empty($this->options['db_pass'])) ? '' : $this->options['db_pass'];
$this->database = (empty($this->options['db_database'])) ? 'logging' : $this->options['db_database'];
$this->prefix = (empty($this->options['db_prefix'])) ? 'jos_' : $this->options['db_prefix'];
}
// The table name is independent of how we arrived at the connection object.
$this->table = (empty($this->options['db_table'])) ? '#__log_entries' : $this->options['db_table'];
}
/**
* Method to add an entry to the log.
*
* @param LogEntry $entry The log entry object to add to the log.
*
* @return void
*
* @since 1.7.0
* @throws \RuntimeException
*/
public function addEntry(LogEntry $entry)
{
// Connect to the database if not connected.
if (empty($this->db))
{
$this->connect();
}
// Convert the date.
$entry->date = $entry->date->toSql(false, $this->db);
$this->db->insertObject($this->table, $entry);
}
/**
* Method to connect to the database server based on object properties.
*
* @return void
*
* @since 1.7.0
* @throws \RuntimeException
*/
protected function connect()
{
// Build the configuration object to use for JDatabaseDriver.
$options = array(
'driver' => $this->driver,
'host' => $this->host,
'user' => $this->user,
'password' => $this->password,
'database' => $this->database,
'prefix' => $this->prefix,
);
$this->db = \JDatabaseDriver::getInstance($options);
}
}
Log.php 0000604 00000022231 15245540366 0006004 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log;
defined('JPATH_PLATFORM') or die;
/**
* Joomla! Log Class
*
* This class hooks into the global log configuration settings to allow for user configured
* logging events to be sent to where the user wishes them to be sent. On high load sites
* Syslog is probably the best (pure PHP function), then the text file based loggers (CSV, W3c
* or plain Formattedtext) and finally MySQL offers the most features (e.g. rapid searching)
* but will incur a performance hit due to INSERT being issued.
*
* @since 1.7.0
*/
class Log
{
/**
* All log priorities.
*
* @var integer
* @since 1.7.0
*/
const ALL = 30719;
/**
* The system is unusable.
*
* @var integer
* @since 1.7.0
*/
const EMERGENCY = 1;
/**
* Action must be taken immediately.
*
* @var integer
* @since 1.7.0
*/
const ALERT = 2;
/**
* Critical conditions.
*
* @var integer
* @since 1.7.0
*/
const CRITICAL = 4;
/**
* Error conditions.
*
* @var integer
* @since 1.7.0
*/
const ERROR = 8;
/**
* Warning conditions.
*
* @var integer
* @since 1.7.0
*/
const WARNING = 16;
/**
* Normal, but significant condition.
*
* @var integer
* @since 1.7.0
*/
const NOTICE = 32;
/**
* Informational message.
*
* @var integer
* @since 1.7.0
*/
const INFO = 64;
/**
* Debugging message.
*
* @var integer
* @since 1.7.0
*/
const DEBUG = 128;
/**
* The global Log instance.
*
* @var Log
* @since 1.7.0
*/
protected static $instance;
/**
* Container for Logger configurations.
*
* @var array
* @since 1.7.0
*/
protected $configurations = array();
/**
* Container for Logger objects.
*
* @var Logger[]
* @since 1.7.0
*/
protected $loggers = array();
/**
* Lookup array for loggers.
*
* @var array
* @since 1.7.0
*/
protected $lookup = array();
/**
* Constructor.
*
* @since 1.7.0
*/
protected function __construct()
{
}
/**
* Method to add an entry to the log.
*
* @param mixed $entry The LogEntry object to add to the log or the message for a new LogEntry object.
* @param integer $priority Message priority.
* @param string $category Type of entry
* @param string $date Date of entry (defaults to now if not specified or blank)
* @param array $context An optional array with additional message context.
*
* @return void
*
* @since 1.7.0
*/
public static function add($entry, $priority = self::INFO, $category = '', $date = null, array $context = array())
{
// Automatically instantiate the singleton object if not already done.
if (empty(static::$instance))
{
static::setInstance(new Log);
}
// If the entry object isn't a LogEntry object let's make one.
if (!($entry instanceof LogEntry))
{
$entry = new LogEntry((string) $entry, $priority, $category, $date, $context);
}
static::$instance->addLogEntry($entry);
}
/**
* Add a logger to the Log instance. Loggers route log entries to the correct files/systems to be logged.
*
* @param array $options The object configuration array.
* @param integer $priorities Message priority
* @param array $categories Types of entry
* @param boolean $exclude If true, all categories will be logged except those in the $categories array
*
* @return void
*
* @since 1.7.0
*/
public static function addLogger(array $options, $priorities = self::ALL, $categories = array(), $exclude = false)
{
// Automatically instantiate the singleton object if not already done.
if (empty(static::$instance))
{
static::setInstance(new Log);
}
static::$instance->addLoggerInternal($options, $priorities, $categories, $exclude);
}
/**
* Add a logger to the Log instance. Loggers route log entries to the correct files/systems to be logged.
* This method allows you to extend Log completely.
*
* @param array $options The object configuration array.
* @param integer $priorities Message priority
* @param array $categories Types of entry
* @param boolean $exclude If true, all categories will be logged except those in the $categories array
*
* @return void
*
* @since 1.7.0
*/
protected function addLoggerInternal(array $options, $priorities = self::ALL, $categories = array(), $exclude = false)
{
// The default logger is the formatted text log file.
if (empty($options['logger']))
{
$options['logger'] = 'formattedtext';
}
$options['logger'] = strtolower($options['logger']);
// Special case - if a Closure object is sent as the callback (in case of CallbackLogger)
// Closure objects are not serializable so swap it out for a unique id first then back again later
if (isset($options['callback']))
{
if (is_a($options['callback'], 'closure'))
{
$callback = $options['callback'];
$options['callback'] = spl_object_hash($options['callback']);
}
elseif (is_array($options['callback']) && count($options['callback']) == 2 && is_object($options['callback'][0]))
{
$callback = $options['callback'];
$options['callback'] = spl_object_hash($options['callback'][0]) . '::' . $options['callback'][1];
}
}
// Generate a unique signature for the Log instance based on its options.
$signature = md5(serialize($options));
// Now that the options array has been serialized, swap the callback back in
if (isset($callback))
{
$options['callback'] = $callback;
}
// Register the configuration if it doesn't exist.
if (empty($this->configurations[$signature]))
{
$this->configurations[$signature] = $options;
}
$this->lookup[$signature] = (object) array(
'priorities' => $priorities,
'categories' => array_map('strtolower', (array) $categories),
'exclude' => (bool) $exclude,
);
}
/**
* Creates a delegated PSR-3 compatible logger from the current singleton instance. This method always returns a new delegated logger.
*
* @return DelegatingPsrLogger
*
* @since 3.8.0
*/
public static function createDelegatedLogger()
{
// Ensure a singleton instance has been created first
if (empty(static::$instance))
{
static::setInstance(new static);
}
return new DelegatingPsrLogger(static::$instance);
}
/**
* Returns a reference to the a Log object, only creating it if it doesn't already exist.
* Note: This is principally made available for testing and internal purposes.
*
* @param Log $instance The logging object instance to be used by the static methods.
*
* @return void
*
* @since 1.7.0
*/
public static function setInstance($instance)
{
if (($instance instanceof Log) || $instance === null)
{
static::$instance = & $instance;
}
}
/**
* Method to add an entry to the appropriate loggers.
*
* @param LogEntry $entry The LogEntry object to send to the loggers.
*
* @return void
*
* @since 1.7.0
* @throws \RuntimeException
*/
protected function addLogEntry(LogEntry $entry)
{
// Find all the appropriate loggers based on priority and category for the entry.
$loggers = $this->findLoggers($entry->priority, $entry->category);
foreach ((array) $loggers as $signature)
{
// Attempt to instantiate the logger object if it doesn't already exist.
if (empty($this->loggers[$signature]))
{
$class = __NAMESPACE__ . '\\Logger\\' . ucfirst($this->configurations[$signature]['logger']) . 'Logger';
if (!class_exists($class))
{
throw new \RuntimeException('Unable to create a Logger instance: ' . $class);
}
$this->loggers[$signature] = new $class($this->configurations[$signature]);
}
// Add the entry to the logger.
$this->loggers[$signature]->addEntry(clone $entry);
}
}
/**
* Method to find the loggers to use based on priority and category values.
*
* @param integer $priority Message priority.
* @param string $category Type of entry
*
* @return array The array of loggers to use for the given priority and category values.
*
* @since 1.7.0
*/
protected function findLoggers($priority, $category)
{
$loggers = array();
// Sanitize inputs.
$priority = (int) $priority;
$category = strtolower($category);
// Let's go iterate over the loggers and get all the ones we need.
foreach ((array) $this->lookup as $signature => $rules)
{
// Check to make sure the priority matches the logger.
if ($priority & $rules->priorities)
{
if ($rules->exclude)
{
// If either there are no set categories or the category (including the empty case) is not in the list of excluded categories, add this logger.
if (empty($rules->categories) || !in_array($category, $rules->categories))
{
$loggers[] = $signature;
}
}
else
{
// If either there are no set categories (meaning all) or the specific category is set, add this logger.
if (empty($rules->categories) || in_array($category, $rules->categories))
{
$loggers[] = $signature;
}
}
}
}
return $loggers;
}
}
Logger.php 0000604 00000002706 15245540366 0006507 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log;
defined('JPATH_PLATFORM') or die;
/**
* Joomla! Logger Base Class
*
* This class is used to be the basis of logger classes to allow for defined functions
* to exist regardless of the child class.
*
* @since 3.0.1
*/
abstract class Logger
{
/**
* Options array for the JLog instance.
*
* @var array
* @since 3.0.1
*/
protected $options = array();
/**
* Translation array for LogEntry priorities to text strings.
*
* @var array
* @since 3.0.1
*/
protected $priorities = array(
Log::EMERGENCY => 'EMERGENCY',
Log::ALERT => 'ALERT',
Log::CRITICAL => 'CRITICAL',
Log::ERROR => 'ERROR',
Log::WARNING => 'WARNING',
Log::NOTICE => 'NOTICE',
Log::INFO => 'INFO',
Log::DEBUG => 'DEBUG',
);
/**
* Constructor.
*
* @param array &$options Log object options.
*
* @since 3.0.1
*/
public function __construct(array &$options)
{
// Set the options for the class.
$this->options = & $options;
}
/**
* Method to add an entry to the log.
*
* @param LogEntry $entry The log entry object to add to the log.
*
* @return void
*
* @since 3.0.1
* @throws \RuntimeException
*/
abstract public function addEntry(LogEntry $entry);
}
DelegatingPsrLogger.php 0000604 00000005320 15245540366 0011153 0 ustar 00 <?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Log;
defined('JPATH_PLATFORM') or die;
use Psr\Log\AbstractLogger;
use Psr\Log\InvalidArgumentException;
use Psr\Log\LogLevel;
/**
* Delegating logger which delegates log messages received from the PSR-3 interface to the Joomla! Log object.
*
* @since 3.8.0
*/
class DelegatingPsrLogger extends AbstractLogger
{
/**
* The Log instance to delegate messages to.
*
* @var Log
* @since 3.8.0
*/
protected $logger;
/**
* Mapping array to map a PSR-3 level to a Joomla priority.
*
* @var array
* @since 3.8.0
*/
protected $priorityMap = array(
LogLevel::EMERGENCY => Log::EMERGENCY,
LogLevel::ALERT => Log::ALERT,
LogLevel::CRITICAL => Log::CRITICAL,
LogLevel::ERROR => Log::ERROR,
LogLevel::WARNING => Log::WARNING,
LogLevel::NOTICE => Log::NOTICE,
LogLevel::INFO => Log::INFO,
LogLevel::DEBUG => Log::DEBUG
);
/**
* Constructor.
*
* @param Log $logger The Log instance to delegate messages to.
*
* @since 3.8.0
*/
public function __construct(Log $logger)
{
$this->logger = $logger;
}
/**
* Logs with an arbitrary level.
*
* @param mixed $level The log level.
* @param string $message The log message.
* @param array $context Additional message context.
*
* @return void
*
* @since 3.8.0
* @throws InvalidArgumentException
*/
public function log($level, $message, array $context = array())
{
// Make sure the log level is valid
if (!array_key_exists($level, $this->priorityMap))
{
throw new \InvalidArgumentException('An invalid log level has been given.');
}
// Map the level to Joomla's priority
$priority = $this->priorityMap[$level];
$category = null;
$date = null;
// If a message category is given, map it
if (!empty($context['category']))
{
$category = $context['category'];
}
// If a message timestamp is given, map it
if (!empty($context['date']))
{
$date = $context['date'];
}
// Joomla's logging API will only process a string or a LogEntry object, if $message is an object without __toString() we can't use it
if (!is_string($message) && !($message instanceof LogEntry))
{
if (!is_object($message) || !method_exists($message, '__toString'))
{
throw new \InvalidArgumentException(
'The message must be a string, a LogEntry object, or an object implementing the __toString() method.'
);
}
$message = (string) $message;
}
$this->logger->add($message, $priority, $category, $date, $context);
}
}
default.blade.php 0000604 00000004612 15245624464 0007762 0 ustar 00 <?php
/**
* @package akeebabackup
* @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
defined('_JEXEC') || die();
/** @var \Akeeba\Backup\Admin\View\Log\Html $this */
?>
@jhtml('formbehavior.chosen')
@if(isset($this->logs) && count($this->logs))
<form name="adminForm" id="adminForm" action="index.php" method="post" class="akeeba-form--inline">
<div class="akeeba-form-group">
<label for="tag">@lang('COM_AKEEBA_LOG_CHOOSE_FILE_TITLE')</label>
{{-- Joomla 3.x: Chosen does not work with attached event handlers, only with inline event scripts (e.g. onchange) --}}
@jhtml('select.genericlist', $this->logs, 'tag', ['list.select' => $this->tag, 'list.attr' => ['class' => 'advancedSelect', 'onchange' => 'document.forms.adminForm.submit();'], 'id' => 'comAkeebaLogTagSelector'])
</div>
@if(!empty($this->tag))
<div class="akeeba-form-group--actions">
<a class="akeeba-btn--primary" href="{{{ JUri::base() }}}index.php?option=com_akeeba&view=Log&task=download&tag={{{ $this->tag }}}">
<span class="akion-ios-download"></span>
@lang('COM_AKEEBA_LOG_LABEL_DOWNLOAD')
</a>
</div>
@endif
<div class="akeeba-hidden-fields-container">
<input name="option" value="com_akeeba" type="hidden" />
<input name="view" value="Log" type="hidden" />
<input type="hidden" name="@token(true)" value="1" />
</div>
</form>
@endif
@if(!empty($this->tag))
@if ($this->logTooBig)
<div class="akeeba-block--warning">
<p>
@sprintf('COM_AKEEBA_LOG_SIZE_WARNING', number_format($this->logSize / (1024 * 1024), 2))
</p>
<a class="akeeba-btn--dark" id="showlog" href="#">
@lang('COM_AKEEBA_LOG_SHOW_LOG')
</a>
</div>
@endif
<div id="iframe-holder" class="akeeba-panel--primary" style="display: {{ $this->logTooBig ? 'none' : 'block' }};">
@if(!$this->logTooBig)
<iframe
src="index.php?option=com_akeeba&view=Log&task=iframe&format=raw&tag={{ urlencode($this->tag) }}"
width="99%" height="400px">
</iframe>
@endif
</div>
@endif
@if( ! (isset($this->logs) && count($this->logs)))
<div class="akeeba-block--failure">
@lang('COM_AKEEBA_LOG_NONE_FOUND')
</div>
@endif
raw.blade.php 0000604 00000003537 15245624464 0007134 0 ustar 00 <?php
/**
* @package akeebabackup
* @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
defined('_JEXEC') || die();
use Akeeba\Engine\Factory;
use Joomla\CMS\Language\Text;
/** @var \Akeeba\Backup\Admin\View\Log\Raw $this */
// -- Get the log's file name
$tag = $this->tag;
$logFile = Factory::getLog()->getLogFilename($tag);
if (!@is_file($logFile) && @file_exists(substr($logFile, 0, -4)))
{
/**
* Transitional period: the log file akeeba.tag.log.php may not exist but the akeeba.tag.log does. This
* addresses this transition.
*/
$logFile = substr($logFile, 0, -4);
}
@ob_end_clean();
if (!@file_exists($logFile))
{
// Oops! The log doesn't exist!
echo '<p>' . Text::_('COM_AKEEBA_LOG_ERROR_LOGFILENOTEXISTS') . '</p>';
return;
}
else
{
// Allright, let's load and render it
$fp = fopen($logFile, "r");
if ($fp === FALSE)
{
// Oops! The log isn't readable?!
echo '<p>' . Text::_('COM_AKEEBA_LOG_ERROR_UNREADABLE') . '</p>';
return;
}
while (!feof($fp))
{
$line = fgets($fp);
if (!$line) return;
$exploded = explode("|", $line, 3);
unset($line);
if (count($exploded) < 3) continue;
switch (trim($exploded[0]))
{
case "ERROR":
$fmtString = "<span style=\"color: red; font-weight: bold;\">[";
break;
case "WARNING":
$fmtString = "<span style=\"color: #D8AD00; font-weight: bold;\">[";
break;
case "INFO":
$fmtString = "<span style=\"color: black;\">[";
break;
case "DEBUG":
$fmtString = "<span style=\"color: #666666; font-size: small;\">[";
break;
default:
$fmtString = "<span style=\"font-size: small;\">[";
break;
}
$fmtString .= $exploded[1] . "] " . htmlspecialchars($exploded[2]) . "</span><br/>\n";
unset($exploded);
echo $fmtString;
unset($fmtString);
}
}
@ob_start();
LoggerInterface.php 0000604 00000006052 15245703241 0010317 0 ustar 00 <?php
namespace Psr\Log;
/**
* Describes a logger instance.
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data. The only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named "exception".
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*/
interface LoggerInterface
{
/**
* System is unusable.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function emergency($message, array $context = array());
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function alert($message, array $context = array());
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function critical($message, array $context = array());
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function error($message, array $context = array());
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function warning($message, array $context = array());
/**
* Normal but significant events.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function notice($message, array $context = array());
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function info($message, array $context = array());
/**
* Detailed debug information.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function debug($message, array $context = array());
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param mixed[] $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
public function log($level, $message, array $context = array());
}
LogLevel.php 0000604 00000000520 15245703241 0006762 0 ustar 00 <?php
namespace Psr\Log;
/**
* Describes log levels.
*/
class LogLevel
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
}
LoggerAwareInterface.php 0000604 00000000451 15245703241 0011274 0 ustar 00 <?php
namespace Psr\Log;
/**
* Describes a logger-aware instance.
*/
interface LoggerAwareInterface
{
/**
* Sets a logger instance on the object.
*
* @param LoggerInterface $logger
*
* @return void
*/
public function setLogger(LoggerInterface $logger);
}
LoggerTrait.php 0000604 00000006527 15245703241 0007511 0 ustar 00 <?php
namespace Psr\Log;
/**
* This is a simple Logger trait that classes unable to extend AbstractLogger
* (because they extend another class, etc) can include.
*
* It simply delegates all log-level-specific methods to the `log` method to
* reduce boilerplate code that a simple Logger that does the same thing with
* messages regardless of the error level has to implement.
*/
trait LoggerTrait
{
/**
* System is unusable.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
abstract public function log($level, $message, array $context = array());
}
InvalidArgumentException.php 0000604 00000000140 15245703241 0012217 0 ustar 00 <?php
namespace Psr\Log;
class InvalidArgumentException extends \InvalidArgumentException
{
}
LoggerAwareTrait.php 0000604 00000000622 15245703241 0010457 0 ustar 00 <?php
namespace Psr\Log;
/**
* Basic Implementation of LoggerAwareInterface.
*/
trait LoggerAwareTrait
{
/**
* The logger instance.
*
* @var LoggerInterface|null
*/
protected $logger;
/**
* Sets a logger.
*
* @param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
AbstractLogger.php 0000604 00000006040 15245703241 0010157 0 ustar 00 <?php
namespace Psr\Log;
/**
* This is a simple Logger implementation that other Loggers can inherit from.
*
* It simply delegates all log-level-specific methods to the `log` method to
* reduce boilerplate code that a simple Logger that does the same thing with
* messages regardless of the error level has to implement.
*/
abstract class AbstractLogger implements LoggerInterface
{
/**
* System is unusable.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}
}
NullLogger.php 0000604 00000001303 15245703241 0007323 0 ustar 00 <?php
namespace Psr\Log;
/**
* This Logger can be used to avoid conditional log calls.
*
* Logging should always be optional, and if no logger is provided to your
* library creating a NullLogger instance to have something to throw logs at
* is a good way to avoid littering your code with `if ($this->logger) { }`
* blocks.
*/
class NullLogger extends AbstractLogger
{
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
public function log($level, $message, array $context = array())
{
// noop
}
}