Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>
| 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 |
+} |