Last active
August 7, 2025 19:20
-
-
Save xram64/97435ddac2c1418545ee6e34c3391a3a to your computer and use it in GitHub Desktop.
Nginx live formatted access log viewer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| ## Nginx live formatted access log viewer | |
| ## xram | 1/30/24 | v3 (8/7/25) | |
| # Notes: | |
| # - The regex below must match the log format defined in `/etc/nginx/nginx.conf`. | |
| # - `gawk` version of `awk` must be installed for `match` statement syntax to work. | |
| # TODO: | |
| # - Create options for printing unused log values (currently `bytes_sent`, `request_length`, and `http_referer`). | |
| # Nginx log format: | |
| # ``` | |
| # log_format main '$remote_addr - [$time_local] ' | |
| # '<$bytes_sent:$request_length> $status ' | |
| # '($host) "$request" | $http_referer | ' | |
| # '"$http_user_agent"'; | |
| # ``` | |
| # ============================================================================ # | |
| # Nginx log file | |
| LOG_FILE="/var/log/nginx/access.log" | |
| # Parse options in args using getopts | |
| OPT_USER_AGENT=false | |
| n_lines=0 | |
| # Get system timezone code to pass into `gawk` | |
| t_tz=$(date +"%Z") | |
| HELP_TEXT='Prints aligned Nginx `access.log` output based on a custom log format.\n' | |
| HELP_TEXT+='Options:\n' | |
| HELP_TEXT+=' [-n LINES] Number of initial lines to print from tail of log. (Default: 0)\n' | |
| HELP_TEXT+=' [-u] Print a user agent line with each request.\n' | |
| HELP_TEXT+=' [-h] Show help text.\n' | |
| while getopts 'n:uh' opt; do | |
| case $opt in | |
| n) n_lines=$OPTARG ;; | |
| u) OPT_USER_AGENT=true ;; | |
| h) echo -e "$HELP_TEXT"; exit 2 ;; | |
| esac | |
| done | |
| # Follow the log file and pipe it to `gawk` for processing | |
| tail -f -n$n_lines "$LOG_FILE" | awk -v OPT_USER_AGENT="$OPT_USER_AGENT" -v t_tz="$t_tz" '{ | |
| # Regex to parse log entry | |
| match($0, /([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+) - \[([^\]]+)\] <([0-9]+):([0-9]+)> ([0-9]+) \(([^\)]+)\) "([^"]*)" \| ([^S]+) \| "([^"]*)"/, arr); | |
| # Extract components of log entry | |
| remote_addr = arr[1] | |
| time_local = arr[2] | |
| bytes_sent = arr[3] | |
| request_length = arr[4] | |
| status = arr[5] | |
| host = arr[6] | |
| request = arr[7] | |
| http_referer = arr[8] | |
| http_user_agent = arr[9] | |
| # Split the request to method, path, and protocol (unreliable since some requests can have malformed `request` fields) | |
| split(request, request_parts, " ") | |
| method = request_parts[1] | |
| path = request_parts[2] | |
| protocol = request_parts[3] | |
| # Split the full timestamp into separate date and time components | |
| split(time_local, time_local_parts, " ") | |
| timestamp = time_local_parts[1] # leave off +0000 UTC offset | |
| split(timestamp, timestamp_parts, ":") | |
| t_date = timestamp_parts[1] | |
| t_hour = timestamp_parts[2] | |
| t_min = timestamp_parts[3] | |
| t_sec = timestamp_parts[4] | |
| # Define ANSI color codes | |
| # [Bold] | |
| f_bold="\033[1m" | |
| f_red_b="\033[1;31m" | |
| f_green_b="\033[1;32m" | |
| f_yellow_b="\033[1;93m" | |
| f_blue_b="\033[1;36m" | |
| f_magenta_b="\033[1;35m" | |
| # [Regular] | |
| f_darkgray="\033[90m" | |
| f_reset="\033[m" | |
| # Wrap HTTP status with an ANSI color code depending on the status class | |
| if (status >= 500) status_color=f_yellow_b; # 500: Server error | |
| else if (status >= 400) status_color=f_red_b; # 400: Client error | |
| else if (status >= 300) status_color=f_blue_b; # 300: Redirect | |
| else if (status >= 200) status_color=f_green_b; # 200: Success | |
| else status_color=f_bold; | |
| # Print formatted log entry | |
| printf f_magenta_b "%15s" f_darkgray " @ " f_reset "%11s %s:%s:%s %s | " status_color "%3s" f_reset " | %-16s | \"%s\"\n", | |
| remote_addr, t_date, t_hour, t_min, t_sec, t_tz, status, host, request; | |
| # Print the user agent on a separate line, if `-u` option was set | |
| if (OPT_USER_AGENT == "true") printf " " f_darkgray "(%s)" reset "\n", http_user_agent; | |
| }' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment