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:
- 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
- Uninstall existing libevent
~ sabhinav$ port uninstall libevent
- 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"
- 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
- Compile libevent-1.4.12-stable
~ sabhinav$ cd libevent-1.4.12-stable ~ sabhinav$ ./configure ~ sabhinav$ make ~ sabhinav$ sudo make install
- 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
- Enable libevent extension in your php.ini
extension=libevent.so
- Reload apache server
~ sabhinav$ sudo apachectl restart
- 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!
Abhi's Weblog is a collection of blog articles written by
Social comments and analytics for this post…
This post was mentioned on Twitter by imoracle: http://tinyurl.com/yg6mbeu – Writing a custom #unix style #tail in #PHP using #Libevent API on #Mac #OSX 10.5.x and other platforms…
[...] However you can configure JAXL_SERVER_LOAD_POLL_INTERVAL to make it poll faster. You can also use libevent extension in PHP to make it real time in real [...]
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')…
Reply
Abhinav Singh
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.
Mihai Secasiu
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
Abhinav Singh
I think that part can be taken care by setting right permissions on the file you want to set descriptors on and by running the tail script with enough permissions.
Mihai Secasiu
that’s what I thought too… but then I made myself root and had the same problem
Abhinav Singh
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
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 …
Reply
[...] interessant sieht auch diese tail-Lösung mittels libevent unter PHP aus. Dazu muss man allerdings libevent und die PHP-extension libevent installieren, es läuft also [...]