github.com/sujit-baniya/log@v1.0.73/tsv.go (about)

     1  package log
     2  
     3  import (
     4  	"io"
     5  	"net"
     6  	"net/netip"
     7  	"os"
     8  	"runtime"
     9  	"strconv"
    10  	"sync"
    11  )
    12  
    13  // TSVLogger represents an active logging object that generates lines of TSV output to an io.Writer.
    14  type TSVLogger struct {
    15  	Separator byte
    16  	Writer    io.Writer
    17  }
    18  
    19  // TSVEntry represents a tsv log entry. It is instanced by one of TSVLogger and finalized by the Msg method.
    20  type TSVEntry struct {
    21  	buf []byte
    22  	w   io.Writer
    23  	sep byte
    24  }
    25  
    26  var tepool = sync.Pool{
    27  	New: func() interface{} {
    28  		return new(TSVEntry)
    29  	},
    30  }
    31  
    32  // New starts a new tsv message.
    33  func (l *TSVLogger) New() (e *TSVEntry) {
    34  	e = tepool.Get().(*TSVEntry)
    35  	e.sep = l.Separator
    36  	if l.Writer != nil {
    37  		e.w = l.Writer
    38  	} else {
    39  		e.w = os.Stderr
    40  	}
    41  	if e.sep == 0 {
    42  		e.sep = '\t'
    43  	}
    44  	e.buf = e.buf[:0]
    45  	return
    46  }
    47  
    48  // Timestamp adds the current time as UNIX timestamp
    49  func (e *TSVEntry) Timestamp() *TSVEntry {
    50  	var tmp [11]byte
    51  	sec, _, _ := now()
    52  	// separator
    53  	tmp[10] = e.sep
    54  	// seconds
    55  	is := sec % 100 * 2
    56  	sec /= 100
    57  	tmp[9] = smallsString[is+1]
    58  	tmp[8] = smallsString[is]
    59  	is = sec % 100 * 2
    60  	sec /= 100
    61  	tmp[7] = smallsString[is+1]
    62  	tmp[6] = smallsString[is]
    63  	is = sec % 100 * 2
    64  	sec /= 100
    65  	tmp[5] = smallsString[is+1]
    66  	tmp[4] = smallsString[is]
    67  	is = sec % 100 * 2
    68  	sec /= 100
    69  	tmp[3] = smallsString[is+1]
    70  	tmp[2] = smallsString[is]
    71  	is = sec % 100 * 2
    72  	tmp[1] = smallsString[is+1]
    73  	tmp[0] = smallsString[is]
    74  	// append to buf
    75  	e.buf = append(e.buf, tmp[:]...)
    76  	return e
    77  }
    78  
    79  // TimestampMS adds the current time with milliseconds as UNIX timestamp
    80  func (e *TSVEntry) TimestampMS() *TSVEntry {
    81  	var tmp [14]byte
    82  	sec, nsec, _ := now()
    83  	// separator
    84  	tmp[13] = e.sep
    85  	// milli seconds
    86  	a := int64(nsec) / 1000000
    87  	is := a % 100 * 2
    88  	tmp[12] = smallsString[is+1]
    89  	tmp[11] = smallsString[is]
    90  	tmp[10] = byte('0' + a/100)
    91  	// seconds
    92  	is = sec % 100 * 2
    93  	sec /= 100
    94  	tmp[9] = smallsString[is+1]
    95  	tmp[8] = smallsString[is]
    96  	is = sec % 100 * 2
    97  	sec /= 100
    98  	tmp[7] = smallsString[is+1]
    99  	tmp[6] = smallsString[is]
   100  	is = sec % 100 * 2
   101  	sec /= 100
   102  	tmp[5] = smallsString[is+1]
   103  	tmp[4] = smallsString[is]
   104  	is = sec % 100 * 2
   105  	sec /= 100
   106  	tmp[3] = smallsString[is+1]
   107  	tmp[2] = smallsString[is]
   108  	is = sec % 100 * 2
   109  	tmp[1] = smallsString[is+1]
   110  	tmp[0] = smallsString[is]
   111  	// append to buf
   112  	e.buf = append(e.buf, tmp[:]...)
   113  	return e
   114  }
   115  
   116  // Caller adds the file:line of to the entry.
   117  func (e *TSVEntry) Caller(depth int) *TSVEntry {
   118  	var rpc [1]uintptr
   119  	i := callers(depth, rpc[:])
   120  	if i < 1 {
   121  		return e
   122  	}
   123  	frame, _ := runtime.CallersFrames(rpc[:]).Next()
   124  	file := frame.File
   125  	for i = len(file) - 1; i >= 0; i-- {
   126  		if file[i] == '/' {
   127  			break
   128  		}
   129  	}
   130  	if i > 0 {
   131  		file = file[i+1:]
   132  	}
   133  	e.buf = append(e.buf, file...)
   134  	e.buf = append(e.buf, ':')
   135  	e.buf = strconv.AppendInt(e.buf, int64(frame.Line), 10)
   136  	e.buf = append(e.buf, e.sep)
   137  	return e
   138  }
   139  
   140  // Bool append the b as a bool to the entry, the value of output bool is 0 or 1.
   141  func (e *TSVEntry) Bool(b bool) *TSVEntry {
   142  	if b {
   143  		e.buf = append(e.buf, '1', e.sep)
   144  	} else {
   145  		e.buf = append(e.buf, '0', e.sep)
   146  	}
   147  	return e
   148  }
   149  
   150  // BoolString append the b as a bool to the entry, the value of output bool is false or true.
   151  func (e *TSVEntry) BoolString(b bool) *TSVEntry {
   152  	if b {
   153  		e.buf = append(e.buf, 't', 'r', 'u', 'e', e.sep)
   154  	} else {
   155  		e.buf = append(e.buf, 'f', 'a', 'l', 's', 'e', e.sep)
   156  	}
   157  	return e
   158  }
   159  
   160  // Byte append the b as a byte to the entry.
   161  func (e *TSVEntry) Byte(b byte) *TSVEntry {
   162  	e.buf = append(e.buf, b, e.sep)
   163  	return e
   164  }
   165  
   166  // Float64 adds a float64 to the entry.
   167  func (e *TSVEntry) Float64(f float64) *TSVEntry {
   168  	e.buf = strconv.AppendFloat(e.buf, f, 'f', -1, 64)
   169  	e.buf = append(e.buf, e.sep)
   170  	return e
   171  }
   172  
   173  // Int64 adds a int64 to the entry.
   174  func (e *TSVEntry) Int64(i int64) *TSVEntry {
   175  	e.buf = strconv.AppendInt(e.buf, i, 10)
   176  	e.buf = append(e.buf, e.sep)
   177  	return e
   178  }
   179  
   180  // Uint64 adds a uint64 to the entry.
   181  func (e *TSVEntry) Uint64(i uint64) *TSVEntry {
   182  	e.buf = strconv.AppendUint(e.buf, i, 10)
   183  	e.buf = append(e.buf, e.sep)
   184  	return e
   185  }
   186  
   187  // Float32 adds a float32 to the entry.
   188  func (e *TSVEntry) Float32(f float32) *TSVEntry {
   189  	return e.Float64(float64(f))
   190  }
   191  
   192  // Int adds a int to the entry.
   193  func (e *TSVEntry) Int(i int) *TSVEntry {
   194  	return e.Int64(int64(i))
   195  }
   196  
   197  // Int32 adds a int32 to the entry.
   198  func (e *TSVEntry) Int32(i int32) *TSVEntry {
   199  	return e.Int64(int64(i))
   200  }
   201  
   202  // Int16 adds a int16 to the entry.
   203  func (e *TSVEntry) Int16(i int16) *TSVEntry {
   204  	return e.Int64(int64(i))
   205  }
   206  
   207  // Int8 adds a int8 to the entry.
   208  func (e *TSVEntry) Int8(i int8) *TSVEntry {
   209  	return e.Int64(int64(i))
   210  }
   211  
   212  // Uint32 adds a uint32 to the entry.
   213  func (e *TSVEntry) Uint32(i uint32) *TSVEntry {
   214  	return e.Uint64(uint64(i))
   215  }
   216  
   217  // Uint16 adds a uint16 to the entry.
   218  func (e *TSVEntry) Uint16(i uint16) *TSVEntry {
   219  	return e.Uint64(uint64(i))
   220  }
   221  
   222  // Uint8 adds a uint8 to the entry.
   223  func (e *TSVEntry) Uint8(i uint8) *TSVEntry {
   224  	return e.Uint64(uint64(i))
   225  }
   226  
   227  // Uint adds a uint to the entry.
   228  func (e *TSVEntry) Uint(i uint) *TSVEntry {
   229  	return e.Uint64(uint64(i))
   230  }
   231  
   232  // Str adds a string to the entry.
   233  func (e *TSVEntry) Str(val string) *TSVEntry {
   234  	e.buf = append(e.buf, val...)
   235  	e.buf = append(e.buf, e.sep)
   236  	return e
   237  }
   238  
   239  // Bytes adds a bytes as string to the entry.
   240  func (e *TSVEntry) Bytes(val []byte) *TSVEntry {
   241  	e.buf = append(e.buf, val...)
   242  	e.buf = append(e.buf, e.sep)
   243  	return e
   244  }
   245  
   246  // IPAddr adds IPv4 or IPv6 Address to the entry.
   247  func (e *TSVEntry) IPAddr(ip net.IP) *TSVEntry {
   248  	if ip4 := ip.To4(); ip4 != nil {
   249  		e.buf = strconv.AppendInt(e.buf, int64(ip4[0]), 10)
   250  		e.buf = append(e.buf, '.')
   251  		e.buf = strconv.AppendInt(e.buf, int64(ip4[1]), 10)
   252  		e.buf = append(e.buf, '.')
   253  		e.buf = strconv.AppendInt(e.buf, int64(ip4[2]), 10)
   254  		e.buf = append(e.buf, '.')
   255  		e.buf = strconv.AppendInt(e.buf, int64(ip4[3]), 10)
   256  	} else {
   257  		e.buf = append(e.buf, ip.String()...)
   258  	}
   259  	e.buf = append(e.buf, e.sep)
   260  	return e
   261  }
   262  
   263  // NetIPAddr adds IPv4 or IPv6 Address to the entry.
   264  func (e *TSVEntry) NetIPAddr(ip netip.Addr) *TSVEntry {
   265  	e.buf = ip.AppendTo(e.buf)
   266  	e.buf = append(e.buf, e.sep)
   267  	return e
   268  }
   269  
   270  // NetIPAddrPort adds IPv4 or IPv6 with Port Address to the entry.
   271  func (e *TSVEntry) NetIPAddrPort(ipPort netip.AddrPort) *TSVEntry {
   272  	e.buf = ipPort.AppendTo(e.buf)
   273  	e.buf = append(e.buf, e.sep)
   274  	return e
   275  }
   276  
   277  // NetIPPrefix adds IPv4 or IPv6 Prefix (address and mask) to the entry.
   278  func (e *TSVEntry) NetIPPrefix(pfx netip.Prefix) *TSVEntry {
   279  	e.buf = pfx.AppendTo(e.buf)
   280  	e.buf = append(e.buf, e.sep)
   281  	return e
   282  }
   283  
   284  // Msg sends the entry.
   285  func (e *TSVEntry) Msg() {
   286  	if len(e.buf) != 0 {
   287  		e.buf[len(e.buf)-1] = '\n'
   288  	}
   289  	_, _ = e.w.Write(e.buf)
   290  	if cap(e.buf) <= bbcap {
   291  		tepool.Put(e)
   292  	}
   293  }