Browse code

pkg/jsonlog: add JSONLogBytes for low allocations

Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>

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