GithubHelp home page GithubHelp logo

limlog's Introduction

limlog

Golang logger with rate limiting

Overview

Logging often gets in that uncomfortable place where you spam too much, or omit too much, and it's hard to always get it just right -- where "just right" means enough logging to tell you what's going on, and not so much that you're drowning in log lines.

Enter rate limiting and limlog. This package uses simple token bucket rate limiting -- usually the same algorithm generating 429 on your requests -- and applies that to log lines. It's simple to use, and works out of the box with the standard log package, the logrus package, and zap.

Install

Just run

go get -u github.com/jar-o/limlog

to install.

Get a feel for it

You can run the included examples pretty easily, e.g.

go run examples/log/main.go

Details

limlog is a simple and lightweight level logger at its core. There are several examples in this repo that you can refer to. However, a quick example of using the standard log package would look a little like

package main

import (
	"log"
	"time"
	"github.com/jar-o/limlog"
)

func main() {
	l := limlog.NewLimlog()

	// All entirely optional
	log.SetPrefix("HELOWRLD: ")
	log.SetFlags(log.Ldate | log.Lmicroseconds)
	log.SetOutput(os.Stdout)

	// Total of 4 log lines per second, with a burst of 6
	l.SetLimiter("limiter1", 4, 1*time.Second, 6)

	l.Info("You don't have to limit your log lines if you don't want.")

	for i := 0; i <= 10000000; i++ {
		l.DebugL("limiter1", i)
	}
}

(Note, the standard log package doesn't have an actual concept of levels. E.g. calling Debug() above really only prefixes the log line with a DEBUG tag. It doesn't constrain logging based on levels like the other two implementations.)

Loggers that want to integrate into limlog must implement the following interface:

type Logger interface {
	GetLogger() interface{}
	Error(v ...interface{})
	Warn(v ...interface{})
	Info(v ...interface{})
	Debug(v ...interface{})
	Trace(v ...interface{})
	Fatal(v ...interface{})
	Panic(v ...interface{})
}

As you can see limlog provides all the common logging levels. To do a basic logging call (no limiting) you would do something like

l.Error(...)
l.Debug(...)
... etc ...

However, for limiting you first setup a limiter, then use the L version of the log level calls. E.g.

// This limiter allows only one log line per second,
// with a burst of one (i.e. no burst)
l.SetLimiter("mylimiterkey", 1, 1*time.Second, 1)

// In a loop somwhere:
l.InfoL("mylimiterkey", ...)

Note that we're using InfoL() instead of Info().

The rate limiter is designed around keys, which are just strings that should make sense for whatever context in which you find yourself logging. For example, say you have organizations using a service, and at some point they reach the max for their subscription level. However, they are using scripts and so the log line for reaching their subscription level begins to spam your logs.

my-cool-service time="2019-09-23T08:54:15Z" level=warning msg="Org 1679 has reached their subscription limit for item 111" metric=warning

my-cool-service time="2019-09-23T08:54:15Z" level=warning msg="Org 1679 has reached their subscription limit for item 123" metric=warning

... etc ...

Because of the scripts these log lines fill up your logs. However, it's a useful signal, knowing that the org is frequently bumping up against their subscription limits, so omitting them entirely is not helpful either. With limlog you'd setup a key for this and use WarnL():

lkey := fmt.Sprintf("sub%d-reached-limit", orgID)
l.SetLimiter(lkey, 1, 30*time.Second, 1)
l.WarnL(lkey, fmt.Sprintf("Org %d has reached their subscription limit at item %d", orgID, itemID)

Now you'll see a log line for when the customer's subscription is hit, but no more than once every 30 seconds.

Logrus

The logrus package provides more advanced behavior than the standard log package. For starters, it can have logger instances in addition to a single package logger. The advantage of logger instances is that you can have multiple custom loggers within a single process.

To set that up, just call NewLimlogrusInstance().

l := limlog.NewLimlogrusInstance()
inst := l.L.GetLogger().(*logrus.Logger)
// ... Adjust settings on inst ...

See the advanced example for details on how this works.

Zap

The zap package is a full featured level logger, similar to logrus. See the provided example for usage.

limlog's People

Contributors

jar-o avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.