zapfilter

package module
v1.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 12, 2022 License: Apache-2.0, MIT Imports: 6 Imported by: 3

README

zapfilter

⚡💊 advanced filtering for uber's zap logger

go.dev reference License GitHub release Made by Manfred Touron

Go Release PR GolangCI codecov Go Report Card CodeFactor

Usage

import "moul.io/zapfilter"

func ExampleParseRules() {
	core := zap.NewExample().Core()
	// *=myns             => any level, myns namespace
    // info,warn:myns.*   => info or warn level, any namespace matching myns.*
	// error=*            => everything with error level
	logger := zap.New(zapfilter.NewFilteringCore(core, zapfilter.MustParseRules("*:myns info,warn:myns.* error:*")))
	defer logger.Sync()

	logger.Debug("top debug")                                 // no match
	logger.Named("myns").Debug("myns debug")                  // matches *:myns
	logger.Named("bar").Debug("bar debug")                    // no match
	logger.Named("myns").Named("foo").Debug("myns.foo debug") // no match

	logger.Info("top info")                                 // no match
	logger.Named("myns").Info("myns info")                  // matches *:myns
	logger.Named("bar").Info("bar info")                    // no match
	logger.Named("myns").Named("foo").Info("myns.foo info") // matches info,warn:myns.*

	logger.Warn("top warn")                                 // no match
	logger.Named("myns").Warn("myns warn")                  // matches *:myns
	logger.Named("bar").Warn("bar warn")                    // no match
	logger.Named("myns").Named("foo").Warn("myns.foo warn") // matches info,warn:myns.*

	logger.Error("top error")                                 // matches error:*
	logger.Named("myns").Error("myns error")                  // matches *:myns and error:*
	logger.Named("bar").Error("bar error")                    // matches error:*
	logger.Named("myns").Named("foo").Error("myns.foo error") // matches error:*

	// Output:
	// {"level":"debug","logger":"myns","msg":"myns debug"}
	// {"level":"info","logger":"myns","msg":"myns info"}
	// {"level":"info","logger":"myns.foo","msg":"myns.foo info"}
	// {"level":"warn","logger":"myns","msg":"myns warn"}
	// {"level":"warn","logger":"myns.foo","msg":"myns.foo warn"}
	// {"level":"error","msg":"top error"}
	// {"level":"error","logger":"myns","msg":"myns error"}
	// {"level":"error","logger":"bar","msg":"bar error"}
	// {"level":"error","logger":"myns.foo","msg":"myns.foo error"}
}
FUNCTIONS

func CheckAnyLevel(logger *zap.Logger) bool
    CheckAnyLevel determines whether at least one log level isn't filtered-out
    by the logger.

func CheckLevel(logger *zap.Logger, level zapcore.Level) bool
    CheckLevel determines whether a specific log level would produce log or not.

func NewFilteringCore(next zapcore.Core, filter FilterFunc) zapcore.Core
    NewFilteringCore returns a core middleware that uses the given filter
    function to determine whether to actually call Write on the next core in the
    chain.


TYPES

type FilterFunc func(zapcore.Entry, []zapcore.Field) bool
    FilterFunc is used to check whether to filter the given entry and filters
    out.

func All(filters ...FilterFunc) FilterFunc
    All checks if all filters return true.

func Any(filters ...FilterFunc) FilterFunc
    Any checks if any filter returns true.

func ByLevels(pattern string) (FilterFunc, error)
    ByLevels creates a FilterFunc based on a pattern.

    Level Patterns

        | Pattern | Debug | Info | Warn | Error | DPanic | Panic | Fatal |
        | ------- | ----- | ---- | ---- | ----- | ------ | ----- | ----- |
        | <empty> | X     | X    | X    | X     | X      | X     | X     |
        | *       | X     | X    | X    | X     | x      | X     | X     |
        | debug   | X     |      |      |       |        |       |       |
        | info    |       | X    |      |       |        |       |       |
        | warn    |       |      | X    |       |        |       |       |
        | error   |       |      |      | X     |        |       |       |
        | dpanic  |       |      |      |       | X      |       |       |
        | panic   |       |      |      |       |        | X     |       |
        | fatal   |       |      |      |       |        |       | X     |
        | debug+  | X     | X    | x    | X     | X      | X     | X     |
        | info+   |       | X    | X    | X     | X      | X     | X     |
        | warn+   |       |      | X    | X     | X      | X     | X     |
        | error+  |       |      |      | X     | X      | X     | X     |
        | dpanic+ |       |      |      |       | X      | X     | X     |
        | panic+  |       |      |      |       |        | X     | X     |
        | fatal+  |       |      |      |       |        |       | X     |

func ByNamespaces(input string) FilterFunc
    ByNamespaces takes a list of patterns to filter out logs based on their
    namespaces. Patterns are checked using path.Match.

func ExactLevel(level zapcore.Level) FilterFunc
    ExactLevel filters out entries with an invalid level.

func MinimumLevel(level zapcore.Level) FilterFunc
    MinimumLevel filters out entries with a too low level.

func MustParseRules(pattern string) FilterFunc
    MustParseRules calls ParseRules and panics if initialization failed.

func ParseRules(pattern string) (FilterFunc, error)
    ParseRules takes a CLI-friendly set of rules to construct a filter.

    Syntax

        pattern: RULE [RULE...]
        RULE: one of:
         - LEVELS:NAMESPACES
         - NAMESPACES
        LEVELS: LEVEL,[,LEVEL]
        LEVEL: see `Level Patterns`
        NAMESPACES: NAMESPACE[,NAMESPACE]
        NAMESPACE: one of:
         - namespace     // should be exactly this namespace
         - *mat*ch*      // should match
         - -NAMESPACE    // should not match

    Examples

        *                            everything
        *:*                          everything
        info:*                       level info;  any namespace
        info+:*                      levels info, warn, error, dpanic, panic, and fatal; any namespace
        info,warn:*                  levels info, warn; any namespace
        ns1                          any level; namespace 'ns1'
        *:ns1                        any level; namespace 'ns1'
        ns1*                         any level; namespaces matching 'ns1*'
        *:ns1*                       any level; namespaces matching 'ns1*'
        *:ns1,ns2                    any level; namespaces 'ns1' and 'ns2'
        *:ns*,-ns3*                  any level; namespaces matching 'ns*' but not matching 'ns3*'
        info:ns1                     level info; namespace 'ns1'
        info,warn:ns1,ns2            levels info and warn; namespaces 'ns1' and 'ns2'
        info:ns1 warn:n2             level info + namespace 'ns1' OR level warn and namespace 'ns2'
        info,warn:myns* error+:*     levels info or warn and namespaces matching 'myns*' OR levels error, dpanic, panic or fatal for any namespace

func Reverse(filter FilterFunc) FilterFunc
    Reverse checks is the passed filter returns false.

More examples on https://pkg.golang.ir/moul.io/zapfilter

Install

Using go
$ go get -u moul.io/zapfilter
Releases

See https://github.com/moul/zapfilter/releases

Contribute

I really welcome contributions. Your input is the most precious material. I'm well aware of that and I thank you in advance. Everyone is encouraged to look at what they can do on their own scale; no effort is too small.

Everything on contribution is sum up here: CONTRIBUTING.md

Contributors ✨

All Contributors

Thanks goes to these wonderful people (emoji key):


Manfred Touron

🚧 📖 ⚠️ 💻

moul-bot

🚧

This project follows the all-contributors specification. Contributions of any kind welcome!

Stargazers over time

Stargazers over time

License

© 2020 Manfred Touron

Licensed under the Apache License, Version 2.0 (LICENSE-APACHE) or the MIT license (LICENSE-MIT), at your option. See the COPYRIGHT file for more details.

SPDX-License-Identifier: (Apache-2.0 OR MIT)

Documentation

Overview

message from the author:

+--------------------------------------------------------------+
| * * * ░░░░░░░░░░░░░░░░░░░░  Hello  ░░░░░░░░░░░░░░░░░░░░░░░░░░|
+--------------------------------------------------------------+
|                                                              |
|     ++              ______________________________________   |
|     ++++           /                                      \  |
|      ++++          |                                      |  |
|    ++++++++++      |   Feel free to contribute to this    |  |
|   +++       |      |       project or contact me on       |  |
|   ++         |     |    manfred.life if you like this     |  |
|   +  -==   ==|     |               project!               |  |
|  (   <*>   <*>     |                                      |  |
|   |          |    /|                  :)                  |  |
|   |         _)   / |                                      |  |
|   |      +++    /  \______________________________________/  |
|    \      =+   /                                             |
|     \      +                                                 |
|     |\++++++                                                 |
|     |  ++++      ||//                                        |
|  ___|   |___    _||/__                                     __|
| /    ---    \   \|  |||                   __ _  ___  __ __/ /|
|/  |       |  \    \ /                    /  ' \/ _ \/ // / / |
||  |       |  |    | |                   /_/_/_/\___/\_,_/_/  |
+--------------------------------------------------------------+
Example (Check)
package main

import (
	"fmt"

	"go.uber.org/zap"
	"moul.io/zapfilter"
)

func main() {
	c := zap.NewExample().Core()
	logger := zap.New(zapfilter.NewFilteringCore(c, zapfilter.MustParseRules("debug:* info:demo*")))

	if ce := logger.Check(zap.DebugLevel, "AAA"); ce != nil {
		// here you can make expensive computing
		fmt.Println("BBB")
		ce.Write()
	}
	if ce := logger.Check(zap.InfoLevel, "CCC"); ce != nil {
		// here you can make expensive computing
		fmt.Println("DDD")
		ce.Write()
	}
	if ce := logger.Named("demo").Check(zap.InfoLevel, "EEE"); ce != nil {
		// here you can make expensive computing
		fmt.Println("FFF")
		ce.Write()
	}
	if ce := logger.Check(zap.WarnLevel, "GGG"); ce != nil {
		// here you can make expensive computing
		fmt.Println("HHH")
		ce.Write()
	}
}
Output:

BBB
{"level":"debug","msg":"AAA"}
FFF
{"level":"info","logger":"demo","msg":"EEE"}
Example (With)
package main

import (
	"go.uber.org/zap"
	"moul.io/zapfilter"
)

func main() {
	core := zap.NewExample().Core()
	logger := zap.New(zapfilter.NewFilteringCore(core, zapfilter.ByNamespaces("demo1.*,demo3.*")))
	defer logger.Sync()

	logger.With(zap.String("lorem", "ipsum")).Debug("hello city!")
	logger.With(zap.String("lorem", "ipsum")).Named("demo1.frontend").Debug("hello region!")
	logger.With(zap.String("lorem", "ipsum")).Named("demo2.frontend").Debug("hello planet!")
	logger.With(zap.String("lorem", "ipsum")).Named("demo3.frontend").Debug("hello solar system!")

}
Output:

{"level":"debug","logger":"demo1.frontend","msg":"hello region!","lorem":"ipsum"}
{"level":"debug","logger":"demo3.frontend","msg":"hello solar system!","lorem":"ipsum"}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckAnyLevel

func CheckAnyLevel(logger *zap.Logger) bool

CheckAnyLevel determines whether at least one log level isn't filtered-out by the logger.

Example
package main

import (
	"fmt"

	"go.uber.org/zap"
	"moul.io/zapfilter"
)

func main() {
	c := zap.NewExample().Core()
	logger := zap.New(zapfilter.NewFilteringCore(c, zapfilter.MustParseRules("debug:*.* info:demo*")))

	fmt.Println(zapfilter.CheckAnyLevel(logger))
	fmt.Println(zapfilter.CheckAnyLevel(logger.Named("demo")))
	fmt.Println(zapfilter.CheckAnyLevel(logger.Named("blahdemo")))
	fmt.Println(zapfilter.CheckAnyLevel(logger.Named("demoblah")))
	fmt.Println(zapfilter.CheckAnyLevel(logger.Named("blah")))
	fmt.Println(zapfilter.CheckAnyLevel(logger.Named("blah.blah")))
}
Output:

false
true
false
true
false
true

func CheckLevel added in v1.7.0

func CheckLevel(logger *zap.Logger, level zapcore.Level) bool

CheckLevel determines whether a specific log level would produce log or not.

Example
package main

import (
	"fmt"

	"go.uber.org/zap"
	"moul.io/zapfilter"
)

func main() {
	c := zap.NewExample().Core()
	logger := zap.New(zapfilter.NewFilteringCore(c, zapfilter.MustParseRules("debug:*.* info:demo*")))

	fmt.Println(zapfilter.CheckLevel(logger, zap.DebugLevel))
	fmt.Println(zapfilter.CheckLevel(logger.Named("demo"), zap.DebugLevel))
	fmt.Println(zapfilter.CheckLevel(logger.Named("blahdemo"), zap.DebugLevel))
	fmt.Println(zapfilter.CheckLevel(logger.Named("demoblah"), zap.DebugLevel))
	fmt.Println(zapfilter.CheckLevel(logger.Named("blah"), zap.DebugLevel))
	fmt.Println(zapfilter.CheckLevel(logger.Named("blah.blah"), zap.DebugLevel))
	fmt.Println(zapfilter.CheckLevel(logger, zap.InfoLevel))
	fmt.Println(zapfilter.CheckLevel(logger.Named("demo"), zap.InfoLevel))
	fmt.Println(zapfilter.CheckLevel(logger.Named("blahdemo"), zap.InfoLevel))
	fmt.Println(zapfilter.CheckLevel(logger.Named("demoblah"), zap.InfoLevel))
	fmt.Println(zapfilter.CheckLevel(logger.Named("blah"), zap.InfoLevel))
	fmt.Println(zapfilter.CheckLevel(logger.Named("blah.blah"), zap.InfoLevel))
}
Output:

false
false
false
false
false
true
false
true
false
true
false
false

func NewFilteringCore

func NewFilteringCore(next zapcore.Core, filter FilterFunc) zapcore.Core

NewFilteringCore returns a core middleware that uses the given filter function to determine whether to actually call Write on the next core in the chain.

Example (Newlogger)
package main

import (
	"go.uber.org/zap"
	"moul.io/zapfilter"
)

func main() {
	c := zap.NewExample().Core()

	logger := zap.New(zapfilter.NewFilteringCore(c, zapfilter.MustParseRules("demo*")))
	defer logger.Sync()

	logger.Debug("hello world!")
	logger.Named("demo").Debug("hello earth!")
	logger.Named("other").Debug("hello universe!")

}
Output:

{"level":"debug","logger":"demo","msg":"hello earth!"}
Example (Wrap)
package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"moul.io/zapfilter"
)

func main() {
	filtered := zap.WrapCore(func(c zapcore.Core) zapcore.Core {
		return zapfilter.NewFilteringCore(c, zapfilter.MustParseRules("demo*"))
	})

	logger := zap.NewExample()
	defer logger.Sync()

	logger.WithOptions(filtered).Debug("hello world!")
	logger.WithOptions(filtered).Named("demo").Debug("hello earth!")
	logger.WithOptions(filtered).Named("other").Debug("hello universe!")

}
Output:

{"level":"debug","logger":"demo","msg":"hello earth!"}

Types

type FilterFunc

type FilterFunc func(zapcore.Entry, []zapcore.Field) bool

FilterFunc is used to check whether to filter the given entry and filters out.

Example (Custom)
package main

import (
	"math/rand"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"moul.io/zapfilter"
)

func main() {
	rand.Seed(42)

	core := zap.NewExample().Core()
	filterFunc := func(entry zapcore.Entry, fields []zapcore.Field) bool {
		return rand.Intn(2) == 1
	}
	logger := zap.New(zapfilter.NewFilteringCore(core, filterFunc))
	defer logger.Sync()

	logger.Debug("hello city!")
	logger.Debug("hello region!")
	logger.Debug("hello planet!")
	logger.Debug("hello solar system!")
	logger.Debug("hello universe!")
	logger.Debug("hello multiverse!")

}
Output:

{"level":"debug","msg":"hello city!"}
{"level":"debug","msg":"hello solar system!"}

func All

func All(filters ...FilterFunc) FilterFunc

All checks if all filters return true.

func Any

func Any(filters ...FilterFunc) FilterFunc

Any checks if any filter returns true.

func ByLevels added in v1.6.1

func ByLevels(pattern string) (FilterFunc, error)

ByLevels creates a FilterFunc based on a pattern.

Level Patterns

| Pattern | Debug | Info | Warn | Error | DPanic | Panic | Fatal |
| ------- | ----- | ---- | ---- | ----- | ------ | ----- | ----- |
| <empty> | X     | X    | X    | X     | X      | X     | X     |
| *       | X     | X    | X    | X     | x      | X     | X     |
| debug   | X     |      |      |       |        |       |       |
| info    |       | X    |      |       |        |       |       |
| warn    |       |      | X    |       |        |       |       |
| error   |       |      |      | X     |        |       |       |
| dpanic  |       |      |      |       | X      |       |       |
| panic   |       |      |      |       |        | X     |       |
| fatal   |       |      |      |       |        |       | X     |
| debug+  | X     | X    | x    | X     | X      | X     | X     |
| info+   |       | X    | X    | X     | X      | X     | X     |
| warn+   |       |      | X    | X     | X      | X     | X     |
| error+  |       |      |      | X     | X      | X     | X     |
| dpanic+ |       |      |      |       | X      | X     | X     |
| panic+  |       |      |      |       |        | X     | X     |
| fatal+  |       |      |      |       |        |       | X     |

func ByNamespaces

func ByNamespaces(input string) FilterFunc

ByNamespaces takes a list of patterns to filter out logs based on their namespaces. Patterns are checked using path.Match.

Example
package main

import (
	"go.uber.org/zap"
	"moul.io/zapfilter"
)

func main() {
	core := zap.NewExample().Core()
	logger := zap.New(zapfilter.NewFilteringCore(core, zapfilter.ByNamespaces("demo1.*,demo3.*")))
	defer logger.Sync()

	logger.Debug("hello city!")
	logger.Named("demo1.frontend").Debug("hello region!")
	logger.Named("demo2.frontend").Debug("hello planet!")
	logger.Named("demo3.frontend").Debug("hello solar system!")

}
Output:

{"level":"debug","logger":"demo1.frontend","msg":"hello region!"}
{"level":"debug","logger":"demo3.frontend","msg":"hello solar system!"}

func ExactLevel

func ExactLevel(level zapcore.Level) FilterFunc

ExactLevel filters out entries with an invalid level.

func MinimumLevel

func MinimumLevel(level zapcore.Level) FilterFunc

MinimumLevel filters out entries with a too low level.

func MustParseRules

func MustParseRules(pattern string) FilterFunc

MustParseRules calls ParseRules and panics if initialization failed.

func ParseRules

func ParseRules(pattern string) (FilterFunc, error)

ParseRules takes a CLI-friendly set of rules to construct a filter.

Syntax

pattern: RULE [RULE...]
RULE: one of:
 - LEVELS:NAMESPACES
 - NAMESPACES
LEVELS: LEVEL,[,LEVEL]
LEVEL: see `Level Patterns`
NAMESPACES: NAMESPACE[,NAMESPACE]
NAMESPACE: one of:
 - namespace     // should be exactly this namespace
 - *mat*ch*      // should match
 - -NAMESPACE    // should not match

Examples

  • everything *:* everything info:* level info; any namespace info+:* levels info, warn, error, dpanic, panic, and fatal; any namespace info,warn:* levels info, warn; any namespace ns1 any level; namespace 'ns1' *:ns1 any level; namespace 'ns1' ns1* any level; namespaces matching 'ns1*' *:ns1* any level; namespaces matching 'ns1*' *:ns1,ns2 any level; namespaces 'ns1' and 'ns2' *:ns*,-ns3* any level; namespaces matching 'ns*' but not matching 'ns3*' info:ns1 level info; namespace 'ns1' info,warn:ns1,ns2 levels info and warn; namespaces 'ns1' and 'ns2' info:ns1 warn:n2 level info + namespace 'ns1' OR level warn and namespace 'ns2' info,warn:myns* error+:* levels info or warn and namespaces matching 'myns*' OR levels error, dpanic, panic or fatal for any namespace
Example
package main

import (
	"go.uber.org/zap"
	"moul.io/zapfilter"
)

func main() {
	core := zap.NewExample().Core()
	// *=myns             => any level, myns namespace
	// info,warn:myns.*   => info or warn level, any namespace matching myns.*
	// error=*            => everything with error level
	logger := zap.New(zapfilter.NewFilteringCore(core, zapfilter.MustParseRules("*:myns info,warn:myns.* error:*")))
	defer logger.Sync()

	logger.Debug("top debug")                                 // no match
	logger.Named("myns").Debug("myns debug")                  // matches *:myns
	logger.Named("bar").Debug("bar debug")                    // no match
	logger.Named("myns").Named("foo").Debug("myns.foo debug") // no match

	logger.Info("top info")                                 // no match
	logger.Named("myns").Info("myns info")                  // matches *:myns
	logger.Named("bar").Info("bar info")                    // no match
	logger.Named("myns").Named("foo").Info("myns.foo info") // matches info,warn:myns.*

	logger.Warn("top warn")                                 // no match
	logger.Named("myns").Warn("myns warn")                  // matches *:myns
	logger.Named("bar").Warn("bar warn")                    // no match
	logger.Named("myns").Named("foo").Warn("myns.foo warn") // matches info,warn:myns.*

	logger.Error("top error")                                 // matches error:*
	logger.Named("myns").Error("myns error")                  // matches *:myns and error:*
	logger.Named("bar").Error("bar error")                    // matches error:*
	logger.Named("myns").Named("foo").Error("myns.foo error") // matches error:*

}
Output:

{"level":"debug","logger":"myns","msg":"myns debug"}
{"level":"info","logger":"myns","msg":"myns info"}
{"level":"info","logger":"myns.foo","msg":"myns.foo info"}
{"level":"warn","logger":"myns","msg":"myns warn"}
{"level":"warn","logger":"myns.foo","msg":"myns.foo warn"}
{"level":"error","msg":"top error"}
{"level":"error","logger":"myns","msg":"myns error"}
{"level":"error","logger":"bar","msg":"bar error"}
{"level":"error","logger":"myns.foo","msg":"myns.foo error"}

func Reverse

func Reverse(filter FilterFunc) FilterFunc

Reverse checks is the passed filter returns false.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL