diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 09d9c493d1..2a8af743fe 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -185,7 +185,7 @@ func init() { app.Before = func(ctx *cli.Context) error { runtime.GOMAXPROCS(runtime.NumCPU()) - if err := debug.Setup(ctx); err != nil { + if err := debug.Setup(ctx, ctx.GlobalBool(utils.DashboardEnabledFlag.Name), utils.DataDirFlag.Value.Value); err != nil { return err } // Start system runtime metrics collection diff --git a/cmd/swarm/main.go b/cmd/swarm/main.go index 360020b77b..8ac0f884dc 100644 --- a/cmd/swarm/main.go +++ b/cmd/swarm/main.go @@ -363,7 +363,7 @@ DEPRECATED: use 'swarm db clean'. app.Flags = append(app.Flags, swarmmetrics.Flags...) app.Before = func(ctx *cli.Context) error { runtime.GOMAXPROCS(runtime.NumCPU()) - if err := debug.Setup(ctx); err != nil { + if err := debug.Setup(ctx, ctx.GlobalBool(utils.DashboardEnabledFlag.Name), utils.DataDirFlag.Value.Value); err != nil { return err } swarmmetrics.Setup(ctx) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 5eb58e9eef..4b1785d26e 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -108,13 +108,17 @@ func init() { // Setup initializes profiling and logging based on the CLI flags. // It should be called as early as possible in the program. -func Setup(ctx *cli.Context) error { +func Setup(ctx *cli.Context, dashboard bool, path string) error { // logging log.PrintOrigins(ctx.GlobalBool(debugFlag.Name)) glogger.Verbosity(log.Lvl(ctx.GlobalInt(verbosityFlag.Name))) glogger.Vmodule(ctx.GlobalString(vmoduleFlag.Name)) glogger.BacktraceAt(ctx.GlobalString(backtraceAtFlag.Name)) - log.Root().SetHandler(glogger) + h := log.Handler(glogger) + if dashboard { + h = log.MultiHandler(h, log.DashboardHandler(path+"/dashboard/logs")) + } + log.Root().SetHandler(h) // profiling, tracing runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) diff --git a/log/handler.go b/log/handler.go index 3c99114dcb..657ec0972b 100644 --- a/log/handler.go +++ b/log/handler.go @@ -9,6 +9,7 @@ import ( "sync" "github.com/go-stack/stack" + "strings" ) // Handler defines where and how log records are written. @@ -70,6 +71,36 @@ func FileHandler(path string, fmtr Format) (Handler, error) { return closingHandler{f, StreamHandler(f, fmtr)}, nil } +// DashboardHandler returns a handler which writes log records to file chunks +// at the given path. When a file's size reaches the 1MB, the handler creates +// a new file named with the timestamp of the first log record it will contain. +func DashboardHandler(path string) Handler { + if _, err := os.Stat(path); os.IsNotExist(err) { + if err = os.MkdirAll(path, 0755); err != nil { + // TODO (kurkomisi): handle error? + return DiscardHandler() + } + } + + var size uint + maxSize := uint(1048576) + var h Handler + formatter := JsonFormat() + + return FuncHandler(func(r *Record) error { + var err error + if h == nil || size > maxSize { + if h, err = FileHandler(fmt.Sprintf("%s/%s.log", path, + strings.Replace(r.Time.Format("060102150405.00"), ".", "", 1)), formatter); err != nil { + return err + } + size = 0 + } + size += uint(len(formatter.Format(r))) + return h.Log(r) + }) +} + // NetHandler opens a socket to the given address and writes records // over the connection. func NetHandler(network, addr string, fmtr Format) (Handler, error) {