Apache Logging Guide:
The Basics

October 31, 2022

Logging is an important part of the Apache web server. All successful client requests are logged in the Apache access log, and all error events are logged in the Apache error log. These logs play a pivotal role when troubleshooting web application issues.

In this guide—part one of two in our series on Apache logging—we’ll learn about Apache web server logging and how to configure it. We’ll also cover the different log levels and formats, log rotation, and how to configure the logs for virtual hosts.

Log Types

There are mainly two types of Apache web server logs: the access logs and the error logs.

Access Logs

Access logs contain information about client requests processed by the web server. Information in each log entry includes:

  • Client IP address
  • Time of the request
  • The resource requested
  • The user agent string identifying the requester’s OS and browser
  • HTTP response code returned
  • The number of bytes returned to the client

The following snippet shows a sample access log:

116.35.41.41 - - [21/May/2022:11:22:39 +0000] "GET / HTTP/1.1" 403 199691 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15"
116.35.41.41 - - [21/May/2022:11:22:41 +0000] "GET /icons/poweredby.png HTTP/1.1" 200 643 "http://34.227.9.153/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15"

Error Logs

Error logs contain information about any internal errors encountered when the Apache web server starts or runs, as well as errors raised when processing a client request. The following is a typical example of an error log entry:

[Sat May 21 11:26:28.733503 2022] [autoindex:error] [pid 13075:tid 139684223059712] [client 116.15.141.41:57782] AH01276: Cannot serve directory /var/www/html/: No matching DirectoryIndex (index.html) found, and server-generated directory index forbidden by Options directive

Log Locations

The location of log files for the Apache web server can vary based on the operating system. For example, the default location on a CentOS/RedHat system is the /var/log/httpd directory, whereas in an Ubuntu system, the location is typically /var/log/apache2.

You can change the default log location by setting certain parameters in the Apache configuration file. For example, to change the error log location on a CentOS system, you can edit the /etc/httpd/conf/httpd.conffile and set the ErrorLog directive like this:

ErrorLog "/var/log/httpd2/error_log"

When you change the log location, you need to make sure the new directory exists on the server and the Apache process user has the permissions to read from and write to that directory. The changes take effect once you restart the Apache web service. 

Similarly, you can change the access log location by setting the CustomLog directive:

CustomLog "/var/log/httpd2/access_log" common

Log Levels

The log level configuration dictates the type of messages logged in the error log. You can set this value to any of the following values:

  • debug (lowest level)
  • info
  • notice
  • warn
  • error
  • crit
  • alert
  • emerg

A value between trace1 to trace8 (highest level)

The lower the log level, the more verbose log entries are. The warn level is the default log level setting, but you can change it by setting the LogLevel directive in the Apache configuration file to a different value.

Let’s see how changing the log level affects the verbosity. The following entries are recorded when the LogLevel is set to warn:

[Sat May 21 12:40:54.624596 2022] [core:info] [pid 15124:tid 139735416445248] AH00096: removed PID file /etc/httpd/run/httpd.pid (pid=15124)
[Sat May 21 12:40:54.624633 2022] [mpm_event:notice] [pid 15124:tid 139735416445248] AH00492: caught SIGWINCH, shutting down gracefully
[Sat May 21 12:40:55.679086 2022] [core:notice] [pid 15362:tid 140527999998272] SELinux policy enabled; httpd running as context system_u:system_r:httpd_t:s0
[Sat May 21 12:40:55.679815 2022] [suexec:notice] [pid 15362:tid 140527999998272] AH01232: suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
…

After changing the LogLevel to info, we restart Apache and clear the old log entries. The resulting error log looks like this:

…
[Sat May 21 12:45:09.179408 2022] [suexec:notice] [pid 15612:tid 140629236357440] AH01232: suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
[Sat May 21 12:45:09.196807 2022] [lbmethod_heartbeat:notice] [pid 15612:tid 140629236357440] AH02282: No slotmem from mod_heartmonitor
[Sat May 21 12:45:09.197368 2022] [http2:info] [pid 15612:tid 140629236357440] AH03090: mod_http2 (v1.15.7-git, feats=CHPRIO+SHA256+INVHD+DWINS, nghttp2 1.33.0), initializing...
[Sat May 21 12:45:09.197397 2022] [http2:warn] [pid 15612:tid 140629236357440] AH02951: mod_ssl does not seem to be enabled
[Sat May 21 12:45:09.197448 2022] [proxy_http2:info] [pid 15612:tid 140629236357440] AH03349: mod_proxy_http2 (v1.15.7-git, nghttp2 1.33.0), initializing...
…

As you can see, the error log now has some entries of type http2:infowhich were not there before. That’s because the server is now also logging the info type messages.

Log Format

By default, the Apache web server access log uses a combined log format. You can see the field definition for the log format from the Apache configuration file (httpd.conf or apache2.conf). The following snippet, for example, shows the LogFormat directive in a CentOS server:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

The common log format is defined as:

LogFormat "%h %l %u %t \"%r\" %>s %O" common

As you can see, the combined log format is similar to the common log format, except it has two extra fields: Referrer and User-Agent. A % symbol precedes the field names. Some of the important fields in the access log are:

%hHostname/IP address of the client.
%tTimestamp when the request was received.
%rHTTP request type.
%sHTTPS status code returned by the server.
%bNumber of bytes transferred.
%User-AgentUser-agent (including browser, operating system)

Using these basic field definitions, you can easily identify the key information from the access log. Let’s consider the access log snippet below.

116.35.41.41 - - [21/May/2022:11:22:39 +0000] "GET / HTTP/1.1" 403 199691 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15"
116.35.41.41 - - [21/May/2022:11:22:41 +0000] "GET /icons/poweredby.png HTTP/1.1" 200 643 "http://34.227.9.153/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15"

You can see the first entry shows the client IP address is 116.35.41.41.. The client was using the Safari browser running on Mac OS X. The HTTP request method was GET, and the web server responded with a status code of 403 (forbidden). In other words, it refused the client’s request. The total number of bytes transferred to the client was 199691.

You can also change the log format by specifying the value of the CustomLog directive in the Apache configuration file. In the snippet below, we change the log format to common:

CustomLog "/var/log/httpd2/access_log" common

After setting the CustomLog directive and restarting the Apache web server, you can see the access log now contains some important fields like timestamp, level of the message, process id, and a message:

[Sat May 21 12:45:08.082210 2022] [mpm_event:notice] [pid 15362:tid 140527999998272] AH00492: caught SIGWINCH, shutting down gracefully
[Sat May 21 12:45:09.178590 2022] [core:notice] [pid 15612:tid 140629236357440] SELinux policy enabled; httpd running as context system_u:system_r:httpd_t:s0

If you wish to change the error log format, you can add an ErrorLogFormat directive in the Apache configuration file. The following snippet shows an example:

ErrorLogFormat "[%t] [%l] [pid %P] %F: %M"

The following table shows some of the important fields in the error log:

%tTimestamp of the event.
%lMessage level.
%PID of the process that caused the error.
%FSource code file and line number of the module that caused the error.
%MLog message

Restarting the Apache web server service will show error messages like the following:

[Sun May 22 07:06:15 2022] [notice] [pid 19297] event.c(3127): [client AH00492: caught SIGWINCH, shutting down gracefully
[Sun May 22 07:06:16.191416 2022] [core:notice] [pid 19535:tid 140251660302656] SELinux policy enabled; httpd running as context system_u:system_r:httpd_t:s0
[Sun May 22 07:06:16 2022] [notice] [pid 19535] mod_suexec.c(101): AH01232: suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
…

Configuring Apache Logging For VirtualHosts

When you have multiple websites running on the same Apache web server, it’s best to set a separate log file location for each VirtualHost. This makes log management and error triage a lot easier. You can troubleshoot issues with a particular VirtualHost by searching through its log file only.

The snippet below shows how to set up a log file location for a VirtualHost in the Apache configuration file:

<VirtualHost *:80>
    ServerName www.test.com
    ServerAlias test.com
    DocumentRoot /var/www/html/test.com
    ErrorLog /var/log/httpd/test.com/error_log
    CustomLog /var/log/httpd/test.com/access_log combined
</VirtualHost>

Here, we configure the VirtualHost www.test.com and specify a custom location for its access and error logs. 

You can also override server-level log directives at the VirtualHost level. For example, if you set up a LogLevel of warn at the overall Apache web server level, you can set a different LogLevel for a particular VirtualHost, as shown below:

<VirtualHost *:80>
    ServerName www.test.com
    ServerAlias test.com
    DocumentRoot /var/www/html/test.com
    ErrorLog /var/log/httpd/test.com/error_log
    CustomLog /var/log/httpd/test.com/access_log combined
    LogLevel debug
</VirtualHost>

With this configuration, the log level for www.test.com will be debug instead of the default warn.

Log Rotation

Log rotation is a log management technique in which log files older than a specified time or larger than a specific size are deleted, moved, renamed, or compressed. Without log rotation, the same log file continues to be used. Over time, your web server may run out of disk space. Also, since log files grow very large over time, this creates performance bottlenecks when reading from or writing to those log files.

You can use utilities like the Linux logrotate to configure log rotation for Apache web server. It’s also advisable to set proper log retention policies so older log files can be deleted or moved to a different location. In a production system with multiple Apache web servers running, it’s best to send all the logs to a central log management system.

Setting up log rotation With logrotate

Both CentOS and Ubuntu ship with the logrotate package. In order to set up Apache web server log rotation in RHEL-based systems, you can create a file called /etc/logrotate.d/httpd.conf with the following settings:

/var/log/httpd/* {
    daily
    rotate 7
    size 100M
    compress
    delaycompress
}

This configuration will rotate all files under the /var/log/httpd directory (in Debian-based systems like Ubuntu, change this to /var/log/apache2) every day. Apache will rotate the log files in this directory when they reach 100MB in size and keep only the last seven rotated logs. All rotated log files will also be automatically compressed.

Conclusion

In Part One of our guide, we covered the basics of Apache web server logging. We looked at the two different types of log files, their locations, logging levels, and different log formats. We also covered how to configure some of these settings and rotate the log files.

Next, in Part Two of this guide, we’ll learn more advanced concepts like conditional logging, different logging modules, log file integrity monitoring, centralized log management, and log analysis.