github.com/damirazo/docker@v1.9.0/pkg/jsonlog/jsonlogbytes.go (about)

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