tlog.app/go/tlog@v0.23.1/README.md (about) 1 [![Documentation](https://pkg.go.dev/badge/tlog.app/go/tlog)](https://pkg.go.dev/tlog.app/go/tlog?tab=doc) 2 [![Go workflow](https://github.com/tlog-dev/tlog/actions/workflows/go.yml/badge.svg)](https://github.com/tlog-dev/tlog/actions/workflows/go.yml) 3 [![CircleCI](https://circleci.com/gh/tlog-dev/tlog.svg?style=svg)](https://circleci.com/gh/tlog-dev/tlog) 4 [![codecov](https://codecov.io/gh/tlog-dev/tlog/tags/latest/graph/badge.svg)](https://codecov.io/gh/tlog-dev/tlog) 5 [![Go Report Card](https://goreportcard.com/badge/tlog.app/go/tlog)](https://goreportcard.com/report/tlog.app/go/tlog) 6 ![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/tlog-dev/tlog?sort=semver) 7 8 # tlog 9 10 At least it is a logger, but it is much more than that. 11 It is an observability events system. 12 Event is a log or tracing message, tracing span start or finish, metric value, or anything you need. 13 Tons of work has been done to make it effective yet comfortable to use. 14 The events are encoded in a machine-readable format to be processed in any way, instant or later. 15 Events could be printed as logs, combined to build distributed traces, filtered and sent to an alerting service, processed and analyzed, and more. 16 17 tlog is a new way of instrumentation. Log once use smart. 18 19 Explore [examples](examples) and [extensions](ext). 20 21 # Status 22 23 The logging API is pretty solid. Now I'm working mostly on backend parts, web interface, integrations. 24 25 # Quick Start 26 27 ## Logger 28 29 ```go 30 tlog.Printf("just like log.Printf") 31 32 tlog.Printw("but structured is", "much", "better") 33 34 type Req struct { 35 Start time.Time 36 Path string 37 } 38 39 tlog.Printw("any value type is", "supported", &Req{Start: time.Now(), Path: "/resource/path"}) 40 41 l := tlog.New(ioWriter) 42 l.Printw("yet another logger, seriously?") 43 ``` 44 45 ## Debug Topics Instead of Log Levels 46 47 No need to choose between tons of unrelated Debug logs and scant Info logs. 48 Each event can be filtered precisely and filter can be changed at runtime. 49 50 ```go 51 tlog.SetVerbosity("rawdb,dump_request") 52 53 tlog.V("rawdb").Printw("make db query", "query", query) // V is inspired by glog.V 54 55 if tlog.If("dump_request") { 56 // some heavy calculations could also be here 57 tlog.Printw("full request data", "request", request) 58 } 59 60 if tlog.If("full_token") { 61 tlog.Printw("db token", "token", token) 62 } else { 63 tlog.Printw("db token", "token", token.ID) 64 } 65 ``` 66 67 Filtering is very flexible. 68 You can select topics, functions, types, files, packages, topics in locations. 69 You can select all in the file and then unselect some functions, etc. 70 71 ## Traces 72 73 Traces are vital if you have simultaneous requests or distributed request propagation. 74 So they integrated into the logger to have the best experience. 75 76 ```go 77 func ServeRequest(req *Request) { 78 span := tlog.Start("request_root", "client", req.RemoteAddr, "path", req.URL.Path) 79 defer span.Finish() 80 81 ctx := tlog.ContextWithSpan(req.Context(), span) 82 83 doc, err := loadFromDB(ctx, req.URL.Path) 84 // if err ... 85 86 _ = doc 87 } 88 89 func loadFromDB(ctx context.Context, doc string) (err error) { 90 parent := tlog.SpanFromContext(ctx) 91 span := parent.V("dbops").Spawn("load_from_db", "doc", doc) 92 defer func() { 93 span.Finish("err", err) // record result error 94 }() 95 96 span.Printw("prepare query") 97 // ... 98 99 if dirtyPages > tooMuch { 100 // record event to the local span or to the parent if the local was not selected 101 span.Or(parent).Printw("too much of dirty pages", "durty_pages", dirtyPages, 102 tlog.KeyLogLevel, tlog.Warn) 103 } 104 } 105 ``` 106 107 Trace events are the same to log events, except they have IDs. 108 You do not need to add the same data to trace attributes and write them to logs. It's the same! 109 110 ## Data Format 111 112 Events are just key-value associative arrays. All keys are optional, any can be added. 113 Some keys have special meaning, like event timestamp or log level. 114 But it's only a convention; representational parts primarily use it: console pretty text formatter moves time to the first column, for example. 115 116 The default format is a machine readable CBOR-like binary format. And the logger backend is just io.Writer. 117 Text, JSON, Logfmt converters are provided. Any other can be implemented. 118 119 There is also a special compression format: as fast and efficient as snappy 120 yet safe in a sense that each event (or batch write) emits single Write to the file (io.Writer actually). 121 122 # Performance 123 124 Performance was in mind from the very beginning. The idea is to emit as many events as you want and not to pay for that by performance. 125 In a typical efficient application CPU profile, the logger takes only 1-3% of CPU usage with no events economy. 126 Almost all allocations were eliminated. That means less work is done, no garbage collector pressure, and lower memory usage.