Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Structured log: replace ngaut/log with logrus #612

Merged
merged 21 commits into from
Apr 24, 2017

Conversation

andelf
Copy link
Contributor

@andelf andelf commented Apr 11, 2017

Changes:

  • vendor: logrus for structured log
  • vendor: lumberjack for logrotate
  • server/util: additional wrapper, to make log format consistent

review link: https://github.com/pingcap/pd/pull/612/files/18ba74fb8628ad0c7f1b75b70af8724bc3ba8840..b99587ae691568efde81b68572e688bac8827fa5 (without vendor changes)

@andelf andelf force-pushed the structured-log-stage1-use-logrus branch from 97fca69 to b99587a Compare April 11, 2017 18:33
server/util.go Outdated
for i := 0; i < cnt; i++ {
fu := runtime.FuncForPC(pc[i] - 1)
name := fu.Name()
if !strings.Contains(name, "github.com/Sirupsen/logrus") &&
Copy link
Contributor

Choose a reason for hiding this comment

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

extract the contain check to a function

Copy link
Contributor Author

@andelf andelf Apr 12, 2017

Choose a reason for hiding this comment

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

how about a separate variable

Copy link
Contributor

Choose a reason for hiding this comment

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

you mean defining a table variable for these?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for standalone sub-package, a function is ok.
for mess up with server/util.go, another function may not be acceptable.

never mind 😹

@siddontang
Copy link
Contributor

I think we should move the log to pkg logutil package. PD client may use this later.

Btw, please add test for it.

@andelf
Copy link
Contributor Author

andelf commented Apr 12, 2017

"move the log to pkg logutil package" is #602 😹

For that log setting up depends on Config, there will be a circular reference between logutil and server.

😞

@siddontang
Copy link
Contributor

You can define a LogConfig for the log, and then embed it into ServerConfig. This can decouple the logic.

server/util.go Outdated
} else {
b = &bytes.Buffer{}
}
b.WriteString(entry.Time.Format("2006/01/02 15:04:05"))
Copy link
Contributor

Choose a reason for hiding this comment

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

define a const var for the time format

server/util.go Outdated
}
b.WriteString(entry.Time.Format("2006/01/02 15:04:05"))
if file, ok := entry.Data["file"]; ok {
b.WriteString(fmt.Sprintf(" %s:%v:", file, entry.Data["line"]))
Copy link
Contributor

Choose a reason for hiding this comment

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

seem you can use fmt.Fprintf(b, format, args...) directly to reduce the allocation cost for fmt.Sprintf?

@andelf
Copy link
Contributor Author

andelf commented Apr 12, 2017

LogConfig comes up with [log], may be done with #459 .

@andelf andelf requested review from overvenus and nolouch April 12, 2017 05:35
@andelf
Copy link
Contributor Author

andelf commented Apr 12, 2017

Update:

  • isolated sub-package pkg/logutil
  • logutil.LogConfig embedded in server.Config
  • tests

Incompatible Changes:

  • pd.toml: [log] section

@@ -56,10 +57,8 @@ type Config struct {
// Etcd onlys support seoncds TTL, so here is second too.
LeaderLease int64 `toml:"lease" json:"lease"`

// Log level.
LogLevel string `toml:"log-level" json:"log-level"`
Copy link
Contributor

Choose a reason for hiding this comment

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

seem this can cause compatibility

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any other package references pd/server?

Copy link
Contributor

Choose a reason for hiding this comment

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

users have to change their config after updating. We should avoid this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For Ansible deployment log-level is specified via command line argument: https://github.com/pingcap/tidb-ansible/blob/master/roles/pd/templates/run_pd.sh.j2

Shall we add a migration support for backward compatibility?

Copy link
Contributor

Choose a reason for hiding this comment

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

Not only for ansible, some users deploy manually. As far as I know, we have only one user who deploys manually, so we should help him changing the config before updating.

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 default behavior is not changed. Only matters when a user changes default log level or specifies log file path in pd.toml .

conf/config.toml Outdated
tso-save-interval = "3s"

[log]
log-level = "info"
Copy link
Contributor

Choose a reason for hiding this comment

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

no need log-file here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

previously, log-file is always specified via command line arguments.

Copy link
Contributor

Choose a reason for hiding this comment

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

should add it but comment here.

// Fire implements logrus.Hook interface
// https://github.com/sirupsen/logrus/issues/63
func (hook *contextHook) Fire(entry *log.Entry) error {
pc := make([]uintptr, 3, 3)
Copy link
Contributor

Choose a reason for hiding this comment

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

make([]uinptr, 3) is enough.

func (rf *redirectFormatter) Flush() {}

// isSKippedPackageName tests wether path name is on log library calling stack.
func isSkippedPackageName(name string) bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

add a simple test for this function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

meaningless to add tests for such stupid library function calls.
Or else I'll make it a variable before if condition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

btw: coverage already covers this.

Copy link
Contributor

@siddontang siddontang Apr 13, 2017

Choose a reason for hiding this comment

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

If we only cover "github.com/Sirupsen/logrus" but miss "github.com/coreos/pkg/capnslog", how do we know it, at run time?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

log_test.go checks against "log.go"(all capnslog) and "log_test.go".

Copy link
Contributor

Choose a reason for hiding this comment

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

It is nonintuitive. Please test it explicitly.

@siddontang
Copy link
Contributor

Rest LGTM

conf/config.toml Outdated
@@ -18,7 +18,8 @@ lease = 3
tso-save-interval = "3s"

[log]
log-level = "info"
level = "info"
Copy link
Contributor

Choose a reason for hiding this comment

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

do we need to update ansible now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

leave it what it is now

@siddontang
Copy link
Contributor

PTAL @disksing

entry, err = s.buf.ReadString('\n')
c.Assert(err, IsNil)
c.Assert(entry, Matches, logPattern)
c.Assert(strings.Contains(entry, thisFilename), IsTrue)
Copy link
Contributor

Choose a reason for hiding this comment

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

can use "log_test.go" here directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK!

case "warn":
return log.WarnLevel
case "warning":
return log.WarnLevel
Copy link
Contributor

Choose a reason for hiding this comment

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

case "warn", "warning":

// trim square brackets
if len(logStr) > 2 && logStr[0] == '[' {
logStr = logStr[1 : len(logStr)-1]
}
Copy link
Contributor

Choose a reason for hiding this comment

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

When will it starts with '['? And the last char will always be ']' if first is '['?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All logs from etcd are wrapped in [] pairs. and yes.

case capnslog.DEBUG:
log.Debugf(logStr)
case capnslog.TRACE:
log.Debugf(logStr)
Copy link
Contributor

Choose a reason for hiding this comment

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

case sapnslog.DEBUG, sapnslog.TRACE:

if k != "file" && k != "line" {
fmt.Fprintf(b, " %v=%v", k, entry.Data[k])
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

how about for k, v := range entry.Data?

@andelf
Copy link
Contributor Author

andelf commented Apr 14, 2017

+Update: add backward compatibility check + warning

server/config.go Outdated
@@ -175,6 +182,19 @@ func (c *Config) Parse(arguments []string) error {
if err != nil {
return errors.Trace(err)
}

// Backward compatibility for toml config
fmt.Printf("fuck %+v\n", c)
Copy link
Contributor

Choose a reason for hiding this comment

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

?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for test .

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

server/config.go Outdated
if c.LogFileDeprecated != "" && c.Log.Filename == "" {
c.Log.Filename = c.LogFileDeprecated
msg := fmt.Sprintf("log-file in %s is deprecated, use [log] instead", c.configFile)
c.WarningMsgs = append(c.WarningMsgs, msg)
Copy link
Contributor

Choose a reason for hiding this comment

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

output the warning message here directly

Copy link
Contributor

Choose a reason for hiding this comment

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

ignore it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should be logged after logger is initialized. :)

Copy link
Contributor

Choose a reason for hiding this comment

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

How about returning warning messages as []string and log them afterwards?

Copy link
Contributor

Choose a reason for hiding this comment

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

returning the warning message seems better.

Copy link
Contributor

Choose a reason for hiding this comment

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

any update?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Current implementation is OK for future planning.
config.Parse(), logutil.InitLogger() may all update warning messages.

return log.AllLevels
}

func stringToLogLevel(level string) log.Level {
Copy link
Contributor

Choose a reason for hiding this comment

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

add test to cover all the conditions.

@@ -85,6 +88,9 @@ type Config struct {
electionMs uint64

configFile string

// For all warnings during parsing.
WarningMsgs []string
Copy link
Contributor

Choose a reason for hiding this comment

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

/WarningMsgs/warningMsgs/s

Copy link
Contributor Author

Choose a reason for hiding this comment

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

public field here

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it, but can we use a function to do this? exporting fields seems strange.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

GetWarningMsgs() 🤣

Copy link
Contributor

Choose a reason for hiding this comment

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

LogWarningMsgs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ugly and export a meaningless function with side effect.

Copy link
Contributor

Choose a reason for hiding this comment

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

Exporting WarningMsg is too, what is the WarningMsgs for? what I first see is that there is a WarningMsg config.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

........

@@ -41,6 +41,16 @@ func (s *testLogSuite) SetUpSuite(c *C) {
s.buf = &bytes.Buffer{}
}

func (s *testLogSuite) TestStringToLogLevel(c *C) {
c.Assert(stringToLogLevel("fatal"), Equals, log.FatalLevel)
Copy link
Contributor

Choose a reason for hiding this comment

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

you can use table-driven test here.

let tt = []struct {
    name string
    level Level
} {
    {"ERROR", log.ErrorLevel},
    ...
}

for _, t := range tt {
   c.Assert()
}

@siddontang
Copy link
Contributor

Rest LGTM

PTAL @disksing @nolouch

@ngaut
Copy link
Member

ngaut commented Apr 22, 2017

LGTM

@siddontang
Copy link
Contributor

LGTM

PTAL @disksing

@shenli
Copy link
Member

shenli commented Apr 24, 2017

Should we also do this in tidb repo?
/cc @coocood @tiancaiamao

@disksing
Copy link
Contributor

LGTM.

@andelf
Copy link
Contributor Author

andelf commented Apr 24, 2017

I'll fix circleCI status.

@siddontang siddontang merged commit 4d52abb into tikv:master Apr 24, 2017
@andelf andelf deleted the structured-log-stage1-use-logrus branch April 24, 2017 13:03
@sre-bot sre-bot added the contribution This PR is from a community contributor. label Dec 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution This PR is from a community contributor.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants