logging
- David Grudl
- Nette Core | 8227
Integrované je jen logování chyb.
Pokud si potřebuju logovat něco jiného, obvykle si vystačím s
file_put_contents('log.txt', $message, FILE_APPEND);
- peci1
- Člen | 60
Ahoj, zrovna jsem se nad chybejicim logovanim taky podivoval. Ja osobne bych ho v Nette klidne videl integrovany… Pokud clovek potrebuje neco jednoduchyho, tak file_put_contents mozna staci, ale co treba logovani do databaze? Inu, napsal jsem si vlastni logger. Je napsany (snad)tak, aby se dal hodit i do distribuce, ale nechavam to na zvazeni vyssich instanci :)
ILogger.php
<?php
/**
* Interface for an object, that is able to log messages
*
* @package Nette\Logger
* @version $id$
* @copyright (c) 2009 Martin Pecka (Clevis)
* @author Martin Pecka <martin.pecka@clevis.cz>
* @license
*/
interface /*Nette\Logger\*/ILogger
{
/**
* Append the message to the log
*
* @param string $message The message to log
* @param string|NULL $class Optional class (severity etc...) of the message
* @return void
*/
function logMessage($message, $class = NULL);
}
?>
FileLogger.php
<?php
/**
* This is a logger that logs the messages into a file
*
* @package
* @version $id$
* @copyright (c) 2009 Martin Pecka (Clevis)
* @author Martin Pecka <martin.pecka@clevis.cz>
* @license
*/
class /*Nette\Logger\*/FileLogger extends /*Nette\*/Object implements /*Nette\Logger\*/ILogger
{
/** @var string Name of the log file */
protected $logFile;
/** @var resource Handle of the log file */
protected $logHandle = NULL;
/** @var bool If true, log newer messages at the top of the file */
protected $newerHigher;
/**
* Initialize the logger, setup the log file
*
* @param string $logFile The file we want to log into
* @param bool $newerHigher Log newer messages at the beggining of the
* file? BEWARE - this rapidly reduces performance!!!
*
* @return void
*/
public function __construct($logFile, $newerHigher = FALSE)
{
if (!is_string($logFile))
throw new InvalidArgumentException(
'Argument 1 passed to FileLogger\'s constructor must be string');
$this->logFile = $logFile;
$this->newerHigher = $newerHigher;
}
/**
* Close the log file if needed
*
* @return void
*/
public function __destruct()
{
if ($this->logHandle !== NULL)
fclose($this->logHandle);
}
/**
* Log the message to file, with optional class
*
* @param string $message
* @param string|NULL $class
* @return void
*/
public function logMessage($message, $class = NULL)
{
$message = date('Y-m-d H:i:s') . ': ' . $message . "\n\r";
if ($class !== NULL)
$message = "[$class] " . $message;
$this->writeToFile($message);
}
/**
* Physically write the message to the file using safestream
*
* If $newerHigher, write the message before the beginning
*
* @param mixed $message
* @return void
*/
protected function writeToFile($message)
{
if ($this->logHandle === NULL) {
$this->openLogFile();
}
if ($this->newerHigher) {
$contents = fread($this->logHandle, 1000000);
$message .= $contents;
rewind($this->logHandle);
}
fwrite($this->logHandle, $message);
}
/**
* Open the file as safestream for appending
*
* If not newerHigher, move the cursor to the end
*
* @return void
*/
protected function openLogFile()
{
SafeStream::register();
//this is not stream safe, but will be called just once
if (!file_exists($this->logFile))
touch($this->logFile);
if (($this->logHandle = @fopen('safe://' . $this->logFile, 'r+')) === FALSE) {
throw new InvalidArgumentException('Cannot open logFile: ' . $this->logFile);
}
if (!$this->newerHigher) {
//seek to the end of the file
fseek($this->logHandle, -1, SEEK_END);
}
}
}
?>
A pak treba do bootstrap.php
<?php
Environment::getServiceLocator()->addService('ILogger',
new FileLogger(APP_DIR . '/log/logfile.txt'));
Environment::setServiceAlias('ILogger', 'Logger');
?>
A pak uz si vesele muzete volat
<?php
Environment::getLogger()->logMessage('Message');
Environment::getLogger()->logMessage('Mess', 'age');
?>
Jeste bych podotknul, ze FileLogger vyuziva Nette SafeStream, takze by mel byt bezpecny pri vice zadostech o zapis soucasne (doufam tedy, ze jsem praci se safeStream pochopil dobre).
A na zaver opravdu varuju pred pouzivanim $newerHigher, v podstate se pri kazdem zapisu musi zapsat cely logfile znovu…
Editoval peci1 (14. 10. 2009 0:36)
- kravčo
- Člen | 721
peci1 napsal(a):
Koukal jsem, ze Environment ma __callStatic, ale asi nevim, jak ho pouzit. Zkousel jsem Environment::ILoggger()->logMessage(). Kde delam chybu?
Správne má byť:
Environment::setServiceAlias('Whatever\ILogger', 'Logger');
Environment::getLogger()->logMessage(...);
A na zaver opravdu varuju pred pouzivanim $newerHigher, v podstate se pri kazdem zapisu musi zapsat cely logfile znovu…
Prečo ho teda implementuješ?
- Filip Procházka
- Moderator | 4668
Protože to má i mnohem lepší řešení, sice delší, ale pamětově
nenáročné
""stačilo by"" (je to jeden z několika jednoduchým postupů):
- vytvoříš nový soubor „…/log/logger(2).txt“ do něj zapíšeš log
- pomocí zápisového módu append tam přepíšeš úplně všechny řádky z prvního souboru načítané pomocí fgets()
- smažeš soubor logger.txt
- přejmenuješ logger(2).txt na logger.txt
btw, bude to chtít zámek vytvořenej pomocí safe_stream :)
- Jakub Šulák
- Člen | 222
jen se vrátím k původní myšlence, zda implementovat do nette:
myslím že by to nebylo špatné, ale jen pod podmínkou, že to bude postaveno
na adaptéru (výběr kam ukladat). ale pak se ptám, má to cenu tedy dávat
vůbec do nette? nebo to nechat na programatorovi.
- Filip Procházka
- Moderator | 4668
jasir napsal(a):
Zeptám se ze zvědavosti – k čemu je dobrý zápis na začátek souboru?
třeba kdysi, když jsem se přisockoval na jeden server tak tam měli logy ze hry zapisované podle data od nejstaršího, a pak když chtěl člověk přes webové rozhraní prohlížet logy tak musel čekat až se celé načtou a že nebyly malé. Ale to je zase otázka implementace že, jaký si to uděláš…
- peci1
- Člen | 60
HosipLan napsal(a):
jasir napsal(a):
Zeptám se ze zvědavosti – k čemu je dobrý zápis na začátek souboru?
třeba kdysi, když jsem se přisockoval na jeden server tak tam měli logy ze hry zapisované podle data od nejstaršího, a pak když chtěl člověk přes webové rozhraní prohlížet logy tak musel čekat až se celé načtou a že nebyly malé. Ale to je zase otázka implementace že, jaký si to uděláš…
Tohle je presne ten duvod, proc jsem to implementoval. Logy s „appendem na zacatek“ jsou v mnoha ohledech (krome vytvareni) praktictejsi
- peci1
- Člen | 60
HosipLan napsal(a):
Protože to má i mnohem lepší řešení, sice delší, ale pamětově nenáročné
""stačilo by"" (je to jeden z několika jednoduchým postupů):
- vytvoříš nový soubor „…/log/logger(2).txt“ do něj zapíšeš log
- pomocí zápisového módu append tam přepíšeš úplně všechny řádky z prvního souboru načítané pomocí fgets()
- smažeš soubor logger.txt
- přejmenuješ logger(2).txt na logger.txt
btw, bude to chtít zámek vytvořenej pomocí safe_stream :)
hmm, o pametove narocnosti jsem zase tolik nepremyslel… nicmene se nezbavis toho, abys na disku zkopiroval cely log z mista A na misto B… to je ta hruza, pred kterou jsem varoval
- Filip Procházka
- Moderator | 4668
každopádně myslím že by nebylo od věci když se log přiblíží určité velikosti vytvořit pro něj další soubor a popřípadě původní zarchivovat pro zmenšení velikosti, jako to dělají unixy se svýmy logy :)
Editoval HosipLan (14. 10. 2009 9:25)
- laada
- Člen | 35
HosipLan napsal(a):
každopádně myslím že by nebylo od věci když se log přiblíží určité velikosti vytvořit pro něj další soubor a popřípadě původní zarchivovat pro zmenšení velikosti, jako to dělají unixy se svýmy logy :)
jo to by bylo pekne, ale v unixech se o to staraji separatni aplikace. Ono kopirovat treba 2GB neni uplne hned a kdyby na to mel uzivatel cekat …
Asi by se to muselo resit nejakym forkem.
- peci1
- Člen | 60
laada napsal(a):
HosipLan napsal(a):
každopádně myslím že by nebylo od věci když se log přiblíží určité velikosti vytvořit pro něj další soubor a popřípadě původní zarchivovat pro zmenšení velikosti, jako to dělají unixy se svýmy logy :)
jo to by bylo pekne, ale v unixech se o to staraji separatni aplikace. Ono kopirovat treba 2GB neni uplne hned a kdyby na to mel uzivatel cekat …
Asi by se to muselo resit nejakym forkem.
Ahoj, myslim, ze je jasne, ze fork neni ta prava cesta. Jak by se pak web testoval na windows? Mam dojem, ze takove veci do Nette nepatri. Ale moznost delat to ve skriptu je taky samozrejme nedobra :)
Programator si to muze osetrit i jinymi zpusoby, napr. registrovat logger se jmenem souboru, kde je treba den ci mesic v nazvu… At si sam zvazi, jak huste logy ma a jestli se mu vyplati radit je bezne a nebo novejsi nahoru.
- kravčo
- Člen | 721
peci1 napsal(a):
Logy s „appendem na zacatek“ jsou v mnoha ohledech (krome vytvareni) praktictejsi
Podstatné je, že pri logovaní určite viac záleží na tom, ako rýchle je vytváranie – to je totiž kritické, keďže aplikácia logujúca udalosti je žiadosťami o zápis do logu popretkávaná… Nie je problém cronom cez noc logy obrátiť, problém by bol, ak by sa stránka načítavala 2 sekundy, kvôli „praktickosti“ logov…
- Filip Procházka
- Moderator | 4668
Viděls někdy logy v *nixech ? já mám třeba kubuntu a ani jeden jediný soubor .log nemá víc jak 2MB a 2MB přesuneš za úplně titěrnej čas, každopádně já si udělám verzi pro databázi, protože potřebuju logovat akce v administraci a na to se texťáky nehodí.
- Panda
- Člen | 569
HosipLan napsal(a):
Viděls někdy logy v *nixech ? já mám třeba kubuntu a ani jeden jediný soubor .log nemá víc jak 2MB a 2MB přesuneš za úplně titěrnej čas, každopádně já si udělám verzi pro databázi, protože potřebuju logovat akce v administraci a na to se texťáky nehodí.
Viděl jsi někdy logy v *nixech na serveru? Na našem firemním má jen maillog za poslední 2 dny 55MB. Logy Apache za den přiberou zhruba 90MB. A to ten server zas tak zatížený není… Mohu Tě ujistit, že na serveru v produkčním prostředí jsi s časem a velikostmi někde úplně jinde.
Každopádně teď přepisuji jednu mojí starší třídu na logování, která toho umí o trošku víc, než zde uveřejněná třída. A logování na začátek souboru naštěstí neumí…
- Panda
- Člen | 569
Jak jsem před chvílí řekl, tak teď činím.
Třída se používá téměř stejně, jako zde uveřejněná, ale je tam několik rozdílů.
Místo parametru $class
používá parametr $level
,
který určuje vážnost logované zprávy. Jako hodnoty se dosazují konstanty
z ILogger
. Metodou setLogLevel()
lze nastavit
minimální vážnost zpráv, která se bude logovat. Ve vývojovém prostředí
se jako výchozí hodnota nastaví ILogger::DEBUG
, v produkčním
ILogger::INFO
. Nastavením na ILogger::NONE
se
logování vypne.
Dalším docela podstatným rozdílem je nastavení masky názvy souboru.
Děje se tak prostřednictvím metody setFilenameMask()
. Tato maska
se při prvním zápisu pro danou instanci prožene funkcí
strftime()
, což umožní pojmenování souborů logů podle
aktuálního času. Výchozí je hodnota log-%Y-%m-%d.log
, každý
den se tedy vytváří nový soubor.
Ještě zajímavější je nastavení něčeho, co jsem nazval
granularity
(zrnitost, nespojitost, lepší název jsem
nevymyslel). Určuje časový interval v sekundách, na jaký se čas při
vytváření souborů zaokrouhluje. Pokud nastavíme masku souboru na
log-%Y-%m-%d-%H-%M.log
, bude se nám každou sekundu vytvářet
nový log. To není moc ideální, proto můžeme nastavit „zrnitost“ –
pokud nastavíme hodnotu na 1800s, tedy půl hodiny, bude se nám soubor s logy
vytvářet každé půl hodiny. Kombinací těchto hodnot lze krásně ovlivnit
členění logů. Jako název se vždy zvolí počátek intervalu, při
zmíněném nastavení se budou vytvářet logy s názvy typu
log-2009-10-14-17-30.log
i v případě, že by první zápis
přišel až 17:55.
Toho také můžete využít pro vytváření logů podle týdnů:
nastavením hodnoty na Tools::WEEK
(604800s) se budou vytvářet
logy každý týden. Názvy budou vždy podle prvního dne týdne, dneska by se
tedy při výchozí masce vytvořil soubor log-2009-10-12.log
(pondělí bylo 12.).
Další nastavení jsou, myslím, celkem jasná.
Pokud máte někdo nějaké připomínky či nápady, tak sem s nimi.
Kód:
<?php
/**
* Message logger.
* Slightly inspired by ILogger by Martin Pecka <martin.pecka@clevis.cz>:
* https://forum.nette.org/cs/viewtopic.php?pid=19667#p19667
*
* @author Jan Smitka <jan@smitka.org>
* @copyright Copyright (c) 2009 Jan Smitka
*/
interface ILogger
{
/**#@+ Severity levels */
const NONE = 0; // used only for disabling the logging
const ERROR = 1;
const WARNING = 2;
const INFO = 3;
const DEBUG = 4;
/**#@-*/
/**
* Sets the log verbosity.
* @param int $level Severity level
* @return void
* @throws InvalidArgumentException
*/
public function setLogLevel($level);
/**
* Log a message.
* @param string $message The message to log
* @param int $level Severity of the message
* @throws InvalidArgumentException
*/
public function logMessage($message, $level = ILogger::WARNING);
}
?>
<?php
/**
* Filesystem-based implementation of ILogger.
* Slightly inspired by FileLogger by Martin Pecka <martin.pecka@clevis.cz>:
* https://forum.nette.org/cs/viewtopic.php?pid=19667#p19667
*
* @author Jan Smitka <jan@smitka.org>
* @copyright Copyright (c) 2009 Jan Smitka
*/
class FileLogger extends Object implements ILogger
{
/** @var string */
private $filenameMask = 'log-%Y-%m-%d.log';
/** @var string */
private $logDir = '%logDir%';
/** @var string internal file path */
private $file;
/** @var int */
private $logLevel;
/** @var int seconds */
private $granularity = 0;
/** @var string for date() */
private $dateFormat = 'r';
public function __construct($logLevel = NULL, $logDir = NULL, $filenameMask = NULL, $granularity = 0)
{
if ($logLevel === NULL)
$logLevel = Environment::isDebugging() ? ILogger::DEBUG : ILogger::INFO;
$this->setLogLevel($logLevel);
if ($logDir !== NULL)
$this->logDir = $logDir;
if ($filenameMask !== NULL)
$this->filenameMask = $filenameMask;
$this->granularity = $granularity;
}
/**
* Returns the logger verbosity.
* @return int
*/
public function getLogLevel()
{
return $this->logLevel;
}
/**
* Sets the logger verbosity.
* @param int $level one of the ILogger severity constants
* @return void
* @throws InvalidArgumentException
*/
public function setLogLevel($level)
{
if ($level > ILogger::DEBUG || $level < ILogger::NONE)
throw new InvalidArgumentException('Log level must be one of the ILogger severity constants.');
$this->logLevel = $level;
}
/**
* Returns the filename mask of log file.
* @return string
*/
public function getFilenameMask()
{
return $this->filenameMask;
}
/**
* Sets the filename mask for log files.
* You can use the strftime specifiers.
* @param string $filenameMask
* @return void
* @see strftime()
*/
public function setFilenameMask($filenameMask)
{
$this->filenameMask = $filenameMask;
$this->file = NULL;
}
/**
* Returns the directory path where log files reside.
* @return string with untranslated environment variables
*/
public function getLogDir()
{
return $this->logDir;
}
/**
* Sets the directory path where log files reside.
* You can use environment variables.
* @param string $logDir
* @return void
* @see Environment::expand()
*/
public function setLogDir($logDir)
{
$this->logDir = $logDir;
$this->file = NULL;
}
/**
* Returns log files granularity.
* @return int in seconds
*/
public function getGranularity()
{
return $this->granularity;
}
/**
* Sets log files granularity.
* Please note that real granularity is also determined by filename mask.
* @param int $granularity
* @return void
* @throws InvalidArgumentException
*/
public function setGranularity($granularity)
{
if ($granularity < 0)
throw new InvalidArgumentException('Granularity must be greater than or equal to 0.');
$this->granularity = $granularity;
$this->file = NULL;
}
/**
* Returns the date format used inside log files.
* @return string
*/
public function getDateFormat()
{
return $this->dateFormat;
}
/**
* Sets the date format used inside log files.
* Format is the same as used by date() function.
* @param string $dateFormat
* @return void
* @see date()
*/
public function setDateFormat($dateFormat)
{
$this->dateFormat = $dateFormat;
}
/**
* Returns the full path to the current log file.
* @return string
* @throws InvalidStateException
*/
public function getFile()
{
if ($this->file === NULL) {
// granularity calculations
if ($this->granularity > 1) {
$offset = 345600 - (int) date('Z');
$timestamp = $offset + floor((time() - $offset) / $this->granularity) * $this->granularity;
} else
$timestamp = time();
$this->file = ($path = Environment::expand($this->logDir))
. (String::endsWith($path, '/') ? '' : '/')
. strftime($this->filenameMask, $timestamp);
}
return $this->file;
}
/**
* Log a message.
* @param string $message
* @param int $level one of the ILogger severity constants
* @return void
* @throws InvalidArgumentException
* @throws InvalidStateException
*/
public function logMessage($message, $level = ILogger::INFO)
{
if ($level > ILogger::DEBUG || $level <= ILogger::NONE)
throw new InvalidArgumentException('Log level must be one of the ILogger severity constants except ILogger::NONE.');
if ($level <= $this->logLevel) {
$message = sprintf("%s %s: %s\r\n", date($this->dateFormat), $this->logLevelToString($level), $message);
file_put_contents($this->getFile(), $message, FILE_APPEND);
// Please note that FILE_APPEND operation is atomic (tested):
// http://us2.php.net/manual/en/function.file-put-contents.php
}
}
/**
* Translate log severity level into a readable string.
* @param int $level
* @return void
*/
protected function logLevelToString($level)
{
switch ($level) {
case ILogger::ERROR:
return 'ERROR';
case ILogger::WARNING:
return 'WARNING';
case ILogger::INFO:
return 'INFO';
case ILogger::DEBUG:
return 'DEBUG';
default:
throw new InvalidArgumentException('Unknown severity level.');
}
}
}
?>
Editoval Panda (14. 10. 2009 18:00)
- peci1
- Člen | 60
Krasa, Pando :)
Jeste jsem si ji trochu upravil, aby brala printf-like argumenty.
Taky v ni pouzivas deprecated Environment::isDebugging().
A taky jsem prehazel parametry konstruktoru podle meho nazoru, ktere clovek
potrebuje nejcasteji prepisovat.
Co me zaujalo, je, ze mi prestal fungovat setServiceAlias (resp. ten funguje, ale __callStatic se nezavola – vsechno testuju na PHP 5.2, takze se ani zavolat nema. Jenze proc mi to s mym loggerem fungovalo??? A proc neni v dokumentaci Nette napsano, ze Alias je PHP 5.3 only?)
<?php
/**
* Filesystem-based implementation of ILogger.
* Slightly inspired by FileLogger by Martin Pecka <martin.pecka@clevis.cz>:
* https://forum.nette.org/cs/viewtopic.php?pid=19667#p19667
*
* @author Jan Smitka <jan@smitka.org>
* @copyright Copyright (c) 2009 Jan Smitka
*/
class FileLogger extends Object implements ILogger
{
/** @var string Mask of the log filename, can contain strftime formatting */
private $filenameMask = 'log-%Y-%m-%d.log';
/** @var string The directory where we save the logs */
private $logDir = '%logDir%';
/** @var string The log file path */
private $file;
/** @var int Maximum level of events logged */
private $logLevel;
/** @var int seconds If > 0, defines a time span used for one log
*
* eg. if you want to save two logs a day, you can define mask
* "%Y-%m-%d-%H" and set this to half a day of seconds, so the logs
* won't create each hour (as defined in the mask) */
private $granularity = 0;
/** @var string Log date format as in date() */
private $dateFormat = 'r';
/**
* Just set member variables given as parameters
*
* @param string $filenameMask Mask of the log filename, can contain strftime formatting
* @param int $logLevel One of the ILogger constants, maximum level of events logged
* @param mixed $logDir Directory for saving the logs
* @param int $granularity If > 0, defines a time span used for one log
*
* @return void
*/
public function __construct($filenameMask = NULL, $logLevel = NULL, $logDir = NULL, $granularity = 0)
{
if ($logLevel === NULL)
$logLevel = Environment::isProduction() ? ILogger::INFO : ILogger::DEBUG;
$this->setLogLevel($logLevel);
if ($logDir !== NULL)
$this->logDir = $logDir;
if ($filenameMask !== NULL)
$this->filenameMask = $filenameMask;
$this->granularity = $granularity;
}
/**
* Returns the logger verbosity.
*
* @return int
*/
public function getLogLevel()
{
return $this->logLevel;
}
/**
* Sets the logger verbosity.
* @param int $level one of the ILogger severity constants
*
* @return void
*
* @throws InvalidArgumentException If the given level is not one of
* ILogger's constants
*/
public function setLogLevel($level)
{
if ($level > ILogger::DEBUG || $level < ILogger::NONE)
throw new InvalidArgumentException('Log level must be one of the ILogger severity constants.');
$this->logLevel = $level;
}
/**
* Returns the filename mask of log file.
*
* @return string
*/
public function getFilenameMask()
{
return $this->filenameMask;
}
/**
* Sets the filename mask for log files.
* You can use the strftime specifiers.
*
* @param string $filenameMask
*
* @return void
*
* @see strftime()
*/
public function setFilenameMask($filenameMask)
{
$this->filenameMask = $filenameMask;
$this->file = NULL;
}
/**
* Returns the directory path where log files reside.
*
* @return string with untranslated environment variables
*/
public function getLogDir()
{
return $this->logDir;
}
/**
* Sets the directory path where log files reside.
* You can use environment variables.
*
* @param string $logDir
*
* @return void
*
* @see Environment::expand()
*/
public function setLogDir($logDir)
{
$this->logDir = $logDir;
$this->file = NULL;
}
/**
* Returns log files granularity.
*
* @return int in seconds
*/
public function getGranularity()
{
return $this->granularity;
}
/**
* Sets log files granularity.
* Please note that real granularity is also determined by filename mask.
*
* @param int $granularity
*
* @return void
*
* @throws InvalidArgumentException If the grannularity is not non-negative number
*/
public function setGranularity($granularity)
{
if ($granularity < 0)
throw new InvalidArgumentException('Granularity must be greater than or equal to 0.');
$this->granularity = $granularity;
$this->file = NULL;
}
/**
* Returns the date format used inside log files.
*
* @return string
*/
public function getDateFormat()
{
return $this->dateFormat;
}
/**
* Sets the date format used inside log files.
* Format is the same as used by date() function.
*
* @param string $dateFormat
*
* @return void
*
* @see date()
*/
public function setDateFormat($dateFormat)
{
$this->dateFormat = $dateFormat;
}
/**
* Returns the full path to the current log file.
*
* @return string
*
* @throws InvalidStateException
*/
public function getFile()
{
if ($this->file === NULL) {
// granularity calculations
if ($this->granularity > 1) {
$offset = 345600 - (int) date('Z');
$timestamp = $offset + floor((time() - $offset) / $this->granularity) * $this->granularity;
} else
$timestamp = time();
$this->file = ($path = Environment::expand($this->logDir))
. (String::endsWith($path, '/') ? '' : '/')
. strftime($this->filenameMask, $timestamp);
}
return $this->file;
}
/**
* Log a message.
*
* The message can be formatted as in printf
*
* @param string $message The message to log
* @param int $level Severity of the message
* @param mixed $args Following arguments are interpreted as printf arguments
*
* @throws InvalidArgumentException If the given level is not one of
* the interfaces' constants
* @throws InvalidStateException If file operation failed
*/
public function logMessage($message, $level = ILogger::INFO)
{
if ($level > ILogger::DEBUG || $level <= ILogger::NONE)
throw new InvalidArgumentException('Log level must be one of the ILogger severity constants except ILogger::NONE.');
//had the user passed some printf arguments?
if (func_num_args() > 2) {
$args = func_get_args();
array_shift($args);
array_shift($args);
$message = vsprintf($message, $args);
}
if ($level <= $this->logLevel) {
$message = sprintf("%s %s: %s\r\n", date($this->dateFormat), $this->logLevelToString($level), $message);
file_put_contents($this->getFile(), $message, FILE_APPEND);
// Please note that FILE_APPEND operation is atomic (tested):
// http://us2.php.net/manual/en/function.file-put-contents.php
}
}
/**
* Translate log severity level into a readable string.
*
* @param int $level One of ILogger's constants
*
* @return void
*
* @throws InvalidArgumentException If the level is unknown
*/
protected function logLevelToString($level)
{
switch ($level) {
case ILogger::ERROR:
return 'ERROR';
case ILogger::WARNING:
return 'WARNING';
case ILogger::INFO:
return 'INFO';
case ILogger::DEBUG:
return 'DEBUG';
default:
throw new InvalidArgumentException('Unknown severity level.');
}
}
}
?>
- Jan Tvrdík
- Nette guru | 2595
peci1 napsal(a):
Co me zaujalo, je, ze mi prestal fungovat setServiceAlias (resp. ten funguje, ale __callStatic se nezavola – vsechno testuju na PHP 5.2, takze se ani zavolat nema. )
Magická metoda __callStatic
je k dispozici až od PHP
5.3. Nette s tím nic neudělá.
- peci1
- Člen | 60
Jan Tvrdík napsal(a):
peci1 napsal(a):
Co me zaujalo, je, ze mi prestal fungovat setServiceAlias (resp. ten funguje, ale __callStatic se nezavola – vsechno testuju na PHP 5.2, takze se ani zavolat nema. )
Magická metoda
__callStatic
je k dispozici až od PHP 5.3. Nette s tím nic neudělá.
No me prave udivuje, ze s mym puvodnim loggerem ten alias fungoval… :-/