Skip to content

Commit

Permalink
Customize geth logging - add ability to use both stderr and stdout (e…
Browse files Browse the repository at this point in the history
…thereum#87)

* Add a command-line flag to split console output

Add a command-line flag to split console output into stderr for warning
and above, and stdout for info and below levels.

This allows one to selectively see error/warning output.
The default behavior is still everything to stderr. And to enable this
behavior, pass `--consoleoutput split`

* Modify Android logging to log at different log levels

Before this diff,
All mobile logs were logged at error level `Log.e`

After this diff,
Mobile logs warning and above will be logged at error level `Log.e` and
logs below that like info, debug, verbose etc. will be logged at info
level `Log.i`

As of now, there is no way to customize this behavior for the mobile
logging.
  • Loading branch information
ashishb authored Nov 2, 2018
1 parent 70a0d69 commit 1dc5d58
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 30 deletions.
Binary file modified build/bin/geth.aar
Binary file not shown.
126 changes: 101 additions & 25 deletions internal/debug/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,12 @@ var (
Name: "consoleformat",
Usage: "Write console logs as 'json' or 'term'",
}
stdoutFlag = cli.BoolFlag{
Name: "stdout",
Usage: "Write console logs to stdout (not stderr)",
consoleOutputFlag = cli.StringFlag{
Name: "consoleoutput",
Usage: "(stderr|stdout|split) By default, console output goes to stderr. " +
"In stdout mode, write console logs to stdout (not stderr). " +
"In split mode, write critical(warning, error, and critical) console logs to stderr " +
"and non-critical (info, debug, and trace) to stdout",
}
)

Expand All @@ -101,14 +104,40 @@ var Flags = []cli.Flag{
verbosityFlag, vmoduleFlag, backtraceAtFlag, debugFlag,
pprofFlag, pprofAddrFlag, pprofPortFlag,
memprofilerateFlag, blockprofilerateFlag, cpuprofileFlag, traceFlag,
consoleFormatFlag, stdoutFlag,
consoleFormatFlag, consoleOutputFlag,
}

var (
ostream log.Handler
glogger *log.GlogHandler
)

type StdoutStderrHandler struct {
stdoutHandler log.Handler
stderrHandler log.Handler
}

func (this StdoutStderrHandler) Log(r *log.Record) error {
switch r.Lvl {
case log.LvlCrit:
fallthrough
case log.LvlError:
fallthrough
case log.LvlWarn:
return this.stderrHandler.Log(r)

case log.LvlInfo:
fallthrough
case log.LvlDebug:
fallthrough
case log.LvlTrace:
return this.stdoutHandler.Log(r)

default:
return this.stdoutHandler.Log(r)
}
}

func init() {
ostream = log.StreamHandler(io.Writer(os.Stderr), log.TerminalFormat(false))
glogger = log.NewGlogHandler(ostream)
Expand All @@ -119,28 +148,10 @@ func init() {
func Setup(ctx *cli.Context, logdir string) error {
// logging

var output io.Writer
var usecolor bool
consoleFormat := ctx.GlobalString(consoleFormatFlag.Name)
consoleOutputMode := ctx.GlobalString(consoleOutputFlag.Name)

if ctx.GlobalBool(stdoutFlag.Name) {
output = io.Writer(os.Stdout)
usecolor = (isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())) && os.Getenv("TERM") != "dumb"
if usecolor {
output = colorable.NewColorableStdout()
}
} else {
output = io.Writer(os.Stderr)
usecolor = (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
if usecolor {
output = colorable.NewColorableStderr()
}
}

if consoleFormat := ctx.GlobalString(consoleFormatFlag.Name); consoleFormat == "json" {
ostream = log.StreamHandler(output, log.JSONFormat())
} else {
ostream = log.StreamHandler(output, log.TerminalFormat(usecolor))
}
ostream := CreateStreamHandler(consoleFormat, consoleOutputMode)
glogger = log.NewGlogHandler(ostream)

log.PrintOrigins(ctx.GlobalBool(debugFlag.Name))
Expand Down Expand Up @@ -182,6 +193,71 @@ func Setup(ctx *cli.Context, logdir string) error {
return nil
}

func CreateStreamHandler(consoleFormat string, consoleOutputMode string) log.Handler {
if consoleOutputMode == "stdout" {
usecolor := useColor(os.Stdout)
var output io.Writer
if usecolor {
output = colorable.NewColorableStdout()
} else {
output = io.Writer(os.Stdout)
}
return log.StreamHandler(output, getConsoleLogFormat(consoleFormat, usecolor))
}

// This is the default mode to maintain backward-compatibility with the geth command-line
if consoleOutputMode == "stderr" || len(consoleOutputMode) == 0 {
usecolor := useColor(os.Stderr)
var output io.Writer
if usecolor {
output = colorable.NewColorableStderr()
} else {
output = io.Writer(os.Stderr)
}
return log.StreamHandler(output, getConsoleLogFormat(consoleFormat, usecolor))
}

if consoleOutputMode == "split" {
usecolorStdout := useColor(os.Stdout)
usecolorStderr := useColor(os.Stderr)

var outputStdout io.Writer
var outputStderr io.Writer

if usecolorStdout {
outputStdout = colorable.NewColorableStdout()
} else {
outputStdout = io.Writer(os.Stdout)
}

if usecolorStderr {
outputStderr = colorable.NewColorableStderr()
} else {
outputStderr = io.Writer(os.Stderr)
}

return StdoutStderrHandler{
stdoutHandler: log.StreamHandler(outputStdout, getConsoleLogFormat(consoleFormat, usecolorStdout)),
stderrHandler: log.StreamHandler(outputStderr, getConsoleLogFormat(consoleFormat, usecolorStderr))}
}

panic(fmt.Sprintf("Unexpected value for \"%s\" flag: \"%s\"", consoleOutputFlag.Name, consoleOutputMode))
}

func useColor(file *os.File) bool {
return (isatty.IsTerminal(file.Fd()) || isatty.IsCygwinTerminal(file.Fd())) && os.Getenv("TERM") != "dumb"
}

func getConsoleLogFormat(consoleFormat string, usecolor bool) log.Format {
if consoleFormat == "json" {
return log.JSONFormat()
}
if consoleFormat == "term" || len(consoleFormat) == 0 /* No explicit format specified */ {
return log.TerminalFormat(usecolor)
}
panic(fmt.Sprintf("Unexpected value for \"%s\" flag: \"%s\"", consoleFormatFlag.Name, consoleFormat))
}

func StartPProf(address string) {
// Hook go-metrics into expvar on any /debug/metrics request, load all vars
// from the registry into expvar, and execute regular expvar handler.
Expand Down
5 changes: 3 additions & 2 deletions mobile/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@
package geth

import (
"os"
"runtime"

"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/log"
)

func init() {
handler := debug.CreateStreamHandler("term", "split")
// Initialize the logger
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, handler))

// Initialize the goroutine count
runtime.GOMAXPROCS(runtime.NumCPU())
Expand Down
6 changes: 3 additions & 3 deletions mobile/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
package geth

import (
"os"

"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/log"
)

// SetVerbosity sets the global verbosity level (between 0 and 6 - see logger/verbosity.go).
func SetVerbosity(level int) {
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(level), log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
handler := debug.CreateStreamHandler("term", "split")
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(level), handler))
}

0 comments on commit 1dc5d58

Please sign in to comment.