123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- package jsonlog
- import (
- "bytes"
- "encoding/json"
- "time"
- "unicode/utf8"
- )
- // JSONLogs marshals encoded JSONLog objects
- type JSONLogs struct {
- Log []byte `json:"log,omitempty"`
- Stream string `json:"stream,omitempty"`
- Created time.Time `json:"time"`
- Tag string `json:"tag,omitempty"`
- // json-encoded bytes
- RawAttrs json.RawMessage `json:"attrs,omitempty"`
- }
- // MarshalJSONBuf is an optimized JSON marshaller that avoids reflection
- // and unnecessary allocation.
- func (mj *JSONLogs) MarshalJSONBuf(buf *bytes.Buffer) error {
- var first = true
- buf.WriteString(`{`)
- if len(mj.Log) != 0 {
- first = false
- buf.WriteString(`"log":`)
- ffjsonWriteJSONBytesAsString(buf, mj.Log)
- }
- if len(mj.Stream) != 0 {
- if first {
- first = false
- } else {
- buf.WriteString(`,`)
- }
- buf.WriteString(`"stream":`)
- ffjsonWriteJSONBytesAsString(buf, []byte(mj.Stream))
- }
- if len(mj.Tag) > 0 {
- if first {
- first = false
- } else {
- buf.WriteString(`,`)
- }
- buf.WriteString(`"tag":`)
- ffjsonWriteJSONBytesAsString(buf, []byte(mj.Tag))
- }
- if len(mj.RawAttrs) > 0 {
- if first {
- first = false
- } else {
- buf.WriteString(`,`)
- }
- buf.WriteString(`"attrs":`)
- buf.Write(mj.RawAttrs)
- }
- if !first {
- buf.WriteString(`,`)
- }
- created, err := fastTimeMarshalJSON(mj.Created)
- if err != nil {
- return err
- }
- buf.WriteString(`"time":`)
- buf.WriteString(created)
- buf.WriteString(`}`)
- return nil
- }
- func ffjsonWriteJSONBytesAsString(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('"')
- }
|