PHP

Writing a custom unix style tail in PHP using Libevent API on Mac OS X 10.5.x and other platforms

Libevent is a library which provides a mechanism to execute a callback function when a specific event occurs on a file descriptor or after a timeout has been reached. Many famous applications/frameworks/libraries like memcached are using libevent. In this blog post, I will demonstrate how to write a custom unix style tail script using Libevent API in PHP.

Setting up the environment:
Setting up libevent with PHP is a little tricky. Below are the steps, I followed to make it work on Mac OSX 10.5. However the steps should be same for any other OS you choose to code on. Here we go:

  1. Check the version of libevent installed on your system. If you don’t have libevent or the installed version is < 1.4, you will need to compile libevent-1.4.x
    ~ sabhinav$ port list | grep libevent
    libevent                       @1.4.12         devel/libevent
  2. Uninstall existing libevent
    ~ sabhinav$ port uninstall libevent
  3. Add the following into your .bash_profile file:
    export MACOSX_DEPLOYMENT_TARGET=10.5
    export CFLAGS="-arch x86_64 -g -Os -pipe -no-cpp-precomp"
    export CCFLAGS="-arch x86_64 -g -Os -pipe"
    export CXXFLAGS="-arch x86_64 -g -Os -pipe"
    export LDFLAGS="-arch x86_64 -bind_at_load"
  4. Open a new terminal window. Download and extract libevent-1.4.12-stable
    ~ sabhinav$ wget http://www.monkey.org/~provos/libevent-1.4.12-stable.tar.gz
    ~ sabhinav$ tar -xvzf libevent-1.4.12-stable.tar.gz
  5. Compile libevent-1.4.12-stable
    ~ sabhinav$ cd libevent-1.4.12-stable
    ~ sabhinav$ ./configure
    ~ sabhinav$ make
    ~ sabhinav$ sudo make install
  6. Assuming you have a successful installation, lets install PECL package libevent-0.0.2.
    ~ sabhinav$ pecl download libevent-0.0.2
    ~ sabhinav$ tar -xvzf libevent-0.0.2.tgz libevent-0.0.2
    ~ sabhinav$ cd libevent-0.0.2
    ~ sabhinav$ phpize
    ~ sabhinav$ ./configure
    ~ sabhinav$ make
    ~ sabhinav$ sudo make install
  7. Enable libevent extension in your php.ini
    extension=libevent.so
  8. Reload apache server
    ~ sabhinav$ sudo apachectl restart
  9. Confirm we have libevent extension enabled using phpinfo(); or
    ~ sabhinav$ php -i | grep libevent

Writing a custom unix style tail script in PHP (tail.php)
Below is a sample script which can be used as a base for writing custom unix style tail script. Comments in the code will help you understanding the flow of the code. Also do view official documentation for PHP Libevent extension usage.

<?php

	// callback function called whenever the registered event is triggered
	function eventFd($fd, $events, $arg) {
		echo fread($fd, 4096);
	}

	// create event base
	$base_fd = event_base_new();

	// create a new event
	$event_fd = event_new();

	// resource to be monitored
	$fd = fopen($argv[1], 'r');

	// set event on passed file name
	event_set($event_fd, $fd, EV_WRITE | EV_PERSIST, 'eventFd', array($event_fd, $base_fd));

	// associate base with this event
	event_base_set($event_fd, $base_fd);

	// register event
	event_add($event_fd);

	// start event loop
	event_base_loop($base_fd);

?>

Trying out tail.php
Save the above code file and issue the following on the terminal:

~ sabhinav$ php tail.php /var/log/apache2/access_log

Try accessing a page on your webserver and you should see the access log being tailed by the php script. 😀

Enjoy!

16 thoughts on “Writing a custom unix style tail in PHP using Libevent API on Mac OS X 10.5.x and other platforms

  1. this doesn’t seem to be working on regular files. But it does work when the file is STDIN or a socket opened with fsockopen or any similar file descriptor like a http connection opened with fopen(“http://patchlog.com”,’r’)…

    1. I am not sure if it has to do something with libevent version you have. But on my MacOSX every thing seems perfect to me. Didn’t tried elsewhere due to libevent version compatibility issues.

      Also point to note is that libevent binding of PHP seems a bit shaky to me. When a event watcher is set on a regular file, utilities like top, htop show high CPU IO cycle usage by the script.

    2. I’m on Linux and this script will just exit when I run it on a regular file.
      I straced it and it seems like the epoll_ctl syscall just fails with EPERM ( permission denied ) when it tries to set polling for the file descriptor

    3. Well I guess it’s mainly because of inconsistent php binding of libevent library. There shd be no other reason why it works on Mac and not on other OS. BTW do you have libevent-1.4 installed? I think php libevent binding works well with libevent-1.4

  2. And also I think the code should be:
    event_set($event_fd, $fd, EV_READ | EV_PERSIST, ‘eventFd’, array($event_fd, $base_fd));

    because you want to be notified when you can read …

  3. Well i just tried it mysql using
    – debian lenny x64
    – php 5.3.2
    – libevent 1.4.3 stable
    – libevent-0.0.2 of PECL

    Results in the same behavior Mihai already posted. Script just exits.

Leave a Reply