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  }