--- date: 2022-12-01 23:41:15-05:00 draft: false math: false medium_enabled: true medium_post_id: be642b59857 tags: - Nginx title: Visualizing Nginx logs with GoAccess --- I currently use [Ackee](https://ackee.electerious.com/) to collect minimal analytics on this website. That comes as an additional Javascript library which has its own set of possible issues: - Doesn't count visits with javascript disabled - Some visitors may block the API On the other hand, nginx which is my webserver of choice comes with the capability of logging requests. In fact, when setting it up as a podman/docker container, it already is configured to do so. ## Configuring nginx To see where it's configured within the container, take a look at `/config/nginx/nginx.conf` ```nginx access_log /config/log/nginx/access.log; ``` If it's not already there, you can add it to configure logging. In fact, you can also change the logging location, however, the rest of this post will assume the one listed. If we're using `nginx` within a container, then we'll need a volume mount to keep the log data persistent. Here is how we do it via `docker-compose`. ```yaml nginx: # Other attributes volumes: # Other volume mounts - /var/log/nginx:/config/log/nginx ``` Within the container, the logs are stored in `/config/log/nginx`. This configuration then maps it so it shows up at `/var/log/nginx` on the host system. Okay so we are now logging to `access.log`, how do these logs look like? By default it looks like the following: ``` 60.37.199.123 - - [27/Nov/2022:02:04:44 -0500] "GET /offline HTTP/2.0" 301 162 "https://brandonrozek.com/serviceworker.js" "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/87.0.4280.141 Safari/537.36 Edg/87.0.664.75" 60.37.199.123 - - [27/Nov/2022:02:04:44 -0500] "GET /offline HTTP/2.0" 301 162 "https://brandonrozek.com/serviceworker.js" "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/87.0.4280.141 Safari/537.36 Edg/87.0.664.75" ``` Now it's difficult to parse a log file filled with entries like this. This is where `GoAccess` comes to play. ## GoAccess GoAccess is a real-time web log analyzer which displays in both a terminal and browser visitor metrics. ![GoAccess Screenshot](/files/images/blog/goaccess-dashboard.png) I've been running it for the past week, and there's a section where it displays pages that are 404ing. ![Screenshot of pages that are 404ing](/files/images/blog/20221201233536.png) This has inspired me to fix my theme and upload a `robots.txt`! By default, GoAccess is not a daemon, and will start by parsing the log file at its current point. To start it, all you need to specify is the location of the log file. ```bash goaccess /var/log/nginx/access.log ``` Then, it will ask you some questions about the type of log that it's parsing. To save those options permanently, we'll need to edit `/etc/goaccess/goaccess.conf`. These are the settings for the default `nginx` log type. ``` log-file /var/log/nginx/access.log time-format %H:%M:%S date-format %d/%b/%Y # NCSA Combined Log Format log-format %h %^[%d:%t %^] "%r" %s %b "%R" "%u" ``` Other options to consider: ``` # Prompt log/date configuration window on program start. config-dialog false # Color highlight active panel. hl-header true # Ignore request's query string. # i.e., www.google.com/page.htm?query => www.google.com/page.htm # # Note: Removing the query string can greatly decrease memory # consumption, especially on timestamped requests. no-query-string true ``` ## Pros/Cons to Log Analyzing Pros: - No database to manage - No extra software to install - No javascript dependency Cons: - Bot traffic may overshadow regular visitors - More complex logging behavior can't be replicated - Though from a human privacy standpoint, this is a good thing :) ## Things to look at later I've been only using GoAccess for the past week now, and there are still many features that I haven't tried out. I hope to update this post as I play around. ### Custom Logging Formats Nginx allows us to customize the log format so that we only record the bits we care about. This can save on both disk space and time to parse if done correctly. Here's an example from the [Nginx Documentation](https://docs.nginx.com/nginx/admin-guide/monitoring/logging/): ```nginx http { log_format compression '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" "$gzip_ratio"'; } ``` ### Report Generation GoAccess allows for generation of reports. This can be a nice visualization such as HTML, as well as outputs to CSV and JSON for more programatic manipulation. Here's a JSON report for the GoAccess website itself: ```json "general": { "date_time": "2016-11-22 21:48:12 -0600", "total_requests": 248660, "valid_requests": 248660, "failed_requests": 0, "generation_time": 20, "unique_visitors": 22953, "unique_files": 14622, "excluded_hits": 0, "unique_referrers": 5587, "unique_not_found": 994, "unique_static_files": 10521, "log_size": 64570946, "bandwidth": 3650756631, "log_path": "/var/log/nginx/access.log" } ``` We can do many things with a JSON export of website traffic, but one of my favorite ideas is to have a "Most Popular Posts" section of my website.