How do PHP logging frameworks fare when pushed to their limits? This analysis can help us decide which option is best for our PHP applications. Performance, speed, and reliability are important for logging frameworks because we want the best performance out of our application and to minimize loss of data.
Our goals for the fastest PHP framework benchmark tests are to measure the time different frameworks require to process a large number of log messages, considering various logging handlers, as well as which logging frameworks are more reliable at their limits (dropping none or less messages).
The frameworks we tried are:
- native PHP logging (error_log and syslog built-in functions)
- Apache Log4php
All of these frameworks use synchronous or “blocking” calls, as PHP functions typically do. The web server execution waits until the function/method call is finished in order to continue. As for the handlers: error_log, KLogger, Log4php, and Monolog can write log messages to text file, while error_log/syslog, Log4php, and Monolog are able to send the messages to the local system logger. Finally, only Log4php and Monolog allow remote Syslog connections.
NOTE: The term syslog can refer to various things. In this article, this includes the PHP function of the same name, the system logger daemon (e.g.
syslogd), or a remote syslog server (i.e.
Application and Handlers
For this framework benchmark, we built a PHP CodeIgniter 3 web app with a controller for each logging mechanism. Controller methods echo the microtime difference before and after logging, which is useful for manual tests. Each controller method call has a loop that writes 10,000
INFO log messages in the case of file handlers (except error_log which can only produce
E_ERROR), or 100,000
INFO messages to syslog. This helps us stress the logging system while not over-burdening the web server request handler.
NOTE: You may see the full app source code at https://github.com/jorgeorpinel/php-logging-benchmark
For the local handlers, first we tested writing to local files and kept track of the number of written logs in each test. We then tested the local system logger handler (which uses the
/dev/log UNIX socket by default) and counted the number of logs
syslogd wrote to
As for the “remote” syslog server, we set up rsyslog on the system and configured it to accept both TCP and UDP logs, writing them to /var/log/messages. We recorded the number of logs there to determine whether any of them were dropped.
We ran the application locally on Ubuntu with Apache (and mod-php). First, each Controller/method was “warmed up” by requesting that URL with
curl, which ensures the PHP source is already precompiled when we run the actual framework benchmark tests. Then we used ApacheBench to stress test the local web app with 100 or 10 serial requests (file or syslog, respectively). For example:
ab -ln 100 localhost:8080/Native/error_log
ab -ln 10 localhost:8080/Monolog/syslog_udp
The total number of log calls in each test was 1,000,000 (each method). We gathered performance statistics from the tool’s report for each Controller/method (refer to figure 1).
Please note in normal operations the actual drop rates should be much smaller, if any.
Hardware and OS
We ran both the sample app and the tests on AWS EC2 micro instance. It’s set up as a 64-bit Ubuntu 16.04 Linux box with an Intel(R) Xeon(R) CPU @ 2.40GHz processors and 1GiB of memory, and an 8 GB storage SSD.
The “native” controller uses a couple of PHP built-in error handling functions. It has two methods: one that calls error_log, which is configured in php.ini to write to a file, and one that calls syslog to reach the system logger. Both functions are used with their default parameters.
error_log to file
By definition, no log messages can be lost by this method as long as the web server doesn’t fail. Its performance when writing to file will depend on the underlying file system and storage speed. Our test results:
|error_log (native PHP file logger)|
|Requests per sec||23.55 [#/sec] (mean)|
|Time per request||42.459 [ms] (mean)|
↑ Divide by 10,000 logs written per request.
NOTE: error_log can also be used to send messages to system log, among other message types.
Using error_log when error_log = syslog in php.ini, or simply using the syslog function, we can reach the system logger. This is similar to using the
logger command in Linux.
|syslog (native PHP system logger)|
|Requests per sec||0.25 [#/sec] (mean)|
|Time per request||4032.164 [ms] (mean) ← ÷ 100,000 logs sent per request|
This is typically the fastest logger, and
syslogd is as robust as the web server or more, so no messages should be dropped (none were in our tests). Another advantage of the system logger is that it can be configured to write to a file and to forward logs via network.
KLogger is a “simple logging class for PHP” with its first stable release in 2104. It’s only able to write logs to file. Its simplicity helps its performance, however. KLogger is PSR-3 compliant: It implements the
|K2Logger (simple PHP logging class)|
|Requests per sec||14.11 [#/sec] (mean)|
|Time per request||70.848 [ms] (mean) ← Divide by 10,000 = 0.0070848 ms / msg|
NOTE: This GitHub fork of KLogger allows local syslog usage as well. We did not try it.
Log4php, first released in 2010, is one in the suite of loggers that Apache provides for several popular programming languages. Logging to file, it turns out to be a speedy contender, at least on Apache. Running the application on Apache probably helps the performance of Log4php. In local tests using PHP’s built-in server (
php -S command), it was actually the slowest contender!
|Log4php (Apache PHP file logger)|
|Requests per sec||18.70 [#/sec] (mean) * 10k = 187k msg per sec|
|Time per request||53.470 [ms] (mean) / 10k = .0053 ms / msg|
As for sending to syslog, it was actually our least performant option, but not by far:
|Log4php to syslog|
|Local syslog socket||Syslog over TCP/IP||Syslog over UDP/IP|
|0.08 ms per log||Around 24 ms per log||0.07 ms per log|
|0% dropped||0% dropped||0.15% dropped|
Some of the advantages Log4php has, which may offset its lack of performance, are Java-like XML configuration files (same as other Apache loggers, such as the popular log4j), six logging destinations, and three message formats.
NOTE: Remote syslog over TCP however, doesn’t seem to be well supported at this time. We had to use the general-purpose LoggerAppenderSocket, which was really slow, so we only ran 100,000.
Monolog, like KLogger, is a PSR-3; and, like Log4php, a full logging framework that can send logs to files, sockets, email, databases, and various web services. It was first released in 2011.
Monolog features many integrations with popular PHP frameworks, making it a popular alternative. Monolog beat its competitor Log4php in our tests, but is still not the fastest PHP framework nor most reliable of options, although probably one of the easiest for web developers.
|Monolog (full PHP logging framework)|
|Requests per sec||4.93 [#/sec] (mean) x 10k|
|Time per request||202.742 [ms] (mean) / 10k|
Monolog over Syslog:
|Monolog over syslog|
|0.062 ms per log||0.06 ms per log||0.079 ms per log|
|Less than 0.01% dropped||0.29% dropped||0% dropped|
Now let’s take a look at graphs that summarize and compare all the results above. These charts show the tradeoff between using faster native or basic logging methods, more limited and lower level in nature vs. relatively less performant but full-featured frameworks:
Local File Performance Comparison
Local Syslog Performance and Drop Rates
Log handler or “appender” names vary from framework to framework. For native PHP, we just use the syslog function (Klogger doesn’t support this); in Log4php, it’s a class called
LoggerAppenderSyslog; and it’s called
SyslogHandler in Monolog.
Remote Syslog Performance and Drop Rates
To measure the drop rates, we leveraged the
$RepeatedMsgReduction config param of
rsyslog, which collapses identical messages into a single one and a second message with the count of further repetitions. In the case of Log4php, since the default message includes a timestamp that varies in every single log, we forwarded the logs to SolarWinds® Loggly® (syslog setup in seconds) and used a filtered, interactive log monitoring dashboard to count the total logs received.
Fig 6. Drop rates to rsyslog (TCP) [%]
Fig 7. Time per message sent on UDP to rsyslog
Fig 8. Drop rates to rsyslog (UDP)
Each logging framework is different, and while each could be best fit to specific projects, our recommendations are as follows. Nothing beats the performance of native syslog for system admins who know their way around
syslog-ng daemons, or to forward logs to a cloud service such as Loggly. If what’s needed is a simple, yet powerful way to log locally to files, KLogger offers PSR-3 compliance and is almost as fast as native error_log, although Log4php does seem to edge it out when the app is running on Apache. For a more complete framework, Monolog seems to be the more well-rounded option, particularly when considering remote logging via TCP/IP.
After deciding on a logging framework, your next big decision is choosing a log management solution. Loggly provides unified log analysis and monitoring for all your servers in a single place. You can configure your PHP servers to forward syslog to Loggly or simply use Monolog’s
LogglyHandler, which is easy to set up in your app’s code. Try Loggly for free and take control over your PHP application logs.