mirror of
https://codeberg.org/cunicu/cunicu.git
synced 2025-09-26 21:01:14 +08:00
Implement log filter expressions to replace verbosity level
Signed-off-by: Steffen Vogel <post@steffenvogel.de>
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stv0g/cunicu/pkg/config"
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -45,7 +46,7 @@ fc2f:9a4d:777f:7a97:8197:4a5d:1d1b:ed79
|
||||
}
|
||||
|
||||
func addresses(_ *cobra.Command, args []string, opts *addressesOptions) {
|
||||
logger := zap.L()
|
||||
logger := log.Global
|
||||
|
||||
keyB64, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
|
@@ -88,8 +88,8 @@ func daemonRun(_ *cobra.Command, args []string, cfg *config.Config) {
|
||||
|
||||
logger.Debug("Loaded configuration:")
|
||||
wr := tty.NewIndenter(&zapio.Writer{
|
||||
Log: logger,
|
||||
Level: zap.DebugLevel,
|
||||
Log: logger.Logger,
|
||||
Level: zap.DebugLevel - 1,
|
||||
}, " ")
|
||||
|
||||
if err := cfg.Marshal(wr); err != nil {
|
||||
|
@@ -6,6 +6,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stv0g/cunicu/pkg/config"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
osx "github.com/stv0g/cunicu/pkg/os"
|
||||
rpcproto "github.com/stv0g/cunicu/pkg/proto/rpc"
|
||||
"go.uber.org/zap"
|
||||
@@ -39,7 +40,7 @@ func init() { //nolint:gochecknoinits
|
||||
type monitorEventHandler struct {
|
||||
opts *monitorOptions
|
||||
mo *protojson.MarshalOptions
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (h *monitorEventHandler) OnEvent(e *rpcproto.Event) {
|
||||
|
@@ -9,11 +9,8 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stv0g/cunicu/pkg/config"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/tty"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -53,14 +50,13 @@ Code & Issues:
|
||||
)
|
||||
|
||||
type options struct {
|
||||
logLevel config.Level
|
||||
verbosityLevel int
|
||||
logFile string
|
||||
colorMode string
|
||||
logFilter string
|
||||
logFile string
|
||||
colorMode string
|
||||
}
|
||||
|
||||
var (
|
||||
logger *zap.Logger //nolint:gochecknoglobals
|
||||
logger *log.Logger //nolint:gochecknoglobals
|
||||
color bool //nolint:gochecknoglobals
|
||||
stdout io.Writer //nolint:gochecknoglobals
|
||||
|
||||
@@ -83,11 +79,7 @@ in which WireGuard kernel support has not landed yet.`,
|
||||
)
|
||||
|
||||
func init() { //nolint:gochecknoinits
|
||||
opts := &options{
|
||||
logLevel: config.Level{
|
||||
Level: zapcore.InfoLevel,
|
||||
},
|
||||
}
|
||||
opts := &options{}
|
||||
|
||||
rootCmd.SetUsageTemplate(usageTemplate)
|
||||
|
||||
@@ -99,8 +91,7 @@ func init() { //nolint:gochecknoinits
|
||||
f.SortFlags = false
|
||||
|
||||
pf := rootCmd.PersistentFlags()
|
||||
pf.IntVarP(&opts.verbosityLevel, "verbose", "v", 0, "verbosity level")
|
||||
pf.VarP(&opts.logLevel, "log-level", "d", "log level (one of: debug, info, warn, error, dpanic, panic, and fatal)")
|
||||
pf.StringVarP(&opts.logFilter, "log-level", "d", "info", "log level filter rule (one of: debug, info, warn, error, dpanic, panic, and fatal)")
|
||||
pf.StringVarP(&opts.logFile, "log-file", "l", "", "path of a file to write logs to")
|
||||
pf.StringVarP(&opts.colorMode, "color", "q", "auto", "Enable colorization of output (one of: auto, always, never)")
|
||||
|
||||
@@ -131,14 +122,16 @@ func onInitialize(opts *options) {
|
||||
|
||||
// Setup logging
|
||||
outputPaths := []string{"stdout"}
|
||||
errOutputPaths := []string{"stderr"}
|
||||
|
||||
if opts.logFile != "" {
|
||||
outputPaths = append(outputPaths, opts.logFile)
|
||||
errOutputPaths = append(errOutputPaths, opts.logFile)
|
||||
}
|
||||
|
||||
logger = log.SetupLogging(opts.logLevel.Level, opts.verbosityLevel, outputPaths, errOutputPaths, color)
|
||||
var err error
|
||||
logger, err = log.SetupLogging(opts.logFilter, outputPaths, color)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stv0g/cunicu/pkg/config"
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
rpcproto "github.com/stv0g/cunicu/pkg/proto/rpc"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
@@ -90,7 +89,7 @@ func status(_ *cobra.Command, args []string, opts *statusOptions) {
|
||||
}
|
||||
|
||||
case config.OutputFormatHuman:
|
||||
if err := sts.Dump(stdout, log.Verbosity.Level()); err != nil {
|
||||
if err := sts.Dump(stdout, logger.Level()); err != nil {
|
||||
logger.Fatal("Failed to write to stdout", zap.Error(err))
|
||||
}
|
||||
|
||||
|
@@ -32,7 +32,7 @@ See: https://wiki.wireshark.org/WireGuard#key-log-format
|
||||
}
|
||||
|
||||
func wgExtractHandshakes(cmd *cobra.Command, args []string) error {
|
||||
logger := zap.L().Named("tracer")
|
||||
logger := log.Global.Named("tracer")
|
||||
|
||||
ht, err := tracer.NewHandshakeTracer()
|
||||
if err != nil {
|
||||
|
2
go.mod
2
go.mod
@@ -29,7 +29,6 @@ require (
|
||||
github.com/pion/zapion v0.0.0-20230529023309-3bb052e9490b
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/vishvananda/netlink v1.2.1-beta.2.0.20221214185949-378a404a26f0
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.10.0
|
||||
@@ -84,6 +83,7 @@ require (
|
||||
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.2 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
|
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/knadh/koanf/v2"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -39,7 +40,7 @@ type Config struct {
|
||||
onInterfaceChanged map[string]*Meta
|
||||
|
||||
flags *pflag.FlagSet
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// ParseArgs creates a new configuration instance and loads all configuration
|
||||
@@ -66,7 +67,6 @@ func New(flags *pflag.FlagSet) *Config {
|
||||
Runtime: koanf.New("."),
|
||||
onInterfaceChanged: map[string]*Meta{},
|
||||
flags: flags,
|
||||
logger: zap.L().Named("config"),
|
||||
}
|
||||
|
||||
// Feature flags
|
||||
@@ -119,7 +119,7 @@ func (c *Config) Init(args []string) error {
|
||||
// We recreate the logger here, as the logger created
|
||||
// in New() was created in init() before the logging system
|
||||
// was initialized.
|
||||
c.logger = zap.L().Named("config")
|
||||
c.logger = log.Global.Named("config")
|
||||
|
||||
// Initialize some defaults configuration settings at runtime
|
||||
if err := InitDefaults(); err != nil {
|
||||
|
@@ -13,8 +13,8 @@ import (
|
||||
|
||||
"github.com/pion/ice/v2"
|
||||
icex "github.com/stv0g/cunicu/pkg/ice"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -102,7 +102,7 @@ var (
|
||||
)
|
||||
|
||||
func InitDefaults() error {
|
||||
logger := zap.L().Named("config")
|
||||
logger := log.Global.Named("config")
|
||||
|
||||
s := &DefaultSettings.DefaultInterfaceSettings
|
||||
|
||||
|
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/knadh/koanf/v2"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/pion/stun"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
@@ -33,11 +34,11 @@ type LookupProvider struct {
|
||||
settings map[string]any
|
||||
|
||||
mu sync.Mutex
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewLookupProvider(domain string) *LookupProvider {
|
||||
logger := zap.L().Named("lookup")
|
||||
logger := log.Global.Named("lookup")
|
||||
|
||||
return &LookupProvider{
|
||||
domain: domain,
|
||||
|
@@ -12,8 +12,8 @@ import (
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/link"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ var errNotSupported = errors.New("not supported on this platform")
|
||||
type WireGuardProvider struct {
|
||||
path string
|
||||
order []string
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewWireGuardProvider() *WireGuardProvider {
|
||||
@@ -34,7 +34,7 @@ func NewWireGuardProvider() *WireGuardProvider {
|
||||
return &WireGuardProvider{
|
||||
path: path,
|
||||
|
||||
logger: zap.L().Named("config.wg"),
|
||||
logger: log.Global.Named("config.wg"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,8 +8,6 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
type BackendURL struct {
|
||||
@@ -104,11 +102,3 @@ func (f *OutputFormat) Set(str string) error {
|
||||
func (f *OutputFormat) Type() string {
|
||||
return "string"
|
||||
}
|
||||
|
||||
type Level struct {
|
||||
zapcore.Level
|
||||
}
|
||||
|
||||
func (l *Level) Type() string {
|
||||
return "string"
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/config"
|
||||
"github.com/stv0g/cunicu/pkg/device"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
osx "github.com/stv0g/cunicu/pkg/os"
|
||||
"github.com/stv0g/cunicu/pkg/signaling"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
@@ -35,7 +36,7 @@ type Daemon struct {
|
||||
stop chan any
|
||||
reexecOnClose bool
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewDaemon(cfg *config.Config) (*Daemon, error) {
|
||||
@@ -50,7 +51,7 @@ func NewDaemon(cfg *config.Config) (*Daemon, error) {
|
||||
Config: cfg,
|
||||
devices: []device.Device{},
|
||||
stop: make(chan any),
|
||||
logger: zap.L().Named("daemon"),
|
||||
logger: log.Global.Named("daemon"),
|
||||
}
|
||||
|
||||
// Create WireGuard netlink socket
|
||||
|
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/link"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
netx "github.com/stv0g/cunicu/pkg/net"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
"go.uber.org/zap"
|
||||
@@ -27,13 +28,13 @@ var Get = daemon.RegisterFeature(New, 10) //nolint:gochecknoglobals
|
||||
type Interface struct {
|
||||
*daemon.Interface
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func New(i *daemon.Interface) (*Interface, error) {
|
||||
a := &Interface{
|
||||
Interface: i,
|
||||
logger: zap.L().Named("autocfg").With(zap.String("intf", i.Name())),
|
||||
logger: log.Global.Named("autocfg").With(zap.String("intf", i.Name())),
|
||||
}
|
||||
|
||||
i.AddModifiedHandler(a)
|
||||
|
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
@@ -23,13 +24,13 @@ var Get = daemon.RegisterFeature(New, 20) //nolint:gochecknoglobals
|
||||
type Interface struct {
|
||||
*daemon.Interface
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func New(i *daemon.Interface) (*Interface, error) {
|
||||
c := &Interface{
|
||||
Interface: i,
|
||||
logger: zap.L().Named("cfgsync").With(zap.String("intf", i.Name())),
|
||||
logger: log.Global.Named("cfgsync").With(zap.String("intf", i.Name())),
|
||||
}
|
||||
|
||||
return c, nil
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/pion/stun"
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
epdiscproto "github.com/stv0g/cunicu/pkg/proto/feature/epdisc"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -39,7 +40,7 @@ type Interface struct {
|
||||
|
||||
Peers map[*daemon.Peer]*Peer
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func New(di *daemon.Interface) (*Interface, error) {
|
||||
@@ -51,7 +52,7 @@ func New(di *daemon.Interface) (*Interface, error) {
|
||||
Interface: di,
|
||||
Peers: map[*daemon.Peer]*Peer{},
|
||||
|
||||
logger: zap.L().Named("epdisc").With(zap.String("intf", di.Name())),
|
||||
logger: log.Global.Named("epdisc").With(zap.String("intf", di.Name())),
|
||||
}
|
||||
|
||||
i.AddPeerHandler(i)
|
||||
|
@@ -50,10 +50,8 @@ func (i *Interface) OnPeerModified(cp *daemon.Peer, _ *wgtypes.Peer, m daemon.Pe
|
||||
}
|
||||
|
||||
func (i *Interface) OnBindOpen(b *wg.Bind, _ uint16) {
|
||||
logger := i.logger.Named("bind_conn")
|
||||
|
||||
for _, muxConn := range i.muxConns {
|
||||
bindConn := wg.NewBindPacketConn(b, muxConn, logger)
|
||||
bindConn := wg.NewBindPacketConn(b, muxConn, i.logger)
|
||||
b.Conns = append(b.Conns, bindConn)
|
||||
}
|
||||
}
|
||||
|
@@ -39,13 +39,8 @@ func (i *Interface) setupUDPMux() error {
|
||||
|
||||
i.muxConns = append(i.muxConns, filteredConn)
|
||||
|
||||
var stunLogger *zap.Logger
|
||||
if i.logger.Core().Enabled(zap.DebugLevel) {
|
||||
stunLogger = i.logger.Named("stun_conn").WithOptions(log.WithVerbose(5))
|
||||
}
|
||||
|
||||
stunConn := filteredConn.AddPacketReadHandlerConn(&netx.STUNPacketHandler{
|
||||
Logger: stunLogger,
|
||||
Logger: i.logger.Named("stun_conn"),
|
||||
})
|
||||
|
||||
return stunConn, nil
|
||||
@@ -95,10 +90,10 @@ func (i *Interface) setupUniversalUDPMux() error {
|
||||
i.muxConns = append(i.muxConns, filteredConn)
|
||||
|
||||
lf := zapion.ZapFactory{
|
||||
BaseLogger: zap.L().Named("ice"),
|
||||
BaseLogger: log.Global.Named("ice").Logger,
|
||||
}
|
||||
|
||||
var stunLogger *zap.Logger
|
||||
var stunLogger *log.Logger
|
||||
if i.logger.Core().Enabled(zap.DebugLevel) {
|
||||
stunLogger = i.logger.Named("stun_conn")
|
||||
}
|
||||
|
@@ -54,7 +54,7 @@ type Peer struct {
|
||||
signalingMessages chan *signaling.Message
|
||||
newConnection chan *ice.Conn
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewPeer(cp *daemon.Peer, e *Interface) (*Peer, error) {
|
||||
@@ -343,7 +343,7 @@ func (p *Peer) createAgent() error {
|
||||
acfg.UDPMux = p.Interface.mux
|
||||
acfg.UDPMuxSrflx = p.Interface.muxSrflx
|
||||
acfg.LoggerFactory = &zapion.ZapFactory{
|
||||
BaseLogger: p.logger.WithOptions(log.WithVerbose(6)),
|
||||
BaseLogger: p.logger.Named("ice").Logger,
|
||||
}
|
||||
|
||||
p.localCredentials = epdiscproto.NewCredentials()
|
||||
|
@@ -11,9 +11,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pion/ice/v2"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
"go.uber.org/zap"
|
||||
wgconn "golang.zx2c4.com/wireguard/conn"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
)
|
||||
|
||||
// Compile-time assertions
|
||||
@@ -27,10 +29,10 @@ type BindProxy struct {
|
||||
|
||||
iceConn *ice.Conn
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewBindProxy(bind *wg.Bind, cp *ice.CandidatePair, conn *ice.Conn, logger *zap.Logger) (*BindProxy, *net.UDPAddr, error) {
|
||||
func NewBindProxy(bind *wg.Bind, cp *ice.CandidatePair, conn *ice.Conn, logger *log.Logger) (*BindProxy, *net.UDPAddr, error) {
|
||||
p := &BindProxy{
|
||||
iceConn: conn,
|
||||
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/pion/ice/v2"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
"go.uber.org/zap"
|
||||
wgdevice "golang.zx2c4.com/wireguard/device"
|
||||
@@ -27,10 +28,10 @@ type KernelConnProxy struct {
|
||||
|
||||
kernelConn *net.UDPConn
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewKernelConnProxy(bind *wg.Bind, cp *ice.CandidatePair, conn *ice.Conn, listenPort int, logger *zap.Logger) (*KernelConnProxy, *net.UDPAddr, error) {
|
||||
func NewKernelConnProxy(bind *wg.Bind, cp *ice.CandidatePair, conn *ice.Conn, listenPort int, logger *log.Logger) (*KernelConnProxy, *net.UDPAddr, error) {
|
||||
bp, _, err := NewBindProxy(bind, cp, conn, logger)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@@ -10,6 +10,8 @@ import (
|
||||
|
||||
"github.com/pion/ice/v2"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -32,10 +34,10 @@ var (
|
||||
type KernelNATProxy struct {
|
||||
rule *NATRule
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewKernelNATProxy(cp *ice.CandidatePair, nat *NAT, listenPort int, logger *zap.Logger) (*KernelNATProxy, *net.UDPAddr, error) {
|
||||
func NewKernelNATProxy(cp *ice.CandidatePair, nat *NAT, listenPort int, logger *log.Logger) (*KernelNATProxy, *net.UDPAddr, error) {
|
||||
var err error
|
||||
|
||||
if !CandidatePairCanBeNATted(cp) {
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/stv0g/cunicu/pkg/config"
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/daemon/feature/epdisc"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
"go.uber.org/zap"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
@@ -23,7 +24,7 @@ import (
|
||||
type ExecHook struct {
|
||||
*config.ExecHookSetting
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (i *Interface) NewExecHook(cfg *config.ExecHookSetting) *ExecHook {
|
||||
|
@@ -6,6 +6,7 @@ package hooks
|
||||
import (
|
||||
"github.com/stv0g/cunicu/pkg/config"
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -21,7 +22,7 @@ type Interface struct {
|
||||
|
||||
hooks []Hook
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func New(i *daemon.Interface) (*Interface, error) {
|
||||
@@ -31,7 +32,7 @@ func New(i *daemon.Interface) (*Interface, error) {
|
||||
|
||||
h := &Interface{
|
||||
Interface: i,
|
||||
logger: zap.L().Named("hooks").With(zap.String("intf", i.Name())),
|
||||
logger: log.Global.Named("hooks").With(zap.String("intf", i.Name())),
|
||||
}
|
||||
|
||||
for _, hks := range i.Settings.Hooks {
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/stv0g/cunicu/pkg/config"
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/daemon/feature/epdisc"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
hooksproto "github.com/stv0g/cunicu/pkg/proto/feature/hooks"
|
||||
rpcproto "github.com/stv0g/cunicu/pkg/proto/rpc"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
@@ -25,7 +26,7 @@ import (
|
||||
type WebHook struct {
|
||||
*config.WebHookSetting
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (i *Interface) NewWebHook(cfg *config.WebHookSetting) *WebHook {
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
slicesx "github.com/stv0g/cunicu/pkg/types/slices"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
@@ -25,11 +26,11 @@ var Get = daemon.RegisterFeature(New, 200) //nolint:gochecknoglobals
|
||||
type Interface struct {
|
||||
*daemon.Interface
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func New(i *daemon.Interface) (*Interface, error) {
|
||||
logger := zap.L().Named("hsync").With(zap.String("intf", i.Name()))
|
||||
logger := log.Global.Named("hsync").With(zap.String("intf", i.Name()))
|
||||
|
||||
if writable, err := isWritable(hostsPath); err != nil || !writable {
|
||||
logger.Warn("Disabling /etc/hosts synchronization as it is not writable")
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/stv0g/cunicu/pkg/buildinfo"
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
proto "github.com/stv0g/cunicu/pkg/proto/core"
|
||||
pdiscproto "github.com/stv0g/cunicu/pkg/proto/feature/pdisc"
|
||||
"github.com/stv0g/cunicu/pkg/signaling"
|
||||
@@ -30,7 +31,7 @@ type Interface struct {
|
||||
filter map[crypto.Key]bool
|
||||
descs map[crypto.Key]*pdiscproto.PeerDescription
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func New(i *daemon.Interface) (*Interface, error) {
|
||||
@@ -42,7 +43,7 @@ func New(i *daemon.Interface) (*Interface, error) {
|
||||
Interface: i,
|
||||
filter: map[crypto.Key]bool{},
|
||||
descs: map[crypto.Key]*pdiscproto.PeerDescription{},
|
||||
logger: zap.L().Named("pdisc").With(zap.String("intf", i.Name())),
|
||||
logger: log.Global.Named("pdisc").With(zap.String("intf", i.Name())),
|
||||
}
|
||||
|
||||
for _, k := range pd.Settings.Whitelist {
|
||||
@@ -188,7 +189,7 @@ func (i *Interface) sendPeerDescription(chg pdiscproto.PeerDescriptionChange, pk
|
||||
return err
|
||||
}
|
||||
|
||||
i.logger.Debug("Send peer description", zap.Any("description", d))
|
||||
i.logger.Debug("Send peer description", zap.Reflect("description", d))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"net/netip"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -22,7 +23,7 @@ type Interface struct {
|
||||
gwMap map[netip.Addr]*daemon.Peer
|
||||
stop chan struct{}
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func New(i *daemon.Interface) (*Interface, error) {
|
||||
@@ -34,7 +35,7 @@ func New(i *daemon.Interface) (*Interface, error) {
|
||||
Interface: i,
|
||||
gwMap: map[netip.Addr]*daemon.Peer{},
|
||||
stop: make(chan struct{}),
|
||||
logger: zap.L().Named("rtsync").With(zap.String("intf", i.Name())),
|
||||
logger: log.Global.Named("rtsync").With(zap.String("intf", i.Name())),
|
||||
}
|
||||
|
||||
i.AddPeerHandler(rs)
|
||||
|
@@ -11,7 +11,6 @@ import (
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/link"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
netx "github.com/stv0g/cunicu/pkg/net"
|
||||
"github.com/vishvananda/netlink"
|
||||
"go.uber.org/zap"
|
||||
@@ -135,22 +134,20 @@ func (i *Interface) watchKernel() error {
|
||||
}
|
||||
|
||||
func (i *Interface) handleRouteUpdate(ru *netlink.RouteUpdate) error {
|
||||
logger := i.logger.WithOptions(log.WithVerbose(10))
|
||||
|
||||
logger.Debug("Received netlink route update", zap.Any("update", ru))
|
||||
i.logger.DebugV(10, "Received netlink route update", zap.Reflect("update", ru))
|
||||
|
||||
if ru.Table != i.Settings.RoutingTable {
|
||||
logger.Debug("Ignore route from another table")
|
||||
i.logger.DebugV(10, "Ignore route from another table")
|
||||
return nil
|
||||
}
|
||||
|
||||
if ru.Protocol == link.RouteProtocol {
|
||||
logger.Debug("Ignoring route which was installed by ourself")
|
||||
i.logger.DebugV(10, "Ignoring route which was installed by ourself")
|
||||
return nil
|
||||
}
|
||||
|
||||
if ru.Gw == nil {
|
||||
logger.Debug("Ignoring route with missing gateway")
|
||||
i.logger.DebugV(10, "Ignoring route with missing gateway")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -161,14 +158,14 @@ func (i *Interface) handleRouteUpdate(ru *netlink.RouteUpdate) error {
|
||||
|
||||
p, ok := i.gwMap[gw]
|
||||
if !ok {
|
||||
logger.Debug("Ignoring unknown gateway", zap.Any("gw", ru.Gw))
|
||||
i.logger.DebugV(10, "Ignoring unknown gateway", zap.Any("gw", ru.Gw))
|
||||
return nil
|
||||
}
|
||||
|
||||
logger = logger.With(zap.String("peer", p.String()))
|
||||
logger := i.logger.With(zap.String("peer", p.String()))
|
||||
|
||||
if ru.LinkIndex != p.Interface.Device.Index() {
|
||||
logger.Debug("Ignoring gateway due to interface mismatch", zap.Any("gw", ru.Gw))
|
||||
logger.DebugV(10, "Ignoring gateway due to interface mismatch", zap.Any("gw", ru.Gw))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -176,7 +173,7 @@ func (i *Interface) handleRouteUpdate(ru *netlink.RouteUpdate) error {
|
||||
aip := aip
|
||||
|
||||
if netx.ContainsNet(&aip, ru.Dst) {
|
||||
logger.Debug("Ignoring route as it is already covered by the current AllowedIPs",
|
||||
logger.DebugV(10, "Ignoring route as it is already covered by the current AllowedIPs",
|
||||
zap.Any("allowed_ip", aip),
|
||||
zap.Any("dst", ru.Dst))
|
||||
return nil
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/stv0g/cunicu/pkg/config"
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/device"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
proto "github.com/stv0g/cunicu/pkg/proto"
|
||||
coreproto "github.com/stv0g/cunicu/pkg/proto/core"
|
||||
slicesx "github.com/stv0g/cunicu/pkg/types/slices"
|
||||
@@ -42,7 +43,7 @@ type Interface struct {
|
||||
|
||||
features map[*Feature]FeatureInterface
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewInterface(wgDev *wgtypes.Device, client *wgctrl.Client) (*Interface, error) {
|
||||
@@ -59,7 +60,7 @@ func NewInterface(wgDev *wgtypes.Device, client *wgctrl.Client) (*Interface, err
|
||||
|
||||
features: map[*Feature]FeatureInterface{},
|
||||
|
||||
logger: zap.L().Named("intf").With(
|
||||
logger: log.Global.Named("intf").With(
|
||||
zap.String("intf", wgDev.Name),
|
||||
),
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
netx "github.com/stv0g/cunicu/pkg/net"
|
||||
proto "github.com/stv0g/cunicu/pkg/proto"
|
||||
coreproto "github.com/stv0g/cunicu/pkg/proto/core"
|
||||
@@ -36,7 +37,7 @@ type Peer struct {
|
||||
state types.AtomicEnum[PeerState]
|
||||
client *wgctrl.Client
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// NewPeer creates a peer and initiates a new ICE agent
|
||||
@@ -52,7 +53,7 @@ func NewPeer(wgp *wgtypes.Peer, i *Interface) (*Peer, error) {
|
||||
|
||||
p.state.Store(PeerStateNew)
|
||||
|
||||
p.logger = zap.L().Named("peer").With(
|
||||
p.logger = log.Global.Named("peer").With(
|
||||
zap.String("intf", i.Name()),
|
||||
zap.String("peer", p.String()),
|
||||
)
|
||||
|
@@ -72,7 +72,7 @@ type Watcher struct {
|
||||
filter InterfaceFilterFunc
|
||||
interval time.Duration
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewWatcher(client *wgctrl.Client, interval time.Duration, filter InterfaceFilterFunc) (*Watcher, error) {
|
||||
@@ -92,7 +92,7 @@ func NewWatcher(client *wgctrl.Client, interval time.Duration, filter InterfaceF
|
||||
stop: make(chan any),
|
||||
stopped: make(chan any),
|
||||
|
||||
logger: zap.L().Named("watcher"),
|
||||
logger: log.Global.Named("watcher"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -122,13 +122,11 @@ func (w *Watcher) Watch() {
|
||||
defer ticker.Stop()
|
||||
}
|
||||
|
||||
logger := w.logger.WithOptions(log.WithVerbose(10))
|
||||
|
||||
out:
|
||||
for {
|
||||
select {
|
||||
case <-w.manualTrigger:
|
||||
logger.Debug("Start interface synchronization")
|
||||
w.logger.DebugV(10, "Start interface synchronization")
|
||||
if err := w.syncInterfaces(); err != nil {
|
||||
w.logger.Error("Synchronization failed", zap.Error(err))
|
||||
}
|
||||
@@ -136,13 +134,13 @@ out:
|
||||
// We still a need periodic sync we can not (yet) monitor WireGuard interfaces
|
||||
// for changes via a netlink socket (patch is pending)
|
||||
case <-ticker.C:
|
||||
logger.Debug("Start periodic interface synchronization")
|
||||
w.logger.DebugV(10, "Start periodic interface synchronization")
|
||||
if err := w.syncInterfaces(); err != nil {
|
||||
w.logger.Error("Synchronization failed", zap.Error(err))
|
||||
}
|
||||
|
||||
case event := <-w.events:
|
||||
logger.Debug("Received interface event", zap.Any("event", event))
|
||||
w.logger.DebugV(10, "Received interface event", zap.Any("event", event))
|
||||
if err := w.syncInterfaces(); err != nil {
|
||||
w.logger.Error("Synchronization failed", zap.Error(err))
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/link"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
"go.uber.org/zap"
|
||||
wgconn "golang.zx2c4.com/wireguard/conn"
|
||||
@@ -23,11 +24,11 @@ type KernelDevice struct {
|
||||
ListenPort int
|
||||
bind *wg.Bind
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewKernelDevice(name string) (*KernelDevice, error) {
|
||||
logger := zap.L().Named("dev").With(
|
||||
logger := log.Global.Named("dev").With(
|
||||
zap.String("dev", name),
|
||||
zap.String("type", "kernel"),
|
||||
)
|
||||
@@ -45,7 +46,7 @@ func NewKernelDevice(name string) (*KernelDevice, error) {
|
||||
}
|
||||
|
||||
func FindKernelDevice(name string) (*KernelDevice, error) {
|
||||
logger := zap.L().Named("dev").With(
|
||||
logger := log.Global.Named("dev").With(
|
||||
zap.String("dev", name),
|
||||
zap.String("type", "kernel"),
|
||||
)
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/link"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
"go.uber.org/zap"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
@@ -32,13 +33,13 @@ type UserDevice struct {
|
||||
|
||||
apiListener net.Listener
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewUserDevice(name string) (*UserDevice, error) {
|
||||
var err error
|
||||
|
||||
logger := zap.L().Named("dev").With(
|
||||
logger := log.Global.Named("dev").With(
|
||||
zap.String("dev", name),
|
||||
zap.String("type", "user"),
|
||||
)
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/pion/ice/v2"
|
||||
"github.com/pion/zapion"
|
||||
"go.uber.org/zap"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
)
|
||||
|
||||
type PacketListener interface{}
|
||||
@@ -38,7 +38,7 @@ func NewMultiUDPMuxWithListen(listen func(ip net.IP) (net.PacketConn, error), in
|
||||
}
|
||||
|
||||
lf := zapion.ZapFactory{
|
||||
BaseLogger: zap.L().Named("ice"),
|
||||
BaseLogger: log.Global.Named("ice").Logger,
|
||||
}
|
||||
|
||||
muxes := make([]ice.UDPMux, 0, len(conns))
|
||||
|
@@ -27,7 +27,7 @@ var _ Link = (*BSDLink)(nil)
|
||||
type BSDLink struct {
|
||||
created bool
|
||||
index int
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func CreateWireGuardLink(name string) (*BSDLink, error) {
|
||||
@@ -47,7 +47,7 @@ func FindLink(name string) (*BSDLink, error) {
|
||||
return &BSDLink{
|
||||
created: false,
|
||||
index: i.Index,
|
||||
logger: zap.L().Named("dev").With(
|
||||
logger: log.Global.Named("dev").With(
|
||||
zap.String("dev", name),
|
||||
zap.String("type", "kernel")),
|
||||
}, nil
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/vishvananda/netlink"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/sys/unix"
|
||||
@@ -31,11 +32,11 @@ const (
|
||||
type LinuxLink struct {
|
||||
link netlink.Link
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func CreateWireGuardLink(name string) (*LinuxLink, error) {
|
||||
logger := zap.L().Named("dev").With(
|
||||
logger := log.Global.Named("dev").With(
|
||||
zap.String("dev", name),
|
||||
zap.String("type", "kernel"),
|
||||
)
|
||||
@@ -56,7 +57,7 @@ func CreateWireGuardLink(name string) (*LinuxLink, error) {
|
||||
}
|
||||
|
||||
func FindLink(name string) (*LinuxLink, error) {
|
||||
logger := zap.L().Named("dev").With(
|
||||
logger := log.Global.Named("dev").With(
|
||||
zap.String("dev", name),
|
||||
zap.String("type", "kernel"),
|
||||
)
|
||||
|
@@ -13,7 +13,7 @@ import (
|
||||
type WindowsLink struct {
|
||||
index int
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (d *WindowsLink) AddAddress(ip net.IPNet) error {
|
||||
|
100
pkg/log/filter_core.go
Normal file
100
pkg/log/filter_core.go
Normal file
@@ -0,0 +1,100 @@
|
||||
// SPDX-FileCopyrightText: 2023 Steffen Vogel <post@steffenvogel.de>
|
||||
// SPDX-FileCopyrightText: 2020 Manfred Touron <https://manfred.life>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package log
|
||||
|
||||
// This filter implements a filtering zap core
|
||||
// Based on: https://github.com/moul/zapfilter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnsupportedKeyword = errors.New("unsupported keyword")
|
||||
ErrBadSyntax = errors.New("bad syntax")
|
||||
)
|
||||
|
||||
// NewFilteredCore returns a core middleware that uses the given filter function to
|
||||
// determine whether to actually call Write on the next core in the chain.
|
||||
func NewFilteredCore(next zapcore.Core, rule *AtomicFilterRule) zapcore.Core {
|
||||
return &filteringCore{next, rule}
|
||||
}
|
||||
|
||||
// CheckAnyLevel determines whether at least one log level isn't filtered-out by the logger.
|
||||
func CheckAnyLevel(logger *zap.Logger) bool {
|
||||
for lvl := LevelMin; lvl <= LevelMax; lvl++ {
|
||||
if lvl >= zapcore.PanicLevel {
|
||||
continue // Panic and fatal cannot be skipped
|
||||
}
|
||||
if logger.Check(lvl, "") != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CheckLevel determines whether a specific log level would produce log or not.
|
||||
func CheckLevel(logger *zap.Logger, level zapcore.Level) bool {
|
||||
return logger.Check(level, "") != nil
|
||||
}
|
||||
|
||||
type filteringCore struct {
|
||||
next zapcore.Core
|
||||
rule *AtomicFilterRule
|
||||
}
|
||||
|
||||
// Check determines whether the supplied zapcore.Entry should be logged.
|
||||
// If the entry should be logged, the filteringCore adds itself to the zapcore.CheckedEntry
|
||||
// and returns the results.
|
||||
func (core *filteringCore) Check(entry zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
|
||||
// FIXME: consider calling downstream core.Check too, but need to document how to
|
||||
// properly set logging level.
|
||||
if r := core.rule.Load(); r != nil && r.Filter(entry, nil) {
|
||||
ce = ce.AddCore(entry, core)
|
||||
}
|
||||
return ce
|
||||
}
|
||||
|
||||
// Write determines whether the supplied zapcore.Entry with provided []zapcore.Field should
|
||||
// be logged, then calls the wrapped zapcore.Write.
|
||||
func (core *filteringCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
|
||||
if r := core.rule.Load(); r != nil && r.Filter(entry, fields) {
|
||||
return core.next.Write(entry, fields)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// With adds structured context to the wrapped zapcore.Core.
|
||||
func (core *filteringCore) With(fields []zapcore.Field) zapcore.Core {
|
||||
return &filteringCore{
|
||||
next: core.next.With(fields),
|
||||
rule: core.rule,
|
||||
}
|
||||
}
|
||||
|
||||
// Enabled asks the wrapped zapcore.Core to decide whether a given logging level is enabled
|
||||
// when logging a message.
|
||||
func (core *filteringCore) Enabled(level zapcore.Level) bool {
|
||||
// FIXME: Maybe it's better to always return true and only rely on the Check() func?
|
||||
// Another way to consider it is to keep the smaller log level configured on
|
||||
// zapfilter.
|
||||
return core.next.Enabled(level)
|
||||
}
|
||||
|
||||
func (core *filteringCore) Level() zapcore.Level {
|
||||
if r := core.rule.Load(); r != nil {
|
||||
return zapcore.Level(r.Level)
|
||||
}
|
||||
return zapcore.InvalidLevel
|
||||
}
|
||||
|
||||
// Sync flushed buffered logs (if any).
|
||||
func (core *filteringCore) Sync() error {
|
||||
return core.next.Sync()
|
||||
}
|
323
pkg/log/filter_rule.go
Normal file
323
pkg/log/filter_rule.go
Normal file
@@ -0,0 +1,323 @@
|
||||
// SPDX-FileCopyrightText: 2023 Steffen Vogel <post@steffenvogel.de>
|
||||
// SPDX-FileCopyrightText: 2020 Manfred Touron <https://manfred.life>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// FilterFunc is used to check whether to filter the given entry and filters out.
|
||||
type FilterFunc func(zapcore.Entry, []zapcore.Field) bool
|
||||
|
||||
type FilterRule struct {
|
||||
Filter FilterFunc
|
||||
Expression string
|
||||
Level Level
|
||||
}
|
||||
|
||||
type AtomicFilterRule struct {
|
||||
atomic.Pointer[FilterRule]
|
||||
}
|
||||
|
||||
func NewFilterRule(ff FilterFunc) *FilterRule {
|
||||
return &FilterRule{
|
||||
Filter: ff,
|
||||
Level: Level(ff.Level()),
|
||||
}
|
||||
}
|
||||
|
||||
func ParseFilterRule(expr string) (*FilterRule, error) {
|
||||
ff, err := ParseRules(expr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &FilterRule{
|
||||
Filter: ff,
|
||||
Level: Level(ff.Level()),
|
||||
Expression: expr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f FilterFunc) Level() zapcore.Level {
|
||||
for lvl := LevelMin; lvl <= LevelMax; lvl++ {
|
||||
if f(zapcore.Entry{
|
||||
Level: lvl,
|
||||
}, nil) {
|
||||
return lvl
|
||||
}
|
||||
}
|
||||
|
||||
return zapcore.InvalidLevel
|
||||
}
|
||||
|
||||
// ByNamespaces takes a list of patterns to filter out logs based on their namespaces.
|
||||
// Patterns are checked using path.Match.
|
||||
func ByNamespaces(input string) FilterFunc { //nolint:gocognit
|
||||
if input == "" {
|
||||
return AlwaysFalseFilter
|
||||
}
|
||||
patterns := strings.Split(input, ",")
|
||||
|
||||
// Edge case optimization (always true)
|
||||
{
|
||||
hasIncludeWildcard := false
|
||||
hasExclude := false
|
||||
for _, pattern := range patterns {
|
||||
if pattern == "" {
|
||||
continue
|
||||
}
|
||||
if pattern == "*" {
|
||||
hasIncludeWildcard = true
|
||||
}
|
||||
if pattern[0] == '-' {
|
||||
hasExclude = true
|
||||
}
|
||||
}
|
||||
if hasIncludeWildcard && !hasExclude {
|
||||
return AlwaysTrueFilter
|
||||
}
|
||||
}
|
||||
|
||||
var mutex sync.Mutex
|
||||
matchMap := map[string]bool{}
|
||||
return func(entry zapcore.Entry, fields []zapcore.Field) bool {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if _, found := matchMap[entry.LoggerName]; !found {
|
||||
matchMap[entry.LoggerName] = false
|
||||
matchInclude := false
|
||||
matchExclude := false
|
||||
for _, pattern := range patterns {
|
||||
switch {
|
||||
case pattern[0] == '-' && !matchExclude:
|
||||
if matched, _ := path.Match(pattern[1:], entry.LoggerName); matched {
|
||||
matchExclude = true
|
||||
}
|
||||
case pattern[0] != '-' && !matchInclude:
|
||||
if matched, _ := path.Match(pattern, entry.LoggerName); matched {
|
||||
matchInclude = true
|
||||
}
|
||||
}
|
||||
}
|
||||
matchMap[entry.LoggerName] = matchInclude && !matchExclude
|
||||
}
|
||||
return matchMap[entry.LoggerName]
|
||||
}
|
||||
}
|
||||
|
||||
// ExactLevel filters out entries with an invalid level.
|
||||
func ExactLevel(level zapcore.Level) FilterFunc {
|
||||
return func(entry zapcore.Entry, fields []zapcore.Field) bool {
|
||||
return entry.Level == level
|
||||
}
|
||||
}
|
||||
|
||||
// MinimumLevel filters out entries with a too low level.
|
||||
func MinimumLevel(level zapcore.Level) FilterFunc {
|
||||
return func(entry zapcore.Entry, fields []zapcore.Field) bool {
|
||||
return entry.Level >= level
|
||||
}
|
||||
}
|
||||
|
||||
// Any checks if any filter returns true.
|
||||
func Any(filters ...FilterFunc) FilterFunc {
|
||||
return func(entry zapcore.Entry, fields []zapcore.Field) bool {
|
||||
for _, filter := range filters {
|
||||
if filter == nil {
|
||||
continue
|
||||
}
|
||||
if filter(entry, fields) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse checks is the passed filter returns false.
|
||||
func Reverse(filter FilterFunc) FilterFunc {
|
||||
return func(entry zapcore.Entry, fields []zapcore.Field) bool {
|
||||
return !filter(entry, fields)
|
||||
}
|
||||
}
|
||||
|
||||
// All checks if all filters return true.
|
||||
func All(filters ...FilterFunc) FilterFunc {
|
||||
return func(entry zapcore.Entry, fields []zapcore.Field) bool {
|
||||
var atLeastOneSuccessful bool
|
||||
for _, filter := range filters {
|
||||
if filter == nil {
|
||||
continue
|
||||
}
|
||||
if !filter(entry, fields) {
|
||||
return false
|
||||
}
|
||||
atLeastOneSuccessful = true
|
||||
}
|
||||
return atLeastOneSuccessful
|
||||
}
|
||||
}
|
||||
|
||||
// ParseRules takes a CLI-friendly set of rules to construct a filter.
|
||||
//
|
||||
// Syntax
|
||||
//
|
||||
// pattern: RULE [RULE...]
|
||||
// RULE: one of:
|
||||
// - LEVELS:NAMESPACES
|
||||
// - LEVELS
|
||||
// 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
|
||||
// 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 ParseRules(expr string) (FilterFunc, error) {
|
||||
var filters []FilterFunc
|
||||
|
||||
// Rules are separated by spaces, tabs or \n
|
||||
for _, rule := range strings.Fields(expr) {
|
||||
// Split rule into parts (separated by ':')
|
||||
rule = strings.TrimSpace(rule)
|
||||
if rule == "" {
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(rule, ":", 2)
|
||||
var left, right string
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
left = parts[0] // If no separator, right matches everything
|
||||
right = "*"
|
||||
case 2:
|
||||
if parts[0] == "" || parts[1] == "" {
|
||||
return nil, ErrBadSyntax
|
||||
}
|
||||
left = parts[0]
|
||||
right = parts[1]
|
||||
default:
|
||||
return nil, ErrBadSyntax
|
||||
}
|
||||
|
||||
levelFilter, err := ByLevels(left)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
namespaceFilter := ByNamespaces(right)
|
||||
|
||||
filters = append(filters, All(levelFilter, namespaceFilter))
|
||||
}
|
||||
|
||||
return Any(filters...), nil
|
||||
}
|
||||
|
||||
// ByLevels creates a FilterFunc based on a pattern.
|
||||
//
|
||||
// Level Patterns
|
||||
//
|
||||
// | Pattern | Debug(X) | Debug | Info | Warn | Error | DPanic | Panic | Fatal |
|
||||
// | ------- | ----- | ----- | ---- | ---- | ----- | ------ | ----- | ----- |
|
||||
// | <empty> | X | X | X | X | X | X | X | X |
|
||||
// | * | X | X | X | X | X | x | X | X |
|
||||
// | =debugX | X | | | | | | | |
|
||||
// | =debug | | X | | | | | | |
|
||||
// | =info | | | X | | | | | |
|
||||
// | =warn | | | | X | | | | |
|
||||
// | =error | | | | | X | | | |
|
||||
// | =dpanic | | | | | | X | | |
|
||||
// | =panic | | | | | | | X | |
|
||||
// | =fatal | | | | | | | | X |
|
||||
// | debug | X | 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 ByLevels(pattern string) (FilterFunc, error) {
|
||||
var enabled uint64
|
||||
for _, part := range strings.Split(pattern, ",") {
|
||||
if part == "" || part == "*" {
|
||||
enabled |= math.MaxUint64
|
||||
} else {
|
||||
op := part[0]
|
||||
switch op {
|
||||
case '=', '<', '>':
|
||||
part = part[1:]
|
||||
default:
|
||||
op = '>'
|
||||
}
|
||||
|
||||
var level Level
|
||||
if err := level.UnmarshalText([]byte(part)); err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrUnsupportedKeyword, part)
|
||||
}
|
||||
|
||||
bit := levelToBit(level)
|
||||
|
||||
switch op {
|
||||
case '=':
|
||||
enabled |= bit
|
||||
case '<':
|
||||
enabled |= bit
|
||||
enabled |= ^(bit - 1)
|
||||
case '>':
|
||||
enabled |= bit
|
||||
enabled |= bit - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return func(e zapcore.Entry, f []zapcore.Field) bool {
|
||||
return levelToBit(Level(e.Level))&enabled != 0
|
||||
}, nil
|
||||
}
|
||||
|
||||
func levelToBit(l Level) uint64 {
|
||||
return 1 << (Level(zapcore.FatalLevel) - l)
|
||||
}
|
||||
|
||||
// MustParseRules calls ParseRules and panics if initialization failed.
|
||||
func MustParseRules(expr string) FilterFunc {
|
||||
filter, err := ParseRules(expr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return filter
|
||||
}
|
||||
|
||||
func AlwaysFalseFilter(_ zapcore.Entry, _ []zapcore.Field) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func AlwaysTrueFilter(_ zapcore.Entry, _ []zapcore.Field) bool {
|
||||
return true
|
||||
}
|
550
pkg/log/filter_test.go
Normal file
550
pkg/log/filter_test.go
Normal file
@@ -0,0 +1,550 @@
|
||||
// SPDX-FileCopyrightText: 2023 Steffen Vogel <post@steffenvogel.de>
|
||||
// SPDX-FileCopyrightText: 2020 Manfred Touron <https://manfred.life>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package log_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/gomega/gcustom"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"go.uber.org/zap/zaptest/observer"
|
||||
)
|
||||
|
||||
var (
|
||||
errMismatchingLogMessage = errors.New("mismatch in log message")
|
||||
errMismatchingLoggerName = errors.New("mismatch in logger name")
|
||||
errMismatchingLogLevel = errors.New("mismatch in log level")
|
||||
errMismatchingField = errors.New("mismatch in context field")
|
||||
)
|
||||
|
||||
func MatchEntry(expectedEntry zapcore.Entry, expectedFields ...zapcore.Field) OmegaMatcher {
|
||||
return gcustom.MakeMatcher(func(actualEntry observer.LoggedEntry) (bool, error) {
|
||||
if expectedEntry.Message != "" && expectedEntry.Message != actualEntry.Message {
|
||||
return false, fmt.Errorf("%w: %s != %s", errMismatchingLogMessage, expectedEntry.Message, actualEntry.Message)
|
||||
}
|
||||
|
||||
if expectedEntry.LoggerName != "" && expectedEntry.LoggerName != actualEntry.LoggerName {
|
||||
return false, fmt.Errorf("%w: %s != %s", errMismatchingLoggerName, expectedEntry.LoggerName, actualEntry.LoggerName)
|
||||
}
|
||||
|
||||
if expectedEntry.Level != zapcore.InfoLevel && expectedEntry.Level != actualEntry.Level {
|
||||
return false, fmt.Errorf("%w: %s != %s", errMismatchingLogLevel, expectedEntry.Level, actualEntry.Level)
|
||||
}
|
||||
|
||||
if len(expectedFields) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
expectedFieldMap := map[string]zapcore.Field{}
|
||||
for _, field := range expectedFields {
|
||||
expectedFieldMap[field.Key] = field
|
||||
}
|
||||
|
||||
for _, actualField := range actualEntry.Context {
|
||||
if expectedField, ok := expectedFieldMap[actualField.Key]; ok && !expectedField.Equals(actualField) {
|
||||
return false, fmt.Errorf("%w: %s", errMismatchingField, actualField.Key)
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
}
|
||||
|
||||
func makeLogger(filterFunc log.FilterFunc) (*zap.Logger, *observer.ObservedLogs) {
|
||||
observed, logs := observer.New(zapcore.DebugLevel)
|
||||
|
||||
rule := new(log.AtomicFilterRule)
|
||||
rule.Store(log.NewFilterRule(filterFunc))
|
||||
|
||||
filtered := log.NewFilteredCore(observed, rule)
|
||||
|
||||
return zap.New(filtered), logs
|
||||
}
|
||||
|
||||
var _ = Describe("filter", func() {
|
||||
Describe("NewFilteredCore", func() {
|
||||
It("wrap", func() {
|
||||
next, logs := observer.New(zapcore.DebugLevel)
|
||||
logger := zap.New(next)
|
||||
defer logger.Sync() //nolint:errcheck
|
||||
|
||||
rule := new(log.AtomicFilterRule)
|
||||
rule.Store(log.NewFilterRule(log.MustParseRules("demo*")))
|
||||
|
||||
logger = logger.WithOptions(zap.WrapCore(func(c zapcore.Core) zapcore.Core {
|
||||
return log.NewFilteredCore(c, rule)
|
||||
}))
|
||||
|
||||
logger.Debug("hello world!")
|
||||
logger.Named("demo").Debug("hello earth!")
|
||||
logger.Named("other").Debug("hello universe!")
|
||||
|
||||
Expect(logs.All()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "hello earth!"}),
|
||||
))
|
||||
})
|
||||
|
||||
It("new logger", func() {
|
||||
logger, logs := makeLogger(log.MustParseRules("demo*"))
|
||||
defer logger.Sync() //nolint:errcheck
|
||||
|
||||
logger.Debug("hello world!")
|
||||
logger.Named("demo").Debug("hello earth!")
|
||||
logger.Named("other").Debug("hello universe!")
|
||||
|
||||
Expect(logs.All()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "hello earth!"}),
|
||||
))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("FilterFunc", func() {
|
||||
It("ByNamespace", func() {
|
||||
logger, logs := makeLogger(log.ByNamespaces("demo1.*,demo3.*"))
|
||||
defer logger.Sync() //nolint:errcheck
|
||||
|
||||
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!")
|
||||
|
||||
Expect(logs.All()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "hello region!", LoggerName: "demo1.frontend", Level: zapcore.DebugLevel}),
|
||||
MatchEntry(zapcore.Entry{Message: "hello solar system!", LoggerName: "demo3.frontend", Level: zapcore.DebugLevel}),
|
||||
))
|
||||
})
|
||||
|
||||
It("custom", func() {
|
||||
rand.Seed(42) //nolint:staticcheck
|
||||
|
||||
logger, logs := makeLogger(func(entry zapcore.Entry, fields []zapcore.Field) bool {
|
||||
return rand.Intn(2) == 1 //nolint:gosec
|
||||
})
|
||||
defer logger.Sync() //nolint:errcheck
|
||||
|
||||
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!")
|
||||
|
||||
Expect(logs.All()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "hello city!"}),
|
||||
MatchEntry(zapcore.Entry{Message: "hello solar system!"}),
|
||||
))
|
||||
})
|
||||
|
||||
DescribeTable("simple",
|
||||
func(
|
||||
filterFunc log.FilterFunc,
|
||||
expectedLogs []string,
|
||||
) {
|
||||
logger, logs := makeLogger(filterFunc)
|
||||
defer logger.Sync() //nolint:errcheck
|
||||
|
||||
logger.Debug("a")
|
||||
logger.Info("b")
|
||||
logger.Warn("c")
|
||||
logger.Error("d")
|
||||
|
||||
gotLogs := []string{}
|
||||
for _, log := range logs.All() {
|
||||
gotLogs = append(gotLogs, log.Message)
|
||||
}
|
||||
|
||||
Expect(gotLogs).To(Equal(expectedLogs))
|
||||
},
|
||||
Entry("allow-all",
|
||||
func(entry zapcore.Entry, fields []zapcore.Field) bool {
|
||||
return true
|
||||
},
|
||||
[]string{"a", "b", "c", "d"},
|
||||
),
|
||||
Entry("disallow-all",
|
||||
func(entry zapcore.Entry, fields []zapcore.Field) bool {
|
||||
return false
|
||||
},
|
||||
[]string{},
|
||||
),
|
||||
Entry("minimum-debug",
|
||||
log.MinimumLevel(zapcore.DebugLevel),
|
||||
[]string{"a", "b", "c", "d"},
|
||||
),
|
||||
Entry("minimum-info",
|
||||
log.MinimumLevel(zapcore.InfoLevel),
|
||||
[]string{"b", "c", "d"},
|
||||
),
|
||||
Entry("minimum-warn",
|
||||
log.MinimumLevel(zapcore.WarnLevel),
|
||||
[]string{"c", "d"},
|
||||
),
|
||||
Entry("minimum-error",
|
||||
log.MinimumLevel(zapcore.ErrorLevel),
|
||||
[]string{"d"},
|
||||
),
|
||||
Entry("exact-debug",
|
||||
log.ExactLevel(zapcore.DebugLevel),
|
||||
[]string{"a"},
|
||||
),
|
||||
Entry("exact-info",
|
||||
log.ExactLevel(zapcore.InfoLevel),
|
||||
[]string{"b"},
|
||||
),
|
||||
Entry("exact-warn",
|
||||
log.ExactLevel(zapcore.WarnLevel),
|
||||
[]string{"c"},
|
||||
),
|
||||
Entry("exact-error",
|
||||
log.ExactLevel(zapcore.ErrorLevel),
|
||||
[]string{"d"},
|
||||
),
|
||||
Entry("all-except-debug",
|
||||
log.Reverse(log.ExactLevel(zapcore.DebugLevel)),
|
||||
[]string{"b", "c", "d"},
|
||||
),
|
||||
Entry("all-except-info",
|
||||
log.Reverse(log.ExactLevel(zapcore.InfoLevel)),
|
||||
[]string{"a", "c", "d"},
|
||||
),
|
||||
Entry("all-except-warn",
|
||||
log.Reverse(log.ExactLevel(zapcore.WarnLevel)),
|
||||
[]string{"a", "b", "d"},
|
||||
),
|
||||
Entry("all-except-error",
|
||||
log.Reverse(log.ExactLevel(zapcore.ErrorLevel)),
|
||||
[]string{"a", "b", "c"},
|
||||
),
|
||||
Entry("any",
|
||||
log.Any(
|
||||
log.ExactLevel(zapcore.DebugLevel),
|
||||
log.ExactLevel(zapcore.WarnLevel),
|
||||
),
|
||||
[]string{"a", "c"},
|
||||
),
|
||||
Entry("all-1",
|
||||
log.All(
|
||||
log.ExactLevel(zapcore.DebugLevel),
|
||||
log.ExactLevel(zapcore.WarnLevel),
|
||||
),
|
||||
[]string{},
|
||||
),
|
||||
Entry("all-2",
|
||||
log.All(
|
||||
log.ExactLevel(zapcore.DebugLevel),
|
||||
log.ExactLevel(zapcore.DebugLevel),
|
||||
),
|
||||
[]string{"a"},
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
const (
|
||||
allDebug = "aeimquy2"
|
||||
allInfo = "bfjnrvz3"
|
||||
allWarn = "cgkosw04"
|
||||
allError = "dhlptx15"
|
||||
everything = "abcdefghijklmnopqrstuvwxyz012345"
|
||||
)
|
||||
|
||||
It("ParseRule", func() {
|
||||
// *=myns => any level, myns namespace
|
||||
// info,warn:myns.* => info or warn level, any namespace matching myns.*
|
||||
// error=* => everything with error level
|
||||
logger, logs := makeLogger(log.MustParseRules("*:myns info,warn:myns.* error:*"))
|
||||
defer logger.Sync() //nolint:errcheck
|
||||
|
||||
logger.Debug("top debug") // No match
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
|
||||
logger.Named("myns").Debug("myns debug") // Matches *:myns
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "myns debug", LoggerName: "myns", Level: zapcore.DebugLevel}),
|
||||
))
|
||||
|
||||
logger.Named("bar").Debug("bar debug") // No match
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
|
||||
logger.Named("myns").Named("foo").Debug("myns.foo debug") // No match
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
|
||||
logger.Info("top info") // No match
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
|
||||
logger.Named("myns").Info("myns info") // Matches *:myns
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "myns info", LoggerName: "myns", Level: zapcore.InfoLevel}),
|
||||
))
|
||||
|
||||
logger.Named("bar").Info("bar info") // No match
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
|
||||
logger.Named("myns").Named("foo").Info("myns.foo info") // Matches info,warn:myns.*
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "myns.foo info", LoggerName: "myns.foo", Level: zapcore.InfoLevel}),
|
||||
))
|
||||
|
||||
logger.Warn("top warn") // No match
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
|
||||
logger.Named("myns").Warn("myns warn") // Matches *:myns
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "myns warn", LoggerName: "myns", Level: zapcore.WarnLevel}),
|
||||
))
|
||||
|
||||
logger.Named("bar").Warn("bar warn") // No match
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
|
||||
logger.Named("myns").Named("foo").Warn("myns.foo warn") // Matches info,warn:myns.*
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "myns.foo warn", LoggerName: "myns.foo", Level: zapcore.WarnLevel}),
|
||||
))
|
||||
|
||||
logger.Error("top error") // Matches error:*
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "top error", Level: zapcore.ErrorLevel}),
|
||||
))
|
||||
|
||||
logger.Named("myns").Error("myns error") // Matches *:myns and error:*
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "myns error", LoggerName: "myns", Level: zapcore.ErrorLevel}),
|
||||
))
|
||||
|
||||
logger.Named("bar").Error("bar error") // Matches error:*
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "bar error", LoggerName: "bar", Level: zapcore.ErrorLevel}),
|
||||
))
|
||||
|
||||
logger.Named("myns").Named("foo").Error("myns.foo error") // Matches error:*
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "myns.foo error", LoggerName: "myns.foo", Level: zapcore.ErrorLevel}),
|
||||
))
|
||||
})
|
||||
|
||||
DescribeTable("ParseRules",
|
||||
func(
|
||||
input string,
|
||||
expectedLogs string,
|
||||
expectedError error,
|
||||
) {
|
||||
filterFunc, err := log.ParseRules(input)
|
||||
if err != nil {
|
||||
Expect(err).To(MatchError(expectedError))
|
||||
return
|
||||
}
|
||||
|
||||
logger, logs := makeLogger(filterFunc)
|
||||
defer logger.Sync() //nolint:errcheck
|
||||
|
||||
logger.Debug("a")
|
||||
logger.Info("b")
|
||||
logger.Warn("c")
|
||||
logger.Error("d")
|
||||
|
||||
logger.Named("foo").Debug("e")
|
||||
logger.Named("foo").Info("f")
|
||||
logger.Named("foo").Warn("g")
|
||||
logger.Named("foo").Error("h")
|
||||
|
||||
logger.Named("bar").Debug("i")
|
||||
logger.Named("bar").Info("j")
|
||||
logger.Named("bar").Warn("k")
|
||||
logger.Named("bar").Error("l")
|
||||
|
||||
logger.Named("baz").Debug("m")
|
||||
logger.Named("baz").Info("n")
|
||||
logger.Named("baz").Warn("o")
|
||||
logger.Named("baz").Error("p")
|
||||
|
||||
logger.Named("foo").Named("bar").Debug("q")
|
||||
logger.Named("foo").Named("bar").Info("r")
|
||||
logger.Named("foo").Named("bar").Warn("s")
|
||||
logger.Named("foo").Named("bar").Error("t")
|
||||
|
||||
logger.Named("foo").Named("foo").Debug("u")
|
||||
logger.Named("foo").Named("foo").Info("v")
|
||||
logger.Named("foo").Named("foo").Warn("w")
|
||||
logger.Named("foo").Named("foo").Error("x")
|
||||
|
||||
logger.Named("bar").Named("foo").Debug("y")
|
||||
logger.Named("bar").Named("foo").Info("z")
|
||||
logger.Named("bar").Named("foo").Warn("0")
|
||||
logger.Named("bar").Named("foo").Error("1")
|
||||
|
||||
logger.Named("qux").Named("foo").Debug("2")
|
||||
logger.Named("qux").Named("foo").Info("3")
|
||||
logger.Named("qux").Named("foo").Warn("4")
|
||||
logger.Named("qux").Named("foo").Error("5")
|
||||
|
||||
gotLogs := []string{}
|
||||
for _, log := range logs.All() {
|
||||
gotLogs = append(gotLogs, log.Message)
|
||||
}
|
||||
|
||||
Expect(strings.Join(gotLogs, "")).To(Equal(expectedLogs))
|
||||
},
|
||||
Entry("empty", "", "", nil),
|
||||
Entry("everything", "*", everything, nil),
|
||||
Entry("debug+", "debug+:*", everything, nil),
|
||||
Entry("all-debug", "debug:*", allDebug, nil),
|
||||
Entry("all-info", "info:*", allInfo, nil),
|
||||
Entry("all-warn", "warn:*", allWarn, nil),
|
||||
Entry("all-error", "error:*", allError, nil),
|
||||
Entry("all-info-and-warn-1", "info,warn:*", "bcfgjknorsvwz034", nil),
|
||||
Entry("all-info-and-warn-2", "info:* warn:*", "bcfgjknorsvwz034", nil),
|
||||
Entry("warn+", "warn+:*", "cdghklopstwx0145", nil),
|
||||
Entry("redundant-1", "info,info:* info:*", allInfo, nil),
|
||||
Entry("redundant-2", "* *:* info:*", everything, nil),
|
||||
Entry("foo-ns", "foo", "efgh", nil),
|
||||
Entry("foo-ns-wildcard", "*:foo", "efgh", nil),
|
||||
Entry("foo-ns-debug,info", "debug,info:foo", "ef", nil),
|
||||
Entry("foo.star-ns", "foo.*", "qrstuvwx", nil),
|
||||
Entry("foo.star-ns-wildcard", "*:foo.*", "qrstuvwx", nil),
|
||||
Entry("foo.star-ns-debug,info", "debug,info:foo.*", "qruv", nil),
|
||||
Entry("all-in-one", "*:foo debug:foo.* info,warn:bar error:*", "defghjklpqtux15", nil),
|
||||
Entry("exclude-1", "info:test,foo*,-foo.foo", "fr", nil),
|
||||
Entry("exclude-2", "info:test,foo*,-*.foo", "fr", nil),
|
||||
Entry("exclude-3", "test,*.foo,-foo.*", "yz012345", nil),
|
||||
Entry("exclude-4", "*,-foo,-bar", "abcdmnopqrstuvwxyz012345", nil),
|
||||
Entry("exclude-5", "foo*,bar*,-foo.foo,-bar.foo", "efghijklqrst", nil),
|
||||
Entry("exclude-6", "foo*,-foo.foo,bar*,-bar.foo", "efghijklqrst", nil),
|
||||
Entry("invalid-left", "invalid:*", "", log.ErrUnsupportedKeyword),
|
||||
Entry("missing-left", ":*", "", log.ErrBadSyntax),
|
||||
Entry("missing-right", ":*", "", log.ErrBadSyntax),
|
||||
PEntry("missing-exclude-pattern", "*:-", "", log.ErrBadSyntax),
|
||||
)
|
||||
|
||||
Describe("Check", func() {
|
||||
DescribeTable("simple",
|
||||
func(
|
||||
rules string,
|
||||
namespace string,
|
||||
checked bool,
|
||||
) {
|
||||
filterFunc, err := log.ParseRules(rules)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
logger, _ := makeLogger(filterFunc)
|
||||
defer logger.Sync() //nolint:errcheck
|
||||
|
||||
if namespace != "" {
|
||||
logger = logger.Named(namespace)
|
||||
}
|
||||
|
||||
entry := logger.Check(zap.DebugLevel, "")
|
||||
if checked {
|
||||
Expect(entry).NotTo(BeNil())
|
||||
} else {
|
||||
Expect(entry).To(BeNil())
|
||||
}
|
||||
},
|
||||
Entry(nil, "", "", false),
|
||||
Entry(nil, "", "foo", false),
|
||||
Entry(nil, "*", "", true),
|
||||
Entry(nil, "*", "foo", true),
|
||||
Entry(nil, "*:foo", "", false),
|
||||
Entry(nil, "*:foo", "foo", true),
|
||||
Entry(nil, "*:foo", "bar", false),
|
||||
)
|
||||
|
||||
DescribeTable("any level",
|
||||
func(name string, expected bool) {
|
||||
logger, _ := makeLogger(log.MustParseRules("debug:*.* info:demo*"))
|
||||
if name != "" {
|
||||
logger = logger.Named(name)
|
||||
}
|
||||
|
||||
Expect(log.CheckAnyLevel(logger)).To(Equal(expected))
|
||||
},
|
||||
Entry(nil, "", false),
|
||||
Entry(nil, "demo", true),
|
||||
Entry(nil, "blahdemo", false),
|
||||
Entry(nil, "demoblah", true),
|
||||
Entry(nil, "blah", false),
|
||||
Entry(nil, "blah.blah", true),
|
||||
)
|
||||
|
||||
DescribeTable("level",
|
||||
func(name string, lvl zapcore.Level, expected bool) {
|
||||
logger, _ := makeLogger(log.MustParseRules("debug:*.* info:demo*"))
|
||||
|
||||
if name != "" {
|
||||
logger = logger.Named(name)
|
||||
}
|
||||
|
||||
Expect(log.CheckLevel(logger, lvl)).To(Equal(expected))
|
||||
},
|
||||
Entry(nil, "", zap.DebugLevel, false),
|
||||
Entry(nil, "demo", zap.DebugLevel, false),
|
||||
Entry(nil, "blahdemo", zap.DebugLevel, false),
|
||||
Entry(nil, "demoblah", zap.DebugLevel, false),
|
||||
Entry(nil, "blah", zap.DebugLevel, false),
|
||||
Entry(nil, "blah.blah", zap.DebugLevel, true),
|
||||
Entry(nil, "", zap.InfoLevel, false),
|
||||
Entry(nil, "demo", zap.InfoLevel, true),
|
||||
Entry(nil, "blahdemo", zap.InfoLevel, false),
|
||||
Entry(nil, "demoblah", zap.InfoLevel, true),
|
||||
Entry(nil, "blah", zap.InfoLevel, false),
|
||||
Entry(nil, "blah.blah", zap.InfoLevel, false),
|
||||
)
|
||||
})
|
||||
|
||||
It("With", func() {
|
||||
logger, logs := makeLogger(log.ByNamespaces("demo1.*,demo3.*"))
|
||||
defer logger.Sync() //nolint:errcheck
|
||||
|
||||
logger.With(zap.String("lorem", "ipsum")).Debug("hello city!")
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
|
||||
logger.With(zap.String("lorem", "ipsum")).Named("demo1.frontend").Debug("hello region!")
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "hello region!", LoggerName: "demo1.frontend", Level: zapcore.DebugLevel}, zap.String("lorem", "ipsum")),
|
||||
))
|
||||
|
||||
logger.With(zap.String("lorem", "ipsum")).Named("demo2.frontend").Debug("hello planet!")
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
|
||||
logger.With(zap.String("lorem", "ipsum")).Named("demo3.frontend").Debug("hello solar system!")
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "hello solar system!", LoggerName: "demo3.frontend", Level: zapcore.DebugLevel}, zap.String("lorem", "ipsum")),
|
||||
))
|
||||
})
|
||||
|
||||
It("Check", func() {
|
||||
logger, logs := makeLogger(log.MustParseRules("debug:* info:demo*"))
|
||||
defer logger.Sync() //nolint:errcheck
|
||||
|
||||
ce := logger.Check(zap.DebugLevel, "a")
|
||||
Expect(ce).NotTo(BeNil())
|
||||
ce.Write()
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "a"}),
|
||||
))
|
||||
|
||||
ce = logger.Check(zap.InfoLevel, "b")
|
||||
Expect(ce).To(BeNil())
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
|
||||
ce = logger.Named("demo").Check(zap.InfoLevel, "c")
|
||||
Expect(ce).NotTo(BeNil())
|
||||
ce.Write()
|
||||
Expect(logs.TakeAll()).To(HaveExactElements(
|
||||
MatchEntry(zapcore.Entry{Message: "c"}),
|
||||
))
|
||||
|
||||
ce = logger.Check(zap.WarnLevel, "d")
|
||||
Expect(ce).To(BeNil())
|
||||
Expect(logs.TakeAll()).To(BeEmpty())
|
||||
})
|
||||
})
|
@@ -21,7 +21,7 @@ type grpcLogger struct {
|
||||
verbosity int
|
||||
}
|
||||
|
||||
func NewGRPCLogger(logger *zap.Logger, verbosity int) grpclog.LoggerV2 {
|
||||
func NewGRPCLogger(logger *Logger, verbosity int) grpclog.LoggerV2 {
|
||||
var level zapcore.Level
|
||||
|
||||
verbosityLevel := os.Getenv("GRPC_GO_LOG_VERBOSITY_LEVEL")
|
||||
@@ -41,7 +41,7 @@ func NewGRPCLogger(logger *zap.Logger, verbosity int) grpclog.LoggerV2 {
|
||||
logger = logger.WithOptions(zap.IncreaseLevel(level))
|
||||
|
||||
return &grpcLogger{
|
||||
SugaredLogger: logger.Sugar(),
|
||||
SugaredLogger: logger.Logger.Sugar(),
|
||||
verbosity: verbosity,
|
||||
}
|
||||
}
|
||||
|
154
pkg/log/log.go
154
pkg/log/log.go
@@ -5,6 +5,9 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/tty"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
@@ -12,73 +15,116 @@ import (
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var (
|
||||
Verbosity VerbosityLevel
|
||||
Severity zap.AtomicLevel
|
||||
Rule AtomicFilterRule
|
||||
Global *Logger
|
||||
)
|
||||
|
||||
func SetupLogging(severity zapcore.Level, verbosity int, outputPaths []string, errOutputPaths []string, color bool) *zap.Logger {
|
||||
Severity = zap.NewAtomicLevelAt(severity)
|
||||
Verbosity = NewVerbosityLevelAt(verbosity)
|
||||
func DebugLevel(verbosity int) Level {
|
||||
return Level(zapcore.DebugLevel) - Level(verbosity)
|
||||
}
|
||||
|
||||
cfg := zap.NewDevelopmentConfig()
|
||||
|
||||
cfg.Level = Severity
|
||||
cfg.EncoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("15:04:05.000000")
|
||||
if color {
|
||||
cfg.EncoderConfig.EncodeLevel = zapcore.LowercaseColorLevelEncoder
|
||||
} else {
|
||||
cfg.EncoderConfig.EncodeLevel = zapcore.LowercaseLevelEncoder
|
||||
}
|
||||
cfg.DisableCaller = true
|
||||
cfg.DisableStacktrace = true
|
||||
cfg.OutputPaths = outputPaths
|
||||
cfg.ErrorOutputPaths = errOutputPaths
|
||||
|
||||
if len(cfg.OutputPaths) == 0 {
|
||||
cfg.OutputPaths = []string{"stdout"}
|
||||
func openSink(path string) zapcore.WriteSyncer {
|
||||
if path == "stdout" {
|
||||
return os.Stdout
|
||||
} else if path == "stderr" {
|
||||
return os.Stderr
|
||||
}
|
||||
|
||||
if len(cfg.ErrorOutputPaths) == 0 {
|
||||
cfg.ErrorOutputPaths = []string{"stderr"}
|
||||
}
|
||||
|
||||
logger, err := cfg.Build()
|
||||
f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Redirect gRPC log to Zap
|
||||
glogger := logger.Named("grpc")
|
||||
grpclog.SetLoggerV2(NewGRPCLogger(glogger, verbosity))
|
||||
|
||||
zap.RedirectStdLog(logger)
|
||||
zap.ReplaceGlobals(logger)
|
||||
|
||||
return logger
|
||||
return tty.NewANSIStripperSynced(f)
|
||||
}
|
||||
|
||||
func WithVerbose(verbose int) zap.Option {
|
||||
return zap.WrapCore(func(core zapcore.Core) zapcore.Core {
|
||||
return &verbosityCore{
|
||||
Core: core,
|
||||
verbose: verbose,
|
||||
}
|
||||
})
|
||||
}
|
||||
type alwaysEnabled struct{}
|
||||
|
||||
type verbosityCore struct {
|
||||
zapcore.Core
|
||||
verbose int
|
||||
}
|
||||
func (e *alwaysEnabled) Enabled(zapcore.Level) bool { return true }
|
||||
|
||||
func (c *verbosityCore) Enabled(lvl zapcore.Level) bool {
|
||||
return c.Core.Enabled(lvl) && (lvl != zap.DebugLevel || Verbosity.Enabled(c.verbose))
|
||||
}
|
||||
|
||||
func (c *verbosityCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
|
||||
if c.Enabled(ent.Level) {
|
||||
return ce.AddCore(ent, c)
|
||||
func SetupLogging(rule string, paths []string, color bool) (logger *Logger, err error) {
|
||||
cfg := encoderConfig{
|
||||
EncoderConfig: zapcore.EncoderConfig{
|
||||
TimeKey: "T",
|
||||
LevelKey: "L",
|
||||
NameKey: "N",
|
||||
CallerKey: "C",
|
||||
FunctionKey: zapcore.OmitKey,
|
||||
MessageKey: "M",
|
||||
StacktraceKey: "S",
|
||||
ConsoleSeparator: " ",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeTime: zapcore.TimeEncoderOfLayout("15:04:05.000000"),
|
||||
EncodeDuration: zapcore.StringDurationEncoder,
|
||||
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||
EncodeLevel: levelEncoder,
|
||||
},
|
||||
}
|
||||
|
||||
return ce
|
||||
if color {
|
||||
cfg.ColorTime = ColorTime
|
||||
cfg.ColorContext = ColorContext
|
||||
cfg.ColorStacktrace = ColorStacktrace
|
||||
cfg.ColorName = ColorName
|
||||
cfg.ColorCaller = ColorCaller
|
||||
cfg.ColorLevel = ColorLevel
|
||||
} else {
|
||||
cfg.ColorLevel = func(lvl zapcore.Level) string {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
wss := []zapcore.WriteSyncer{}
|
||||
|
||||
for _, path := range paths {
|
||||
wss = append(wss, openSink(path))
|
||||
}
|
||||
|
||||
if len(wss) == 0 {
|
||||
wss = append(wss, os.Stdout)
|
||||
}
|
||||
|
||||
ws := zapcore.NewMultiWriteSyncer(wss...)
|
||||
enc := newEncoder(cfg)
|
||||
core := zapcore.NewCore(enc, ws, &alwaysEnabled{})
|
||||
|
||||
if rule == "" {
|
||||
rule = "*"
|
||||
}
|
||||
|
||||
filterRule, err := ParseFilterRule(rule)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Rule.Store(filterRule)
|
||||
|
||||
zlogger := zap.New(core,
|
||||
zap.ErrorOutput(ws),
|
||||
zap.WrapCore(func(c zapcore.Core) zapcore.Core {
|
||||
return NewFilteredCore(c, &Rule)
|
||||
}))
|
||||
|
||||
zlogger.Level()
|
||||
|
||||
zap.RedirectStdLog(zlogger)
|
||||
zap.ReplaceGlobals(zlogger)
|
||||
|
||||
logger = &Logger{zlogger}
|
||||
|
||||
Global = logger
|
||||
|
||||
// Redirect gRPC log to Zap
|
||||
glogger := logger.Named("grpc")
|
||||
grpclog.SetLoggerV2(NewGRPCLogger(glogger, Level(zlogger.Level()).Verbosity()))
|
||||
|
||||
return logger, nil
|
||||
}
|
||||
|
||||
type forceReflect struct {
|
||||
any
|
||||
}
|
||||
|
||||
func ForceReflect(key string, val any) zapcore.Field {
|
||||
return zapcore.Field{Key: key, Type: zapcore.ReflectType, Interface: forceReflect{val}}
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@
|
||||
package log_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
stdlog "log"
|
||||
"os"
|
||||
@@ -17,7 +16,6 @@ import (
|
||||
"github.com/pion/zapion"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/tty"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
@@ -30,15 +28,15 @@ func TestSuite(t *testing.T) {
|
||||
// TODO: This test is currently broken on Windows due:
|
||||
// https://github.com/uber-go/zap/issues/621
|
||||
var _ = Context("log", Label("broken-on-windows"), func() {
|
||||
var logger *zap.Logger
|
||||
var logger *log.Logger
|
||||
var lvl zapcore.Level
|
||||
var logPath, msg, scope string
|
||||
var logPath, msg, name string
|
||||
|
||||
BeforeEach(func() {
|
||||
tmpDir := GinkgoT().TempDir()
|
||||
|
||||
logPath = filepath.Join(tmpDir, "std.log")
|
||||
msg = fmt.Sprintf("Test message %s", tty.Mods("something red", tty.FgRed))
|
||||
msg = "Test message"
|
||||
|
||||
os.Setenv("GRPC_GO_LOG_VERBOSITY_LEVEL", "2")
|
||||
os.Setenv("GRPC_GO_LOG_SEVERITY_LEVEL", lvl.String())
|
||||
@@ -46,37 +44,39 @@ var _ = Context("log", Label("broken-on-windows"), func() {
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
logger = log.SetupLogging(lvl, 0, []string{logPath}, nil, true)
|
||||
var err error
|
||||
logger, err = log.SetupLogging("", []string{logPath}, true)
|
||||
Expect(err).To(Succeed())
|
||||
})
|
||||
|
||||
Context("simple", func() {
|
||||
It("can log via created logger", func() {
|
||||
scope = ""
|
||||
name = ""
|
||||
logger.Info(msg)
|
||||
})
|
||||
|
||||
It("can log via std logger", func() {
|
||||
scope = ""
|
||||
name = ""
|
||||
stdlog.Print(msg)
|
||||
})
|
||||
|
||||
It("can log via global logger", func() {
|
||||
scope = ""
|
||||
zap.L().Info(msg)
|
||||
name = ""
|
||||
log.Global.Info(msg)
|
||||
})
|
||||
|
||||
It("can log via pion logger", func() {
|
||||
lf := zapion.ZapFactory{
|
||||
BaseLogger: logger.Named("ice"),
|
||||
BaseLogger: logger.Named("ice").Logger,
|
||||
}
|
||||
logger := lf.NewLogger("myscope")
|
||||
|
||||
scope = "ice.myscope"
|
||||
name = "ice.myscope"
|
||||
logger.Info(msg)
|
||||
})
|
||||
|
||||
It("can log via gRPC logger", func() {
|
||||
scope = "grpc"
|
||||
name = "grpc"
|
||||
grpclog.Info(msg)
|
||||
})
|
||||
})
|
||||
@@ -94,14 +94,25 @@ var _ = Context("log", Label("broken-on-windows"), func() {
|
||||
Expect(err).To(Succeed(), "Failed to read standard log contents: %s", err)
|
||||
Expect(logContents).NotTo(BeEmpty())
|
||||
|
||||
if scope != "" {
|
||||
scope += `\t`
|
||||
regexTime := regexpQuoteColor(`\d{2}:\d{2}:\d{2}.\d{6}`, log.ColorTime) + " "
|
||||
regexLevel := regexpQuoteColor(lvl.String(), log.ColorLevel(lvl)) + " "
|
||||
regexName := regexpQuoteColor(name, log.ColorName) + " "
|
||||
|
||||
var regex string
|
||||
if name != "" {
|
||||
regex = regexTime + regexLevel + regexName + msg
|
||||
} else {
|
||||
regex = regexTime + regexLevel + msg
|
||||
}
|
||||
|
||||
regex := fmt.Sprintf(`\d{2}:\d{2}:\d{2}.\d{6}\t%s\t%s%s`,
|
||||
regexp.QuoteMeta(tty.Mods(lvl.String(), tty.FgBlue)), scope,
|
||||
regexp.QuoteMeta(msg))
|
||||
|
||||
Expect(logContents).To(MatchRegexp(regex), "Log output '%s' does not match regex '%s'", logContents, regex)
|
||||
Expect(string(logContents)).To(MatchRegexp(regex), "Log output '%s' does not match regex '%s'", logContents, regex)
|
||||
})
|
||||
})
|
||||
|
||||
func regexpQuoteColor(str, color string) string {
|
||||
if color == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
return regexp.QuoteMeta(color) + str + regexp.QuoteMeta(tty.Reset)
|
||||
}
|
||||
|
30
pkg/log/logger.go
Normal file
30
pkg/log/logger.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
*zap.Logger
|
||||
}
|
||||
|
||||
func (l *Logger) Level() Level {
|
||||
return Level(l.Logger.Level())
|
||||
}
|
||||
|
||||
func (l *Logger) DebugV(verboseLevel int, message string, fields ...zap.Field) {
|
||||
l.Log(zap.DebugLevel-zapcore.Level(verboseLevel), message, fields...)
|
||||
}
|
||||
|
||||
func (l *Logger) With(fields ...zap.Field) *Logger {
|
||||
return &Logger{l.Logger.With(fields...)}
|
||||
}
|
||||
|
||||
func (l *Logger) WithOptions(opts ...zap.Option) *Logger {
|
||||
return &Logger{l.Logger.WithOptions(opts...)}
|
||||
}
|
||||
|
||||
func (l *Logger) Named(s string) *Logger {
|
||||
return &Logger{l.Logger.Named(s)}
|
||||
}
|
@@ -1,37 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 Steffen Vogel <post@steffenvogel.de>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type VerbosityLevel struct {
|
||||
l atomic.Int32
|
||||
}
|
||||
|
||||
func NewVerbosityLevel() VerbosityLevel {
|
||||
return VerbosityLevel{
|
||||
l: atomic.Int32{},
|
||||
}
|
||||
}
|
||||
|
||||
func NewVerbosityLevelAt(l int) VerbosityLevel {
|
||||
a := NewVerbosityLevel()
|
||||
a.SetLevel(l)
|
||||
return a //nolint:govet
|
||||
}
|
||||
|
||||
func (lvl *VerbosityLevel) Enabled(l int) bool {
|
||||
return lvl.Level() >= l || l == 0
|
||||
}
|
||||
|
||||
func (lvl *VerbosityLevel) Level() int {
|
||||
return int(lvl.l.Load())
|
||||
}
|
||||
|
||||
// SetLevel alters the logging level.
|
||||
func (lvl *VerbosityLevel) SetLevel(l int) {
|
||||
lvl.l.Store(int32(l))
|
||||
}
|
@@ -8,8 +8,9 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
)
|
||||
|
||||
var ErrFiltered = errors.New("packet has been filtered")
|
||||
@@ -24,10 +25,10 @@ type FilteredConn struct {
|
||||
net.PacketConn
|
||||
|
||||
onPacket []PacketHandler
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewFilteredConn(c net.PacketConn, logger *zap.Logger) *FilteredConn {
|
||||
func NewFilteredConn(c net.PacketConn, logger *log.Logger) *FilteredConn {
|
||||
return &FilteredConn{
|
||||
PacketConn: c,
|
||||
logger: logger,
|
||||
|
@@ -8,10 +8,12 @@ import (
|
||||
|
||||
"github.com/pion/stun"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
)
|
||||
|
||||
type STUNPacketHandler struct {
|
||||
Logger *zap.Logger
|
||||
Logger *log.Logger
|
||||
}
|
||||
|
||||
func (ph *STUNPacketHandler) OnPacketRead(buf []byte, rAddr net.Addr) (bool, error) {
|
||||
@@ -25,14 +27,14 @@ func (ph *STUNPacketHandler) OnPacketRead(buf []byte, rAddr net.Addr) (bool, err
|
||||
}
|
||||
|
||||
if err := msg.Decode(); err == nil {
|
||||
ph.Logger.Debug("Received STUN message",
|
||||
ph.Logger.DebugV(6, "Received STUN message",
|
||||
zap.String("addr", rAddr.String()),
|
||||
zap.Any("type", msg.Type),
|
||||
zap.Binary("id", msg.TransactionID[:]),
|
||||
zap.Int("#attrs", len(msg.Attributes)),
|
||||
zap.Int("len", int(msg.Length)))
|
||||
} else {
|
||||
ph.Logger.Debug("Received invalid STUN message",
|
||||
ph.Logger.DebugV(6, "Received invalid STUN message",
|
||||
zap.String("addr", rAddr.String()),
|
||||
zap.Int("len", len(buf)),
|
||||
zap.Binary("msg", buf))
|
||||
|
@@ -11,8 +11,8 @@ import (
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/pion/stun"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
netx "github.com/stv0g/cunicu/pkg/net"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ = Context("STUNPacketHandler", func() {
|
||||
@@ -34,7 +34,7 @@ var _ = Context("STUNPacketHandler", func() {
|
||||
|
||||
ppc1, ppc2 = netx.NewPacketPipeConn(l1, l2, 128)
|
||||
|
||||
fc = netx.NewFilteredConn(ppc2, zap.L())
|
||||
fc = netx.NewFilteredConn(ppc2, log.Global)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
@@ -50,7 +50,7 @@ var _ = Context("STUNPacketHandler", func() {
|
||||
|
||||
It("can handle STUN", func() {
|
||||
fc.AddPacketReadHandler(&netx.STUNPacketHandler{
|
||||
Logger: zap.L(),
|
||||
Logger: log.Global,
|
||||
})
|
||||
|
||||
m := stun.New()
|
||||
@@ -71,7 +71,7 @@ var _ = Context("STUNPacketHandler", func() {
|
||||
|
||||
It("can handle STUN with conn", func() {
|
||||
stunConn := fc.AddPacketReadHandlerConn(&netx.STUNPacketHandler{
|
||||
Logger: zap.L(),
|
||||
Logger: log.Global,
|
||||
})
|
||||
|
||||
m := stun.New()
|
||||
|
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
netx "github.com/stv0g/cunicu/pkg/net"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ = Context("FilteredConn", func() {
|
||||
@@ -33,7 +33,7 @@ var _ = Context("FilteredConn", func() {
|
||||
|
||||
ppc1, ppc2 = netx.NewPacketPipeConn(l1, l2, 128)
|
||||
|
||||
fc = netx.NewFilteredConn(ppc2, zap.L())
|
||||
fc = netx.NewFilteredConn(ppc2, log.Global)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/tty"
|
||||
"github.com/stv0g/cunicu/pkg/wg"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
@@ -32,7 +33,7 @@ func (i *Interface) Device() *wg.Interface {
|
||||
|
||||
// Dump writes a human readable version of the interface status to the supplied writer.
|
||||
// The format resembles the one used by wg(8).
|
||||
func (i *Interface) Dump(wr io.Writer, verbosity int) error {
|
||||
func (i *Interface) Dump(wr io.Writer, level log.Level) error {
|
||||
wri := tty.NewIndenter(wr, " ")
|
||||
|
||||
if _, err := fmt.Fprintf(wr, tty.Mods("interface", tty.Bold, tty.FgGreen)+": "+tty.Mods("%s", tty.FgGreen)+"\n", i.Name); err != nil {
|
||||
@@ -43,7 +44,7 @@ func (i *Interface) Dump(wr io.Writer, verbosity int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if verbosity > 5 {
|
||||
if level > log.DebugLevel(5) {
|
||||
if _, err := tty.FprintKV(wri, "private key", base64.StdEncoding.EncodeToString(i.PrivateKey)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -75,12 +76,12 @@ func (i *Interface) Dump(wr io.Writer, verbosity int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if i.Ice != nil && verbosity > 3 {
|
||||
if i.Ice != nil && level.Verbosity() > 3 {
|
||||
if _, err := fmt.Fprintln(wr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := i.Ice.Dump(wri, verbosity); err != nil {
|
||||
if err := i.Ice.Dump(wri, level.Verbosity()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -90,7 +91,7 @@ func (i *Interface) Dump(wr io.Writer, verbosity int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := p.Dump(wri, verbosity); err != nil {
|
||||
if err := p.Dump(wri, level.Verbosity()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@@ -7,10 +7,11 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (e *Event) Log(l *zap.Logger, msg string, fields ...zap.Field) {
|
||||
func (e *Event) Log(l *log.Logger, msg string, fields ...zap.Field) {
|
||||
fields = append(fields, zap.String("type", strings.ToLower(e.Type.String())))
|
||||
|
||||
if e.Event != nil {
|
||||
|
@@ -6,9 +6,11 @@ package rpc
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
)
|
||||
|
||||
func (s *GetStatusResp) Dump(wr io.Writer, verbosity int) error {
|
||||
func (s *GetStatusResp) Dump(wr io.Writer, level log.Level) error {
|
||||
for k, i := range s.Interfaces {
|
||||
if k > 0 {
|
||||
if _, err := fmt.Fprintln(wr); err != nil {
|
||||
@@ -16,7 +18,7 @@ func (s *GetStatusResp) Dump(wr io.Writer, verbosity int) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := i.Dump(wr, verbosity); err != nil {
|
||||
if err := i.Dump(wr, level); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/stv0g/cunicu/pkg/buildinfo"
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/proto"
|
||||
rpcproto "github.com/stv0g/cunicu/pkg/proto/rpc"
|
||||
"go.uber.org/zap"
|
||||
@@ -39,7 +40,7 @@ type Client struct {
|
||||
rpcproto.DaemonClient
|
||||
|
||||
conn *grpc.ClientConn
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
onEvent []EventHandler
|
||||
|
||||
peerStates map[crypto.Key]daemon.PeerState
|
||||
@@ -84,7 +85,7 @@ func Connect(path string) (*Client, error) {
|
||||
DaemonClient: rpcproto.NewDaemonClient(conn),
|
||||
|
||||
conn: conn,
|
||||
logger: zap.L().Named("rpc.client").With(zap.String("path", path)),
|
||||
logger: log.Global.Named("rpc.client").With(zap.String("path", path)),
|
||||
peerStates: make(map[crypto.Key]daemon.PeerState),
|
||||
}
|
||||
c.peerStatesCond = sync.NewCond(&c.peerStatesLock)
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/daemon"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
rpcproto "github.com/stv0g/cunicu/pkg/proto/rpc"
|
||||
"github.com/stv0g/cunicu/pkg/types"
|
||||
"go.uber.org/zap"
|
||||
@@ -29,13 +30,13 @@ type Server struct {
|
||||
|
||||
events *types.FanOut[*rpcproto.Event]
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewServer(d *daemon.Daemon, socket string) (*Server, error) {
|
||||
s := &Server{
|
||||
events: types.NewFanOut[*rpcproto.Event](1),
|
||||
logger: zap.L().Named("rpc.server"),
|
||||
logger: log.Global.Named("rpc.server"),
|
||||
}
|
||||
|
||||
s.waitGroup.Add(1)
|
||||
@@ -92,8 +93,8 @@ func (s *Server) unaryInterceptor(ctx context.Context, req any, info *grpc.Unary
|
||||
} else {
|
||||
s.logger.Debug("Handling RPC request",
|
||||
zap.String("method", info.FullMethod),
|
||||
zap.Any("request", req),
|
||||
zap.Any("response", resp),
|
||||
zap.Reflect("request", req),
|
||||
zap.Reflect("response", resp),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -12,7 +12,6 @@ import (
|
||||
"net"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/buildinfo"
|
||||
@@ -25,17 +24,12 @@ import (
|
||||
coreproto "github.com/stv0g/cunicu/pkg/proto/core"
|
||||
rpcproto "github.com/stv0g/cunicu/pkg/proto/rpc"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var (
|
||||
errInvalidVerbosityLevel = errors.New("invalid verbosity level (must be between 0 and 10 inclusive)")
|
||||
errInvalidSeverityLevel = errors.New("invalid severity level")
|
||||
errNoSettingChanged = errors.New("no setting was changed")
|
||||
)
|
||||
var errNoSettingChanged = errors.New("no setting was changed")
|
||||
|
||||
type DaemonServer struct {
|
||||
rpcproto.UnimplementedDaemonServer
|
||||
@@ -185,31 +179,17 @@ func (s *DaemonServer) SetConfig(_ context.Context, p *rpcproto.SetConfigParams)
|
||||
errs := []error{}
|
||||
settings := map[string]any{}
|
||||
|
||||
numChanges := 0
|
||||
|
||||
for key, value := range p.Settings {
|
||||
switch key {
|
||||
case "log.verbosity":
|
||||
level, err := strconv.Atoi(value)
|
||||
case "log.level":
|
||||
rule, err := log.ParseFilterRule(value)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("invalid level: %w", err))
|
||||
break
|
||||
} else if level > 10 || level < 0 {
|
||||
errs = append(errs, errInvalidVerbosityLevel)
|
||||
break
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
log.Verbosity.SetLevel(level)
|
||||
|
||||
case "log.severity":
|
||||
level, err := zapcore.ParseLevel(value)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("invalid level: %w", err))
|
||||
break
|
||||
} else if level < zapcore.DebugLevel || level > zapcore.FatalLevel {
|
||||
errs = append(errs, errInvalidSeverityLevel)
|
||||
break
|
||||
}
|
||||
|
||||
log.Severity.SetLevel(level)
|
||||
log.Rule.Store(rule)
|
||||
numChanges++
|
||||
|
||||
default:
|
||||
if value == "" { // Unset value
|
||||
@@ -223,7 +203,10 @@ func (s *DaemonServer) SetConfig(_ context.Context, p *rpcproto.SetConfigParams)
|
||||
changes, err := s.Config.Update(settings)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else if len(changes) == 0 {
|
||||
}
|
||||
|
||||
numChanges += len(changes)
|
||||
if numChanges == 0 {
|
||||
errs = append(errs, errNoSettingChanged)
|
||||
}
|
||||
|
||||
@@ -250,12 +233,8 @@ func (s *DaemonServer) GetConfig(_ context.Context, p *rpcproto.GetConfigParams)
|
||||
return p.KeyFilter == "" || strings.HasPrefix(key, p.KeyFilter)
|
||||
}
|
||||
|
||||
if match("log.verbosity") {
|
||||
settings["log.verbosity"] = fmt.Sprint(log.Verbosity.Level())
|
||||
}
|
||||
|
||||
if match("log.severity") {
|
||||
settings["log.severity"] = log.Severity.String()
|
||||
if match("log.level") {
|
||||
settings["log.level"] = log.Rule.Load().Expression
|
||||
}
|
||||
|
||||
for key, value := range s.Config.All() {
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/tty"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -23,7 +24,7 @@ var (
|
||||
// DownloadAndVerifyRelease downloads a released version of
|
||||
// cunīcu and saves it to target. It returns the version string for the newest
|
||||
// version. The function printf is used to print progress information.
|
||||
func DownloadAndVerifyRelease(ctx context.Context, rel *Release, target string, logger *zap.Logger) error {
|
||||
func DownloadAndVerifyRelease(ctx context.Context, rel *Release, target string, logger *log.Logger) error {
|
||||
fn, sha256sums, err := getGithubDataFile(ctx, rel.Assets, checksumsFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -24,6 +24,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/buildinfo"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -42,7 +43,7 @@ var (
|
||||
errArchiveMultipleFiles = errors.New("archive contains more than one file")
|
||||
)
|
||||
|
||||
func SelfUpdate(output string, logger *zap.Logger) (*Release, error) {
|
||||
func SelfUpdate(output string, logger *log.Logger) (*Release, error) {
|
||||
fi, err := os.Lstat(output)
|
||||
if err != nil {
|
||||
dirname := filepath.Dir(output)
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
signalingproto "github.com/stv0g/cunicu/pkg/proto/signaling"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -24,7 +25,7 @@ var (
|
||||
|
||||
type BackendType string // URL schemes
|
||||
|
||||
type BackendFactory func(*BackendConfig, *zap.Logger) (Backend, error)
|
||||
type BackendFactory func(*BackendConfig, *log.Logger) (Backend, error)
|
||||
|
||||
type BackendPlugin struct {
|
||||
New BackendFactory
|
||||
@@ -71,7 +72,7 @@ func NewBackend(cfg *BackendConfig) (Backend, error) {
|
||||
}
|
||||
|
||||
loggerName := fmt.Sprintf("backend.%s", typ)
|
||||
logger := zap.L().Named(loggerName).With(zap.Any("backend", cfg.URI))
|
||||
logger := log.Global.Named(loggerName).With(zap.Any("backend", cfg.URI))
|
||||
|
||||
be, err := p.New(cfg, logger)
|
||||
if err != nil {
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/proto"
|
||||
signalingproto "github.com/stv0g/cunicu/pkg/proto/signaling"
|
||||
"github.com/stv0g/cunicu/pkg/signaling"
|
||||
@@ -32,10 +33,10 @@ type Backend struct {
|
||||
|
||||
config BackendConfig
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewBackend(cfg *signaling.BackendConfig, logger *zap.Logger) (signaling.Backend, error) {
|
||||
func NewBackend(cfg *signaling.BackendConfig, logger *log.Logger) (signaling.Backend, error) {
|
||||
var err error
|
||||
|
||||
b := &Backend{
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/buildinfo"
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/proto"
|
||||
signalingproto "github.com/stv0g/cunicu/pkg/proto/signaling"
|
||||
"github.com/stv0g/cunicu/pkg/signaling"
|
||||
@@ -29,11 +30,11 @@ type Server struct {
|
||||
|
||||
*grpc.Server
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewSignalingServer(opts ...grpc.ServerOption) *Server {
|
||||
logger := zap.L().Named("grpc.server")
|
||||
logger := log.Global.Named("grpc.server")
|
||||
|
||||
s := &Server{
|
||||
topicRegistry: topicRegistry{
|
||||
|
@@ -13,9 +13,9 @@ import (
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
icex "github.com/stv0g/cunicu/pkg/ice"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/pkg/proto"
|
||||
signalingproto "github.com/stv0g/cunicu/pkg/proto/signaling"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
@@ -106,14 +106,14 @@ type RelayAPIServer struct {
|
||||
|
||||
*grpc.Server
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewRelayAPIServer(relays []RelayInfo, opts ...grpc.ServerOption) (*RelayAPIServer, error) {
|
||||
s := &RelayAPIServer{
|
||||
relays: relays,
|
||||
Server: grpc.NewServer(opts...),
|
||||
logger: zap.L().Named("grpc.relay"),
|
||||
logger: log.Global.Named("grpc.relay"),
|
||||
}
|
||||
|
||||
signalingproto.RegisterRelayRegistryServer(s, s)
|
||||
|
@@ -7,9 +7,9 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
signalingproto "github.com/stv0g/cunicu/pkg/proto/signaling"
|
||||
"github.com/stv0g/cunicu/pkg/signaling"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
@@ -23,10 +23,10 @@ func init() { //nolint:gochecknoinits
|
||||
}
|
||||
|
||||
type Backend struct {
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewBackend(cfg *signaling.BackendConfig, logger *zap.Logger) (signaling.Backend, error) {
|
||||
func NewBackend(cfg *signaling.BackendConfig, logger *log.Logger) (signaling.Backend, error) {
|
||||
b := &Backend{
|
||||
logger: logger,
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
@@ -134,7 +135,7 @@ func (s *Subscription) NewMessage(env *Envelope) error {
|
||||
return err
|
||||
}
|
||||
|
||||
zap.L().Named("backend").Debug("Received signaling message", zap.Any("msg", msg), zap.Any("pkp", pkp))
|
||||
log.Global.Named("backend").Debug("Received signaling message", zap.Any("msg", msg), zap.Any("pkp", pkp))
|
||||
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
@@ -25,6 +25,26 @@ func (a *ansiStripper) Write(p []byte) (int, error) {
|
||||
return a.Writer.Write(line)
|
||||
}
|
||||
|
||||
type WriteSyncer interface {
|
||||
io.Writer
|
||||
Sync() error
|
||||
}
|
||||
|
||||
type ansiStripperSynced struct {
|
||||
WriteSyncer
|
||||
}
|
||||
|
||||
func NewANSIStripperSynced(wr WriteSyncer) WriteSyncer {
|
||||
return &ansiStripperSynced{
|
||||
WriteSyncer: wr,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *ansiStripperSynced) Write(p []byte) (int, error) {
|
||||
line := stripANSI.ReplaceAll(p, []byte{})
|
||||
return a.WriteSyncer.Write(line)
|
||||
}
|
||||
|
||||
func StripANSI(s string) string {
|
||||
return stripANSI.ReplaceAllString(s, "")
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/pion/ice/v2"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
netx "github.com/stv0g/cunicu/pkg/net"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
@@ -52,10 +53,10 @@ type Bind struct {
|
||||
|
||||
endpoints sync.Map
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewBind(logger *zap.Logger) *Bind {
|
||||
func NewBind(logger *log.Logger) *Bind {
|
||||
return &Bind{
|
||||
logger: logger.Named("bind"),
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
wgconn "golang.zx2c4.com/wireguard/conn"
|
||||
)
|
||||
@@ -21,10 +22,10 @@ type BindPacketConn struct {
|
||||
net.PacketConn
|
||||
|
||||
bind *Bind
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewBindPacketConn(bind *Bind, conn net.PacketConn, logger *zap.Logger) *BindPacketConn {
|
||||
func NewBindPacketConn(bind *Bind, conn net.PacketConn, logger *log.Logger) *BindPacketConn {
|
||||
return &BindPacketConn{
|
||||
PacketConn: conn,
|
||||
bind: bind,
|
||||
|
@@ -12,12 +12,13 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func CleanupUserSockets() error {
|
||||
logger := zap.L().Named("wg")
|
||||
logger := log.Global.Named("wg")
|
||||
|
||||
// Ignore non-existing dir
|
||||
if _, err := os.Stat(SocketPath); err != nil && errors.Is(err, os.ErrNotExist) {
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
osx "github.com/stv0g/cunicu/pkg/os"
|
||||
"github.com/stv0g/cunicu/pkg/tty"
|
||||
"github.com/stv0g/cunicu/test"
|
||||
@@ -19,10 +20,9 @@ import (
|
||||
g "github.com/stv0g/gont/v2/pkg"
|
||||
gopt "github.com/stv0g/gont/v2/pkg/options"
|
||||
copt "github.com/stv0g/gont/v2/pkg/options/capture"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var logger *zap.Logger
|
||||
var logger *log.Logger
|
||||
|
||||
type Network struct {
|
||||
*g.Network
|
||||
@@ -235,7 +235,8 @@ func (n *Network) Init() {
|
||||
Expect(err).To(Succeed(), "Failed to create test case result directory: %s", err)
|
||||
|
||||
// Ginkgo log
|
||||
logger = test.SetupLoggingWithFile(logFilename, true)
|
||||
logger, err = test.SetupLoggingWithFile(logFilename, true)
|
||||
Expect(err).To(Succeed())
|
||||
|
||||
n.AgentOptions = append(n.AgentOptions,
|
||||
gopt.RedirectToLog(false),
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/crypto"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
rpcproto "github.com/stv0g/cunicu/pkg/proto/rpc"
|
||||
"github.com/stv0g/cunicu/pkg/rpc"
|
||||
g "github.com/stv0g/gont/v2/pkg"
|
||||
@@ -41,7 +42,7 @@ type Agent struct {
|
||||
|
||||
logFile io.WriteCloser
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewAgent(m *g.Network, name string, opts ...g.Option) (*Agent, error) {
|
||||
@@ -53,7 +54,7 @@ func NewAgent(m *g.Network, name string, opts ...g.Option) (*Agent, error) {
|
||||
a := &Agent{
|
||||
Host: h,
|
||||
|
||||
logger: zap.L().Named("node.agent").With(zap.String("node", name)),
|
||||
logger: log.Global.Named("node.agent").With(zap.String("node", name)),
|
||||
}
|
||||
|
||||
// Apply agent options
|
||||
|
@@ -7,8 +7,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/test"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@@ -128,7 +128,7 @@ func (al AgentList) ForEachInterfacePairOneDir(cb func(a, b *WireGuardInterface)
|
||||
|
||||
func (al AgentList) WaitConnectionsReady(ctx context.Context) error {
|
||||
handler := &test.DefaultProgressHandler{
|
||||
Logger: zap.L().Named("wait-conns"),
|
||||
Logger: log.Global.Named("wait-conns"),
|
||||
}
|
||||
|
||||
return test.WithProgress(ctx, func(started, completed chan string) error {
|
||||
@@ -146,7 +146,7 @@ func (al AgentList) WaitConnectionsReady(ctx context.Context) error {
|
||||
|
||||
func (al AgentList) PingPeers(ctx context.Context) error {
|
||||
handler := &test.DefaultProgressHandler{
|
||||
Logger: zap.L().Named("ping"),
|
||||
Logger: log.Global.Named("ping"),
|
||||
}
|
||||
|
||||
return test.WithProgress(ctx, func(started, completed chan string) error {
|
||||
|
@@ -14,6 +14,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
"github.com/stv0g/cunicu/test"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -93,7 +94,7 @@ func buildBinary(packagePath string) (string, []string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
logger := zap.L().Named("builder")
|
||||
logger := log.Global.Named("builder")
|
||||
|
||||
var cmdArgs []string
|
||||
var test bool
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pion/stun"
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
g "github.com/stv0g/gont/v2/pkg"
|
||||
copt "github.com/stv0g/gont/v2/pkg/options/cmd"
|
||||
"go.uber.org/zap"
|
||||
@@ -27,7 +28,7 @@ type CoturnNode struct {
|
||||
|
||||
Config map[string]string
|
||||
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewCoturnNode(n *g.Network, name string, opts ...g.Option) (*CoturnNode, error) {
|
||||
@@ -52,7 +53,7 @@ func NewCoturnNode(n *g.Network, name string, opts ...g.Option) (*CoturnNode, er
|
||||
"realm": "cunicu",
|
||||
"cli-password": "cunicu",
|
||||
},
|
||||
logger: zap.L().Named("node.relay").With(zap.String("node", name)),
|
||||
logger: log.Global.Named("node.relay").With(zap.String("node", name)),
|
||||
}
|
||||
|
||||
t.Config["user"] = fmt.Sprintf("%s:%s", t.Username(), t.Password())
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
g "github.com/stv0g/gont/v2/pkg"
|
||||
copt "github.com/stv0g/gont/v2/pkg/options/cmd"
|
||||
"go.uber.org/zap"
|
||||
@@ -24,7 +25,7 @@ type GrpcSignalingNode struct {
|
||||
Command *g.Cmd
|
||||
|
||||
logFile io.WriteCloser
|
||||
logger *zap.Logger
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewGrpcSignalingNode(n *g.Network, name string, opts ...g.Option) (*GrpcSignalingNode, error) {
|
||||
@@ -36,7 +37,7 @@ func NewGrpcSignalingNode(n *g.Network, name string, opts ...g.Option) (*GrpcSig
|
||||
t := &GrpcSignalingNode{
|
||||
Host: h,
|
||||
port: 8080,
|
||||
logger: zap.L().Named("node.signal").With(zap.String("node", name)),
|
||||
logger: log.Global.Named("node.signal").With(zap.String("node", name)),
|
||||
}
|
||||
|
||||
return t, nil
|
||||
|
13
test/log.go
13
test/log.go
@@ -29,11 +29,16 @@ func (w *writerWrapper) Sync() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetupLogging() *zap.Logger {
|
||||
return SetupLoggingWithFile("", false)
|
||||
func SetupLogging() *log.Logger {
|
||||
logger, err := SetupLoggingWithFile("", false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return logger
|
||||
}
|
||||
|
||||
func SetupLoggingWithFile(fn string, truncate bool) *zap.Logger {
|
||||
func SetupLoggingWithFile(fn string, truncate bool) (*log.Logger, error) {
|
||||
if err := zap.RegisterSink("ginkgo", func(u *url.URL) (zap.Sink, error) {
|
||||
return &writerWrapper{
|
||||
GinkgoWriterInterface: ginkgo.GinkgoWriter,
|
||||
@@ -65,5 +70,5 @@ func SetupLoggingWithFile(fn string, truncate bool) *zap.Logger {
|
||||
ginkgo.GinkgoWriter.TeeTo(tty.NewANSIStripper(f))
|
||||
}
|
||||
|
||||
return log.SetupLogging(zap.DebugLevel, 10, outputPaths, outputPaths, true)
|
||||
return log.SetupLogging("", outputPaths, true)
|
||||
}
|
||||
|
@@ -10,6 +10,8 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/stv0g/cunicu/pkg/log"
|
||||
)
|
||||
|
||||
type ProgressHandler interface {
|
||||
@@ -84,7 +86,7 @@ func WithProgress(ctx context.Context, run func(started, completed chan string)
|
||||
var _ ProgressHandler = (*DefaultProgressHandler)(nil)
|
||||
|
||||
type DefaultProgressHandler struct {
|
||||
Logger *zap.Logger
|
||||
Logger *log.Logger
|
||||
}
|
||||
|
||||
func (ph *DefaultProgressHandler) OnProgress(cntStarted, cntCompleted, cntFailed uint, durElapsed, durRemaining time.Duration, idsMissing []string) {
|
||||
@@ -108,7 +110,7 @@ func (ph *DefaultProgressHandler) OnProgress(cntStarted, cntCompleted, cntFailed
|
||||
|
||||
func (ph *DefaultProgressHandler) OnStart() {
|
||||
if ph.Logger == nil {
|
||||
ph.Logger = zap.L().Named("progress")
|
||||
ph.Logger = log.Global.Named("progress")
|
||||
}
|
||||
|
||||
ph.Logger.Info("Started")
|
||||
|
Reference in New Issue
Block a user