Skip to content

Commit b535ed3

Browse files
committed
pkg/jsonlog: add JSONLogBytes for low allocations
Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>
1 parent f26f405 commit b535ed3

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed

pkg/jsonlog/jsonlogbytes.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package jsonlog
2+
3+
import (
4+
"bytes"
5+
"unicode/utf8"
6+
)
7+
8+
// JSONLogBytes is based on JSONLog.
9+
// It allows marshalling JSONLog from Log as []byte
10+
// and an already marshalled Created timestamp.
11+
type JSONLogBytes struct {
12+
Log []byte `json:"log,omitempty"`
13+
Stream string `json:"stream,omitempty"`
14+
Created string `json:"time"`
15+
}
16+
17+
// MarshalJSONBuf is based on the same method from JSONLog
18+
// It has been modified to take into account the necessary changes.
19+
func (mj *JSONLogBytes) MarshalJSONBuf(buf *bytes.Buffer) error {
20+
var first = true
21+
22+
buf.WriteString(`{`)
23+
if len(mj.Log) != 0 {
24+
if first == true {
25+
first = false
26+
} else {
27+
buf.WriteString(`,`)
28+
}
29+
buf.WriteString(`"log":`)
30+
ffjson_WriteJsonBytesAsString(buf, mj.Log)
31+
}
32+
if len(mj.Stream) != 0 {
33+
if first == true {
34+
first = false
35+
} else {
36+
buf.WriteString(`,`)
37+
}
38+
buf.WriteString(`"stream":`)
39+
ffjson_WriteJsonString(buf, mj.Stream)
40+
}
41+
if first == true {
42+
first = false
43+
} else {
44+
buf.WriteString(`,`)
45+
}
46+
buf.WriteString(`"time":`)
47+
buf.WriteString(mj.Created)
48+
buf.WriteString(`}`)
49+
return nil
50+
}
51+
52+
// This is based on ffjson_WriteJsonString. It has been changed
53+
// to accept a string passed as a slice of bytes.
54+
func ffjson_WriteJsonBytesAsString(buf *bytes.Buffer, s []byte) {
55+
const hex = "0123456789abcdef"
56+
57+
buf.WriteByte('"')
58+
start := 0
59+
for i := 0; i < len(s); {
60+
if b := s[i]; b < utf8.RuneSelf {
61+
if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
62+
i++
63+
continue
64+
}
65+
if start < i {
66+
buf.Write(s[start:i])
67+
}
68+
switch b {
69+
case '\\', '"':
70+
buf.WriteByte('\\')
71+
buf.WriteByte(b)
72+
case '\n':
73+
buf.WriteByte('\\')
74+
buf.WriteByte('n')
75+
case '\r':
76+
buf.WriteByte('\\')
77+
buf.WriteByte('r')
78+
default:
79+
80+
buf.WriteString(`\u00`)
81+
buf.WriteByte(hex[b>>4])
82+
buf.WriteByte(hex[b&0xF])
83+
}
84+
i++
85+
start = i
86+
continue
87+
}
88+
c, size := utf8.DecodeRune(s[i:])
89+
if c == utf8.RuneError && size == 1 {
90+
if start < i {
91+
buf.Write(s[start:i])
92+
}
93+
buf.WriteString(`\ufffd`)
94+
i += size
95+
start = i
96+
continue
97+
}
98+
99+
if c == '\u2028' || c == '\u2029' {
100+
if start < i {
101+
buf.Write(s[start:i])
102+
}
103+
buf.WriteString(`\u202`)
104+
buf.WriteByte(hex[c&0xF])
105+
i += size
106+
start = i
107+
continue
108+
}
109+
i += size
110+
}
111+
if start < len(s) {
112+
buf.Write(s[start:])
113+
}
114+
buf.WriteByte('"')
115+
}

0 commit comments

Comments
 (0)