【问题标题】:Get unique worker/thread/process/request ID in PHP在 PHP 中获取唯一的 worker/thread/process/request ID
【发布时间】:2012-05-11 09:50:01
【问题描述】:

在多线程环境(如大多数网络平台)中,我经常在我的应用程序日志中包含某种线程 ID。当同时有多个请求同时写入同一个日志时,这使我能够准确地知道哪个日志条目来自哪个请求/线程。

在 .NET/C# 中,这可以通过 log4net 的格式化程序来完成,默认情况下包括当前线程的 ManagedThreadId(数字)或 Name(给定名称)。这些属性唯一标识一个线程(参见例如:How to log correct context with Threadpool threads using log4net?

在 PHP 中,我没有找到任何类似的东西(我问过 Google、PHP 文档和 SO)。存在吗?

【问题讨论】:

标签: php multithreading logging webrequest


【解决方案1】:

直到最近,我还在使用 apache_getenv("UNIQUE_ID"),它与 ​​crc32 或其他哈希函数完美配合。

现在我只是使用以下内容,以消除对 Apache 和此 mod 的依赖。

$uniqueid = sprintf("%08x", abs(crc32($_SERVER['REMOTE_ADDR'] . $_SERVER['REQUEST_TIME'] . $_SERVER['REMOTE_PORT'])));

它的独特性足以了解哪些日志属于哪个请求。如果需要更高的精度,可以使用其他哈希函数。

希望这会有所帮助。

【讨论】:

  • 只是提醒一下,如果两个请求同时到来,这个方法会产生两个相同的ID。
  • REMOTE_ADDR 和 REQUEST_TIME 在这种情况下会相似,但 REMOTE_PORT 会有所不同。 REMOTE_PORT 可以类似于之前的请求,在 keepalive 请求的情况下,但 REQUEST_TIME 不会相同。
  • REQUEST_TIME_FLOAT 自 PHP 5.4 起可用,精确到微秒。
  • hash( 'crc32b', $values ) sprintf( "%08x", abs( crc32( $values ) ) ) 似乎更具可读性,我认为它达到了相同的结果。
  • 对于这个问题来说当然足够了——区分来自不同线程的日志条目。但是,我确实在 PHP 日志中收到了通知 - Undefined index: REMOTE_ADDRREMOTE_PORT 相同 - 从 Windows 任务计划程序调用 PHP CLI。
【解决方案2】:

zend_thread_id():

int zend_thread_id ( void ) 

此函数返回当前线程的唯一标识符。

虽然:

此功能仅在 PHP 已使用 ZTS(Zend 线程安全)支持和调试模式 (--enable-debug) 构建时可用。


您也可以尝试调用mysql_thread_id(),当您使用该API 进行数据库访问时(或mysqli::$thread_id,当您使用mysqli 时)。

【讨论】:

  • 谢谢,但很遗憾,我不能使用zend_thread_id(),尽管我在Linux 上运行,exec('gettid')mysql_thread_id() 都没有返回任何内容。也许这是因为我在共享环境中运行。还有其他选择吗?
  • gettid 不是只能从 C 源调用,而不是从终端调用吗?
【解决方案3】:

PHP 似乎没有可用的函数,但您的 Web 服务器可能能够通过环境变量传递标识符。例如,有一个名为“mod_unique_id”[1] 的 Apache 模块,它为每个请求生成一个唯一标识符并将其存储为环境变量。如果变量存在,它应该通过 $_SERVER['unique_id'] [2]

可见

“纯 PHP”解决方案可能是编写一个生成合适随机标识符的脚本,通过 define("unique_id", val) 将其存储,然后使用 php.ini 中的 auto_prepend_file [3] 选项将其包含在每个脚本中执行。这样,在请求开始处理时将创建唯一 ID,并且在处理请求期间可用。

【讨论】:

    【解决方案4】:

    我见过getmypid() 用于此目的,但它在不同系统上的行为似乎不同。在某些情况下,每个请求的 ID 都是唯一的,但在其他情况下,它是共享的。

    因此,您最好选择其他答案之一以确保可移植性。

    【讨论】:

    • getmypid 返回正在运行的 php 实例的进程 ID。因为在某些系统中,例如 CGI php 保持运行和处理请求,它总是返回相同的 id
    【解决方案5】:

    分配一个 ID 以识别服务请求的记录数据可能就像创建 UUID 版本 4(随机)并将其写入日志的每一行一样简单。

    甚至还有软件可以帮助解决这个问题:ramsey/uuid, php-middleware/request-id

    在使用log4php 时,通过将 UUID 放入 LoggerMDC 数据并使用适当的 LogFormatter,可以轻松地将其添加到每一行日志记录中。使用 PSR-3 记录器,它可能会更复杂一些,YMMV。

    一个随机创建的 UUID 将适用于识别单个请求,并且通过在子请求的 HTTP 标头和响应中使用该 UUID,甚至可以在服务器内跨多个系统和平台跟踪一个请求农场。但是,将其作为标题不是我提到的任何包的任务。

    【讨论】:

      猜你喜欢
      • 2023-03-25
      • 1970-01-01
      • 2014-08-21
      • 1970-01-01
      • 1970-01-01
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      • 2017-08-06
      相关资源
      最近更新 更多