Common Log Format

Common Log File Format

這篇算是一篇軟體的考古文吧,最近對部落格做了些調整,其中一個改變就是把 Google Analytic 拿掉了,一部分是因為現在已經不能用 UA 而要改用 GA4 了,然後其實我也想拿掉很久了,這次就順便把它移除,不過我還是有興趣想知道不同文章大家感興趣的程度差異,所以就又研究起以前那種根據 HTTP server log 來整理網站統計資訊的工具,其實以前一直沒成功拿掉 GA 的原因之一就是找不到好的替代工具,一直以來我比較有印象的就是 AWStats,只是那個介面我實在是受不了,然後搜尋其他替代工具的過程也不太順利,直到這次重新研究之後,發現到一個關鍵字 Common Log Format,這聽起來很一般的詞,在軟體工程界其實已經變成是一個專有名詞了。

Common Log Format 的 Wikipedia 條目 寫著這是一種 HTTP server log 的標準格式,不過我覺得應該只能算是 de facto standard(業界標準),因為沒有任何機構真的定義並作為標準發布過,現在網路上可以找到 W3C 的一份格式說明,但是那其實是 CERN 時代的 httpd 這個軟體的說明文件,趁這個機會,我就想著要來搞清楚幾個我一直很疑惑的幾個和 log 相關的單字,分別就是一開始說到的 common,然後就是 combinedextended,這幾個關鍵字都是我以前在設定 Apache HTTPD 的時後常常會看到的,甚至其它的 web server 也有用到,但是一直沒有搞的很清楚,而且使用的字我也覺得很奇怪,像是 combined 是在 combine 什麼。

結果就是,這些問題的答案,幾乎都在 NCSA(National Center for Supercomputing Applications、美國國家超級電腦應用中心) 開發的 HTTPd 軟體文件中,NCSA HTTPd 也就是最早提出這種 log format 的 HTTP server,而 NCSA HTTPd 的 log,其實預設下是有三個的,分別是:

TransferLog 其實就是現在大家說的 access log,格式就是所謂的 CLF,不過其實當時是寫作 Common Log File(CLF) Format,紀錄的資料格式就是:

host rfc931 authuser [DD/Mon/YYYY:hh:mm:ss] "request" ddd bbbb

- host: Either the DNS name or the IP number of the remote client
- rfc931: Any information returned by identd for this person, - otherwise.
- authuser: If user sent a userid for authentication, the user name, - otherwise.
- DD: Day
- Mon: Month (calendar name)
- YYYY: Year
- hh: hour (24-hour format, the machine's timezone)
- mm: minutes
- ss: seconds
- request: The first line of the HTTP request as sent by the client.
- ddd: the status code returned by the server, - if not available.
- bbbb: the total number of bytes sent, *not including the HTTP/1.0 header*, - if not available

然後文件還有定義了一個可擴充版的 Extended CLF Format,允許在這些 log 的末端加上其他的資料,如果 LogOptions 設定為Combined的話,三種 log 會 combine 在一起,使用 Extended CLF Format,多加上了 referrer 和 user-agent 資訊,這也就是 Combined 這個格式名稱的由來,而這邊有另外一個容易混淆的東西,就是 W3C 有一份很古老的 Extended Log File Format 的 Working Draft,這份文件定義的格式和 CLF 其實是沒關係的,所以看文件時,有比較仔細的文件就會寫到是 W3C 的 extended 還是 NCSA 的。

雖然我沒仔細查先後關係,不過 CERN 版的 HTTPd 應該是後來才實作了 NCSA 版的 log format,文件內則是稱為 Common Logfile Format,簡稱也是 CLF,不過單字有一點點不一樣就是,當然格式是一樣的,然後其實它也保留了 CERN HTTPd 的舊版 log,格式是:

time remotehost request

實作是:

fprintf(log, "%24.24s %s %s\n",
		asctime(gorl), HTClientHost, n_noth(HTReqLine));

其中的%24.24s我還是研究了好一陣子才看懂第一個 24 是最短長度,資料不夠長時會加上空白,然後.後面的是精確度,遇到字串時則會變成最長長度,超過的就會不輸出,asctime 則是一個內建函數可以把時間轉成字串,格式是:

Www Mmm dd hh:mm:ss yyyy

長度剛好是 24 個字元,至於那個變數名稱gorl則是我花最多時間才參透的,它的意思是:「GMT time or Local time」,但是它不是 indicator 那種二元值,而是變數本身就是那個時間,而那個時間可能是 GMT 時區時間也可能是本地時間。

這樣,其實很多細節的小疑問都有了解答,像是以前看 log 常常看到兩個-接連出現,其實代表的是連續兩個沒有值的欄位,其中一個是現在已經幾乎沒用到的 Identification Protocol(RFC1413),也是個古早的東西,我稍微看了一下好像 IRC 有用到;然後因為其實沒有標準,所以以前和現在的日期格式用的已經不一樣了,現在是普遍有加上時區,當時 NCSA 的和後來 CERN 實做的都沒有時區資訊;另外就是 Apache HTTPD 文件 的範例也有提到 RefererLog 和 AgentLog,我當時看到時就想說怎麼會有人只要這兩種資訊的 log;發現 CLF 這個專有名詞後,我也循線找到更多的 web log 分析工具了,目前我是先挑了 goaccess 來用。

最後整理一下,這三個關鍵字在 web log 的情境下時:

  • Common 格式,通常指的是 Common Log File(CLF) Format;
  • Extended,不考慮 W3C 的版本的話,這邊指的是 NCSA Extended CLF Foramt,如果 CLF Format 定義的欄位不夠用,需要更多資訊時,就可以使用這種格式,多的資訊是加在 log 尾端;
  • Combined 格式,多加了 referrer 和 user-agent 的 web log,使用 NCSA 版 Extended CLF Foramt 的格式,combine 指的是合併 TransferLog、RefererLog 和 AgentLog 三種 log。

實際上 NCSA HTTPd 就不只 Common 和 Combined 兩種,還有 ServerName 可以加上,當然也是使用 Extended 格式,不過目前流傳下來,最常見的就是這兩種了。