github.com/glycerine/docker@v1.8.2/pkg/jsonlog/jsonlogbytes.go (about)

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