Update to reinstate logfile flag

Fix log to stdout instead of stderr
update files to use new stdout function
Add a flag to toggle logging to temp files instead of stdout
This commit is contained in:
Firescar96 2016-06-03 03:07:13 -04:00
parent ab664c7e17
commit bcf99c2ee9
10 changed files with 98 additions and 43 deletions

View file

@ -42,7 +42,7 @@ func main() {
) )
flag.Var(glog.GetVerbosity(), "verbosity", "log verbosity (0-9)") flag.Var(glog.GetVerbosity(), "verbosity", "log verbosity (0-9)")
flag.Var(glog.GetVModule(), "vmodule", "log verbosity pattern") flag.Var(glog.GetVModule(), "vmodule", "log verbosity pattern")
glog.SetToStderr(true) glog.SetToStdout(true)
flag.Parse() flag.Parse()
if *genKey != "" { if *genKey != "" {

View file

@ -201,7 +201,7 @@ func setupApp(c *cli.Context) {
} }
func main() { func main() {
glog.SetToStderr(true) glog.SetToStdout(true)
app := cli.NewApp() app := cli.NewApp()
app.Name = "ethtest" app.Name = "ethtest"

View file

@ -105,7 +105,7 @@ func init() {
} }
func run(ctx *cli.Context) { func run(ctx *cli.Context) {
glog.SetToStderr(true) glog.SetToStdout(true)
glog.SetV(ctx.GlobalInt(VerbosityFlag.Name)) glog.SetV(ctx.GlobalInt(VerbosityFlag.Name))
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()

View file

@ -50,7 +50,7 @@ func main() {
// Enable logging errors, we really do want to see those // Enable logging errors, we really do want to see those
glog.SetV(2) glog.SetV(2)
glog.SetToStderr(true) glog.SetToStdout(true)
// Load the test suite to run the RPC against // Load the test suite to run the RPC against
tests, err := tests.LoadBlockTests(*testFile) tests, err := tests.LoadBlockTests(*testFile)

View file

@ -30,7 +30,7 @@ import (
) )
func init() { func init() {
// glog.SetToStderr(true) // glog.SetToStdout(true)
// glog.SetV(6) // glog.SetV(6)
} }

View file

@ -38,6 +38,15 @@ var (
Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=6,p2p=5)", Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=6,p2p=5)",
Value: glog.GetVModule(), Value: glog.GetVModule(),
} }
logFileFlag = cli.StringFlag{
Name: "logfile",
Usage: "Log output to this file (default = no log file generated)",
Value: "",
}
templogFileFlag = cli.BoolFlag{
Name: "templog",
Usage: "Disables console output and sends output to timestamped files in the OS temp directory on an interval",
}
backtraceAtFlag = cli.GenericFlag{ backtraceAtFlag = cli.GenericFlag{
Name: "backtrace", Name: "backtrace",
Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")",
@ -73,7 +82,7 @@ var (
// Flags holds all command-line flags required for debugging. // Flags holds all command-line flags required for debugging.
var Flags = []cli.Flag{ var Flags = []cli.Flag{
verbosityFlag, vmoduleFlag, backtraceAtFlag, verbosityFlag, vmoduleFlag, logFileFlag, templogFileFlag, backtraceAtFlag,
pprofFlag, pprofPortFlag, pprofFlag, pprofPortFlag,
memprofilerateFlag, blockprofilerateFlag, cpuprofileFlag, traceFlag, memprofilerateFlag, blockprofilerateFlag, cpuprofileFlag, traceFlag,
} }
@ -83,7 +92,7 @@ var Flags = []cli.Flag{
func Setup(ctx *cli.Context) error { func Setup(ctx *cli.Context) error {
// logging // logging
glog.CopyStandardLogTo("INFO") glog.CopyStandardLogTo("INFO")
glog.SetToStderr(true) glog.SetToStdout(!ctx.GlobalIsSet(templogFileFlag.Name))
// profiling, tracing // profiling, tracing
runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name)
@ -107,6 +116,12 @@ func Setup(ctx *cli.Context) error {
glog.Errorln(http.ListenAndServe(address, nil)) glog.Errorln(http.ListenAndServe(address, nil))
}() }()
} }
//glog.SetV(ctx.GlobalInt(verbosityFlag.Name))
if ctx.GlobalIsSet(logFileFlag.Name) {
logger.New("", ctx.GlobalString(logFileFlag.Name), ctx.GlobalInt(verbosityFlag.Name))
}
return nil return nil
} }

View file

@ -39,11 +39,11 @@
// This package provides several flags that modify this behavior. // This package provides several flags that modify this behavior.
// As a result, flag.Parse must be called before any logging is done. // As a result, flag.Parse must be called before any logging is done.
// //
// -logtostderr=false // -logtostdout=false
// Logs are written to standard error instead of to files. // Logs are written to standard error instead of to files.
// -alsologtostderr=false // -alsologtostdout=false
// Logs are written to standard error as well as to files. // Logs are written to standard error as well as to files.
// -stderrthreshold=ERROR // -stdoutthreshold=ERROR
// Log events at or above this severity are logged to standard // Log events at or above this severity are logged to standard
// error as well as to files. // error as well as to files.
// -log_dir="" // -log_dir=""
@ -91,10 +91,12 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/logger"
) )
// severity identifies the sort of log: info, warning etc. It also implements // severity identifies the sort of log: info, warning etc. It also implements
// the flag.Value interface. The -stderrthreshold flag is of type severity and // the flag.Value interface. The -stdoutthreshold flag is of type severity and
// should be modified only through the flag.Value interface. The values match // should be modified only through the flag.Value interface. The values match
// the corresponding constants in C++. // the corresponding constants in C++.
type severity int32 // sync/atomic int32 type severity int32 // sync/atomic int32
@ -138,10 +140,10 @@ func SetV(v int) {
logging.verbosity.set(Level(v)) logging.verbosity.set(Level(v))
} }
// SetToStderr sets the global output style // SetToStdout sets the global output style
func SetToStderr(toStderr bool) { func SetToStdout(toStdout bool) {
logging.mu.Lock() logging.mu.Lock()
logging.toStderr = toStderr logging.toStdout = toStdout
logging.mu.Unlock() logging.mu.Unlock()
} }
@ -193,7 +195,7 @@ func (s *severity) Set(value string) error {
} }
threshold = severity(v) threshold = severity(v)
} }
logging.stderrThreshold.set(threshold) logging.stdoutThreshold.set(threshold)
return nil return nil
} }
@ -365,7 +367,7 @@ func compileModulePattern(pat string) (*regexp.Regexp, error) {
return regexp.Compile(re + "$") return regexp.Compile(re + "$")
} }
// traceLocation represents the setting of the -log_backtrace_at flag. // TraceLocation represents the setting of the -log_backtrace_at flag.
type TraceLocation struct { type TraceLocation struct {
file string file string
line int line int
@ -405,7 +407,7 @@ func (t *TraceLocation) Get() interface{} {
var errTraceSyntax = errors.New("syntax error: expect file.go:234") var errTraceSyntax = errors.New("syntax error: expect file.go:234")
// Syntax: -log_backtrace_at=gopherflakes.go:234 // Set syntax: -log_backtrace_at=gopherflakes.go:234
// Note that unlike vmodule the file extension is included here. // Note that unlike vmodule the file extension is included here.
func (t *TraceLocation) Set(value string) error { func (t *TraceLocation) Set(value string) error {
if value == "" { if value == "" {
@ -447,15 +449,15 @@ type flushSyncWriter interface {
} }
func init() { func init() {
//flag.BoolVar(&logging.toStderr, "logtostderr", false, "log to standard error instead of files") //flag.BoolVar(&logging.toStdout, "logtostdout", false, "log to standard error instead of files")
//flag.BoolVar(&logging.alsoToStderr, "alsologtostderr", false, "log to standard error as well as files") //flag.BoolVar(&logging.alsoToStdout, "alsologtostdout", false, "log to standard error as well as files")
//flag.Var(&logging.verbosity, "v", "log level for V logs") //flag.Var(&logging.verbosity, "v", "log level for V logs")
//flag.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr") //flag.Var(&logging.stdoutThreshold, "stdoutthreshold", "logs at or above this threshold go to stdout")
//flag.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging") //flag.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging")
//flag.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace") //flag.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace")
// Default stderrThreshold is ERROR. // Default stdoutThreshold is ERROR.
logging.stderrThreshold = errorLog logging.stdoutThreshold = errorLog
logging.setVState(3, nil, false) logging.setVState(3, nil, false)
go logging.flushDaemon() go logging.flushDaemon()
} }
@ -470,11 +472,11 @@ type loggingT struct {
// Boolean flags. Not handled atomically because the flag.Value interface // Boolean flags. Not handled atomically because the flag.Value interface
// does not let us avoid the =true, and that shorthand is necessary for // does not let us avoid the =true, and that shorthand is necessary for
// compatibility. TODO: does this matter enough to fix? Seems unlikely. // compatibility. TODO: does this matter enough to fix? Seems unlikely.
toStderr bool // The -logtostderr flag. toStdout bool // The -logtostdout flag.
alsoToStderr bool // The -alsologtostderr flag. alsoToStdout bool // The -alsologtostdout flag.
// Level flag. Handled atomically. // Level flag. Handled atomically.
stderrThreshold severity // The -stderrthreshold flag. stdoutThreshold severity // The -stdoutthreshold flag.
// freeList is a list of byte buffers, maintained under freeListMu. // freeList is a list of byte buffers, maintained under freeListMu.
freeList *buffer freeList *buffer
@ -486,8 +488,10 @@ type loggingT struct {
// mu protects the remaining elements of this structure and is // mu protects the remaining elements of this structure and is
// used to synchronize logging. // used to synchronize logging.
mu sync.Mutex mu sync.Mutex
// file holds writer for each of the log types. // file holds the temp directory writer for each of the log types.
file [numSeverity]flushSyncWriter file [numSeverity]flushSyncWriter
// generalLogger holds the logging listeners for each of the log types
generalLogger [numSeverity]*logger.Logger
// pcs is used in V to avoid an allocation when computing the caller's PC. // pcs is used in V to avoid an allocation when computing the caller's PC.
pcs [1]uintptr pcs [1]uintptr
// vmap is a cache of the V Level for each V() call site, identified by PC. // vmap is a cache of the V Level for each V() call site, identified by PC.
@ -709,30 +713,37 @@ func (l *loggingT) printfmt(s severity, format string, args ...interface{}) {
// printWithFileLine behaves like print but uses the provided file and line number. If // printWithFileLine behaves like print but uses the provided file and line number. If
// alsoLogToStderr is true, the log message always appears on standard error; it // alsoLogToStderr is true, the log message always appears on standard error; it
// will also appear in the log file unless --logtostderr is set. // will also appear in the log file unless --logtostdout is set.
func (l *loggingT) printWithFileLine(s severity, file string, line int, alsoToStderr bool, args ...interface{}) { func (l *loggingT) printWithFileLine(s severity, file string, line int, alsoToStdout bool, args ...interface{}) {
buf := l.formatHeader(s, file, line) buf := l.formatHeader(s, file, line)
fmt.Fprint(buf, args...) fmt.Fprint(buf, args...)
if buf.Bytes()[buf.Len()-1] != '\n' { if buf.Bytes()[buf.Len()-1] != '\n' {
buf.WriteByte('\n') buf.WriteByte('\n')
} }
l.output(s, buf, file, line, alsoToStderr) l.output(s, buf, file, line, alsoToStdout)
} }
// output writes the data to the log files and releases the buffer. // output writes the data to the log files and releases the buffer.
func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoToStderr bool) { func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoToStdout bool) {
l.mu.Lock() l.mu.Lock()
if l.traceLocation.isSet() { if l.traceLocation.isSet() {
if l.traceLocation.match(file, line) { if l.traceLocation.match(file, line) {
buf.Write(stacks(false)) buf.Write(stacks(false))
} }
} }
data := buf.Bytes() data := buf.Bytes()
if l.toStderr {
os.Stderr.Write(data) if l.generalLogger[s] == nil {
l.generalLogger[s] = logger.NewLogger(severityName[s])
}
l.generalLogger[s].Info(string(data))
if l.toStdout {
os.Stdout.Write(data)
} else { } else {
if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() { if alsoToStdout || l.alsoToStdout || s >= l.stdoutThreshold.get() {
os.Stderr.Write(data) os.Stdout.Write(data)
} }
if l.file[s] == nil { if l.file[s] == nil {
if err := l.createFiles(s); err != nil { if err := l.createFiles(s); err != nil {
@ -740,6 +751,7 @@ func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoTo
l.exit(err) l.exit(err)
} }
} }
switch s { switch s {
case fatalLog: case fatalLog:
l.file[fatalLog].Write(data) l.file[fatalLog].Write(data)
@ -763,16 +775,13 @@ func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoTo
} }
// Dump all goroutine stacks before exiting. // Dump all goroutine stacks before exiting.
// First, make sure we see the trace for the current goroutine on standard error. // First, make sure we see the trace for the current goroutine on standard error.
// If -logtostderr has been specified, the loop below will do that anyway
// as the first stack in the full dump.
if !l.toStderr {
os.Stderr.Write(stacks(false)) os.Stderr.Write(stacks(false))
}
// Write the stack trace for all goroutines to the files. // Write the stack trace for all goroutines to the files.
trace := stacks(true) trace := stacks(true)
logExitFunc = func(error) {} // If we get a write error, we'll still exit below. logExitFunc = func(error) {} // If we get a write error, we'll still exit below.
for log := fatalLog; log >= infoLog; log-- { for log := fatalLog; log >= infoLog; log-- {
if f := l.file[log]; f != nil { // Can be nil if -logtostderr is set. if f := l.file[log]; f != nil { // Can be nil if -logtostdout is set.
f.Write(trace) f.Write(trace)
} }
} }
@ -835,6 +844,8 @@ var logExitFunc func(error)
// l.mu is held. // l.mu is held.
func (l *loggingT) exit(err error) { func (l *loggingT) exit(err error) {
fmt.Fprintf(os.Stderr, "log: exiting because of error: %s\n", err) fmt.Fprintf(os.Stderr, "log: exiting because of error: %s\n", err)
logger := logger.NewLogger("Exit")
logger.Errorf("log: exiting because of error: %s\n", err)
// If logExitFunc is set, we do that instead of exiting. // If logExitFunc is set, we do that instead of exiting.
if logExitFunc != nil { if logExitFunc != nil {
logExitFunc(err) logExitFunc(err)
@ -995,7 +1006,7 @@ func (lb logBridge) Write(b []byte) (n int, err error) {
line = 1 line = 1
} }
} }
// printWithFileLine with alsoToStderr=true, so standard log messages // printWithFileLine with alsoToStdout=true, so standard log messages
// always appear on standard error. // always appear on standard error.
logging.printWithFileLine(severity(lb), file, line, true, text) logging.printWithFileLine(severity(lb), file, line, true, text)
return len(b), nil return len(b), nil

View file

@ -82,7 +82,7 @@ func contains(s severity, str string, t *testing.T) bool {
// setFlags configures the logging flags how the test expects them. // setFlags configures the logging flags how the test expects them.
func setFlags() { func setFlags() {
logging.toStderr = false logging.toStdout = false
} }
// Test that Info works as advertised. // Test that Info works as advertised.

View file

@ -57,6 +57,10 @@ func NewLogger(tag string) *Logger {
return &Logger{"[" + tag + "] "} return &Logger{"[" + tag + "] "}
} }
func (logger *Logger) Send(level LogLevel, v ...interface{}) {
logMessageC <- stdMsg{level, logger.tag + fmt.Sprint(v...)}
}
func (logger *Logger) Sendln(level LogLevel, v ...interface{}) { func (logger *Logger) Sendln(level LogLevel, v ...interface{}) {
logMessageC <- stdMsg{level, logger.tag + fmt.Sprintln(v...)} logMessageC <- stdMsg{level, logger.tag + fmt.Sprintln(v...)}
} }
@ -65,6 +69,31 @@ func (logger *Logger) Sendf(level LogLevel, format string, v ...interface{}) {
logMessageC <- stdMsg{level, logger.tag + fmt.Sprintf(format, v...)} logMessageC <- stdMsg{level, logger.tag + fmt.Sprintf(format, v...)}
} }
// Error writes a message with ErrorLevel.
func (logger *Logger) Error(v ...interface{}) {
logger.Send(ErrorLevel, v...)
}
// Warn writes a message with WarnLevel.
func (logger *Logger) Warn(v ...interface{}) {
logger.Send(WarnLevel, v...)
}
// Info writes a message with InfoLevel.
func (logger *Logger) Info(v ...interface{}) {
logger.Send(InfoLevel, v...)
}
// Debug writes a message with DebugLevel.
func (logger *Logger) Debug(v ...interface{}) {
logger.Send(DebugLevel, v...)
}
// DebugDetail writes a message with DebugDetailLevel.
func (logger *Logger) DebugDetail(v ...interface{}) {
logger.Send(DebugDetailLevel, v...)
}
// Errorln writes a message with ErrorLevel. // Errorln writes a message with ErrorLevel.
func (logger *Logger) Errorln(v ...interface{}) { func (logger *Logger) Errorln(v ...interface{}) {
logger.Sendln(ErrorLevel, v...) logger.Sendln(ErrorLevel, v...)

View file

@ -32,7 +32,7 @@ import (
func init() { func init() {
// glog.SetV(6) // glog.SetV(6)
// glog.SetToStderr(true) // glog.SetToStdout(true)
} }
type testTransport struct { type testTransport struct {