github.com/kjk/siser@v0.0.0-20220410204903-1b1e84ea1397/writer.go (about) 1 package siser 2 3 import ( 4 "io" 5 "strconv" 6 "time" 7 ) 8 9 // Writer writes records to in a structured format 10 type Writer struct { 11 w io.Writer 12 // NoTimestamp disables writing timestamp, which 13 // makes serialized data not depend on when they were written 14 NoTimestamp bool 15 } 16 17 // NewWriter creates a writer 18 func NewWriter(w io.Writer) *Writer { 19 return &Writer{ 20 w: w, 21 } 22 } 23 24 // WriteRecord writes a record in a specified format 25 func (w *Writer) WriteRecord(r *Record) (int, error) { 26 d := r.Marshal() 27 return w.Write(d, r.Timestamp, r.Name) 28 } 29 30 // Write writes a block of data with optional timestamp and name. 31 // Returns number of bytes written (length of d + lenght of metadata) 32 // and an error 33 func (w *Writer) Write(d []byte, t time.Time, name string) (int, error) { 34 var hdr string 35 if w.NoTimestamp { 36 hdr = strconv.Itoa(len(d)) 37 } else { 38 if t.IsZero() { 39 t = time.Now() 40 } 41 ms := TimeToUnixMillisecond(t) 42 hdr = strconv.Itoa(len(d)) + " " + strconv.FormatInt(ms, 10) 43 } 44 if name != "" { 45 hdr += " " + name 46 } 47 hdr += "\n" 48 n := len(d) 49 bufSize := len(hdr) + n 50 // for readability, if the record doesn't end with newline, 51 // we add one at the end. Makes decoding a bit harder but 52 // not by much. 53 needsNewline := (n > 0) && (d[n-1] != '\n') 54 if needsNewline { 55 bufSize += 1 56 } 57 58 buf := make([]byte, 0, bufSize) 59 buf = append(buf, hdr...) 60 buf = append(buf, d...) 61 if needsNewline { 62 buf = append(buf, '\n') 63 } 64 return w.w.Write(buf) 65 }