Skip to content

Commit ddb66e1

Browse files
authored
Add logger middleware template variables: ${time_unix_milli} and ${time_unix_micro} (#2206)
This patch introduces two template variables `${time_unix_milli}` and `${time_unix_micro}` into the logger middleware. Currently, there is no way to interpolate that UNIX milli and micro seconds timestamp in a log entry, and go 1.17 or later runtime supports the utility functions `time#UnixMilli()` and `time#UnixMicro()` so this patch adds them as well. see also: golang/go#44196 Signed-off-by: moznion <[email protected]>
1 parent 0644cd6 commit ddb66e1

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

middleware/logger.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ type (
2323
// Tags to construct the logger format.
2424
//
2525
// - time_unix
26+
// - time_unix_milli
27+
// - time_unix_micro
2628
// - time_unix_nano
2729
// - time_rfc3339
2830
// - time_rfc3339_nano
@@ -126,6 +128,12 @@ func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc {
126128
switch tag {
127129
case "time_unix":
128130
return buf.WriteString(strconv.FormatInt(time.Now().Unix(), 10))
131+
case "time_unix_milli":
132+
// go 1.17 or later, it supports time#UnixMilli()
133+
return buf.WriteString(strconv.FormatInt(time.Now().UnixNano()/1000000, 10))
134+
case "time_unix_micro":
135+
// go 1.17 or later, it supports time#UnixMicro()
136+
return buf.WriteString(strconv.FormatInt(time.Now().UnixNano()/1000, 10))
129137
case "time_unix_nano":
130138
return buf.WriteString(strconv.FormatInt(time.Now().UnixNano(), 10))
131139
case "time_rfc3339":

middleware/logger_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"net/http"
88
"net/http/httptest"
99
"net/url"
10+
"strconv"
1011
"strings"
1112
"testing"
1213
"time"
@@ -244,3 +245,49 @@ func BenchmarkLoggerWithConfig_withMapFields(b *testing.B) {
244245
buf.Reset()
245246
}
246247
}
248+
249+
func TestLoggerTemplateWithTimeUnixMilli(t *testing.T) {
250+
buf := new(bytes.Buffer)
251+
252+
e := echo.New()
253+
e.Use(LoggerWithConfig(LoggerConfig{
254+
Format: `${time_unix_milli}`,
255+
Output: buf,
256+
}))
257+
258+
e.GET("/", func(c echo.Context) error {
259+
return c.String(http.StatusOK, "OK")
260+
})
261+
262+
req := httptest.NewRequest(http.MethodGet, "/", nil)
263+
264+
rec := httptest.NewRecorder()
265+
e.ServeHTTP(rec, req)
266+
267+
unixMillis, err := strconv.ParseInt(buf.String(), 10, 64)
268+
assert.NoError(t, err)
269+
assert.WithinDuration(t, time.Unix(unixMillis/1000, 0), time.Now(), 3*time.Second)
270+
}
271+
272+
func TestLoggerTemplateWithTimeUnixMicro(t *testing.T) {
273+
buf := new(bytes.Buffer)
274+
275+
e := echo.New()
276+
e.Use(LoggerWithConfig(LoggerConfig{
277+
Format: `${time_unix_micro}`,
278+
Output: buf,
279+
}))
280+
281+
e.GET("/", func(c echo.Context) error {
282+
return c.String(http.StatusOK, "OK")
283+
})
284+
285+
req := httptest.NewRequest(http.MethodGet, "/", nil)
286+
287+
rec := httptest.NewRecorder()
288+
e.ServeHTTP(rec, req)
289+
290+
unixMicros, err := strconv.ParseInt(buf.String(), 10, 64)
291+
assert.NoError(t, err)
292+
assert.WithinDuration(t, time.Unix(unixMicros/1000000, 0), time.Now(), 3*time.Second)
293+
}

0 commit comments

Comments
 (0)