Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
47af53f9
Unverified
Commit
47af53f9
authored
Feb 21, 2017
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
log: implement a glog style pattern matching handler
parent
3f923f39
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
227 additions
and
0 deletions
+227
-0
handler_glog.go
log/handler_glog.go
+227
-0
No files found.
log/handler_glog.go
0 → 100644
View file @
47af53f9
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
log
import
(
"errors"
"fmt"
"regexp"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
)
// errVmoduleSyntax is returned when a user vmodule pattern is invalid.
var
errVmoduleSyntax
=
errors
.
New
(
"expect comma-separated list of filename=N"
)
// errTraceSyntax is returned when a user backtrace pattern is invalid.
var
errTraceSyntax
=
errors
.
New
(
"expect file.go:234"
)
// GlogHandler is a log handler that mimics the filtering features of Google's
// glog logger: setting global log levels; overriding with callsite pattern
// matches; and requesting backtraces at certain positions.
type
GlogHandler
struct
{
origin
Handler
// The origin handler this wraps
level
uint32
// Current log level, atomically accessible
override
uint32
// Flag whether overrides are used, atomically accessible
backtrace
uint32
// Flag whether backtrace location is set
patterns
[]
pattern
// Current list of patterns to override with
siteCache
map
[
uintptr
]
Lvl
// 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
// to Google's glog logger. The returned handler implements Handler.
func
NewGlogHandler
(
h
Handler
)
*
GlogHandler
{
return
&
GlogHandler
{
origin
:
h
,
}
}
// pattern contains a filter for the Vmodule option, holding a verbosity level
// and a file pattern to match.
type
pattern
struct
{
pattern
*
regexp
.
Regexp
level
Lvl
}
// Verbosity sets the glog verbosity ceiling. The verbosity of individual packages
// and source files can be raised using Vmodule.
func
(
h
*
GlogHandler
)
Verbosity
(
level
Lvl
)
{
atomic
.
StoreUint32
(
&
h
.
level
,
uint32
(
level
))
}
// Vmodule sets the glog verbosity pattern.
//
// The syntax of the argument is a comma-separated list of pattern=N, where the
// pattern is a literal file name or "glob" pattern matching and N is a V level.
//
// For instance:
//
// pattern="gopher.go=3"
// sets the V level to 3 in all Go files named "gopher.go"
//
// pattern="foo=3"
// sets V to 3 in all files of any packages whose import path ends in "foo"
//
// pattern="foo/*=3"
// sets V to 3 in all files of any packages whose import path contains "foo"
func
(
h
*
GlogHandler
)
Vmodule
(
ruleset
string
)
error
{
var
filter
[]
pattern
for
_
,
rule
:=
range
strings
.
Split
(
ruleset
,
","
)
{
// Empty strings such as from a trailing comma can be ignored
if
len
(
rule
)
==
0
{
continue
}
// Ensure we have a pattern = level filter rule
parts
:=
strings
.
Split
(
rule
,
"="
)
if
len
(
parts
)
!=
2
{
return
errVmoduleSyntax
}
parts
[
0
]
=
strings
.
TrimSpace
(
parts
[
0
])
parts
[
1
]
=
strings
.
TrimSpace
(
parts
[
1
])
if
len
(
parts
[
0
])
==
0
||
len
(
parts
[
1
])
==
0
{
return
errVmoduleSyntax
}
// Parse the level and if correct, assemble the filter rule
level
,
err
:=
strconv
.
Atoi
(
parts
[
1
])
if
err
!=
nil
{
return
errVmoduleSyntax
}
if
level
<=
0
{
continue
// Ignore. It's harmless but no point in paying the overhead.
}
// Compile the rule pattern into a regular expression
matcher
:=
".*"
for
_
,
comp
:=
range
strings
.
Split
(
parts
[
0
],
"/"
)
{
if
comp
==
"*"
{
matcher
+=
"(/.*)?"
}
else
if
comp
!=
""
{
matcher
+=
"/"
+
regexp
.
QuoteMeta
(
comp
)
}
}
if
!
strings
.
HasSuffix
(
parts
[
0
],
".go"
)
{
matcher
+=
"/[^/]+
\\
.go"
}
matcher
=
matcher
+
"$"
re
,
_
:=
regexp
.
Compile
(
matcher
)
filter
=
append
(
filter
,
pattern
{
re
,
Lvl
(
level
)})
}
// Swap out the vmodule pattern for the new filter system
h
.
lock
.
Lock
()
defer
h
.
lock
.
Unlock
()
h
.
patterns
=
filter
h
.
siteCache
=
make
(
map
[
uintptr
]
Lvl
)
atomic
.
StoreUint32
(
&
h
.
override
,
uint32
(
len
(
filter
)))
return
nil
}
// BacktraceAt sets the glog backtrace location. When set to a file and line
// number holding a logging statement, a stack trace will be written to the Info
// log whenever execution hits that statement.
//
// Unlike with Vmodule, the ".go" must be present.
func
(
h
*
GlogHandler
)
BacktraceAt
(
location
string
)
error
{
// Ensure the backtrace location contains two non-empty elements
parts
:=
strings
.
Split
(
location
,
":"
)
if
len
(
parts
)
!=
2
{
return
errTraceSyntax
}
parts
[
0
]
=
strings
.
TrimSpace
(
parts
[
0
])
parts
[
1
]
=
strings
.
TrimSpace
(
parts
[
1
])
if
len
(
parts
[
0
])
==
0
||
len
(
parts
[
1
])
==
0
{
return
errTraceSyntax
}
// Ensure the .go prefix is present and the line is valid
if
!
strings
.
HasSuffix
(
parts
[
0
],
".go"
)
{
return
errTraceSyntax
}
if
_
,
err
:=
strconv
.
Atoi
(
parts
[
1
]);
err
!=
nil
{
return
errTraceSyntax
}
// All seems valid
h
.
lock
.
Lock
()
defer
h
.
lock
.
Unlock
()
h
.
location
=
location
atomic
.
StoreUint32
(
&
h
.
backtrace
,
uint32
(
len
(
location
)))
return
nil
}
// Log implements Handler.Log, filtering a log record through the global, local
// and backtrace filters, finally emitting it if either allow it through.
func
(
h
*
GlogHandler
)
Log
(
r
*
Record
)
error
{
// If backtracing is requested, check whether this is the callsite
if
atomic
.
LoadUint32
(
&
h
.
backtrace
)
>
0
{
// Everything below here is slow. Although we could cache the call sites the
// same way as for vmodule, backtracing is so rare it's not worth the extra
// complexity.
h
.
lock
.
RLock
()
match
:=
h
.
location
==
r
.
Call
.
String
()
h
.
lock
.
RUnlock
()
if
match
{
// Callsite matched, raise the log level to info and gather the stacks
r
.
Lvl
=
LvlInfo
buf
:=
make
([]
byte
,
1024
*
1024
)
buf
=
buf
[
:
runtime
.
Stack
(
buf
,
true
)]
r
.
Msg
+=
"
\n\n
"
+
string
(
buf
)
}
}
// If the global log level allows, fast track logging
if
atomic
.
LoadUint32
(
&
h
.
level
)
>=
uint32
(
r
.
Lvl
)
{
return
h
.
origin
.
Log
(
r
)
}
// If no local overrides are present, fast track skipping
if
atomic
.
LoadUint32
(
&
h
.
override
)
==
0
{
return
nil
}
// Check callsite cache for previously calculated log levels
h
.
lock
.
RLock
()
lvl
,
ok
:=
h
.
siteCache
[
r
.
Call
.
PC
()]
h
.
lock
.
RUnlock
()
// If we didn't cache the callsite yet, calculate it
if
!
ok
{
h
.
lock
.
Lock
()
for
_
,
rule
:=
range
h
.
patterns
{
if
rule
.
pattern
.
MatchString
(
fmt
.
Sprintf
(
"%+s"
,
r
.
Call
))
{
h
.
siteCache
[
r
.
Call
.
PC
()],
lvl
,
ok
=
rule
.
level
,
rule
.
level
,
true
break
}
}
// If no rule matched, remember to drop log the next time
if
!
ok
{
h
.
siteCache
[
r
.
Call
.
PC
()]
=
0
}
h
.
lock
.
Unlock
()
}
if
lvl
>=
r
.
Lvl
{
return
h
.
origin
.
Log
(
r
)
}
return
nil
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment