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 }