mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-18 04:41:36 +00:00
Merge remote-tracking branch 'origin/master' into fix/freezer-incorrect-fsync-ordering
This commit is contained in:
commit
b269abadc9
7 changed files with 266 additions and 85 deletions
|
|
@ -115,7 +115,7 @@ var (
|
||||||
Name: "trace.noreturndata",
|
Name: "trace.noreturndata",
|
||||||
Aliases: []string{"noreturndata"},
|
Aliases: []string{"noreturndata"},
|
||||||
Value: true,
|
Value: true,
|
||||||
Usage: "enable return data output",
|
Usage: "disable return data output",
|
||||||
Category: traceCategory,
|
Category: traceCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1899,7 +1899,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
cfg.StatelessSelfValidation = ctx.Bool(VMStatelessSelfValidationFlag.Name)
|
cfg.StatelessSelfValidation = ctx.Bool(VMStatelessSelfValidationFlag.Name)
|
||||||
}
|
}
|
||||||
// Auto-enable StatelessSelfValidation when witness stats are enabled
|
// Auto-enable StatelessSelfValidation when witness stats are enabled
|
||||||
if ctx.Bool(VMWitnessStatsFlag.Name) {
|
if cfg.EnableWitnessStats {
|
||||||
cfg.StatelessSelfValidation = true
|
cfg.StatelessSelfValidation = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
98
eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/eip7702_deauth.json
vendored
Normal file
98
eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/eip7702_deauth.json
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
{
|
||||||
|
"genesis": {
|
||||||
|
"blobGasUsed": "0",
|
||||||
|
"difficulty": "0",
|
||||||
|
"excessBlobGas": "0",
|
||||||
|
"extraData": "0x",
|
||||||
|
"gasLimit": "11511229",
|
||||||
|
"hash": "0x455b93a512baa4ed5e117508b184a6bb03904b94d665ce38931728eca9cdd8fe",
|
||||||
|
"miner": "0x71562b71999873db5b286df957af199ec94617f7",
|
||||||
|
"mixHash": "0x042877c4fab9f022d29590ae83bad89d6181afb1d6e107619911ea52e5901364",
|
||||||
|
"nonce": "0x0000000000000000",
|
||||||
|
"number": "1",
|
||||||
|
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"stateRoot": "0xc8688ad6433e6b9f4edeb82360d2b99c8e919f493a01cacbe7c4a97184f5d043",
|
||||||
|
"timestamp": "1775654796",
|
||||||
|
"alloc": {
|
||||||
|
"0x71562b71999873db5b286df957af199ec94617f7": {
|
||||||
|
"balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffdb64910c3bf7",
|
||||||
|
"nonce": "1"
|
||||||
|
},
|
||||||
|
"0xe85a1c0e9d5b1c9b417c6c1b34c22cd77f623f50": {
|
||||||
|
"balance": "0x0",
|
||||||
|
"code": "0xef0100d313d93607c016a85e63e557a11ca5ab0b53ad83",
|
||||||
|
"codeHash": "0x9eea9f41ed2b35e6234d1e1c14e88c1136f85d56ed1f32a7efc0096d998dad3d",
|
||||||
|
"nonce": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"chainId": 1337,
|
||||||
|
"homesteadBlock": 0,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip155Block": 0,
|
||||||
|
"eip158Block": 0,
|
||||||
|
"byzantiumBlock": 0,
|
||||||
|
"constantinopleBlock": 0,
|
||||||
|
"petersburgBlock": 0,
|
||||||
|
"istanbulBlock": 0,
|
||||||
|
"muirGlacierBlock": 0,
|
||||||
|
"berlinBlock": 0,
|
||||||
|
"londonBlock": 0,
|
||||||
|
"arrowGlacierBlock": 0,
|
||||||
|
"grayGlacierBlock": 0,
|
||||||
|
"shanghaiTime": 0,
|
||||||
|
"cancunTime": 0,
|
||||||
|
"pragueTime": 0,
|
||||||
|
"terminalTotalDifficulty": 0,
|
||||||
|
"blobSchedule": {
|
||||||
|
"cancun": {
|
||||||
|
"target": 3,
|
||||||
|
"max": 6,
|
||||||
|
"baseFeeUpdateFraction": 3338477
|
||||||
|
},
|
||||||
|
"prague": {
|
||||||
|
"target": 6,
|
||||||
|
"max": 9,
|
||||||
|
"baseFeeUpdateFraction": 5007716
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"number": "2",
|
||||||
|
"difficulty": "0",
|
||||||
|
"timestamp": "1775654797",
|
||||||
|
"gasLimit": "11522469",
|
||||||
|
"miner": "0x71562b71999873db5b286df957af199ec94617f7",
|
||||||
|
"baseFeePerGas": "766499147"
|
||||||
|
},
|
||||||
|
"input": "0x04f8cd82053901843b9aca008477359400830186a09471562b71999873db5b286df957af199ec94617f78080c0f85ef85c8205399400000000000000000000000000000000000000000101a011fc0271f2566e7ebe5ddbff6d48ea97a19afa248452a392781096b7e3b89177a0020107ecefe99c90429b416fe4d1eead5a7fa253761e85cd7cdc7df6e5032d7f80a098495fb16c904f0b67b49afe868b28b0159c8df07522bed99ef6ff2cc2ac2935a048857a9c385d91735a9fdccabc66de7a5ea1897f523a5b9a352e281642a76e6b",
|
||||||
|
"tracerConfig": {
|
||||||
|
"diffMode": true
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"post": {
|
||||||
|
"0x71562b71999873db5b286df957af199ec94617f7": {
|
||||||
|
"balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffc1bd12c85eb7",
|
||||||
|
"nonce": 2
|
||||||
|
},
|
||||||
|
"0xe85a1c0e9d5b1c9b417c6c1b34c22cd77f623f50": {
|
||||||
|
"code": "0x",
|
||||||
|
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
||||||
|
"nonce": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pre": {
|
||||||
|
"0x71562b71999873db5b286df957af199ec94617f7": {
|
||||||
|
"balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffdb64910c3bf7",
|
||||||
|
"nonce": 1
|
||||||
|
},
|
||||||
|
"0xe85a1c0e9d5b1c9b417c6c1b34c22cd77f623f50": {
|
||||||
|
"balance": "0x0",
|
||||||
|
"code": "0xef0100d313d93607c016a85e63e557a11ca5ab0b53ad83",
|
||||||
|
"codeHash": "0x9eea9f41ed2b35e6234d1e1c14e88c1136f85d56ed1f32a7efc0096d998dad3d",
|
||||||
|
"nonce": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,14 +16,14 @@ var _ = (*accountMarshaling)(nil)
|
||||||
func (a account) MarshalJSON() ([]byte, error) {
|
func (a account) MarshalJSON() ([]byte, error) {
|
||||||
type account struct {
|
type account struct {
|
||||||
Balance *hexutil.Big `json:"balance,omitempty"`
|
Balance *hexutil.Big `json:"balance,omitempty"`
|
||||||
Code hexutil.Bytes `json:"code,omitempty"`
|
Code *hexutil.Bytes `json:"code,omitempty"`
|
||||||
CodeHash *common.Hash `json:"codeHash,omitempty"`
|
CodeHash *common.Hash `json:"codeHash,omitempty"`
|
||||||
Nonce uint64 `json:"nonce,omitempty"`
|
Nonce uint64 `json:"nonce,omitempty"`
|
||||||
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
||||||
}
|
}
|
||||||
var enc account
|
var enc account
|
||||||
enc.Balance = (*hexutil.Big)(a.Balance)
|
enc.Balance = (*hexutil.Big)(a.Balance)
|
||||||
enc.Code = a.Code
|
enc.Code = (*hexutil.Bytes)(a.Code)
|
||||||
enc.CodeHash = a.CodeHash
|
enc.CodeHash = a.CodeHash
|
||||||
enc.Nonce = a.Nonce
|
enc.Nonce = a.Nonce
|
||||||
enc.Storage = a.Storage
|
enc.Storage = a.Storage
|
||||||
|
|
@ -47,7 +47,7 @@ func (a *account) UnmarshalJSON(input []byte) error {
|
||||||
a.Balance = (*big.Int)(dec.Balance)
|
a.Balance = (*big.Int)(dec.Balance)
|
||||||
}
|
}
|
||||||
if dec.Code != nil {
|
if dec.Code != nil {
|
||||||
a.Code = *dec.Code
|
a.Code = (*[]byte)(dec.Code)
|
||||||
}
|
}
|
||||||
if dec.CodeHash != nil {
|
if dec.CodeHash != nil {
|
||||||
a.CodeHash = dec.CodeHash
|
a.CodeHash = dec.CodeHash
|
||||||
|
|
|
||||||
|
|
@ -44,21 +44,24 @@ func init() {
|
||||||
type stateMap = map[common.Address]*account
|
type stateMap = map[common.Address]*account
|
||||||
|
|
||||||
type account struct {
|
type account struct {
|
||||||
Balance *big.Int `json:"balance,omitempty"`
|
Balance *big.Int `json:"balance,omitempty"`
|
||||||
Code []byte `json:"code,omitempty"`
|
// Code is a pointer so omitempty can omit unchanged code (nil) while
|
||||||
|
// still emitting "0x" when code is cleared (e.g. EIP-7702 deauth).
|
||||||
|
Code *[]byte `json:"code,omitempty"`
|
||||||
CodeHash *common.Hash `json:"codeHash,omitempty"`
|
CodeHash *common.Hash `json:"codeHash,omitempty"`
|
||||||
Nonce uint64 `json:"nonce,omitempty"`
|
Nonce uint64 `json:"nonce,omitempty"`
|
||||||
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
||||||
empty bool
|
|
||||||
|
empty bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *account) exists() bool {
|
func (a *account) exists() bool {
|
||||||
return a.Nonce > 0 || len(a.Code) > 0 || len(a.Storage) > 0 || (a.Balance != nil && a.Balance.Sign() != 0)
|
return a.Nonce > 0 || (a.Code != nil && len(*a.Code) > 0) || len(a.Storage) > 0 || (a.Balance != nil && a.Balance.Sign() != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
type accountMarshaling struct {
|
type accountMarshaling struct {
|
||||||
Balance *hexutil.Big
|
Balance *hexutil.Big
|
||||||
Code hexutil.Bytes
|
Code *hexutil.Bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
type prestateTracer struct {
|
type prestateTracer struct {
|
||||||
|
|
@ -266,24 +269,28 @@ func (t *prestateTracer) processDiffState() {
|
||||||
modified = true
|
modified = true
|
||||||
postAccount.Nonce = newNonce
|
postAccount.Nonce = newNonce
|
||||||
}
|
}
|
||||||
prevCodeHash := common.Hash{}
|
// Empty code hashes are excluded from the prestate, so default
|
||||||
|
// to EmptyCodeHash to match what GetCodeHash returns for codeless accounts.
|
||||||
|
prevCodeHash := types.EmptyCodeHash
|
||||||
if t.pre[addr].CodeHash != nil {
|
if t.pre[addr].CodeHash != nil {
|
||||||
prevCodeHash = *t.pre[addr].CodeHash
|
prevCodeHash = *t.pre[addr].CodeHash
|
||||||
}
|
}
|
||||||
// Empty code hashes are excluded from the prestate. Normalize
|
|
||||||
// the empty code hash to a zero hash to make it comparable.
|
|
||||||
if newCodeHash == types.EmptyCodeHash {
|
|
||||||
newCodeHash = common.Hash{}
|
|
||||||
}
|
|
||||||
if newCodeHash != prevCodeHash {
|
if newCodeHash != prevCodeHash {
|
||||||
modified = true
|
modified = true
|
||||||
postAccount.CodeHash = &newCodeHash
|
postAccount.CodeHash = &newCodeHash
|
||||||
}
|
}
|
||||||
if !t.config.DisableCode {
|
if !t.config.DisableCode {
|
||||||
newCode := t.env.StateDB.GetCode(addr)
|
newCode := t.env.StateDB.GetCode(addr)
|
||||||
if !bytes.Equal(newCode, t.pre[addr].Code) {
|
var prevCode []byte
|
||||||
|
if t.pre[addr].Code != nil {
|
||||||
|
prevCode = *t.pre[addr].Code
|
||||||
|
}
|
||||||
|
if !bytes.Equal(newCode, prevCode) {
|
||||||
modified = true
|
modified = true
|
||||||
postAccount.Code = newCode
|
if newCode == nil {
|
||||||
|
newCode = []byte{}
|
||||||
|
}
|
||||||
|
postAccount.Code = &newCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -323,10 +330,13 @@ func (t *prestateTracer) lookupAccount(addr common.Address) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code := t.env.StateDB.GetCode(addr)
|
||||||
acc := &account{
|
acc := &account{
|
||||||
Balance: t.env.StateDB.GetBalance(addr).ToBig(),
|
Balance: t.env.StateDB.GetBalance(addr).ToBig(),
|
||||||
Nonce: t.env.StateDB.GetNonce(addr),
|
Nonce: t.env.StateDB.GetNonce(addr),
|
||||||
Code: t.env.StateDB.GetCode(addr),
|
}
|
||||||
|
if len(code) > 0 {
|
||||||
|
acc.Code = &code
|
||||||
}
|
}
|
||||||
codeHash := t.env.StateDB.GetCodeHash(addr)
|
codeHash := t.env.StateDB.GetCodeHash(addr)
|
||||||
// If the code is empty, we don't need to store it in the prestate.
|
// If the code is empty, we don't need to store it in the prestate.
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,7 @@ package log
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"maps"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -38,22 +36,22 @@ var errVmoduleSyntax = errors.New("expect comma-separated list of filename=N")
|
||||||
// matches; and requesting backtraces at certain positions.
|
// matches; and requesting backtraces at certain positions.
|
||||||
type GlogHandler struct {
|
type GlogHandler struct {
|
||||||
origin slog.Handler // The origin handler this wraps
|
origin slog.Handler // The origin handler this wraps
|
||||||
|
lock sync.Mutex // synchronizes writes to config
|
||||||
|
config atomic.Pointer[glogConfig]
|
||||||
|
}
|
||||||
|
|
||||||
level atomic.Int32 // Current log level, atomically accessible
|
type glogConfig struct {
|
||||||
override atomic.Bool // Flag whether overrides are used, atomically accessible
|
patterns []pattern
|
||||||
|
cache sync.Map
|
||||||
patterns []pattern // Current list of patterns to override with
|
level slog.Level
|
||||||
siteCache map[uintptr]slog.Level // Cache of callsite pattern evaluations
|
|
||||||
location string // file:line location where to do a stackdump at
|
|
||||||
lock sync.RWMutex // Lock protecting the override pattern list
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGlogHandler creates a new log handler with filtering functionality similar
|
// NewGlogHandler creates a new log handler with filtering functionality similar
|
||||||
// to Google's glog logger. The returned handler implements Handler.
|
// to Google's glog logger. The returned handler implements Handler.
|
||||||
func NewGlogHandler(h slog.Handler) *GlogHandler {
|
func NewGlogHandler(origin slog.Handler) *GlogHandler {
|
||||||
return &GlogHandler{
|
h := &GlogHandler{origin: origin}
|
||||||
origin: h,
|
h.config.Store(new(glogConfig))
|
||||||
}
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// pattern contains a filter for the Vmodule option, holding a verbosity level
|
// pattern contains a filter for the Vmodule option, holding a verbosity level
|
||||||
|
|
@ -66,7 +64,12 @@ type pattern struct {
|
||||||
// Verbosity sets the glog verbosity ceiling. The verbosity of individual packages
|
// Verbosity sets the glog verbosity ceiling. The verbosity of individual packages
|
||||||
// and source files can be raised using Vmodule.
|
// and source files can be raised using Vmodule.
|
||||||
func (h *GlogHandler) Verbosity(level slog.Level) {
|
func (h *GlogHandler) Verbosity(level slog.Level) {
|
||||||
h.level.Store(int32(level))
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
|
||||||
|
cfg := h.config.Load()
|
||||||
|
newcfg := &glogConfig{level: level, patterns: cfg.patterns}
|
||||||
|
h.config.Store(newcfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vmodule sets the glog verbosity pattern.
|
// Vmodule sets the glog verbosity pattern.
|
||||||
|
|
@ -128,13 +131,13 @@ func (h *GlogHandler) Vmodule(ruleset string) error {
|
||||||
re, _ := regexp.Compile(matcher)
|
re, _ := regexp.Compile(matcher)
|
||||||
filter = append(filter, pattern{re, level})
|
filter = append(filter, pattern{re, level})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swap out the vmodule pattern for the new filter system
|
// Swap out the vmodule pattern for the new filter system
|
||||||
h.lock.Lock()
|
h.lock.Lock()
|
||||||
defer h.lock.Unlock()
|
cfg := h.config.Load()
|
||||||
|
newcfg := &glogConfig{level: cfg.level, patterns: filter}
|
||||||
h.patterns = filter
|
h.config.Store(newcfg)
|
||||||
h.siteCache = make(map[uintptr]slog.Level)
|
h.lock.Unlock()
|
||||||
h.override.Store(len(filter) != 0)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -142,30 +145,9 @@ func (h *GlogHandler) Vmodule(ruleset string) error {
|
||||||
// Enabled implements slog.Handler, reporting whether the handler handles records
|
// Enabled implements slog.Handler, reporting whether the handler handles records
|
||||||
// at the given level.
|
// at the given level.
|
||||||
func (h *GlogHandler) Enabled(ctx context.Context, lvl slog.Level) bool {
|
func (h *GlogHandler) Enabled(ctx context.Context, lvl slog.Level) bool {
|
||||||
// fast-track skipping logging if override not enabled and the provided verbosity is above configured
|
// fast-track skipping logging if vmodule is not enabled or level too low
|
||||||
return h.override.Load() || slog.Level(h.level.Load()) <= lvl
|
cfg := h.config.Load()
|
||||||
}
|
return len(cfg.patterns) > 0 || cfg.level <= lvl
|
||||||
|
|
||||||
// WithAttrs implements slog.Handler, returning a new Handler whose attributes
|
|
||||||
// consist of both the receiver's attributes and the arguments.
|
|
||||||
func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
||||||
h.lock.RLock()
|
|
||||||
siteCache := maps.Clone(h.siteCache)
|
|
||||||
h.lock.RUnlock()
|
|
||||||
|
|
||||||
patterns := []pattern{}
|
|
||||||
patterns = append(patterns, h.patterns...)
|
|
||||||
|
|
||||||
res := GlogHandler{
|
|
||||||
origin: h.origin.WithAttrs(attrs),
|
|
||||||
patterns: patterns,
|
|
||||||
siteCache: siteCache,
|
|
||||||
location: h.location,
|
|
||||||
}
|
|
||||||
|
|
||||||
res.level.Store(h.level.Load())
|
|
||||||
res.override.Store(h.override.Load())
|
|
||||||
return &res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithGroup implements slog.Handler, returning a new Handler with the given
|
// WithGroup implements slog.Handler, returning a new Handler with the given
|
||||||
|
|
@ -178,37 +160,70 @@ func (h *GlogHandler) WithGroup(name string) slog.Handler {
|
||||||
|
|
||||||
// Handle implements slog.Handler, filtering a log record through the global,
|
// Handle implements slog.Handler, filtering a log record through the global,
|
||||||
// local and backtrace filters, finally emitting it if either allow it through.
|
// local and backtrace filters, finally emitting it if either allow it through.
|
||||||
func (h *GlogHandler) Handle(_ context.Context, r slog.Record) error {
|
func (h *GlogHandler) Handle(ctx context.Context, r slog.Record) error {
|
||||||
// If the global log level allows, fast track logging
|
return h.handle(ctx, r, h.origin)
|
||||||
if slog.Level(h.level.Load()) <= r.Level {
|
}
|
||||||
return h.origin.Handle(context.Background(), r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check callsite cache for previously calculated log levels
|
func (h *GlogHandler) handle(ctx context.Context, r slog.Record, origin slog.Handler) error {
|
||||||
h.lock.RLock()
|
cfg := h.config.Load()
|
||||||
lvl, ok := h.siteCache[r.PC]
|
|
||||||
h.lock.RUnlock()
|
|
||||||
|
|
||||||
// If we didn't cache the callsite yet, calculate it
|
|
||||||
if !ok {
|
|
||||||
h.lock.Lock()
|
|
||||||
|
|
||||||
|
var lvl slog.Level
|
||||||
|
cachedLvl, ok := cfg.cache.Load(r.PC)
|
||||||
|
if ok {
|
||||||
|
// Fast path: cache hit
|
||||||
|
lvl = cachedLvl.(slog.Level)
|
||||||
|
} else {
|
||||||
|
// Resolve the callsite file.
|
||||||
fs := runtime.CallersFrames([]uintptr{r.PC})
|
fs := runtime.CallersFrames([]uintptr{r.PC})
|
||||||
frame, _ := fs.Next()
|
frame, _ := fs.Next()
|
||||||
|
file := frame.File
|
||||||
for _, rule := range h.patterns {
|
// Match against patterns and cache the level applied at this callsite.
|
||||||
if rule.pattern.MatchString(fmt.Sprintf("+%s", frame.File)) {
|
lvl = cfg.level // default: use global level
|
||||||
h.siteCache[r.PC], lvl, ok = rule.level, rule.level, true
|
for _, rule := range cfg.patterns {
|
||||||
|
if rule.pattern.MatchString("+" + file) {
|
||||||
|
lvl = rule.level
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If no rule matched, remember to drop log the next time
|
cfg.cache.Store(r.PC, lvl)
|
||||||
if !ok {
|
|
||||||
h.siteCache[r.PC] = 0
|
|
||||||
}
|
|
||||||
h.lock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle the message.
|
||||||
if lvl <= r.Level {
|
if lvl <= r.Level {
|
||||||
return h.origin.Handle(context.Background(), r)
|
return origin.Handle(ctx, r)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithAttrs implements slog.Handler, returning a new Handler whose attributes
|
||||||
|
// consist of both the receiver's attributes and the arguments.
|
||||||
|
//
|
||||||
|
// Note the handler created here will still listen to Verbosity and Vmodule settings
|
||||||
|
// done on the original handler.
|
||||||
|
func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||||
|
return &glogWithAttrs{base: h, origin: h.origin.WithAttrs(attrs)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type glogWithAttrs struct {
|
||||||
|
base *GlogHandler
|
||||||
|
origin slog.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wh *glogWithAttrs) Enabled(ctx context.Context, lvl slog.Level) bool {
|
||||||
|
return wh.base.Enabled(ctx, lvl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wh *glogWithAttrs) Handle(ctx context.Context, r slog.Record) error {
|
||||||
|
return wh.base.handle(ctx, r, wh.origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wh *glogWithAttrs) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||||
|
return &glogWithAttrs{base: wh.base, origin: wh.origin.WithAttrs(attrs)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGroup implements slog.Handler, returning a new Handler with the given
|
||||||
|
// group appended to the receiver's existing groups.
|
||||||
|
//
|
||||||
|
// Note, this function is not implemented.
|
||||||
|
func (wh *glogWithAttrs) WithGroup(name string) slog.Handler {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,64 @@ func TestLoggingWithVmodule(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestLoggingWithVmoduleDowngrade checks that vmodule can be downgraded.
|
||||||
|
func TestLoggingWithVmoduleDowngrade(t *testing.T) {
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false))
|
||||||
|
glog.Verbosity(LevelTrace) // Allow all logs globally
|
||||||
|
logger := NewLogger(glog)
|
||||||
|
|
||||||
|
// This should appear (global level allows it)
|
||||||
|
logger.Info("before vmodule downgrade, this should be logged")
|
||||||
|
if !bytes.Contains(out.Bytes(), []byte("before vmodule downgrade")) {
|
||||||
|
t.Fatal("expected 'before vmodule downgrade' to be logged")
|
||||||
|
}
|
||||||
|
out.Reset()
|
||||||
|
|
||||||
|
// Downgrade this file to only allow Warn and above
|
||||||
|
glog.Vmodule("logger_test.go=2")
|
||||||
|
|
||||||
|
// Info should now be filtered out
|
||||||
|
logger.Info("after vmodule downgrade, this should be filtered")
|
||||||
|
if bytes.Contains(out.Bytes(), []byte("after vmodule downgrade, this should be filtered")) {
|
||||||
|
t.Fatal("expected 'after vmodule downgrade, this should be filtered' to NOT be logged after vmodule downgrade")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn should still appear
|
||||||
|
logger.Warn("after vmodule downgrade, this should be logged")
|
||||||
|
if !bytes.Contains(out.Bytes(), []byte("after vmodule downgrade, this should be logged")) {
|
||||||
|
t.Fatal("expected 'should appear' to be logged")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestWithAttrsVerbosityChange checks that verbosity changes affect child loggers.
|
||||||
|
func TestWithAttrsVerbosityChange(t *testing.T) {
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false))
|
||||||
|
glog.Verbosity(LevelInfo)
|
||||||
|
|
||||||
|
// Create a child logger with an extra attribute.
|
||||||
|
child := slog.New(glog.WithAttrs([]slog.Attr{slog.String("peer", "foo")}))
|
||||||
|
|
||||||
|
// Debug should be filtered at Info level.
|
||||||
|
child.Debug("this should be filtered")
|
||||||
|
if bytes.Contains(out.Bytes(), []byte("this should be filtered")) {
|
||||||
|
t.Fatal("expected debug message to be filtered at Info level")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change verbosity on the parent to allow Debug.
|
||||||
|
glog.Verbosity(LevelDebug)
|
||||||
|
|
||||||
|
// Child should pick up the new level and include its attributes.
|
||||||
|
child.Debug("this should be logged")
|
||||||
|
if !bytes.Contains(out.Bytes(), []byte("this should be logged")) {
|
||||||
|
t.Fatal("expected child logger to pick up verbosity change")
|
||||||
|
}
|
||||||
|
if !bytes.Contains(out.Bytes(), []byte("peer=foo")) {
|
||||||
|
t.Fatal("expected child logger to include WithAttrs attributes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTerminalHandlerWithAttrs(t *testing.T) {
|
func TestTerminalHandlerWithAttrs(t *testing.T) {
|
||||||
out := new(bytes.Buffer)
|
out := new(bytes.Buffer)
|
||||||
glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false).WithAttrs([]slog.Attr{slog.String("baz", "bat")}))
|
glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false).WithAttrs([]slog.Attr{slog.String("baz", "bat")}))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue