github.com/nikandfor/tlog@v0.21.5-0.20231108111739-3ef89426a96d/README.md (about)

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