【发布时间】:2010-07-06 14:40:17
【问题描述】:
如何在 PHP 中保存日志? php 中是否有任何“神奇”功能可用于这样做,或者任何库?还是我每次都必须fopen 归档并转储?我想将我的日志保存在文本文件中。
提前致谢:)
【问题讨论】:
-
我只想要 print_r 数据。有什么用吗?
标签: php
如何在 PHP 中保存日志? php 中是否有任何“神奇”功能可用于这样做,或者任何库?还是我每次都必须fopen 归档并转储?我想将我的日志保存在文本文件中。
提前致谢:)
【问题讨论】:
标签: php
如果你不想使用自己的实现或者只是做 fopen-stuff 你可以使用内置函数 error_log('string to log'); 。这会将所需的字符串写入服务器软件的错误日志中。
【讨论】:
error_log php.ini 设置配置默认记录器:php.net/error-log
我写了一个简单的类来做到这一点。也许你会发现它很有用。
class Log
{
public function __construct($log_name,$page_name)
{
if(!file_exists('/your/directory/'.$log_name)){ $log_name='a_default_log.log'; }
$this->log_name=$log_name;
$this->app_id=uniqid();//give each process a unique ID for differentiation
$this->page_name=$page_name;
$this->log_file='/your/directory/'.$this->log_name;
$this->log=fopen($this->log_file,'a');
}
public function log_msg($msg)
{//the action
$log_line=join(' : ', array( date(DATE_RFC822), $this->page_name, $this->app_id, $msg ) );
fwrite($this->log, $log_line."\n");
}
function __destruct()
{//makes sure to close the file and write lines when the process ends.
$this->log_msg("Closing log");
fclose($this->log);
}
}
$log=new Log('file_name','my_php_page');
$log->log_msg('fizzy soda : 45 bubbles remaining per cubic centimeter');
【讨论】:
$this->app_id=self::real_unique_string()。进程 ID 对日志有何用处?以后查看日志时,进程 ID 如何帮助我?
error_log($msg, 3, $log_name);的一个极其复杂的版本
如果您不喜欢使用其他回复提到的 PHP 错误处理函数 (http://www.php.net/manual/en/ref.errorfunc.php),这里有一个我以前使用过的非常简单的 Logger 类。标准警告适用,因为我没有在高风险应用程序或流量很大的网站上使用它(尽管它应该没问题)。
<?
class Logger
{
private static function addEntry($str)
{
$handle = fopen('./services.log', 'a');
fwrite($handle, sprintf("%s %s\n", date('c'), $str));
fclose($handle);
}
public static function warn($str)
{
self::addEntry("WARNING $str");
}
public static function info($str)
{
self::addEntry("INFO $str");
}
public static function debug($str)
{
self::addEntry("DEBUG $str");
}
}
?>
那么你可以这样使用它:
<?php
require('Logger.php');
Logger::debug('test');
Logger::warn('bwah');
Logger::info('omg');
?>
添加更多功能非常简单(例如Logger::error()),存储文件处理程序,这样您就不必在每次要记录某些内容时都重新打开它(即,将$handle 变量存储在一个私有静态类作用域变量,并让 addEntry() 在运行时检查它是否已设置,如果没有则运行 fopen()),或者更改您记录的格式。
干杯。
【讨论】:
一切都取决于您要记录的内容。默认情况下,您将拥有一个 error_log,它本质上是一个纯文本文件。如果您正在讨论在代码中记录事件以在脚本中进行调试或跟踪活动,那么您将需要为此编写自己的日志处理程序,但这非常简单。正如另一位海报所说,您可以使用 error_log() 函数将内容推送到错误日志,但这会导致一些非常难以管理的日志文件 imv。
【讨论】:
最后一个答案是 2010 年的,所以它需要呼吸新鲜空气。我正在与您分享我在程序中使用的 php 类。
我对上面@Sam-Bisbee 的回答采取了类似的方法,因此很容易添加新的功能和功能,但我也使它更灵活地用于不同的程序/脚本。
我把我的课放在Logg.php文件里,你也可以。
<?php
class Logg
{
public static $fileName = 'new_log';
public static $filePath = '/';
public static $fileType = '.log';
public static function addInfo($logMsg, $fName = null, $fPath = null)
{
$fName = $fName ?: self::$fileName;
$fPath = $fPath ?: self::$filePath;
self::addData($logMsg, $fName, $fPath, ' | INFO |');
}
public static function addWarn($logMsg, $fName = null, $fPath = null)
{
$fName = $fName ?: self::$fileName;
$fPath = $fPath ?: self::$filePath;
self::addData($logMsg, $fName, $fPath, ' | WARNING |');
}
public static function addErr($logMsg, $fName = null, $fPath = null)
{
$fName = $fName ?: self::$fileName;
$fPath = $fPath ?: self::$filePath;
self::addData($logMsg, $fName, $fPath, ' | ERROR |');
}
public static function addConf($logMsg, $fName = null, $fPath = null)
{
$fName = $fName ?: self::$fileName;
$fPath = $fPath ?: self::$filePath;
self::addData($logMsg, $fName, $fPath, ' | CONFIG |');
}
private static function addData($logMsg, $fName, $fPath, $type)
{
$handle = fopen($fPath . $fName . self::$fileType, 'a');
if (gettype($logMsg) == 'array') {
if (count($logMsg)%2 == 0) {
$logText = '';
for ($i = 0; $i < count($logMsg); $i+=2) {
$logText .= str_pad($logMsg[$i], $logMsg[$i+1], " ", STR_PAD_BOTH).'|';
}
fwrite($handle, sprintf("| %s%s", date("Y-m-d H:i:s"), $type.$logText.PHP_EOL));
} else {
throw new Exception('Wrong arguments for Array-type log.');
}
} else {
fwrite($handle, sprintf("| %s%s", date("Y-m-d H:i:s"), $type.' '.$logMsg.PHP_EOL));
}
fclose($handle);
}
public static function addLine($lines = 1, $fName = null, $fPath = null)
{
$fName = $fName ?: self::$fileName;
$fPath = $fPath ?: self::$filePath;
$handle = fopen($fPath . $fName . self::$fileType, 'a');
fwrite($handle, str_repeat(PHP_EOL, $lines));
fclose($handle);
}
}
?>
包括类 - 指定日志文件名和路径:
<?php
require '/Logg.php';
//specifying logs file name and path - best do this right after include
Logg::$fileName = 'ExampleName_'.date("Y_m_d"); //if not specified, default value = 'new_log'
Logg::$filePath = 'C:/Apache24/htdocs/public_html/logs/'; //if not specified, default value = '/'
如果您愿意,您可以稍后在您的程序中再次更改此值。
简单用法:
//Logging simple messages
Logg::addInfo("FooBar"); //sample information log message
Logg::addWarn("Sample warning"); //sample warning log message
Logg::addErr ("Sample error"); //sample error log message
Logg::addConf("Sample config log"); //sample config change log message
//Adding empty lines
Logg::addLine(); //adds empty line
Logg::addInfo("Log after empty line"); //some log
Logg::addLine(3); //adds 3 lines instead of one
Logg::addInfo("Log after 3 empty lines"); //some log
您也可以使用Array(推荐)代替String作为您的“日志消息”,如下例所示。它将使您的日志消息格式化为指定的长度,以使其更具可读性:
Logg::addLine();
Logg::addInfo(['Goo', 5]); //logs 'Goo' as char of length 5
Logg::addInfo(['', 10, 'Goo', 5]); //logs empty space of length 10 and a 'Goo' of length 5 after that
Logg::addInfo(['Foo', 10 , 'Bar', 5, 'Sample message with some length formatted to 75 chars', 75]); //more examples
Logg::addInfo(['FooBar', 10 , 'Baz', 5, 'Another sample message with different length formatted to 75 chars', 75]);
Logg::addLine();
Logg::addInfo(['Different message of length 65 - trying to format it to length 50', 50]); //in this case the message will keep it initial length so we wont be loosing any of the information we are logging
执行上面的代码,在指定的文件路径中创建了一个文件“ExampleName_2021_08_31.log”,内容为:
| 2021-08-31 11:28:52 | INFO | FooBar
| 2021-08-31 11:28:52 | WARNING | Sample warning
| 2021-08-31 11:28:52 | ERROR | Sample error
| 2021-08-31 11:28:52 | CONFIG | Sample config log
| 2021-08-31 11:28:52 | INFO | Log after empty line
| 2021-08-31 11:28:52 | INFO | Log after 3 empty lines
| 2021-08-31 11:28:52 | INFO | Goo |
| 2021-08-31 11:28:52 | INFO | | Goo |
| 2021-08-31 11:28:52 | INFO | Foo | Bar | Sample message with some length formatted to 75 chars |
| 2021-08-31 11:28:52 | INFO | FooBar | Baz | Another sample message with different length formatted to 75 chars |
| 2021-08-31 11:28:52 | INFO |Different message of length 65 - trying to format it to length 50|
您可以通过更改我的 Logg 类的 $fileType 属性来更改为不同的文件类型。默认文件类型为 ".log"。
例如:
//changing file type, can be put after class include
Logg::$fileType = ".txt";
//logging some example messages
Logg::addInfo("Log message now in .txt file");
Logg::addWarn("Everything will be saved to this file from now on!");
现在 "ExampleName_2021_08_31.txt" 文件已创建,内容如下:
| 2021-08-31 09:35:20 | INFO | Log message now in .txt file
| 2021-08-31 09:35:20 | WARNING | Everything will be saved to this file from now on!
每个公共“添加”函数都有两个附加参数 - 文件名和文件路径。指定此参数将临时覆盖之前指定的Logg::$fileName 和Logg::$filePath 类变量值。
如果您想将某些信息记录到具有不同名称的文件或不同路径的文件中,但您不想更改程序中使用的每个日志的文件路径或文件名,它会很有用。
用法:
//Additional parameters
Logg::addErr("New error log"); //no additional parameters - uses filename and path from "Logg::$fileName" and "Logg::$filePath"
Logg::addErr("New error log in different file", "<file name>"); //one additional parameter - uses provided filename instead of "Logg::$fileName"
Logg::addErr("New error log in different file and path", '<file name>', '<file path>'); //two additional parameters - uses provided filename and path instead of "Logg::$fileName" and "Logg::$filePath"
示例:
//this:
{
//logging information to different file in different path
Logg::addInfo(['Some info', 15], 'AnotherFileName', '/some/different/path/');
}
//is equal to this:
{
//changing filename and path
Logg::$fileName = 'AnotherFileName';
Logg::$filePath = '/some/different/path/';
//logging information
Logg::addInfo(['Some info', 15]);
//changing filename and path back to its original values
Logg::$fileName = 'ExampleName_'.date("Y_m_d");
Logg::$filePath = 'C:/Apache24/htdocs/public_html/logs/';
}
我正在等待您的 cmets 和建议。 祝你有美好的一天。
【讨论】: