Skip to content
This repository has been archived by the owner on Oct 4, 2019. It is now read-only.

New feature: log rotation #426

Merged
merged 12 commits into from
Dec 12, 2017
Merged

New feature: log rotation #426

merged 12 commits into from
Dec 12, 2017

Conversation

tzdybal
Copy link
Contributor

@tzdybal tzdybal commented Dec 7, 2017

Changes in logger/glog and cmd/geth to implement highly configurable log rotation.
This resolves #421.

@tzdybal
Copy link
Contributor Author

tzdybal commented Dec 7, 2017

I'll add one more thing - parsing of human readable sizes (like 512K, 10M, 2G).

Value: 0,
}
LogMaxTotalSizeFlag = cli.IntFlag{
Name: "log-max-total-size,log-maxtotalsize",
Copy link
Contributor

@whilei whilei Dec 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest naming this log-total-max-size,log-totalmaxsize to stick with the convention established where <max|min>-size and max-age are "syntax units." What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Value: 0,
}
LogIntervalFlag = cli.StringFlag{
Name: "log-interval",
Copy link
Contributor

@whilei whilei Dec 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this one may log-rotate-interval to avoid confusion with log-status which also controls an interval. And/or log-rotation-interval?

Usage: "Maximum age of the oldest log file, valid time units: 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'",
Value: "0",
}
LogCompressFlag = cli.BoolFlag{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make this a BoolTFlag to enable by default?

I guess this would entail establishing defaults for max/min size and age as well, but if we're going to be generating the logs anyways it might be reasonable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to change the default behavior of keeping logs forever by default.
Enabling compression by default seems very reasonable, min/max size also, but I'm not sure about the max age and total size.
My new proposition for default values:

  • compression: true
  • rotation-interval: hourly,
  • min-size: 1MB or less?
  • max-size: I think 10-20 MB should be OK for hourly rotaiton interval (I was running with 50MB limit for few hours, and only time-based rotation happened)
  • max-age, total-max-size - 0 (keep logs forever)

This gives usable logs - easy to seek by date/time, fine-grained if we wan't to remove old ones, compressed files are quite small so they are easy to search even with editor (not only grep).

I think we should run geth version with output/log split, with default level/verbosity/etc, for some time, and find sane defaults for log rotation empirically.

Copy link
Contributor

@whilei whilei Dec 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those defaults seem very reasonable to me. And agree that we should get an empirical sense. We can also, after getting an averaged empirical sense for a timeframe, do a little extrapolation to give a general sense of log growth too. Like if geth makes 50MB of logs a day running full time, then it will make 350MB a week...

}
LogMaxAgeFlag = cli.StringFlag{
Name: "log-max-age,log-maxage",
Usage: "Maximum age of the oldest log file, valid time units: 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also add 'd' and 'w' for days and weeks? For me at least that would be convenient ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And wait a second... max age of oldest log file in nanoseconds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The units are copied from documentation of time.ParseDuration function. I'll change this, i think 'h', 'd', 'w' should be sufficient. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I think those'll be fine

@whilei
Copy link
Contributor

whilei commented Dec 7, 2017

Running notes as I review...

A couple of questions:

  • Are logs ever deleted? Or only gzipped? Yep.

cmd/geth/main.go Outdated
@@ -223,6 +230,40 @@ func makeCLIApp() (app *cli.App) {

runtime.GOMAXPROCS(runtime.NumCPU())

// log-rotation options
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can shove this logic off to its own file cmd/geth/log_context.go? I've also got a bunch of this kind of stuff from the display logs too and it feels yucky to clutter main.go with all this logic.

// shouldRotate checks if we need to rotate the current log file
func (sb *syncBuffer) shouldRotate(len int, now time.Time) bool {
newLen := sb.nbytes + uint64(len)
if newLen <= MinSize {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about adding

if MaxSize == 0 {
	return false
}

or?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, nm. Because we might not care about size, but care just about age. Gotcha.

func (sb *syncBuffer) rotateOld(now time.Time) {
logs, err := getLogFiles()
if err != nil {
sb.logger.exit(err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an idea -- what about using Fatal(err) here (and below)? sb.logger.exit will write the error to fmt which is stdout and since normally geth logs go through stderr some users might not catch it if they're using 2> redirect?

return logFiles[i].timestamp < logFiles[j].timestamp
})
return logFiles, nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we handle this err?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit tricky loop construct from glog itself ;) It searches for first usable logging directory (configured one or temporary directory). To be consistent with rest of glog, we're complaining only when no directories work for us.

return logs
}

func extractTimestamp(logFile, preffix string) string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor spelling error: "preffix" should be "prefix"

@@ -428,6 +432,309 @@ func TestLogBacktraceAt(t *testing.T) {
}
}

func TestExtractTimestamp(t *testing.T) {
preffix := fmt.Sprintf("%s.%s.%s.log.", "geth_test", "sampleHost", "sampleUser")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/preffix/prefix cuz I'm a spelling nazi

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:%s/preffix/prefix/g ;)

{"valid WARNIG", preffix + "WARNING.20171202-210922.13848", "20171202-210922"},
{"valid gzipped", preffix + "WARNING.20171202-210922.13848.gz", "20171202-210922"},
{"extra long filename", preffix + "WARNING.20171202-210922.13848.gz.bak", "20171202-210922"},
{"to short filename", preffix + "WARNING.20171202-21092", ""},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/to/too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to :set spell before next commit ;)

@@ -223,6 +229,11 @@ func makeCLIApp() (app *cli.App) {

runtime.GOMAXPROCS(runtime.NumCPU())

err := setupLogRotation(ctx)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌮 git add cmd/geth/*

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

return time.Duration(value), nil
}

// reinventing the wheel to avoid external dependency
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

@tzdybal tzdybal merged commit f361e0b into master Dec 12, 2017
@whilei whilei deleted the feature/log-rotation branch February 19, 2018 13:32
@tzdybal tzdybal restored the feature/log-rotation branch March 27, 2018 12:30
@tzdybal tzdybal deleted the feature/log-rotation branch March 27, 2018 12:36
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Log rotation
2 participants