|
@@ -0,0 +1,115 @@
|
|
|
+package jsonlog
|
|
|
+
|
|
|
+import (
|
|
|
+ "bytes"
|
|
|
+ "unicode/utf8"
|
|
|
+)
|
|
|
+
|
|
|
+// JSONLogBytes is based on JSONLog.
|
|
|
+// It allows marshalling JSONLog from Log as []byte
|
|
|
+// and an already marshalled Created timestamp.
|
|
|
+type JSONLogBytes struct {
|
|
|
+ Log []byte `json:"log,omitempty"`
|
|
|
+ Stream string `json:"stream,omitempty"`
|
|
|
+ Created string `json:"time"`
|
|
|
+}
|
|
|
+
|
|
|
+// MarshalJSONBuf is based on the same method from JSONLog
|
|
|
+// It has been modified to take into account the necessary changes.
|
|
|
+func (mj *JSONLogBytes) MarshalJSONBuf(buf *bytes.Buffer) error {
|
|
|
+ var first = true
|
|
|
+
|
|
|
+ buf.WriteString(`{`)
|
|
|
+ if len(mj.Log) != 0 {
|
|
|
+ if first == true {
|
|
|
+ first = false
|
|
|
+ } else {
|
|
|
+ buf.WriteString(`,`)
|
|
|
+ }
|
|
|
+ buf.WriteString(`"log":`)
|
|
|
+ ffjson_WriteJsonBytesAsString(buf, mj.Log)
|
|
|
+ }
|
|
|
+ if len(mj.Stream) != 0 {
|
|
|
+ if first == true {
|
|
|
+ first = false
|
|
|
+ } else {
|
|
|
+ buf.WriteString(`,`)
|
|
|
+ }
|
|
|
+ buf.WriteString(`"stream":`)
|
|
|
+ ffjson_WriteJsonString(buf, mj.Stream)
|
|
|
+ }
|
|
|
+ if first == true {
|
|
|
+ first = false
|
|
|
+ } else {
|
|
|
+ buf.WriteString(`,`)
|
|
|
+ }
|
|
|
+ buf.WriteString(`"time":`)
|
|
|
+ buf.WriteString(mj.Created)
|
|
|
+ buf.WriteString(`}`)
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// This is based on ffjson_WriteJsonString. It has been changed
|
|
|
+// to accept a string passed as a slice of bytes.
|
|
|
+func ffjson_WriteJsonBytesAsString(buf *bytes.Buffer, s []byte) {
|
|
|
+ const hex = "0123456789abcdef"
|
|
|
+
|
|
|
+ buf.WriteByte('"')
|
|
|
+ start := 0
|
|
|
+ for i := 0; i < len(s); {
|
|
|
+ if b := s[i]; b < utf8.RuneSelf {
|
|
|
+ if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
|
|
|
+ i++
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if start < i {
|
|
|
+ buf.Write(s[start:i])
|
|
|
+ }
|
|
|
+ switch b {
|
|
|
+ case '\\', '"':
|
|
|
+ buf.WriteByte('\\')
|
|
|
+ buf.WriteByte(b)
|
|
|
+ case '\n':
|
|
|
+ buf.WriteByte('\\')
|
|
|
+ buf.WriteByte('n')
|
|
|
+ case '\r':
|
|
|
+ buf.WriteByte('\\')
|
|
|
+ buf.WriteByte('r')
|
|
|
+ default:
|
|
|
+
|
|
|
+ buf.WriteString(`\u00`)
|
|
|
+ buf.WriteByte(hex[b>>4])
|
|
|
+ buf.WriteByte(hex[b&0xF])
|
|
|
+ }
|
|
|
+ i++
|
|
|
+ start = i
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ c, size := utf8.DecodeRune(s[i:])
|
|
|
+ if c == utf8.RuneError && size == 1 {
|
|
|
+ if start < i {
|
|
|
+ buf.Write(s[start:i])
|
|
|
+ }
|
|
|
+ buf.WriteString(`\ufffd`)
|
|
|
+ i += size
|
|
|
+ start = i
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ if c == '\u2028' || c == '\u2029' {
|
|
|
+ if start < i {
|
|
|
+ buf.Write(s[start:i])
|
|
|
+ }
|
|
|
+ buf.WriteString(`\u202`)
|
|
|
+ buf.WriteByte(hex[c&0xF])
|
|
|
+ i += size
|
|
|
+ start = i
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ i += size
|
|
|
+ }
|
|
|
+ if start < len(s) {
|
|
|
+ buf.Write(s[start:])
|
|
|
+ }
|
|
|
+ buf.WriteByte('"')
|
|
|
+}
|