github.com/keakon/golog@v0.0.0-20230330091222-cac71197c18d/README.md (about) 1 # golog 2 [![GoDoc](https://pkg.go.dev/badge/github.com/keakon/golog)](https://pkg.go.dev/github.com/keakon/golog) 3 [![Build Status](https://github.com/keakon/golog/actions/workflows/go.yml/badge.svg)](https://github.com/keakon/golog/actions) 4 [![Go Report Card](https://goreportcard.com/badge/github.com/keakon/golog)](https://goreportcard.com/report/github.com/keakon/golog) 5 [![codecov](https://codecov.io/gh/keakon/golog/branch/master/graph/badge.svg?token=dmE2GC9in2)](https://codecov.io/gh/keakon/golog) 6 7 ## Features 8 9 1. Unstructured 10 2. Leveled 11 3. With caller (file path / name and line number) 12 4. Customizable output format 13 5. Rotating by size, date or hour 14 6. Cross platform, tested on Linux, macOS and Windows 15 7. No 3rd party dependance 16 8. Fast 17 9. Thread safe 18 19 ## Installation 20 21 ``` 22 go get -u github.com/keakon/golog 23 ``` 24 25 ## Examples 26 27 ### Logging to console 28 29 ```go 30 package main 31 32 import ( 33 "github.com/keakon/golog" 34 "github.com/keakon/golog/log" 35 ) 36 37 func main() { 38 l := golog.NewStdoutLogger() 39 defer l.Close() 40 41 l.Infof("hello %d", 1) 42 43 log.SetDefaultLogger(l) 44 test() 45 } 46 47 func test() { 48 log.Infof("hello %d", 2) 49 } 50 ``` 51 52 ### Logging to file 53 54 ```go 55 func main() { 56 w, _ := golog.NewBufferedFileWriter("test.log") 57 l := golog.NewLoggerWithWriter(w) 58 defer l.Close() 59 60 l.Infof("hello world") 61 } 62 ``` 63 64 ### Rotating 65 66 ```go 67 func main() { 68 w, _ := golog.NewTimedRotatingFileWriter("test", golog.RotateByDate, 30) 69 l := golog.NewLoggerWithWriter(w) 70 defer l.Close() 71 72 l.Infof("hello world") 73 } 74 ``` 75 76 ### Formatting 77 78 ```go 79 func main() { 80 w := golog.NewStdoutWriter() 81 82 f := golog.ParseFormat("[%l %D %T %S] %m") 83 h := golog.NewHandler(golog.InfoLevel, f) 84 h.AddWriter(w) 85 86 l := golog.NewLogger(golog.InfoLevel) 87 l.AddHandler(h) 88 defer l.Close() 89 90 l.Infof("hello world") 91 } 92 ``` 93 94 Check [document](https://pkg.go.dev/github.com/keakon/golog#Formatter.Format) for more format directives. 95 96 ### Fast timer 97 98 ```go 99 func main() { 100 golog.StartFastTimer() 101 defer golog.StopFastTimer() 102 103 l := golog.NewStdoutLogger() 104 defer l.Close() 105 106 l.Infof("hello world") 107 } 108 ``` 109 110 The fast timer is about 30% faster than calling time.Time() for each logging record. But it's not thread-safe which may cause some problems (I think those are negligible in most cases): 111 1. The timer updates every 1 second, so the logging time can be at most 1 second behind the real time. 112 2. Each thread will notice the changes of timer in a few milliseconds, so the concurrent logging messages may get different logging time (less than 2% probability). eg: 113 ``` 114 [I 2021-09-13 14:31:25 log_test:206] test 115 [I 2021-09-13 14:31:24 log_test:206] test 116 [I 2021-09-13 14:31:25 log_test:206] test 117 ``` 118 3. When the day changing, the logging date and time might belong to different day. eg: 119 ``` 120 [I 2021-09-12 23:59:59 log_test:206] test 121 [I 2021-09-13 23:59:59 log_test:206] test 122 [I 2021-09-12 00:00:00 log_test:206] test 123 ``` 124 125 ### ConcurrentFileWriter *(experimental)* 126 127 128 ```go 129 func main() { 130 w, _ := golog.NewConcurrentFileWriter("test.log") 131 l := golog.NewLoggerWithWriter(w) 132 defer l.Close() 133 134 l.Infof("hello world") 135 } 136 ``` 137 138 The `ConcurrentFileWriter` is designed for high concurrency applications. 139 It is about 140% faster than `BufferedFileWriter` at 6C12H by reducing the lock overhead, but a little slower at single thread. 140 **Note**: The order of logging records from different cpu cores within each 0.1 second is random. 141 142 ## Benchmarks 143 144 ### Platform 145 146 go1.19.2 darwin/amd64 147 cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz 148 149 ### Result 150 151 | Name | Time/op | Time (x) | Alloc/op | allocs/op | 152 | :--- | :---: | :---: | :---: | :---: | 153 | DiscardLogger | 483ns ± 1% | 1.00 | 0B | 0 | 154 | DiscardLoggerParallel | 89.0ns ± 6% | 1.00 | 0B | 0 | 155 | DiscardLoggerWithoutTimer | 691ns ± 7% | 1.43 | 0B | 0 | 156 | DiscardLoggerWithoutTimerParallel | 129ns ± 5% | 1.45 | 0B | 0 | 157 | NopLog | 1.5ns ± 1% | 0.003 | 0B | 0 | 158 | NopLogParallel | 0.22ns ± 3% | 0.002 | 0B | 0 | 159 | MultiLevels | 2.77µs ± 7% | 5.73 | 0B | 0 | 160 | MultiLevelsParallel | 532ns ± 15% | 5.98 | 0B | 0 | 161 | BufferedFileLogger | 588ns ± 2% | 1.22 | 0B | 0 | 162 | BufferedFileLoggerParallel | 241ns ± 1% | 2.71 | 0B | 0 | 163 | ConcurrentFileLogger | 593ns ± 1% | 1.23 | 0B | 0 | 164 | ConcurrentFileLoggerParallel | 101ns ± 2% | 1.13 | 0B | 0 | 165 | | | | | | 166 | DiscardZerolog | 2.24µs ± 1% | 4.64 | 280B | 3 | 167 | DiscardZerologParallel | 408ns ± 10% | 4.58 | 280B | 3 | 168 | DiscardZap | 2.13µs ± 0% | 4.41 | 272B | 5 | 169 | DiscardZapParallel | 465ns ± 5% | 5.22 | 274B | 5 | 170 171 * DiscardLogger: writes logs to `ioutil.Discard` 172 * DiscardLoggerWithoutTimer: the same as above but without fast timer 173 * NopLog: skips logs with lower level than the logger or handler 174 * MultiLevels: writes 5 levels of logs to 5 levels handlers of a warning level logger 175 * BufferedFileLogger: writes logs to a disk file 176 * ConcurrentFileLogger: writes logs to a disk file with `ConcurrentFileWriter` 177 * DiscardZerolog: writes logs to `ioutil.Discard` with [zerolog](https://github.com/rs/zerolog) 178 * DiscardZap: writes logs to `ioutil.Discard` with [zap](https://github.com/uber-go/zap) using `zap.NewProductionEncoderConfig()` 179 180 All the logs include 4 parts: level, time, caller and message. This is an example output of the benchmarks: 181 182 ``` 183 [I 2018-11-20 17:05:37 log_test:118] test 184 ```