php源代码中的哪些是日志记录模块?

时间:2014-05-13 14:20:11

标签: php

这是关于php源而不是每个人说的php语言......

我有php的源代码,我想启用一些额外的日志记录。我们的想法是记录某些操作发生时需要有人在日志记录调用中进行编码。例如,每当有人调用数据库时,请记录调用,并将一些连接详细信息发送到记录器。我知道我可以使用mysqli_get_client_stats获取其中的一些细节,但这需要我编写每个PHP脚本来获取这些值并打印/发送到记录器,但我更喜欢扩展这样的调用以自动为我记录

我应该在源代码中寻找什么呢?我假设我可以找到我想自动启用日志记录的必要功能,但是我还没弄明白我要记录的是什么,我想记录它。

2 个答案:

答案 0 :(得分:1)

使用runkit并使用rename重新定义所需的功能,比使用源代码更简单的方法是猴子修补

Runkit

您可以将auto_prepend_filewhatever()函数this answer添加到old_whatever(),并定义一个新的whatever()包装函数,记录然后调用old_whatever()。要在整个应用程序中执行此操作,您可以使用{{3}}。

实施例

  

注意:默认情况下,只能删除,重命名或用户空间功能   改性。要覆盖内部函数,必须启用   runkit.internal_override 中的php.ini设置。

runkit_function_rename('mysqli_query', 'xyzzy_query');

/* override mysqli_query (procedural version; the OO version is analogous,
   see documentation for runkit at the above links) */
function mysqli_query($link, $query, $resultmode = MYSQLI_STORE_RESULT) {
   $fp = fopen("logs/mysqli.log", "a");
   fwrite($fp, "-- query\n{$query}\n");
   fclose($fp);
   $ret = xyzzy_query($link, $query, $resultmode);
   // Additional logging of results, number of rows, etc. goes here
   return $ret;
}

由于您需要在每个脚本上进行此操作,因此您需要在所有脚本中包含上述代码。

通常,您仅将其包含在基本级别需要脚本或入口点(例如index.php)中,以便首先执行 并执行恰好一次。如果您有很多入口点,则可以使用auto_prepend。你真正做的是你创建一个包装脚本

<?php
    require_once($_SERVER['DOCUMENT_ROOT'] . '/path/to/mysqli_rewriting.php');
?>
使用auto_prepend中的php.ini指令或相应的Apache节/ .htaccess文件,在每个PHP脚本中

自动包含

php_value auto_prepend_file "monkeypatcher.php"

注意:monkeypatcher文件必须位于 php include path 中的一个目录中;如果后者是空的,你需要添加一个“/ patches”文件夹,然后将monkeypatcher文件放在那里。另请参阅{{3}}。

来源

如果您想修改PHP源,我认为您最好的选择是利用syslog工具。您找到的PHP错误函数将中断处理和/或向错误处理程序发送输出,因此如果您走这条路,您必须在所有脚本中提供/修改错误处理程序。哪个会让你再次自动重新上映。

另一方面,syslog工具需要需要syslog功能,它通常捆绑在Unix平台上......在Windows上不太可靠(实际上,我不是最新的Windows 7+和Server 2008+;它们现在可能正在运行。)

如果您决定使用syslog,只需选择适当的日志级别发送到您选择的文件即可。配置syslogd以接收这些消息并将其发送到您想要的任何位置。

然后添加main/php.h(例如,围绕第306行)

#ifdef HAVE_SYSLOG_H
int logprintf(const char *format, ...);
#endif

/* PHPAPI void php_error(int type, const char *format, ...); */
PHPAPI void php_error_docref0(const char *docref TSRMLS_DC, int type, const char *format, ...)
    PHP_ATTRIBUTE_FORMAT(printf, PHP_ATTR_FMT_OFFSET + 3, PHP_ATTR_FMT_OFFSET + 4);
PHPAPI void php_error_docref1(const char *docref TSRMLS_DC, const char *param1, int type, const char *format, ...)

并在main/main.c,某处 - 例如php_verror之后:

/* {{{ logprintf
*/
int logprintf(const char *format, ...) {
    va_list args;
    char *buffer = NULL;
    int size;
    va_start(args, format);
    size = vspprintf(&buffer, 0, format, args);
    #ifdef HAVE_SYSLOG_H
    /* LOG_LOCAL3 is reserved for local use */
    php_syslog(LOG_LOCAL3, "%s", buffer);
    #endif
    efree(buffer);
    va_end(args);
    return size;
}
/* }}} */

此时,您可以使用printf()的相同语法从PHP代码中的任何位置直接与syslog“对话”。

如果需要,您可以使用#define包含发生日志调用的文件名和行,并将其包含在输出中。

您想要记录查询(顺便说一句:小心记录密码和敏感信息......),您会发现 all 将查询传递到服务器的位置,例如

ext/pdo_mysql/mysql_statement.c (line 332)

+++ /* Add logging */
+++ logprintf("running MySQL query: '%s'", stmt->active_query_string);

if (mysql_real_query(H->server, stmt->active_query_string,
    stmt->active_query_stringlen) != 0) {
    pdo_mysql_error_stmt(stmt);
    PDO_DBG_RETURN(0);
}

缺点

请记住,API有许多入口点,即使是PHP(预处理语句,直接查询,模拟准备查询......)。您需要记录所有。如果你只想记录MySQL查询(上面的方法允许记录你想要的任何东西),你可以通过要求 MySQL 记录它收到的查询来更好地 waaaaay 。您可以记录所有查询,甚至只记录那些比给定时间慢的查询。

答案 1 :(得分:0)

我不知道您需要编辑PHP源来执行此操作。您可以通过执行诸如扩展mysqli和编写自己的日志记录例程来轻松完成此操作,该例程在每次运行query()时运行。

class MyLog extends mysqli {
     public function query($sql, $mode) {
          // Do your logging here
          return parent::query($sql, $mode);
     }
}

然后像往常一样调用此连接器。