Commit 8464020f authored by M-A's avatar M-A Committed by Matt Holt

Add {whenISO} to record timestamp in ISO 8601 format in UTC. (#1353)

* Add {whenISO} to record timestamp in ISO 8601 format in UTC.

ISO 8601 is the standard time format and is easy to parse.

This change assumes users desiring ISO 8016 generally prefer UTC for simplicity.
This results in {whenISO} to be significantly shorter than {when}:
{when}    = "02/Jan/2006:15:04:05 +0000"
{whenISO} = "2006-01-02T15:04:12Z"

Add unit test to verify both, as there was no unit test for {when}.

* Rename {whenISO} to {when_iso}
parent 0155b0c5
...@@ -23,6 +23,8 @@ var requestReplacer = strings.NewReplacer( ...@@ -23,6 +23,8 @@ var requestReplacer = strings.NewReplacer(
"\n", "\\n", "\n", "\\n",
) )
var now = time.Now
// Replacer is a type which can replace placeholder // Replacer is a type which can replace placeholder
// substrings in a string with actual values from a // substrings in a string with actual values from a
// http.Request and ResponseRecorder. Always use // http.Request and ResponseRecorder. Always use
...@@ -249,7 +251,9 @@ func (r *replacer) getSubstitution(key string) string { ...@@ -249,7 +251,9 @@ func (r *replacer) getSubstitution(key string) string {
case "{uri_escaped}": case "{uri_escaped}":
return url.QueryEscape(r.request.URL.RequestURI()) return url.QueryEscape(r.request.URL.RequestURI())
case "{when}": case "{when}":
return time.Now().Format(timeFormat) return now().Format(timeFormat)
case "{when_iso}":
return now().UTC().Format(timeFormatISOUTC)
case "{file}": case "{file}":
_, file := path.Split(r.request.URL.Path) _, file := path.Split(r.request.URL.Path)
return file return file
...@@ -311,6 +315,7 @@ func (r *replacer) Set(key, value string) { ...@@ -311,6 +315,7 @@ func (r *replacer) Set(key, value string) {
const ( const (
timeFormat = "02/Jan/2006:15:04:05 -0700" timeFormat = "02/Jan/2006:15:04:05 -0700"
timeFormatISOUTC = "2006-01-02T15:04:05Z" // ISO 8601 with timezone to be assumed as UTC
headerContentType = "Content-Type" headerContentType = "Content-Type"
contentTypeJSON = "application/json" contentTypeJSON = "application/json"
contentTypeXML = "application/xml" contentTypeXML = "application/xml"
......
...@@ -53,6 +53,13 @@ func TestReplace(t *testing.T) { ...@@ -53,6 +53,13 @@ func TestReplace(t *testing.T) {
t.Fatal("Failed to determine hostname\n") t.Fatal("Failed to determine hostname\n")
} }
old := now
now = func() time.Time {
return time.Date(2006, 1, 2, 15, 4, 5, 02, time.FixedZone("hardcoded", -7))
}
defer func() {
now = old
}()
testCases := []struct { testCases := []struct {
template string template string
expect string expect string
...@@ -61,6 +68,8 @@ func TestReplace(t *testing.T) { ...@@ -61,6 +68,8 @@ func TestReplace(t *testing.T) {
{"This host is {host}.", "This host is localhost."}, {"This host is {host}.", "This host is localhost."},
{"This request method is {method}.", "This request method is POST."}, {"This request method is {method}.", "This request method is POST."},
{"The response status is {status}.", "The response status is 200."}, {"The response status is {status}.", "The response status is 200."},
{"{when}", "02/Jan/2006:15:04:05 +0000"},
{"{when_iso}", "2006-01-02T15:04:12Z"},
{"The Custom header is {>Custom}.", "The Custom header is foobarbaz."}, {"The Custom header is {>Custom}.", "The Custom header is foobarbaz."},
{"The CustomAdd header is {>CustomAdd}.", "The CustomAdd header is caddy."}, {"The CustomAdd header is {>CustomAdd}.", "The CustomAdd header is caddy."},
{"The request is {request}.", "The request is POST / HTTP/1.1\\r\\nHost: localhost\\r\\nCustom: foobarbaz\\r\\nCustomadd: caddy\\r\\nShorterval: 1\\r\\n\\r\\n."}, {"The request is {request}.", "The request is POST / HTTP/1.1\\r\\nHost: localhost\\r\\nCustom: foobarbaz\\r\\nCustomadd: caddy\\r\\nShorterval: 1\\r\\n\\r\\n."},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment