16

In multi-threaded environments (like most web platforms) I often include some sort of thread ID to the logs of my apps. This enables me to tell exactly what log entry came from which request/thread, when there are multiple requests at once which are simultaneously writing to the same log.

In .NET/C#, this can be done by the formatters of log4net, which by default include the current thread's ManagedThreadId (a number) or Name (a given name). These properties uniquely identify a thread (see for example: How to log correct context with Threadpool threads using log4net?

In PHP, I have not found anything similar (I asked Google, PHP docs and SO). Does it exist?

Community
  • 1
  • 1
Jonas Sourlier
  • 13,684
  • 16
  • 77
  • 148

5 Answers5

23

Up until recently, I used apache_getenv("UNIQUE_ID"), and it worked perfectly with a crc32 or another hash function.

Nowadays I'm just using the following, in order to remove dependency on Apache and this mod.

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

It's unique enough to understand which logs belong to which request. If you need more precision, you can use other hash functions.

Hope this helps.

gilm
  • 7,690
  • 3
  • 41
  • 41
  • 1
    Just a reminder that if two requests come at the same time, this method will result two identical IDs. – Rangi Lin Jun 10 '15 at 06:58
  • 3
    REMOTE_ADDR and REQUEST_TIME will be similar at that case, but REMOTE_PORT will differ. REMOTE_PORT can be similar to a previous request, in case of keepalive request, but then REQUEST_TIME won't be the same. – gilm Jun 10 '15 at 11:27
  • 2
    `REQUEST_TIME_FLOAT` is available since PHP 5.4, and precise down to the microsecond. – Ian Dunn May 31 '16 at 22:36
  • 3
    `hash( 'crc32b', $values )` seems more readable `sprintf( "%08x", abs( crc32( $values ) ) )`, and I think it achieves the same result. – Ian Dunn May 31 '16 at 22:51
  • Certainly adequate for the purposes of the question - distinguishing log entries that come from different threads. I did, however, get notices in the PHP log - `Undefined index: REMOTE_ADDR` and same for `REMOTE_PORT` - invoking PHP CLI from Windows Task Scheduler. – youcantryreachingme Dec 10 '20 at 05:44
  • @youcantryreachingme that's true. REMOTE_* are not defined if you're not passing through a webserver such as Apache. In those cases, I just take the process id and the current time and hash them together. – gilm Jan 12 '21 at 10:46
7

zend_thread_id():

int zend_thread_id ( void ) 

This function returns a unique identifier for the current thread.

Although:

This function is only available if PHP has been built with ZTS (Zend Thread Safety) support and debug mode (--enable-debug).


You could also try yo call mysql_thread_id(), when you use that API for your database access (or mysqli::$thread_id when using mysqli).

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • Thank you, but unfortunately, I cannot use `zend_thread_id()`, and although I'm running on Linux, both `exec('gettid')` and `mysql_thread_id()` return nothing. Maybe this is because I'm running in a shared environment. Are there any other options? – Jonas Sourlier May 01 '12 at 22:26
  • Isn't gettid only for calling it from C source, not from terminal? – Lukasz Czerwinski May 02 '13 at 21:42
1

PHP does not seem to have a function for this available, but your web server might be able to pass the identifier via environment variables. There is for example an Apache module called "mod_unique_id"[1] which generates a unique identifier for each request and stores it as an environment variables. If the variable is present, it should be visible via $_SERVER['unique_id'] [2]

"Pure PHP" solution could be to write a script that generates suitable random identifier, stores it via define("unique_id", val) and then use auto_prepend_file [3] option in php.ini to include this in every script that executes. This way the unique id would be created when the request starts processing and it would be available during the processing of the request.

Juha Palomäki
  • 26,385
  • 2
  • 38
  • 43
1

I've seen getmypid() used for this purpose, but it seems to behave differently on different systems. In some cases the ID is unique to each request, but on others it's shared.

So, you're probably better of going with one of the other answers to ensure portability.

Ian Dunn
  • 3,541
  • 6
  • 26
  • 44
  • 2
    getmypid returns process id of the running php instance. since in some systems such as CGI php stays runing and processing the requests, it always returns same id – AaA Jan 15 '20 at 09:47
0

Assigning an ID in order to identify logged data from serving a request probably is as simple as creating a UUID version 4 (random) and writing it to every line of the log.

There even is software helping with that: ramsey/uuid, php-middleware/request-id

Adding it to every line of logging is easy when using log4php by putting the UUID to the LoggerMDC data and using an appropriate LogFormatter. With PSR-3 loggers, it might be a bit more complicated, YMMV.

A randomly created UUID will be suitable to identify one single request, and by using that UUID in the HTTP headers of sub requests and in the response, it will even be possible to trace one request across multiple systems and platforms inside the server farm. However, putting it as a header is not the task of any of the packages I mentioned.

Sven
  • 69,403
  • 10
  • 107
  • 109