At the time of writing, the Apache HTTP server isused by 30.8% of all webservers in operation. If you're responsible for managing any system thatutilizes Apache, then you will surely interact with its logging infrastructureon a regular basis. This tutorial will introduce you to logging in Apache andhow it can help you diagnose, troubleshoot, and quickly resolve any problem youmay encounter on your server.
You will learn where logs are stored, how to access them, and how to customizethe log output and location to fit your needs. You will also learn how tocentralize Apache logs in a log management system for easier tracing, searching,and filtering of logs across your entire stack.
Side note: Get an Apache logs dashboard
Save hours of sifting through Apache logs. Centralize withBetter Stackand start visualizing your log data in minutes.
See the Apache demo dashboard live.
Prerequisites
To follow through with this tutorial, you should set up a Linux server thatincludes a non-root user with sudo
privileges. Additionally, you also need theApache HTTP server installed and enabled on the server, which can be done byexecuting the relevant commands below.
On Debian-based distributions like Ubuntu:
Copied!
sudo apt install apache2
Copied!
sudo systemctl enable apache2
Copied!
sudo systemctl start apache2
On RHEL, Fedora or CentOS:
Copied!
sudo dnf install httpd
Copied!
sudo systemctl enable httpd
Copied!
sudo systemctl start httpd
Please note that the rest of the commands, directory configurations, andconventions used in this tutorial pertain to Debian-based distributions likeUbuntu. Still, the concepts remain the same for other distributions.
Step 1 — Getting started with Apache logging
Apache logs are files that record everything the Apache web server is doing forlater analysis by the server administrator. The records of all Apache events areplaced in two different text files:
- Access Log: this file stores information about incoming requests. You'llfind details about each request such as the requested resource, responsecodes, time taken to generate the response, IP address of the client, andmore.
- Error Log: this file contains diagnostic information about any errors wereencountered while processing requests.
Step 2 — Locating the Apache log files
The log files' location depends on the operating system the Apache web server isrunning. On Debian-based operating systems like Ubuntu, the access log file islocated in /var/log/apache2/access.log
. On CentOS, RHEL, or Fedora, the accesslog file is stored in /var/log/httpd/access_log
.
A typical access log entry might look like this:
Output
::1 - - [13/Nov/2020:11:32:22 +0100] "GET / HTTP/1.1" 200 327 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
Similarly, the error log file is located in /var/log/apache2/error.log
onDebian-based systems and /var/log/httpd/error_log
on CentOS, RHEL, or Fedora.A typical error log entry might look like this:
Output
[Thu May 06 12:03:28.470305 2021] [php7:error] [pid 731] [client ::1:51092] script '/var/www/html/missing.php' not found or unable to stat
In the next section, we'll discuss how to view these log files from the commandline.
Step 3 — Viewing Apache Log files
One of the most common ways to view an Apache log file is through the tail
command which prints the last 10 lines from a file. When the -f
option issupplied, the command will watch the file and output its contents in real-time.
Copied!
sudo tail -f /var/log/apache2/access.log
You should observe the following output on the screen:
Output
. . .198.54.132.137 - - [04/Feb/2022:11:34:04 +0000] "GET / HTTP/1.1" 200 3477 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:04 +0000] "GET / HTTP/1.1" 200 3477 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:04 +0000] "GET / HTTP/1.1" 200 3477 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:05 +0000] "GET / HTTP/1.1" 200 3476 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:06 +0000] "GET / HTTP/1.1" 200 3476 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:06 +0000] "GET / HTTP/1.1" 200 3476 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:07 +0000] "GET / HTTP/1.1" 200 3476 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:07 +0000] "GET / HTTP/1.1" 200 3476 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"
To view the entire contents of the file, you can use the cat
command or openthe file in a text editor like nano
or vim
:
Copied!
cat /var/log/apache2/access.log
You may also want to filter the log entries in the log file by a specific term.In such cases, you should use the grep
command. The first argument to grep
is the term you want to search for, while the second is the log file that willbe searched. In example below, we are filtering all the lines that contain theword GET
:
Copied!
sudo grep GET /var/log/apache2/access.log
This should present the following output:
Output
. . .198.54.132.137 - - [04/Feb/2022:11:34:04 +0000] "GET / HTTP/1.1" 200 3477 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:04 +0000] "GET / HTTP/1.1" 200 3477 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:05 +0000] "GET / HTTP/1.1" 200 3476 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:06 +0000] "GET / HTTP/1.1" 200 3476 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:06 +0000] "GET / HTTP/1.1" 200 3476 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:07 +0000] "GET / HTTP/1.1" 200 3476 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"198.54.132.137 - - [04/Feb/2022:11:34:07 +0000] "GET / HTTP/1.1" 200 3476 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36"
Step 4 — Examining Apache access log formats
The access log records all requests that are processed by the server. You cansee what resources are being requested, the status of each request, and how longit took to process their response. In this section, we'll dive deeper into howto customize the information that is displayed in this file.
Before you can derive value from reading a log file, you need to understand theformat that is being used for each of its entries. The CustomLog
directive iswhat controls the location and format of the Apache access log file. Thisdirective can be placed in the server configuration file(/etc/apache2/apache2.conf
) or in your virtual host entry. Note that definingthe same CustomLog
directive in both files may cause problems.
Let's look at the common formats used in Apache access logs and what they mean.
Common Log Format
The Common Log Formatis the standardized access log format format used by many web servers because itis easy to read and understand. It is defined in the /etc/apache2/apache2.conf
configuration file through the LogFormat
directive.
When you run the command below:
Copied!
sudo grep common /etc/apache2/apache2.conf
You will observe the following output:
Output
LogFormat "%h %l %u %t \"%r\" %>s %O" common
The line above defines the nickname common
and associates it with a particularlog format string. A log entry produced by this format will look like this:
Output
127.0.0.1 alice Alice [06/May/2021:11:26:42 +0200] "GET / HTTP/1.1" 200 3477
Here's an explanation of the information contained in the log message above:
%h
→127.0.0.1
: the hostname or IP address of the client that made therequest.%l
→alice
: remote log name (name used to log in a user). A placeholdervalue (-
) will be used if it is not set.%u
→Alice
: remote username (username of logged-in user). A placeholdervalue (-
) will be used if it is not set.%t
→[06/May/2021:11:26:42 +0200]
: the day and time of the request.\"%r\"
→"GET / HTTP/1.1"
- the request method, route, and protocol.%>s
→200
- the response code.%O
→3477
- the size of the response in bytes.
Combined Log Format
The Combined Log Formatis very similar to the Common log format but contains few extra pieces ofinformation.
It's also defined in the /etc/apache2/apache2.conf
configuration file:
Copied!
sudo grep -w combined /etc/apache2/apache2.conf
You will observe the following output:
Output
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
Notice that it is exactly the same as the Common Log Format, with the additionof two extra fields. Entries produced in this format will look like this:
Output
127.0.0.1 alice Alice [06/May/2021:11:18:36 +0200] "GET / HTTP/1.1" 200 3477 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
Here's an explanation of the two additional fields that are not present in theCommon log format:
\"%{Referer}i\"
→"-"
: the URL of the referrer (if available, otherwise-
is used).\"%{User-Agent}i\"
->"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
:detailed information about the user agent of the client that made the request.
Step 5 — Creating a custom log format
You can define a custom log format in the /etc/apache2/apache2.conf
file byusing the LogFormat
directive followed by the actual format of the output anda nickname that will be used as an identifier for the format. After defining thecustom format, you'll pass its nickname to the CustomLog
directive and restartthe apache2
service.
In this example, we will create a log format named custom
that looks likethis:
Output
LogFormat "%t %H %m %U %q %I %>s %O %{ms}T" custom
Open your /etc/apache2/apache2.conf
file and place the line above below theother LogFormat
lines. It will produce access log entries with the followingdetails:
%t
: date and time of the request.%H
: the request protocol.%m
: the request method.%U
: the URL path requested.%q
: query parameters (if any).%I
: total bytes received including the request headers.%>s
: final HTTP status code.%O
: number of bytes sent in the response.%{ms}T
: time taken to generate the response in milliseconds.
You can find all other formatting options and their description onthis page.
To enable the custom format for subsequent access log entries, you must changethe value of the CustomLog
directive in your virtual hosts file and restartthe apache2
service with Systemctl.
Open up the default virtual hosts file using the command below:
Copied!
sudo nano /etc/apache2/sites-available/000-default.conf
Find the following line:
Output
CustomLog ${APACHE_LOG_DIR}/access.log combined
And change it to:
Output
CustomLog ${APACHE_LOG_DIR}/access.log combined
Save the file by pressing Ctrl-O
then Ctrl-X
, then restart the apache2
service using the command below:
Copied!
sudo systemctl restart apache2
Afterward, make the following request to your server using curl
:
Copied!
curl --head 'http://<your_server_ip>?name=john&age=30'
You should observe the following response:
Output
HTTP/1.1 200 OKDate: Mon, 07 Feb 2022 14:21:45 GMTServer: Apache/2.4.41 (Ubuntu)Last-Modified: Mon, 07 Feb 2022 12:57:29 GMTETag: "2aa6-5d76d24a738bc"Accept-Ranges: bytesContent-Length: 10918Vary: Accept-EncodingContent-Type: text/html
Go ahead and view the last 10 messages in the access log file:
Copied!
sudo tail /var/log/apache2/access.log
The log entry that describes the request will look like this:
Output
[07/Feb/2022:14:21:45 +0000] HTTP/1.1 HEAD /index.html ?name=john&age=30 96 200 255 0
It's also possible to create multiple access log files by specifying theCustomLog
directive more than once. In the example below, the first line logsinto a custom.log
file using the custom
log format, while the second usesthe common
format to write entries into access.log
. Similarly, thecombined.log
file contains messages formatted according to the combined
logformat.
Output
CustomLog ${APACHE_LOG_DIR}/custom.log customCustomLog ${APACHE_LOG_DIR}/access.log commonCustomLog ${APACHE_LOG_DIR}/combined.log combined
Step 6 - Formatting your logs as JSON
Although many log management systems support the default Apache logging formats,it might be best to log in a structured format like JSON since that's the go-toformat for structured logging in the industry and it is universally supported.Here's a conversion of our custom
log format into JSON:
Output
LogFormat "{ \"timestamp\":\"%t\", \"protocol\":\"%H\", \"method\":\"%m\", \"request\":\"%U\", \"query\":\"%q\", \"request_size_in_bytes\":\"%I\", \"status_code\":\"%>s\", \"response_size_in_bytes\":\"%O\", \"time_taken_ms\":\"%{ms}T\" }" json
This produces log entries with the following formatting:
Output
{ "timestamp": "[07/Feb/2022:15:09:02 +0000]", "protocol": "HTTP/1.1", "method": "HEAD", "request": "/index.html", "query": "?name=john&age=30", "request_size_in_bytes": "96", "status_code": "200", "response_size_in_bytes": "255", "time_taken_ms": "0"}
Step 7 — Configuring Apache error logs
The server error log contains information about any errors that the web serverencountered while processing incoming requests as well as other diagnosticinformation. You can choose where the error messages will be transported tousing the ErrorLog
directive in your virtual host configuration file. Thistransport is usually a log file on the filesystem.
Here is an example from default virtual host configuration file/etc/apache2/sites-available/000-default.conf
:
Output
ErrorLog ${APACHE_LOG_DIR}/error.log
On Debian-based distributions, the default error log is in the/var/log/apache2/error.log
file, while in Fedora/CentOS/RHEL, it placed in the/var/log/httpd/error_log
file. If the path argument to ErrorLog
is notabsolute, then it is assumed to be relative to theServerRoot.
A common practice is to monitor the error log continuously for any problemsduring development or testing. This is easily achieved through the tail
command:
Copied!
sudo tail -f /var/log/apache2/error.log
You will observe the following output:
Output
[Mon Feb 07 13:03:43.445444 2022] [core:notice] [pid 10469:tid 140561300880448] AH00094: Command line: '/usr/sbin/apache2'[Mon Feb 07 13:07:31.528850 2022] [mpm_event:notice] [pid 10469:tid 140561300880448] AH00491: caught SIGTERM, shutting down[Mon Feb 07 13:07:31.626878 2022] [mpm_event:notice] [pid 10864:tid 140224997284928] AH00489: Apache/2.4.41 (Ubuntu) configured -- resuming normal operations[Mon Feb 07 13:07:31.626980 2022] [core:notice] [pid 10864:tid 140224997284928] AH00094: Command line: '/usr/sbin/apache2'[Mon Feb 07 13:13:25.966501 2022] [mpm_event:notice] [pid 10864:tid 140224997284928] AH00491: caught SIGTERM, shutting down[Mon Feb 07 13:13:26.049222 2022] [mpm_event:notice] [pid 11268:tid 139760377875520] AH00489: Apache/2.4.41 (Ubuntu) configured -- resuming normal operations[Mon Feb 07 13:13:26.049318 2022] [core:notice] [pid 11268:tid 139760377875520] AH00094: Command line: '/usr/sbin/apache2'[Mon Feb 07 15:08:50.856388 2022] [mpm_event:notice] [pid 11268:tid 139760377875520] AH00491: caught SIGTERM, shutting down[Mon Feb 07 15:08:50.940561 2022] [mpm_event:notice] [pid 12096:tid 140473452194880] AH00489: Apache/2.4.41 (Ubuntu) configured -- resuming normal operations[Mon Feb 07 15:08:50.940669 2022] [core:notice] [pid 12096:tid 140473452194880] AH00094: Command line: '/usr/sbin/apache2'
Aside from logging directly to a file, you can also forward your logs to aSyslog. You can do this byspecifying syslog
instead of a file path as the argument to ErrorLog
:
Output
ErrorLog syslog
Step 8 — Customizing the error log format
Like the Apache access logs, the format of the error messages can be controlledthrough the ErrorLogFormat
directive, which should be placed in the mainconfig file or virtual host entry. It looks like this:
Output
ErrorLogFormat "[%{u}t] [%l] [pid %P:tid %T] [client\ %a] %M"
The above configuration produces a log entry in the following format:
Output
[Mon Feb 07 15:52:57.234792 2022] [error] [pid 24372:tid 24507] [client 20.113.27.135:34579] AH01276: Cannot serve directory /var/www/html/: No matching DirectoryIndex (index.html) found, and server-generated directory index forbidden by Options directive
Here's an explanation of the formatting options used above:
%{u}t
: the current time, including microseconds. %l
: the log level of themessage. %P
: the process identifier. %T
: the thread identifier. %a
: theclient IP address. %M
: the actual log message.
Note that when the data for a formatting option is not available in a particularevent, it will be omitted from the log entirely as the Apache error log doesn'tuse placeholder values for missing parameters.
You can find a complete description of all the available error formattingoptions in theApache docs.
Step 9 — Customizing the error log level
In the virtual host configuration file, you can also control the level ofmessages that will be entered into the error log through theLogLevel directive.When you specify a particular value, messages from all other levels of higherseverity will be logged as well. For example, when LogLevel error
isspecified, messages with a severity of crit
, alert
, and emerg
will also belogged.
Output
LogLevel error
These are the levels available in increasing order of severity:
trace1
-trace8
: trace messages (lowest severity).debug
: messages used for debugging.info
: informational messages.notice
: normal but significant conditions.warn
: warnings.error
: error conditions that doesn't necessarily require immediate action.crit
: critical conditions that requires prompt action.alert
: errors that require immediate action.emerg
: system is unusable.
If the LogLevel
directive is not set, the server will set the log level towarn
by default.
Step 10 — Centralizing your Apache logs
Storing your Apache logs on the filesystem may suffice for developmentenvironments or single-server deployments, but when multiple servers areinvolved, it may be more convenient to centralize all your logs in a singlelocation so that you can automatically parse, filter, and search log data fromall sources in real-time.
In this section, we'll demonstrate how you can centralize your Apache logs in alog management service through Vector,a high-performance tool for building observability pipelines. The followinginstructions assume that you've signed up for a freeLogtail account and retrieved your sourcetoken.
Go ahead and follow the relevantinstallation instructions for Vectorfor your operating system. On Ubuntu, you may run the following commands toinstall the Vector CLI:
Copied!
bash -c "$(curl -L https://setup.vector.dev)"
Copied!
sudo apt install vector
After Vector is installed, confirm that it is up and running throughsystemctl
:
Copied!
systemctl status vector
You should observe that it is active and running:
Output
● vector.service - Vector Loaded: loaded (/lib/systemd/system/vector.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2022-02-08 10:52:59 UTC; 48s ago Docs: https://vector.dev Process: 18586 ExecStartPre=/usr/bin/vector validate (code=exited, status=0/SUCCESS) Main PID: 18599 (vector) Tasks: 3 (limit: 2275) Memory: 6.8M CGroup: /system.slice/vector.service └─18599 /usr/bin/vector
Otherwise, go ahead and start it with the command below.
Copied!
sudo systemctl start vector
Afterwards, change into a root shell and append your Logtail vectorconfiguration for Apache into the /etc/vector/vector.toml
file using thecommand below. Don't forget to replace the <your_logtail_source_token>
placeholder below with your source token.
Copied!
sudo -s
Copied!
wget -O ->> /etc/vector/vector.toml \ https://logtail.com/vector-toml/apache2/<your_logtail_source_token>
Then restart the vector
service:
Copied!
sudo systemctl restart vector
You will observe that your Apache logs will start coming through in Logtail:
Conclusion
In this tutorial, you learned about the different types of logs that the Apacheweb server stores, where you can find those logs, and how to view theircontents. We also discussed Apache access and error log formatting and how tocreate your custom log formats, including a structured JSON format. Finally, weconsidered how you can manage all your Apache logs in one place by using theVector CLI to stream each entry to a log management service.
Don't forget to read the docs tofind out more about all the logging features that Apache has to offer. Thanksfor reading!
Ayo is the Head of Content at Better Stack. His passion is simplifying and communicating complex technical ideas effectively. His work was featured on several esteemed publications including LWN.net, Digital Ocean, and CSS-Tricks. When he’s not writing or coding, he loves to travel, bike, and play tennis.
Got an article suggestion?Let us know
Next article
Nginx Logging: A Comprehensive GuideThis article will teach you to effectively leverage Nginx logs for enhancedvisibility and control over your web server→