Commit 9801eb1d authored by protolambda's avatar protolambda

op-service,op-node: utilize dynamic log handler to change log-level

parent 6dcb14f5
......@@ -11,6 +11,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/version"
"github.com/ethereum-optimism/optimism/op-service/eth"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
)
type l2EthClient interface {
......@@ -85,8 +86,13 @@ func (n *adminAPI) SetLogLevel(ctx context.Context, lvlStr string) error {
return err
}
h = log.LvlFilterHandler(lvl, h)
n.log.SetHandler(h)
// We set the log level, and do not wrap the handler with an additional filter handler,
// as the underlying handler would otherwise also still filter with the previous log level.
lvlSetter, ok := h.(oplog.LvlSetter)
if !ok {
return fmt.Errorf("log handler type %T cannot change log level", h)
}
lvlSetter.SetLogLevel(lvl)
return nil
}
......
......@@ -63,6 +63,8 @@ type CLIConfig struct {
Format string // Format the log output. Supported formats: 'text', 'terminal', 'logfmt', 'json', 'json-pretty'
}
// NewLogger creates a new configured logger.
// The log handler of the logger is a LvlSetter, i.e. the log level can be changed as needed.
func NewLogger(ctx *cli.Context, cfg CLIConfig) log.Logger {
var wr io.Writer = os.Stdout
if ctx != nil && ctx.App != nil {
......@@ -70,7 +72,7 @@ func NewLogger(ctx *cli.Context, cfg CLIConfig) log.Logger {
}
handler := log.StreamHandler(wr, Format(cfg.Format, cfg.Color))
handler = log.SyncHandler(handler)
handler = log.LvlFilterHandler(Level(cfg.Level), handler)
handler = NewDynamicLogHandler(Level(cfg.Level), handler)
logger := log.New()
logger.SetHandler(handler)
return logger
......
package log
import "github.com/ethereum/go-ethereum/log"
type LvlSetter interface {
SetLogLevel(lvl log.Lvl)
}
// DynamicLogHandler allow runtime-configuration of the log handler.
type DynamicLogHandler struct {
log.Handler // embedded, to expose any extra methods the underlying handler might provide
maxLvl log.Lvl
}
func NewDynamicLogHandler(lvl log.Lvl, h log.Handler) *DynamicLogHandler {
return &DynamicLogHandler{
Handler: h,
maxLvl: lvl,
}
}
func (d *DynamicLogHandler) SetLogLevel(lvl log.Lvl) {
d.maxLvl = lvl
}
func (d *DynamicLogHandler) Log(r *log.Record) error {
if r.Lvl > d.maxLvl { // lower log level values are more critical
return nil
}
return d.Handler.Log(r) // process the log
}
package log
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/log"
)
func TestDynamicLogHandler_SetLogLevel(t *testing.T) {
var records []*log.Record
h := log.FuncHandler(func(r *log.Record) error {
records = append(records, r)
return nil
})
d := NewDynamicLogHandler(log.LvlInfo, h)
logger := log.New()
logger.SetHandler(d)
logger.Info("hello world") // y
logger.Error("error!") // y
logger.Debug("debugging") // n
// increase log level
logger.GetHandler().(LvlSetter).SetLogLevel(log.LvlDebug)
logger.Info("hello again") // y
logger.Debug("can see debug now") // y
logger.Trace("but no trace") // n
// and decrease log level
logger.GetHandler().(LvlSetter).SetLogLevel(log.LvlWarn)
logger.Warn("visible warning") // y
logger.Info("info should be hidden now") // n
logger.Error("another error") // y
require.Len(t, records, 2+2+2)
require.Equal(t, records[0].Msg, "hello world")
require.Equal(t, records[1].Msg, "error!")
require.Equal(t, records[2].Msg, "hello again")
require.Equal(t, records[3].Msg, "can see debug now")
require.Equal(t, records[4].Msg, "visible warning")
require.Equal(t, records[5].Msg, "another error")
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment