github.com/phuslu/log@v1.0.100/tsv.go (about)

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