github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/daemon/logger/jsonfilelog/jsonlog/jsonlogbytes.go (about)

     1  package jsonlog // import "github.com/demonoid81/moby/daemon/logger/jsonfilelog/jsonlog"
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"time"
     7  	"unicode/utf8"
     8  )
     9  
    10  // JSONLogs marshals encoded JSONLog objects
    11  type JSONLogs struct {
    12  	Log     []byte    `json:"log,omitempty"`
    13  	Stream  string    `json:"stream,omitempty"`
    14  	Created time.Time `json:"time"`
    15  
    16  	// json-encoded bytes
    17  	RawAttrs json.RawMessage `json:"attrs,omitempty"`
    18  }
    19  
    20  // MarshalJSONBuf is an optimized JSON marshaller that avoids reflection
    21  // and unnecessary allocation.
    22  func (mj *JSONLogs) MarshalJSONBuf(buf *bytes.Buffer) error {
    23  	var first = true
    24  
    25  	buf.WriteString(`{`)
    26  	if len(mj.Log) != 0 {
    27  		first = false
    28  		buf.WriteString(`"log":`)
    29  		ffjsonWriteJSONBytesAsString(buf, mj.Log)
    30  	}
    31  	if len(mj.Stream) != 0 {
    32  		if first {
    33  			first = false
    34  		} else {
    35  			buf.WriteString(`,`)
    36  		}
    37  		buf.WriteString(`"stream":`)
    38  		ffjsonWriteJSONBytesAsString(buf, []byte(mj.Stream))
    39  	}
    40  	if len(mj.RawAttrs) > 0 {
    41  		if first {
    42  			first = false
    43  		} else {
    44  			buf.WriteString(`,`)
    45  		}
    46  		buf.WriteString(`"attrs":`)
    47  		buf.Write(mj.RawAttrs)
    48  	}
    49  	if !first {
    50  		buf.WriteString(`,`)
    51  	}
    52  
    53  	created, err := fastTimeMarshalJSON(mj.Created)
    54  	if err != nil {
    55  		return err
    56  	}
    57  
    58  	buf.WriteString(`"time":`)
    59  	buf.WriteString(created)
    60  	buf.WriteString(`}`)
    61  	return nil
    62  }
    63  
    64  func ffjsonWriteJSONBytesAsString(buf *bytes.Buffer, s []byte) {
    65  	const hex = "0123456789abcdef"
    66  
    67  	buf.WriteByte('"')
    68  	start := 0
    69  	for i := 0; i < len(s); {
    70  		if b := s[i]; b < utf8.RuneSelf {
    71  			if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
    72  				i++
    73  				continue
    74  			}
    75  			if start < i {
    76  				buf.Write(s[start:i])
    77  			}
    78  			switch b {
    79  			case '\\', '"':
    80  				buf.WriteByte('\\')
    81  				buf.WriteByte(b)
    82  			case '\n':
    83  				buf.WriteByte('\\')
    84  				buf.WriteByte('n')
    85  			case '\r':
    86  				buf.WriteByte('\\')
    87  				buf.WriteByte('r')
    88  			default:
    89  
    90  				buf.WriteString(`\u00`)
    91  				buf.WriteByte(hex[b>>4])
    92  				buf.WriteByte(hex[b&0xF])
    93  			}
    94  			i++
    95  			start = i
    96  			continue
    97  		}
    98  		c, size := utf8.DecodeRune(s[i:])
    99  		if c == utf8.RuneError && size == 1 {
   100  			if start < i {
   101  				buf.Write(s[start:i])
   102  			}
   103  			buf.WriteString(`\ufffd`)
   104  			i += size
   105  			start = i
   106  			continue
   107  		}
   108  
   109  		if c == '\u2028' || c == '\u2029' {
   110  			if start < i {
   111  				buf.Write(s[start:i])
   112  			}
   113  			buf.WriteString(`\u202`)
   114  			buf.WriteByte(hex[c&0xF])
   115  			i += size
   116  			start = i
   117  			continue
   118  		}
   119  		i += size
   120  	}
   121  	if start < len(s) {
   122  		buf.Write(s[start:])
   123  	}
   124  	buf.WriteByte('"')
   125  }