Rename ctx to logCtx, remove any mention of ctx

This commit is contained in:
Yoann La Cancellera
2023-11-23 10:32:02 +01:00
committed by Sveta Smirnova
parent bb6c5e1abd
commit 955fd75ca9
25 changed files with 552 additions and 552 deletions

View File

@@ -29,22 +29,22 @@ func (c *conflicts) Run() error {
return err
}
ctxs := timeline.GetLatestContextsByNodes()
for _, ctx := range ctxs {
if len(ctx.Conflicts) == 0 {
logCtxs := timeline.GetLatestContextsByNodes()
for _, logCtx := range logCtxs {
if len(logCtx.Conflicts) == 0 {
continue
}
var out string
switch {
case c.Yaml:
tmp, err := yaml.Marshal(ctx.Conflicts)
tmp, err := yaml.Marshal(logCtx.Conflicts)
if err != nil {
return err
}
out = string(tmp)
case c.Json:
tmp, err := json.Marshal(ctx.Conflicts)
tmp, err := json.Marshal(logCtx.Conflicts)
if err != nil {
return err
}
@@ -52,7 +52,7 @@ func (c *conflicts) Run() error {
default:
var b strings.Builder
for _, conflict := range ctx.Conflicts {
for _, conflict := range logCtx.Conflicts {
b.WriteString("\n\n")
b.WriteString(utils.Paint(utils.BlueText, "seqno: "))
b.WriteString(conflict.Seqno)

View File

@@ -30,7 +30,7 @@ func (c *ctx) Run() error {
out.DB = translate.GetDB()
for _, t := range timeline {
out.Contexts = append(out.Contexts, t[len(t)-1].Ctx)
out.Contexts = append(out.Contexts, t[len(t)-1].LogCtx)
}
outjson, err := json.MarshalIndent(out, "", "\t")

View File

@@ -60,13 +60,13 @@ func TimelineCLI(timeline types.Timeline, verbosity types.Verbosity) {
if !utils.SliceContains(nextNodes, node) {
// if there are no events, having a | is needed for tabwriter
// A few color can also help highlighting how the node is doing
ctx := currentContext[node]
args = append(args, utils.PaintForState("| ", ctx.State()))
logCtx := currentContext[node]
args = append(args, utils.PaintForState("| ", logCtx.State()))
continue
}
loginfo := timeline[node][0]
lastContext[node] = currentContext[node]
currentContext[node] = loginfo.Ctx
currentContext[node] = loginfo.LogCtx
timeline.Dequeue(node)
@@ -75,7 +75,7 @@ func TimelineCLI(timeline types.Timeline, verbosity types.Verbosity) {
args = append(args, msg)
displayedValue++
} else {
args = append(args, utils.PaintForState("| ", loginfo.Ctx.State()))
args = append(args, utils.PaintForState("| ", loginfo.LogCtx.State()))
}
}
@@ -127,7 +127,7 @@ func initKeysContext(timeline types.Timeline) ([]string, map[string]types.LogCtx
for node := range timeline {
keys = append(keys, node)
if len(timeline[node]) > 0 {
currentContext[node] = timeline[node][0].Ctx
currentContext[node] = timeline[node][0].LogCtx
} else {
// Avoid crashing, but not ideal: we could have a better default Ctx with filepath at least
currentContext[node] = types.NewLogCtx()
@@ -145,14 +145,14 @@ func headerNodes(keys []string) string {
return "identifier\t" + strings.Join(keys, "\t") + "\t"
}
func headerFilePath(keys []string, ctxs map[string]types.LogCtx) string {
func headerFilePath(keys []string, logCtxs map[string]types.LogCtx) string {
header := "current path\t"
for _, node := range keys {
if ctx, ok := ctxs[node]; ok {
if len(ctx.FilePath) < 50 {
header += ctx.FilePath + "\t"
if logCtx, ok := logCtxs[node]; ok {
if len(logCtx.FilePath) < 50 {
header += logCtx.FilePath + "\t"
} else {
header += "..." + ctx.FilePath[len(ctx.FilePath)-50:] + "\t"
header += "..." + logCtx.FilePath[len(logCtx.FilePath)-50:] + "\t"
}
} else {
header += " \t"
@@ -161,11 +161,11 @@ func headerFilePath(keys []string, ctxs map[string]types.LogCtx) string {
return header
}
func headerIP(keys []string, ctxs map[string]types.LogCtx) string {
func headerIP(keys []string, logCtxs map[string]types.LogCtx) string {
header := "last known ip\t"
for _, node := range keys {
if ctx, ok := ctxs[node]; ok && len(ctx.OwnIPs) > 0 {
header += ctx.OwnIPs[len(ctx.OwnIPs)-1] + "\t"
if logCtx, ok := logCtxs[node]; ok && len(logCtx.OwnIPs) > 0 {
header += logCtx.OwnIPs[len(logCtx.OwnIPs)-1] + "\t"
} else {
header += " \t"
}
@@ -173,21 +173,21 @@ func headerIP(keys []string, ctxs map[string]types.LogCtx) string {
return header
}
func headerVersion(keys []string, ctxs map[string]types.LogCtx) string {
func headerVersion(keys []string, logCtxs map[string]types.LogCtx) string {
header := "mysql version\t"
for _, node := range keys {
if ctx, ok := ctxs[node]; ok {
header += ctx.Version + "\t"
if logCtx, ok := logCtxs[node]; ok {
header += logCtx.Version + "\t"
}
}
return header
}
func headerName(keys []string, ctxs map[string]types.LogCtx) string {
func headerName(keys []string, logCtxs map[string]types.LogCtx) string {
header := "last known name\t"
for _, node := range keys {
if ctx, ok := ctxs[node]; ok && len(ctx.OwnNames) > 0 {
header += ctx.OwnNames[len(ctx.OwnNames)-1] + "\t"
if logCtx, ok := logCtxs[node]; ok && len(logCtx.OwnNames) > 0 {
header += logCtx.OwnNames[len(logCtx.OwnNames)-1] + "\t"
} else {
header += " \t"
}
@@ -198,7 +198,7 @@ func headerName(keys []string, ctxs map[string]types.LogCtx) string {
func removeEmptyColumns(timeline types.Timeline, verbosity types.Verbosity) types.Timeline {
for key := range timeline {
if !timeline[key][len(timeline[key])-1].Ctx.HasVisibleEvents(verbosity) {
if !timeline[key][len(timeline[key])-1].LogCtx.HasVisibleEvents(verbosity) {
delete(timeline, key)
}
}
@@ -245,27 +245,27 @@ const NumberOfPossibleTransition = 4
// it needs an element on each columns so that we don't break columns
// The rows can't have a variable count of elements: it has to be strictly identical each time
// so the whole next functions are here to ensure it takes minimal spaces, while giving context and preserving columns
func transitionSeparator(keys []string, oldctxs, ctxs map[string]types.LogCtx) string {
func transitionSeparator(keys []string, oldlogCtxs, logCtxs map[string]types.LogCtx) string {
ts := map[string]*transitions{}
// For each columns to print, we build tests
for _, node := range keys {
ctx, ok1 := ctxs[node]
oldctx, ok2 := oldctxs[node]
logCtx, ok1 := logCtxs[node]
oldlogCtx, ok2 := oldlogCtxs[node]
ts[node] = &transitions{tests: []*transition{}}
if ok1 && ok2 {
ts[node].tests = append(ts[node].tests, &transition{s1: oldctx.FilePath, s2: ctx.FilePath, changeType: "file path"})
ts[node].tests = append(ts[node].tests, &transition{s1: oldlogCtx.FilePath, s2: logCtx.FilePath, changeType: "file path"})
if len(oldctx.OwnNames) > 0 && len(ctx.OwnNames) > 0 {
ts[node].tests = append(ts[node].tests, &transition{s1: oldctx.OwnNames[len(oldctx.OwnNames)-1], s2: ctx.OwnNames[len(ctx.OwnNames)-1], changeType: "node name"})
if len(oldlogCtx.OwnNames) > 0 && len(logCtx.OwnNames) > 0 {
ts[node].tests = append(ts[node].tests, &transition{s1: oldlogCtx.OwnNames[len(oldlogCtx.OwnNames)-1], s2: logCtx.OwnNames[len(logCtx.OwnNames)-1], changeType: "node name"})
}
if len(oldctx.OwnIPs) > 0 && len(ctx.OwnIPs) > 0 {
ts[node].tests = append(ts[node].tests, &transition{s1: oldctx.OwnIPs[len(oldctx.OwnIPs)-1], s2: ctx.OwnIPs[len(ctx.OwnIPs)-1], changeType: "node ip"})
if len(oldlogCtx.OwnIPs) > 0 && len(logCtx.OwnIPs) > 0 {
ts[node].tests = append(ts[node].tests, &transition{s1: oldlogCtx.OwnIPs[len(oldlogCtx.OwnIPs)-1], s2: logCtx.OwnIPs[len(logCtx.OwnIPs)-1], changeType: "node ip"})
}
if oldctx.Version != "" && ctx.Version != "" {
ts[node].tests = append(ts[node].tests, &transition{s1: oldctx.Version, s2: ctx.Version, changeType: "version"})
if oldlogCtx.Version != "" && logCtx.Version != "" {
ts[node].tests = append(ts[node].tests, &transition{s1: oldlogCtx.Version, s2: logCtx.Version, changeType: "version"})
}
}

View File

@@ -10,19 +10,19 @@ import (
func TestTransitionSeparator(t *testing.T) {
t.Parallel()
tests := []struct {
keys []string
oldctxs, ctxs map[string]types.LogCtx
expectedOut string
name string
keys []string
oldlogCtxs, logCtxs map[string]types.LogCtx
expectedOut string
name string
}{
{
name: "no changes",
keys: []string{"node0", "node1"},
oldctxs: map[string]types.LogCtx{
oldlogCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {},
},
ctxs: map[string]types.LogCtx{
logCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {},
@@ -32,11 +32,11 @@ func TestTransitionSeparator(t *testing.T) {
{
name: "filepath changed on node0",
keys: []string{"node0", "node1"},
oldctxs: map[string]types.LogCtx{
oldlogCtxs: map[string]types.LogCtx{
"node0": {FilePath: "path1"},
"node1": {},
},
ctxs: map[string]types.LogCtx{
logCtxs: map[string]types.LogCtx{
"node0": {FilePath: "path2"},
"node1": {},
@@ -52,11 +52,11 @@ func TestTransitionSeparator(t *testing.T) {
{
name: "filepath changed on node1",
keys: []string{"node0", "node1"},
oldctxs: map[string]types.LogCtx{
oldlogCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {FilePath: "path1"},
},
ctxs: map[string]types.LogCtx{
logCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {FilePath: "path2"},
@@ -66,11 +66,11 @@ func TestTransitionSeparator(t *testing.T) {
{
name: "filepath changed on both",
keys: []string{"node0", "node1"},
oldctxs: map[string]types.LogCtx{
oldlogCtxs: map[string]types.LogCtx{
"node0": {FilePath: "path1_0"},
"node1": {FilePath: "path1_1"},
},
ctxs: map[string]types.LogCtx{
logCtxs: map[string]types.LogCtx{
"node0": {FilePath: "path2_0"},
"node1": {FilePath: "path2_1"},
},
@@ -79,11 +79,11 @@ func TestTransitionSeparator(t *testing.T) {
{
name: "node name changed on node1",
keys: []string{"node0", "node1"},
oldctxs: map[string]types.LogCtx{
oldlogCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {OwnNames: []string{"name1"}},
},
ctxs: map[string]types.LogCtx{
logCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {OwnNames: []string{"name1", "name2"}},
},
@@ -92,11 +92,11 @@ func TestTransitionSeparator(t *testing.T) {
{
name: "node ip changed on node1",
keys: []string{"node0", "node1"},
oldctxs: map[string]types.LogCtx{
oldlogCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {OwnIPs: []string{"ip1"}},
},
ctxs: map[string]types.LogCtx{
logCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {OwnIPs: []string{"ip1", "ip2"}},
},
@@ -105,11 +105,11 @@ func TestTransitionSeparator(t *testing.T) {
{
name: "version changed on node1",
keys: []string{"node0", "node1"},
oldctxs: map[string]types.LogCtx{
oldlogCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {Version: "8.0.28"},
},
ctxs: map[string]types.LogCtx{
logCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {Version: "8.0.30"},
},
@@ -118,11 +118,11 @@ func TestTransitionSeparator(t *testing.T) {
{
name: "node ip, node name and filepath changed on node1", // very possible with operators
keys: []string{"node0", "node1"},
oldctxs: map[string]types.LogCtx{
oldlogCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {OwnIPs: []string{"ip1"}, OwnNames: []string{"name1"}, FilePath: "path1"},
},
ctxs: map[string]types.LogCtx{
logCtxs: map[string]types.LogCtx{
"node0": {},
"node1": {OwnIPs: []string{"ip1", "ip2"}, OwnNames: []string{"name1", "name2"}, FilePath: "path2"},
},
@@ -148,11 +148,11 @@ func TestTransitionSeparator(t *testing.T) {
{
name: "node ip, node name and filepath changed on node1, nodename changed on node2", // very possible with operators
keys: []string{"node0", "node1"},
oldctxs: map[string]types.LogCtx{
oldlogCtxs: map[string]types.LogCtx{
"node0": {OwnNames: []string{"name1_0"}},
"node1": {OwnIPs: []string{"ip1"}, OwnNames: []string{"name1_1"}, FilePath: "path1"},
},
ctxs: map[string]types.LogCtx{
logCtxs: map[string]types.LogCtx{
"node0": {OwnNames: []string{"name1_0", "name2_0"}},
"node1": {OwnIPs: []string{"ip1", "ip2"}, OwnNames: []string{"name1_1", "name2_1"}, FilePath: "path2"},
},
@@ -178,7 +178,7 @@ func TestTransitionSeparator(t *testing.T) {
utils.SkipColor = true
for _, test := range tests {
out := transitionSeparator(test.keys, test.oldctxs, test.ctxs)
out := transitionSeparator(test.keys, test.oldlogCtxs, test.logCtxs)
if out != test.expectedOut {
t.Errorf("testname: %s, expected: \n%#v\n got: \n%#v", test.name, test.expectedOut, out)
}

View File

@@ -177,8 +177,8 @@ func iterateOnGrepResults(path string, regexes types.RegexMap, grepStdout <-chan
displayer types.LogDisplayer
timestamp time.Time
)
ctx := types.NewLogCtx()
ctx.FilePath = path
logCtx := types.NewLogCtx()
logCtx.FilePath = path
for line := range grepStdout {
line = sanitizeLine(line)
@@ -203,7 +203,7 @@ func iterateOnGrepResults(path string, regexes types.RegexMap, grepStdout <-chan
}
filetype := regex.FileType(line, CLI.PxcOperator)
ctx.FileType = filetype
logCtx.FileType = filetype
// We have to find again what regex worked to get this log line
// it can match multiple regexes
@@ -211,8 +211,8 @@ func iterateOnGrepResults(path string, regexes types.RegexMap, grepStdout <-chan
if !regex.Regex.MatchString(line) || utils.SliceContains(CLI.ExcludeRegexes, key) {
continue
}
ctx, displayer = regex.Handle(ctx, line, timestamp)
li := types.NewLogInfo(date, displayer, line, regex, key, ctx, filetype)
logCtx, displayer = regex.Handle(logCtx, line, timestamp)
li := types.NewLogInfo(date, displayer, line, regex, key, logCtx, filetype)
lt = lt.Add(li)
}

View File

@@ -49,7 +49,7 @@ var CLI struct {
}
func main() {
ctx := kong.Parse(&CLI,
kongcli := kong.Parse(&CLI,
kong.Name(toolname),
kong.Description("An utility to merge and help analyzing Galera logs"),
kong.UsageOnError(),
@@ -68,6 +68,6 @@ func main() {
utils.SkipColor = CLI.NoColor
translate.AssumeIPStable = !CLI.PxcOperator
err := ctx.Run()
ctx.FatalIfErrorf(err)
err := kongcli.Run()
kongcli.FatalIfErrorf(err)
}

View File

@@ -17,12 +17,12 @@ var ApplicativeMap = types.RegexMap{
"RegexDesync": &types.LogRegex{
Regex: regexp.MustCompile("desyncs itself from group"),
InternalRegex: regexp.MustCompile("\\(" + regexNodeName + "\\) desyncs"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.Desynced = true
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.Desynced = true
node := submatches[groupNodeName]
return ctx, func(ctx types.LogCtx) string {
if utils.SliceContains(ctx.OwnNames, node) {
return logCtx, func(logCtx types.LogCtx) string {
if utils.SliceContains(logCtx.OwnNames, node) {
return utils.Paint(utils.YellowText, "desyncs itself from group")
}
return node + utils.Paint(utils.YellowText, " desyncs itself from group")
@@ -33,11 +33,11 @@ var ApplicativeMap = types.RegexMap{
"RegexResync": &types.LogRegex{
Regex: regexp.MustCompile("resyncs itself to group"),
InternalRegex: regexp.MustCompile("\\(" + regexNodeName + "\\) resyncs"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.Desynced = false
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.Desynced = false
node := submatches[groupNodeName]
return ctx, func(ctx types.LogCtx) string {
if utils.SliceContains(ctx.OwnNames, node) {
return logCtx, func(logCtx types.LogCtx) string {
if utils.SliceContains(logCtx.OwnNames, node) {
return utils.Paint(utils.YellowText, "resyncs itself to group")
}
return node + utils.Paint(utils.YellowText, " resyncs itself to group")
@@ -48,7 +48,7 @@ var ApplicativeMap = types.RegexMap{
"RegexInconsistencyVoteInit": &types.LogRegex{
Regex: regexp.MustCompile("initiates vote on"),
InternalRegex: regexp.MustCompile("Member " + regexIdx + "\\(" + regexNodeName + "\\) initiates vote on " + regexUUID + ":" + regexSeqno + "," + regexErrorMD5 + ": (?P<error>.*), Error_code:"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
node := submatches[groupNodeName]
seqno := submatches[groupSeqno]
@@ -61,11 +61,11 @@ var ApplicativeMap = types.RegexMap{
VotePerNode: map[string]types.ConflictVote{node: types.ConflictVote{MD5: errormd5, Error: errorstring}},
}
ctx.Conflicts = ctx.Conflicts.Merge(c)
logCtx.Conflicts = logCtx.Conflicts.Merge(c)
return ctx, func(ctx types.LogCtx) string {
return logCtx, func(logCtx types.LogCtx) string {
if utils.SliceContains(ctx.OwnNames, node) {
if utils.SliceContains(logCtx.OwnNames, node) {
return utils.Paint(utils.YellowText, "inconsistency vote started") + "(seqno:" + seqno + ")"
}
@@ -77,22 +77,22 @@ var ApplicativeMap = types.RegexMap{
"RegexInconsistencyVoteRespond": &types.LogRegex{
Regex: regexp.MustCompile("responds to vote on "),
InternalRegex: regexp.MustCompile("Member " + regexIdx + "\\(" + regexNodeName + "\\) responds to vote on " + regexUUID + ":" + regexSeqno + "," + regexErrorMD5 + ": (?P<error>.*)"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
node := submatches[groupNodeName]
seqno := submatches[groupSeqno]
errormd5 := submatches[groupErrorMD5]
errorstring := submatches["error"]
latestConflict := ctx.Conflicts.ConflictWithSeqno(seqno)
latestConflict := logCtx.Conflicts.ConflictWithSeqno(seqno)
if latestConflict == nil {
return ctx, nil
return logCtx, nil
}
latestConflict.VotePerNode[node] = types.ConflictVote{MD5: errormd5, Error: errorstring}
return ctx, func(ctx types.LogCtx) string {
return logCtx, func(logCtx types.LogCtx) string {
for _, name := range ctx.OwnNames {
for _, name := range logCtx.OwnNames {
vote, ok := latestConflict.VotePerNode[name]
if !ok {
continue
@@ -115,38 +115,38 @@ var ApplicativeMap = types.RegexMap{
"RegexInconsistencyVoteInconsistentWithGroup": &types.LogRegex{
Regex: regexp.MustCompile("is inconsistent with group. Leaving cluster"),
InternalRegex: regexp.MustCompile("Vote [0-9] \\(success\\) on " + regexUUID + ":" + regexSeqno + " is inconsistent with group. Leaving cluster"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
seqno := submatches[groupSeqno]
latestConflict := ctx.Conflicts.ConflictWithSeqno(seqno)
latestConflict := logCtx.Conflicts.ConflictWithSeqno(seqno)
if latestConflict == nil {
return ctx, nil
return logCtx, nil
}
if len(ctx.OwnNames) > 0 {
latestConflict.VotePerNode[ctx.OwnNames[len(ctx.OwnNames)-1]] = types.ConflictVote{Error: "Success", MD5: "0000000000000000"}
if len(logCtx.OwnNames) > 0 {
latestConflict.VotePerNode[logCtx.OwnNames[len(logCtx.OwnNames)-1]] = types.ConflictVote{Error: "Success", MD5: "0000000000000000"}
}
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "vote (success) inconsistent, leaving cluster"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "vote (success) inconsistent, leaving cluster"))
},
},
"RegexInconsistencyVoted": &types.LogRegex{
Regex: regexp.MustCompile("Inconsistency detected: Inconsistent by consensus"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "found inconsistent by vote"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "found inconsistent by vote"))
},
},
"RegexInconsistencyWinner": &types.LogRegex{
Regex: regexp.MustCompile("Winner: "),
InternalRegex: regexp.MustCompile("Winner: " + regexErrorMD5),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
errormd5 := submatches[groupErrorMD5]
if len(ctx.Conflicts) == 0 {
return ctx, nil // nothing to guess
if len(logCtx.Conflicts) == 0 {
return logCtx, nil // nothing to guess
}
c := ctx.Conflicts.ConflictFromMD5(errormd5)
c := logCtx.Conflicts.ConflictFromMD5(errormd5)
if c == nil {
// some votes have been observed to be logged again
// sometimes days after the initial one
@@ -154,13 +154,13 @@ var ApplicativeMap = types.RegexMap{
// as they don't add any helpful context, we should ignore
// plus, it would need multiline regexes, which is not supported here
return ctx, nil
return logCtx, nil
}
c.Winner = errormd5
return ctx, func(ctx types.LogCtx) string {
return logCtx, func(logCtx types.LogCtx) string {
out := "consistency vote(seqno:" + c.Seqno + "): "
for _, name := range ctx.OwnNames {
for _, name := range logCtx.OwnNames {
vote, ok := c.VotePerNode[name]
if !ok {
@@ -180,21 +180,21 @@ var ApplicativeMap = types.RegexMap{
"RegexInconsistencyRecovery": &types.LogRegex{
Regex: regexp.MustCompile("Recovering vote result from history"),
InternalRegex: regexp.MustCompile("Recovering vote result from history: " + regexUUID + ":" + regexSeqno + "," + regexErrorMD5),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
if len(ctx.OwnNames) == 0 {
return ctx, nil
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
if len(logCtx.OwnNames) == 0 {
return logCtx, nil
}
errormd5 := submatches[groupErrorMD5]
seqno := submatches[groupSeqno]
c := ctx.Conflicts.ConflictWithSeqno(seqno)
c := logCtx.Conflicts.ConflictWithSeqno(seqno)
if c == nil { // the actual vote could have been lost
return ctx, nil
return logCtx, nil
}
vote := types.ConflictVote{MD5: errormd5}
c.VotePerNode[ctx.OwnNames[len(ctx.OwnNames)-1]] = vote
c.VotePerNode[logCtx.OwnNames[len(logCtx.OwnNames)-1]] = vote
return ctx, types.SimpleDisplayer(voteResponse(vote, *c))
return logCtx, types.SimpleDisplayer(voteResponse(vote, *c))
},
Verbosity: types.DebugMySQL,
},

View File

@@ -11,7 +11,7 @@ func TestApplicativeRegex(t *testing.T) {
{
log: "2001-01-01 1:01:01 0 [Note] WSREP: Member 0.0 (node) desyncs itself from group",
expected: regexTestState{
Ctx: types.LogCtx{Desynced: true},
LogCtx: types.LogCtx{Desynced: true},
},
expectedOut: "node desyncs itself from group",
key: "RegexDesync",
@@ -20,10 +20,10 @@ func TestApplicativeRegex(t *testing.T) {
{
log: "2001-01-01 1:01:01 0 [Note] WSREP: Member 0.0 (node) resyncs itself to group",
expected: regexTestState{
Ctx: types.LogCtx{Desynced: false},
LogCtx: types.LogCtx{Desynced: false},
},
input: regexTestState{
Ctx: types.LogCtx{Desynced: true},
LogCtx: types.LogCtx{Desynced: true},
},
expectedOut: "node resyncs itself to group",
key: "RegexResync",
@@ -33,17 +33,17 @@ func TestApplicativeRegex(t *testing.T) {
log: "{\"log\":\"2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] Member 1(node1) initiates vote on 8c9b5610-e020-11ed-a5ea-e253cc5f629d:20,bdb2b9234ae75cb3: some error, Error_code: 123;\n\",\"file\":\"/var/lib/mysql/mysqld-error.log\"}",
expectedOut: "inconsistency vote started by node1(seqno:20)",
expected: regexTestState{
Ctx: types.LogCtx{Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
key: "RegexInconsistencyVoteInit",
},
{
log: "{\"log\":\"2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] Member 1(node1) initiates vote on 8c9b5610-e020-11ed-a5ea-e253cc5f629d:20,bdb2b9234ae75cb3: some error, Error_code: 123;\n\",\"file\":\"/var/lib/mysql/mysqld-error.log\"}",
input: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node1"}},
LogCtx: types.LogCtx{OwnNames: []string{"node1"}},
},
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expectedOut: "inconsistency vote started(seqno:20)",
key: "RegexInconsistencyVoteInit",
@@ -52,10 +52,10 @@ func TestApplicativeRegex(t *testing.T) {
{
log: "{\"log\":\"2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] Member 2(node2) responds to vote on 8c9b5610-e020-11ed-a5ea-e253cc5f629d:20,0000000000000000: Success\n\",\"file\":\"/var/lib/mysql/mysqld-error.log\"}",
input: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "0000000000000000", Error: "Success"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "0000000000000000", Error: "Success"}}}}},
},
expectedOut: "consistency vote(seqno:20): voted Success",
key: "RegexInconsistencyVoteRespond",
@@ -63,10 +63,10 @@ func TestApplicativeRegex(t *testing.T) {
{
log: "{\"log\":\"2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] Member 2(node2) responds to vote on 8c9b5610-e020-11ed-a5ea-e253cc5f629d:20,bdb2b9234ae75cb3: some error\n\",\"file\":\"/var/lib/mysql/mysqld-error.log\"}",
input: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expectedOut: "consistency vote(seqno:20): voted same error",
key: "RegexInconsistencyVoteRespond",
@@ -75,10 +75,10 @@ func TestApplicativeRegex(t *testing.T) {
// could not actually find a "responds to" with any error for now
log: "{\"log\":\"2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] Member 2(node2) responds to vote on 8c9b5610-e020-11ed-a5ea-e253cc5f629d:20,ed9774a3cad44656: some different error\n\",\"file\":\"/var/lib/mysql/mysqld-error.log\"}",
input: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "ed9774a3cad44656", Error: "some different error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "ed9774a3cad44656", Error: "some different error"}}}}},
},
expectedOut: "consistency vote(seqno:20): voted different error",
key: "RegexInconsistencyVoteRespond",
@@ -93,10 +93,10 @@ func TestApplicativeRegex(t *testing.T) {
{
log: "Winner: bdb2b9234ae75cb3",
input: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expectedOut: "consistency vote(seqno:20): won",
key: "RegexInconsistencyWinner",
@@ -104,10 +104,10 @@ func TestApplicativeRegex(t *testing.T) {
{
log: "Winner: 0000000000000000",
input: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "0000000000000000", Error: "Success"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "0000000000000000", Error: "Success"}}}}},
},
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "0000000000000000", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "0000000000000000", Error: "Success"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "0000000000000000", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "0000000000000000", Error: "Success"}}}}},
},
expectedOut: "consistency vote(seqno:20): lost",
key: "RegexInconsistencyWinner",
@@ -116,10 +116,10 @@ func TestApplicativeRegex(t *testing.T) {
name: "already voted conflict, should not print anything",
log: "Winner: 0000000000000000",
input: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node1"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
displayerExpectedNil: true,
key: "RegexInconsistencyWinner",
@@ -128,10 +128,10 @@ func TestApplicativeRegex(t *testing.T) {
{
log: "{\"log\":\"2001-01-01T01:01:01.000000Z 1 [ERROR] [MY-000000] [Galera] Recovering vote result from history: 8c9b5610-e020-11ed-a5ea-e253cc5f629d:20,bdb2b9234ae75cb3\n\",\"file\":\"/var/lib/mysql/mysqld-error.log\"}",
input: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "bdb2b9234ae75cb3"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "bdb2b9234ae75cb3"}}}}},
},
expectedOut: "consistency vote(seqno:20): voted same error",
key: "RegexInconsistencyRecovery",
@@ -139,10 +139,10 @@ func TestApplicativeRegex(t *testing.T) {
{
log: "{\"log\":\"2001-01-01T01:01:01.000000Z 1 [ERROR] [MY-000000] [Galera] Recovering vote result from history: 8c9b5610-e020-11ed-a5ea-e253cc5f629d:20,0000000000000000\n\",\"file\":\"/var/lib/mysql/mysqld-error.log\"}",
input: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "0000000000000000"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{MD5: "0000000000000000"}}}}},
},
expectedOut: "consistency vote(seqno:20): voted Success",
key: "RegexInconsistencyRecovery",
@@ -151,10 +151,10 @@ func TestApplicativeRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 16 [ERROR] [MY-000000] [Galera] Vote 0 (success) on 7b1a6710-18da-11ed-b777-42b15728f657:20 is inconsistent with group. Leaving cluster.",
input: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}}}}},
},
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{Error: "Success", MD5: "0000000000000000"}}}}},
LogCtx: types.LogCtx{OwnNames: []string{"node2"}, Conflicts: types.Conflicts{&types.Conflict{InitiatedBy: []string{"node1"}, Winner: "bdb2b9234ae75cb3", Seqno: "20", VotePerNode: map[string]types.ConflictVote{"node1": types.ConflictVote{MD5: "bdb2b9234ae75cb3", Error: "some error"}, "node2": types.ConflictVote{Error: "Success", MD5: "0000000000000000"}}}}},
},
expectedOut: "vote (success) inconsistent, leaving cluster",
key: "RegexInconsistencyVoteInconsistentWithGroup",

View File

@@ -17,99 +17,99 @@ var EventsMap = types.RegexMap{
"RegexStarting": &types.LogRegex{
Regex: regexp.MustCompile("starting as process"),
InternalRegex: regexp.MustCompile("\\(mysqld " + regexVersion + ".*\\)"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.Version = submatches[groupVersion]
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.Version = submatches[groupVersion]
msg := "starting(" + ctx.Version
if isShutdownReasonMissing(ctx) {
msg := "starting(" + logCtx.Version
if isShutdownReasonMissing(logCtx) {
msg += ", " + utils.Paint(utils.YellowText, "could not catch how/when it stopped")
}
msg += ")"
ctx.SetState("OPEN")
logCtx.SetState("OPEN")
return ctx, types.SimpleDisplayer(msg)
return logCtx, types.SimpleDisplayer(msg)
},
},
"RegexShutdownComplete": &types.LogRegex{
Regex: regexp.MustCompile("mysqld: Shutdown complete"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("CLOSED")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("CLOSED")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "shutdown complete"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "shutdown complete"))
},
},
"RegexTerminated": &types.LogRegex{
Regex: regexp.MustCompile("mysqld: Terminated"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("CLOSED")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("CLOSED")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "terminated"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "terminated"))
},
},
"RegexGotSignal6": &types.LogRegex{
Regex: regexp.MustCompile("mysqld got signal 6"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("CLOSED")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "crash: got signal 6"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("CLOSED")
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "crash: got signal 6"))
},
},
"RegexGotSignal11": &types.LogRegex{
Regex: regexp.MustCompile("mysqld got signal 11"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("CLOSED")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "crash: got signal 11"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("CLOSED")
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "crash: got signal 11"))
},
},
"RegexShutdownSignal": &types.LogRegex{
Regex: regexp.MustCompile("Normal|Received shutdown"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("CLOSED")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("CLOSED")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "received shutdown"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "received shutdown"))
},
},
// 2023-06-12T07:51:38.135646Z 0 [Warning] [MY-000000] [Galera] Exception while mapping writeset addr: 0x7fb668d4e568, seqno: 2770385572449823232, size: 73316, ctx: 0x56128412e0c0, flags: 1. store: 1, type: 32 into [555, 998): 'deque::_M_new_elements_at_back'. Aborting GCache recovery.
// 2023-06-12T07:51:38.135646Z 0 [Warning] [MY-000000] [Galera] Exception while mapping writeset addr: 0x7fb668d4e568, seqno: 2770385572449823232, size: 73316, logCtx: 0x56128412e0c0, flags: 1. store: 1, type: 32 into [555, 998): 'deque::_M_new_elements_at_back'. Aborting GCache recovery.
"RegexAborting": &types.LogRegex{
Regex: regexp.MustCompile("Aborting"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("CLOSED")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("CLOSED")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "ABORTING"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "ABORTING"))
},
},
"RegexWsrepLoad": &types.LogRegex{
Regex: regexp.MustCompile("wsrep_load\\(\\): loading provider library"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("OPEN")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("OPEN")
if regexWsrepLoadNone.MatchString(log) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.GreenText, "started(standalone)"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.GreenText, "started(standalone)"))
}
return ctx, types.SimpleDisplayer(utils.Paint(utils.GreenText, "started(cluster)"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.GreenText, "started(cluster)"))
},
},
"RegexWsrepRecovery": &types.LogRegex{
// INFO: WSREP: Recovered position 00000000-0000-0000-0000-000000000000:-1
Regex: regexp.MustCompile("Recovered position"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
msg := "wsrep recovery"
// if state is joiner, it can be due to sst
// if state is open, it is just a start sequence depending on platform
if isShutdownReasonMissing(ctx) && ctx.State() != "JOINER" && ctx.State() != "OPEN" {
if isShutdownReasonMissing(logCtx) && logCtx.State() != "JOINER" && logCtx.State() != "OPEN" {
msg += "(" + utils.Paint(utils.YellowText, "could not catch how/when it stopped") + ")"
}
ctx.SetState("RECOVERY")
logCtx.SetState("RECOVERY")
return ctx, types.SimpleDisplayer(msg)
return logCtx, types.SimpleDisplayer(msg)
},
},
"RegexUnknownConf": &types.LogRegex{
Regex: regexp.MustCompile("unknown variable"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
split := strings.Split(log, "'")
v := "?"
if len(split) > 0 {
@@ -118,47 +118,47 @@ var EventsMap = types.RegexMap{
if len(v) > 20 {
v = v[:20] + "..."
}
return ctx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "unknown variable") + ": " + v)
return logCtx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "unknown variable") + ": " + v)
},
},
"RegexAssertionFailure": &types.LogRegex{
Regex: regexp.MustCompile("Assertion failure"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("CLOSED")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("CLOSED")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "ASSERTION FAILURE"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "ASSERTION FAILURE"))
},
},
"RegexBindAddressAlreadyUsed": &types.LogRegex{
Regex: regexp.MustCompile("asio error .bind: Address already in use"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("CLOSED")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("CLOSED")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "bind address already used"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "bind address already used"))
},
},
"RegexTooManyConnections": &types.LogRegex{
Regex: regexp.MustCompile("Too many connections"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "too many connections"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "too many connections"))
},
},
"RegexReversingHistory": &types.LogRegex{
Regex: regexp.MustCompile("Reversing history"),
InternalRegex: regexp.MustCompile("Reversing history: " + regexSeqno + " -> [0-9]*, this member has applied (?P<diff>[0-9]*) more events than the primary component"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.BrightRedText, "having "+submatches["diff"]+" more events than the other nodes, data loss possible"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.BrightRedText, "having "+submatches["diff"]+" more events than the other nodes, data loss possible"))
},
},
}
var regexWsrepLoadNone = regexp.MustCompile("none")
// isShutdownReasonMissing is returning true if the latest wsrep state indicated a "working" node
func isShutdownReasonMissing(ctx types.LogCtx) bool {
return ctx.State() != "DESTROYED" && ctx.State() != "CLOSED" && ctx.State() != "RECOVERY" && ctx.State() != ""
func isShutdownReasonMissing(logCtx types.LogCtx) bool {
return logCtx.State() != "DESTROYED" && logCtx.State() != "CLOSED" && logCtx.State() != "RECOVERY" && logCtx.State() != ""
}
/*

View File

@@ -12,8 +12,8 @@ func TestEventsRegex(t *testing.T) {
name: "8.0.30-22",
log: "2001-01-01T01:01:01.000000Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.30-22) starting as process 1",
expected: regexTestState{
Ctx: types.LogCtx{Version: "8.0.30"},
State: "OPEN",
LogCtx: types.LogCtx{Version: "8.0.30"},
State: "OPEN",
},
expectedOut: "starting(8.0.30)",
key: "RegexStarting",
@@ -22,8 +22,8 @@ func TestEventsRegex(t *testing.T) {
name: "8.0.2-22",
log: "2001-01-01T01:01:01.000000Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.2-22) starting as process 1",
expected: regexTestState{
Ctx: types.LogCtx{Version: "8.0.2"},
State: "OPEN",
LogCtx: types.LogCtx{Version: "8.0.2"},
State: "OPEN",
},
expectedOut: "starting(8.0.2)",
key: "RegexStarting",
@@ -32,8 +32,8 @@ func TestEventsRegex(t *testing.T) {
name: "5.7.31-34-log",
log: "2001-01-01T01:01:01.000000Z 0 [Note] /usr/sbin/mysqld (mysqld 5.7.31-34-log) starting as process 2 ...",
expected: regexTestState{
Ctx: types.LogCtx{Version: "5.7.31"},
State: "OPEN",
LogCtx: types.LogCtx{Version: "5.7.31"},
State: "OPEN",
},
expectedOut: "starting(5.7.31)",
key: "RegexStarting",
@@ -42,8 +42,8 @@ func TestEventsRegex(t *testing.T) {
name: "10.4.25-MariaDB-log",
log: "2001-01-01 01:01:01 0 [Note] /usr/sbin/mysqld (mysqld 10.4.25-MariaDB-log) starting as process 2 ...",
expected: regexTestState{
Ctx: types.LogCtx{Version: "10.4.25"},
State: "OPEN",
LogCtx: types.LogCtx{Version: "10.4.25"},
State: "OPEN",
},
expectedOut: "starting(10.4.25)",
key: "RegexStarting",
@@ -52,8 +52,8 @@ func TestEventsRegex(t *testing.T) {
name: "10.2.31-MariaDB-1:10.2.31+maria~bionic-log",
log: "2001-01-01 01:01:01 0 [Note] /usr/sbin/mysqld (mysqld 10.2.31-MariaDB-1:10.2.31+maria~bionic-log) starting as process 2 ...",
expected: regexTestState{
Ctx: types.LogCtx{Version: "10.2.31"},
State: "OPEN",
LogCtx: types.LogCtx{Version: "10.2.31"},
State: "OPEN",
},
expectedOut: "starting(10.2.31)",
key: "RegexStarting",
@@ -62,8 +62,8 @@ func TestEventsRegex(t *testing.T) {
name: "5.7.28-enterprise-commercial-advanced-log",
log: "2001-01-01T01:01:01.000000Z 0 [Note] /usr/sbin/mysqld (mysqld 5.7.28-enterprise-commercial-advanced-log) starting as process 2 ...",
expected: regexTestState{
Ctx: types.LogCtx{Version: "5.7.28"},
State: "OPEN",
LogCtx: types.LogCtx{Version: "5.7.28"},
State: "OPEN",
},
expectedOut: "starting(5.7.28)",
key: "RegexStarting",
@@ -72,8 +72,8 @@ func TestEventsRegex(t *testing.T) {
name: "8.0.30 operator",
log: "{\"log\":\"2001-01-01T01:01:01.000000Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.30-22.1) starting as process 1\n\",\"file\":\"/var/lib/mysql/mysqld-error.log\"}",
expected: regexTestState{
Ctx: types.LogCtx{Version: "8.0.30"},
State: "OPEN",
LogCtx: types.LogCtx{Version: "8.0.30"},
State: "OPEN",
},
expectedOut: "starting(8.0.30)",
key: "RegexStarting",
@@ -94,8 +94,8 @@ func TestEventsRegex(t *testing.T) {
name: "could not catch how it stopped",
log: "{\"log\":\"2001-01-01T01:01:01.000000Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.30-22.1) starting as process 1\n\",\"file\":\"/var/lib/mysql/mysqld-error.log\"}",
expected: regexTestState{
Ctx: types.LogCtx{Version: "8.0.30"},
State: "OPEN",
LogCtx: types.LogCtx{Version: "8.0.30"},
State: "OPEN",
},
input: regexTestState{
State: "OPEN",

View File

@@ -20,11 +20,11 @@ var IdentsMap = types.RegexMap{
"RegexSourceNode": &types.LogRegex{
Regex: regexp.MustCompile("(local endpoint for a connection, blacklisting address)|(points to own listening address, blacklisting)"),
InternalRegex: regexp.MustCompile("\\(" + regexNodeHash + ", '.+'\\).+" + regexNodeIPMethod),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ip := submatches[groupNodeIP]
ctx.AddOwnIP(ip, date)
return ctx, types.SimpleDisplayer(ip + " is local")
logCtx.AddOwnIP(ip, date)
return logCtx, types.SimpleDisplayer(ip + " is local")
},
Verbosity: types.DebugMySQL,
},
@@ -33,11 +33,11 @@ var IdentsMap = types.RegexMap{
"RegexBaseHost": &types.LogRegex{
Regex: regexp.MustCompile("base_host"),
InternalRegex: regexp.MustCompile("base_host = " + regexNodeIP),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ip := submatches[groupNodeIP]
ctx.AddOwnIP(ip, date)
return ctx, types.SimpleDisplayer(ctx.OwnIPs[len(ctx.OwnIPs)-1] + " is local")
logCtx.AddOwnIP(ip, date)
return logCtx, types.SimpleDisplayer(logCtx.OwnIPs[len(logCtx.OwnIPs)-1] + " is local")
},
Verbosity: types.DebugMySQL,
},
@@ -48,7 +48,7 @@ var IdentsMap = types.RegexMap{
"RegexMemberAssociations": &types.LogRegex{
Regex: regexp.MustCompile("[0-9]: [a-z0-9]+-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]+, [a-zA-Z0-9-_]+"),
InternalRegex: regexp.MustCompile(regexIdx + ": " + regexUUID + ", " + regexNodeName),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
idx := submatches[groupIdx]
hash := utils.UUIDToShortUUID(submatches[groupUUID])
@@ -56,16 +56,16 @@ var IdentsMap = types.RegexMap{
// nodenames are truncated after 32 characters ...
if len(nodename) == 31 {
return ctx, nil
return logCtx, nil
}
translate.AddHashToNodeName(hash, nodename, date)
if ctx.MyIdx == idx && (ctx.IsPrimary() || ctx.MemberCount == 1) {
ctx.AddOwnHash(hash, date)
ctx.AddOwnName(nodename, date)
if logCtx.MyIdx == idx && (logCtx.IsPrimary() || logCtx.MemberCount == 1) {
logCtx.AddOwnHash(hash, date)
logCtx.AddOwnName(nodename, date)
}
return ctx, types.SimpleDisplayer(hash + " is " + nodename)
return logCtx, types.SimpleDisplayer(hash + " is " + nodename)
},
Verbosity: types.DebugMySQL,
},
@@ -73,17 +73,17 @@ var IdentsMap = types.RegexMap{
"RegexMemberCount": &types.LogRegex{
Regex: regexp.MustCompile("members.[0-9]+.:"),
InternalRegex: regexp.MustCompile(regexMembers),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
members := submatches[groupMembers]
membercount, err := strconv.Atoi(members)
if err != nil {
return ctx, nil
return logCtx, nil
}
ctx.MemberCount = membercount
logCtx.MemberCount = membercount
return ctx, types.SimpleDisplayer("view member count: " + members)
return logCtx, types.SimpleDisplayer("view member count: " + members)
},
Verbosity: types.DebugMySQL,
},
@@ -92,13 +92,13 @@ var IdentsMap = types.RegexMap{
"RegexOwnUUID": &types.LogRegex{
Regex: regexp.MustCompile("My UUID"),
InternalRegex: regexp.MustCompile("My UUID: " + regexUUID),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
hash := utils.UUIDToShortUUID(submatches[groupUUID])
ctx.AddOwnHash(hash, date)
logCtx.AddOwnHash(hash, date)
return ctx, types.SimpleDisplayer(hash + " is local")
return logCtx, types.SimpleDisplayer(hash + " is local")
},
Verbosity: types.DebugMySQL,
},
@@ -107,12 +107,12 @@ var IdentsMap = types.RegexMap{
"RegexOwnUUIDFromMessageRelay": &types.LogRegex{
Regex: regexp.MustCompile("turning message relay requesting"),
InternalRegex: regexp.MustCompile("\\(" + regexNodeHash + ", '" + regexNodeIPMethod + "'\\)"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
hash := submatches[groupNodeHash]
ctx.AddOwnHash(hash, date)
logCtx.AddOwnHash(hash, date)
return ctx, types.SimpleDisplayer(hash + " is local")
return logCtx, types.SimpleDisplayer(hash + " is local")
},
Verbosity: types.DebugMySQL,
},
@@ -121,11 +121,11 @@ var IdentsMap = types.RegexMap{
"RegexMyIDXFromComponent": &types.LogRegex{
Regex: regexp.MustCompile("New COMPONENT:"),
InternalRegex: regexp.MustCompile("New COMPONENT:.*my_idx = " + regexIdx),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
idx := submatches[groupIdx]
ctx.MyIdx = idx
return ctx, types.SimpleDisplayer("my_idx=" + idx)
logCtx.MyIdx = idx
return logCtx, types.SimpleDisplayer("my_idx=" + idx)
},
Verbosity: types.DebugMySQL,
},
@@ -154,24 +154,24 @@ var IdentsMap = types.RegexMap{
"RegexOwnNameFromStateExchange": &types.LogRegex{
Regex: regexp.MustCompile("STATE EXCHANGE: got state msg"),
InternalRegex: regexp.MustCompile("STATE EXCHANGE:.* from " + regexIdx + " \\(" + regexNodeName + "\\)"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
r, err := internalRegexSubmatch(internalRegex, log)
if err != nil {
return ctx, nil
return logCtx, nil
}
idx := submatches[groupIdx]
name := submatches[groupNodeName]
if idx != ctx.MyIdx {
return ctx, types.SimpleDisplayer("name(" + name + ") from unknown idx")
if idx != logCtx.MyIdx {
return logCtx, types.SimpleDisplayer("name(" + name + ") from unknown idx")
}
if ctx.State == "NON-PRIMARY" {
return ctx, types.SimpleDisplayer("name(" + name + ") can't be trusted as it's non-primary")
if logCtx.State == "NON-PRIMARY" {
return logCtx, types.SimpleDisplayer("name(" + name + ") can't be trusted as it's non-primary")
}
ctx.AddOwnName(name)
return ctx, types.SimpleDisplayer("local name:" + name)
logCtx.AddOwnName(name)
return logCtx, types.SimpleDisplayer("local name:" + name)
},
Verbosity: types.DebugMySQL,
},
@@ -183,8 +183,8 @@ func init_add_regexes() {
IdentsMap["RegexOwnUUIDFromEstablished"] = &types.LogRegex{
Regex: regexp.MustCompile("connection established to"),
InternalRegex: IdentsMap["RegexOwnUUIDFromMessageRelay"].InternalRegex,
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return IdentsMap["RegexOwnUUIDFromMessageRelay"].Handler(submatches, ctx, log, date)
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return IdentsMap["RegexOwnUUIDFromMessageRelay"].Handler(submatches, logCtx, log, date)
},
Verbosity: types.DebugMySQL,
}
@@ -192,8 +192,8 @@ func init_add_regexes() {
IdentsMap["RegexOwnIndexFromView"] = &types.LogRegex{
Regex: regexp.MustCompile("own_index:"),
InternalRegex: regexp.MustCompile("own_index: " + regexIdx),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return IdentsMap["RegexMyIDXFromComponent"].Handler(submatches, ctx, log, date)
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return IdentsMap["RegexMyIDXFromComponent"].Handler(submatches, logCtx, log, date)
},
Verbosity: types.DebugMySQL,
}
@@ -204,8 +204,8 @@ func init_add_regexes() {
IdentsMap["RegexMyIDXFromClusterView"] = &types.LogRegex{
Regex: regexp.MustCompile("New cluster view:"),
InternalRegex: regexp.MustCompile("New cluster view:.*my index: " + regexIdx + ","),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return IdentsMap["RegexMyIDXFromComponent"].Handler(internalRegex, ctx, log)
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return IdentsMap["RegexMyIDXFromComponent"].Handler(internalRegex, logCtx, log)
},
Verbosity: types.DebugMySQL,
}

View File

@@ -11,7 +11,7 @@ func TestIdentsRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] (90002222-1111, 'ssl://0.0.0.0:4567') Found matching local endpoint for a connection, blacklisting address ssl://127.0.0.1:4567",
expected: regexTestState{
Ctx: types.LogCtx{OwnIPs: []string{"127.0.0.1"}},
LogCtx: types.LogCtx{OwnIPs: []string{"127.0.0.1"}},
},
expectedOut: "127.0.0.1 is local",
key: "RegexSourceNode",
@@ -20,7 +20,7 @@ func TestIdentsRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] Passing config to GCS: base_dir = /var/lib/mysql/; base_host = 127.0.0.1; base_port = 4567; cert.log_conflicts = no; cert.optimistic_pa = no; debug = no; evs.auto_evict = 0; evs.delay_margin = PT1S; evs.delayed_keep_period = PT30S; evs.inactive_check_period = PT0.5S; evs.inactive_timeout = PT15S; evs.join_retrans_period = PT1S; evs.max_install_timeouts = 3; evs.send_window = 10; evs.stats_report_period = PT1M; evs.suspect_timeout = PT5S; evs.user_send_window = 4; evs.view_forget_timeout = PT24H; gcache.dir = /data/mysql/; gcache.freeze_purge_at_seqno = -1; gcache.keep_pages_count = 0; gcache.keep_pages_size = 0; gcache.mem_size = 0; gcache.name = galera.cache; gcache.page_size = 128M; gcache.recover = yes; gcache.size = 128M; gcomm.thread_prio = ; gcs.fc_debug = 0; gcs.fc_factor = 1.0; gcs.fc_limit = 100; gcs.fc_master_slave = no; gcs.max_packet_size = 64500; gcs.max_throttle = 0.25; gcs.recv_q_hard_limit = 9223372036854775807; gcs.recv_q_soft_limit = 0.25; gcs.sync_donor = no; gmcast.segment = 0; gmcast.version = 0; pc.announce_timeout = PT3S; pc.checksum = false; pc.ignore_quorum = false; pc.ignore_sb = false; pc.npvo = false; pc.recovery = true; pc.version = 0; pc.wait_prim = true; pc.wait_prim_timeout = PT30S; pc.weight = 1; protonet.backend = asio; protonet.version = 0; repl.causal_read_timeout = PT30S; repl.commit_order = 3; repl.key_format = FLAT8; repl.max_ws_size = 2147483647; repl.proto_max = 10; socket.checksum = 2; socket.recv_buf_size = auto; socket.send_buf_size = auto; socket.ssl_ca = ca.pem; socket.ssl_cert = server-cert.pem; socket.ssl_cipher = ; socket.ssl_compression = YES; socket.ssl_key = server-key.pem;",
expected: regexTestState{
Ctx: types.LogCtx{OwnIPs: []string{"127.0.0.1"}},
LogCtx: types.LogCtx{OwnIPs: []string{"127.0.0.1"}},
},
expectedOut: "127.0.0.1 is local",
key: "RegexBaseHost",
@@ -29,7 +29,7 @@ func TestIdentsRegex(t *testing.T) {
{
log: " 0: 015702fc-32f5-11ed-a4ca-267f97316394, node1",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "0",
MemberCount: 1,
OwnHashes: []string{},
@@ -39,7 +39,7 @@ func TestIdentsRegex(t *testing.T) {
State: "PRIMARY",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "0",
MemberCount: 1,
OwnHashes: []string{"015702fc-a4ca"},
@@ -54,7 +54,7 @@ func TestIdentsRegex(t *testing.T) {
{
log: " 0: 015702fc-32f5-11ed-a4ca-267f97316394, node1",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "0",
MemberCount: 1,
OwnHashes: []string{},
@@ -64,7 +64,7 @@ func TestIdentsRegex(t *testing.T) {
State: "NON-PRIMARY",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "0",
MemberCount: 1,
OwnHashes: []string{"015702fc-a4ca"},
@@ -79,7 +79,7 @@ func TestIdentsRegex(t *testing.T) {
{
log: " 0: 015702fc-32f5-11ed-a4ca-267f97316394, node1",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "0",
MemberCount: 2,
},
@@ -87,7 +87,7 @@ func TestIdentsRegex(t *testing.T) {
State: "NON-PRIMARY",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "0",
MemberCount: 2,
},
@@ -100,7 +100,7 @@ func TestIdentsRegex(t *testing.T) {
{
log: " 1: 015702fc-32f5-11ed-a4ca-267f97316394, node1",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "1",
MemberCount: 1,
OwnHashes: []string{},
@@ -110,7 +110,7 @@ func TestIdentsRegex(t *testing.T) {
State: "PRIMARY",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "1",
MemberCount: 1,
OwnHashes: []string{"015702fc-a4ca"},
@@ -125,7 +125,7 @@ func TestIdentsRegex(t *testing.T) {
{
log: " 0: 015702fc-32f5-11ed-a4ca-267f97316394, node1",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "1",
MemberCount: 1,
},
@@ -133,7 +133,7 @@ func TestIdentsRegex(t *testing.T) {
State: "PRIMARY",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "1",
MemberCount: 1,
},
@@ -146,7 +146,7 @@ func TestIdentsRegex(t *testing.T) {
{
log: " 0: 015702fc-32f5-11ed-a4ca-267f97316394, node1.with.complete.fqdn",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "1",
MemberCount: 1,
},
@@ -154,7 +154,7 @@ func TestIdentsRegex(t *testing.T) {
State: "PRIMARY",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "1",
MemberCount: 1,
},
@@ -168,14 +168,14 @@ func TestIdentsRegex(t *testing.T) {
name: "name too long and truncated",
log: " 0: 015702fc-32f5-11ed-a4ca-267f97316394, name_so_long_it_will_get_trunca",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "1",
MemberCount: 1,
},
State: "PRIMARY",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "1",
MemberCount: 1,
},
@@ -190,7 +190,7 @@ func TestIdentsRegex(t *testing.T) {
log: " members(1):",
expectedOut: "view member count: 1",
expected: regexTestState{
Ctx: types.LogCtx{MemberCount: 1},
LogCtx: types.LogCtx{MemberCount: 1},
},
key: "RegexMemberCount",
},
@@ -198,10 +198,10 @@ func TestIdentsRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 1 [Note] [MY-000000] [Galera] ####### My UUID: 60205de0-5cf6-11ec-8884-3a01908be11a",
input: regexTestState{
Ctx: types.LogCtx{},
LogCtx: types.LogCtx{},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnHashes: []string{"60205de0-8884"},
},
},
@@ -212,10 +212,10 @@ func TestIdentsRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: (9509c194, 'tcp://0.0.0.0:4567') turning message relay requesting on, nonlive peers:",
input: regexTestState{
Ctx: types.LogCtx{},
LogCtx: types.LogCtx{},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnHashes: []string{"9509c194"},
},
},
@@ -226,10 +226,10 @@ func TestIdentsRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: New COMPONENT: primary = yes, bootstrap = no, my_idx = 0, memb_num = 2",
input: regexTestState{
Ctx: types.LogCtx{},
LogCtx: types.LogCtx{},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "0",
},
},
@@ -240,10 +240,10 @@ func TestIdentsRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: (9509c194, 'tcp://0.0.0.0:4567') connection established to 838ebd6d tcp://172.17.0.2:4567",
input: regexTestState{
Ctx: types.LogCtx{},
LogCtx: types.LogCtx{},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnHashes: []string{"9509c194"},
},
},
@@ -254,10 +254,10 @@ func TestIdentsRegex(t *testing.T) {
{
log: " own_index: 1",
input: regexTestState{
Ctx: types.LogCtx{},
LogCtx: types.LogCtx{},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "1",
},
},

View File

@@ -20,12 +20,12 @@ var PXCOperatorMap = types.RegexMap{
"RegexNodeNameFromEnv": &types.LogRegex{
Regex: regexp.MustCompile(". NODE_NAME="),
InternalRegex: regexp.MustCompile("NODE_NAME=" + regexNodeName),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
nodename := submatches[groupNodeName]
nodename, _, _ = strings.Cut(nodename, ".")
ctx.AddOwnName(nodename, date)
return ctx, types.SimpleDisplayer("local name:" + nodename)
logCtx.AddOwnName(nodename, date)
return logCtx, types.SimpleDisplayer("local name:" + nodename)
},
Verbosity: types.DebugMySQL,
},
@@ -33,11 +33,11 @@ var PXCOperatorMap = types.RegexMap{
"RegexNodeIPFromEnv": &types.LogRegex{
Regex: regexp.MustCompile(". NODE_IP="),
InternalRegex: regexp.MustCompile("NODE_IP=" + regexNodeIP),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ip := submatches[groupNodeIP]
ctx.AddOwnIP(ip, date)
return ctx, types.SimpleDisplayer("local ip:" + ip)
logCtx.AddOwnIP(ip, date)
return logCtx, types.SimpleDisplayer("local ip:" + ip)
},
Verbosity: types.DebugMySQL,
},
@@ -49,8 +49,8 @@ var PXCOperatorMap = types.RegexMap{
// those "operators" regexes do not have the log prefix added implicitly. It's not strictly needed, but
// it will help to avoid catching random piece of log out of order
Regex: regexp.MustCompile(k8sprefix + ".*GCache::RingBuffer initial scan"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer("recovering gcache")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer("recovering gcache")
},
},
@@ -60,28 +60,28 @@ var PXCOperatorMap = types.RegexMap{
"RegexOperatorMemberAssociations": &types.LogRegex{
Regex: regexp.MustCompile("================================================.*View:"),
InternalRegex: regexp.MustCompile("own_index: " + regexIdx + ".*(?P<memberlog>" + IdentsMap["RegexMemberCount"].Regex.String() + ")(?P<compiledAssociations>(....-?[0-9]{1,2}(\\.-?[0-9])?: [a-z0-9]+-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]+, [a-zA-Z0-9-_\\.]+)+)"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.MyIdx = submatches[groupIdx]
logCtx.MyIdx = submatches[groupIdx]
var (
displayer types.LogDisplayer
msg string
)
ctx, displayer = IdentsMap["RegexMemberCount"].Handle(ctx, submatches["memberlog"], date)
msg += displayer(ctx) + "; "
logCtx, displayer = IdentsMap["RegexMemberCount"].Handle(logCtx, submatches["memberlog"], date)
msg += displayer(logCtx) + "; "
subAssociations := strings.Split(submatches["compiledAssociations"], "\\n\\t")
if len(subAssociations) < 2 {
return ctx, types.SimpleDisplayer(msg)
return logCtx, types.SimpleDisplayer(msg)
}
for _, subAssociation := range subAssociations[1:] {
// better to reuse the idents regex
ctx, displayer = IdentsMap["RegexMemberAssociations"].Handle(ctx, subAssociation, date)
msg += displayer(ctx) + "; "
logCtx, displayer = IdentsMap["RegexMemberAssociations"].Handle(logCtx, subAssociation, date)
msg += displayer(logCtx) + "; "
}
return ctx, types.SimpleDisplayer(msg)
return logCtx, types.SimpleDisplayer(msg)
},
Verbosity: types.DebugMySQL,
},

View File

@@ -12,7 +12,7 @@ func TestPXCOperatorRegex(t *testing.T) {
{
log: "{\"log\":\"2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] ================================================\\nView:\\n id: 9f191762-2542-11ee-89be-13bdb1218f0e:9375811\\n status: primary\\n protocol_version: 4\\n capabilities: MULTI-MASTER, CERTIFICATION, PARALLEL_APPLYING, REPLAY, ISOLATION, PAUSE, CAUSAL_READ, INCREMENTAL_WS, UNORDERED, PREORDERED, STREAMING, NBO\\n final: no\\n own_index: 0\\n members(3):\\n\\t0: 45406e8d-2de0-11ee-95fc-f29a5fdf1ee0, cluster1-0\\n\\t1: 5bf18376-2de0-11ee-8333-6e755a3456ca, cluster1-2\\n\\t2: 66e2b7bf-2de0-11ee-8000-f7d68b5cf6f6, cluster1-1\\n=================================================\\n\",\"file\":\"/var/lib/mysql/mysqld-error.log\"}",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnHashes: []string{},
OwnNames: []string{},
},
@@ -20,7 +20,7 @@ func TestPXCOperatorRegex(t *testing.T) {
State: "PRIMARY",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
MyIdx: "0",
MemberCount: 3,
OwnHashes: []string{"45406e8d-95fc"},
@@ -36,7 +36,7 @@ func TestPXCOperatorRegex(t *testing.T) {
{
log: "+ NODE_NAME=cluster1-pxc-0.cluster1-pxc.test-percona.svc.cluster.local",
expected: regexTestState{
Ctx: types.LogCtx{OwnNames: []string{"cluster1-pxc-0"}},
LogCtx: types.LogCtx{OwnNames: []string{"cluster1-pxc-0"}},
},
expectedOut: "local name:cluster1-pxc-0",
key: "RegexNodeNameFromEnv",
@@ -45,7 +45,7 @@ func TestPXCOperatorRegex(t *testing.T) {
{
log: "+ NODE_IP=172.17.0.2",
expected: regexTestState{
Ctx: types.LogCtx{OwnIPs: []string{"172.17.0.2"}},
LogCtx: types.LogCtx{OwnIPs: []string{"172.17.0.2"}},
},
expectedOut: "local ip:172.17.0.2",
key: "RegexNodeIPFromEnv",

View File

@@ -17,7 +17,7 @@ import (
type regexTestState struct {
State string
Ctx types.LogCtx
LogCtx types.LogCtx
HashToNodeNames map[string]string
HashToIP map[string]string
IPToMethods map[string]string
@@ -74,15 +74,15 @@ func iterateRegexTest(t *testing.T, regexmap types.RegexMap, tests []regexTest)
}
if test.input.State != "" {
test.input.Ctx.SetState(test.input.State)
test.input.LogCtx.SetState(test.input.State)
}
// Test 3
// Get the message to display using the input context
ctx, displayer := regexmap[test.key].Handle(test.input.Ctx, test.log, time.Time{})
logCtx, displayer := regexmap[test.key].Handle(test.input.LogCtx, test.log, time.Time{})
msg := ""
if displayer != nil {
msg = displayer(ctx)
msg = displayer(logCtx)
} else if !test.displayerExpectedNil {
t.Errorf("key: %s\ntestname: %s\ndisplayer is nil\nexpected: not nil", test.key, test.name)
}
@@ -91,16 +91,16 @@ func iterateRegexTest(t *testing.T, regexmap types.RegexMap, tests []regexTest)
// Making sure the updated context is what we expect
// alternative to reflect.deepequal, it enables to avoid comparing "states" map
res := cmp.Equal(ctx, test.expected.Ctx, cmpopts.IgnoreUnexported(types.LogCtx{}))
if !res || ctx.State() != test.expected.State {
t.Errorf("context is not as expected: \nkey: %s\ntestname: %s\nctx: %+v\nexpected ctx: %+v\nout: %s\nexpected out: %s\nstate: %s\nexpected state: %s", test.key, test.name, spew.Sdump(ctx), spew.Sdump(test.expected.Ctx), msg, test.expectedOut, ctx.State(), test.expected.State)
res := cmp.Equal(logCtx, test.expected.LogCtx, cmpopts.IgnoreUnexported(types.LogCtx{}))
if !res || logCtx.State() != test.expected.State {
t.Errorf("context is not as expected: \nkey: %s\ntestname: %s\nlogCtx: %+v\nexpected logCtx: %+v\nout: %s\nexpected out: %s\nstate: %s\nexpected state: %s", test.key, test.name, spew.Sdump(logCtx), spew.Sdump(test.expected.LogCtx), msg, test.expectedOut, logCtx.State(), test.expected.State)
t.Fail()
}
// Test 5
// Making sure the displayed message is correct
if msg != test.expectedOut {
t.Errorf("displayed message is not as expected: \nkey: %s\ntestname: %s\nctx: %+v\nout: %s\nexpected out: %s\nstate: %s", test.key, test.name, spew.Sdump(ctx), msg, test.expectedOut, ctx.State())
t.Errorf("displayed message is not as expected: \nkey: %s\ntestname: %s\nlogCtx: %+v\nout: %s\nexpected out: %s\nstate: %s", test.key, test.name, spew.Sdump(logCtx), msg, test.expectedOut, logCtx.State())
t.Fail()
}
@@ -110,25 +110,25 @@ func iterateRegexTest(t *testing.T, regexmap types.RegexMap, tests []regexTest)
maxTime, _ := time.Parse(time.RFC3339, "2100-01-01T01:01:01Z")
for hash, expectedValue := range test.expected.HashToNodeNames {
if value := translate.GetNodeNameFromHash(hash, maxTime); value != expectedValue {
t.Errorf("wrong HashToNodeNames\ntest key: %s\ntestname: %s\nctx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(ctx), msg, hash, expectedValue, value)
t.Errorf("wrong HashToNodeNames\ntest key: %s\ntestname: %s\nlogCtx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(logCtx), msg, hash, expectedValue, value)
t.Fail()
}
}
for hash, expectedValue := range test.expected.HashToIP {
if value := translate.GetIPFromHash(hash); value != expectedValue {
t.Errorf("wrong HashToIP\ntest key: %s\ntestname: %s\nctx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(ctx), msg, hash, expectedValue, value)
t.Errorf("wrong HashToIP\ntest key: %s\ntestname: %s\nlogCtx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(logCtx), msg, hash, expectedValue, value)
t.Fail()
}
}
for ip, expectedValue := range test.expected.IPToMethods {
if value := translate.GetMethodFromIP(ip, maxTime); value != expectedValue {
t.Errorf("wrong IPToMethods\ntest key: %s\ntestname: %s\nctx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(ctx), msg, ip, expectedValue, value)
t.Errorf("wrong IPToMethods\ntest key: %s\ntestname: %s\nlogCtx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(logCtx), msg, ip, expectedValue, value)
t.Fail()
}
}
for ip, expectedValue := range test.expected.IPToNodeNames {
if value := translate.GetNodeNameFromIP(ip, maxTime); value != expectedValue {
t.Errorf("wrong IPToNodeNames\ntest key: %s\ntestname: %s\nctx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(ctx), msg, ip, expectedValue, value)
t.Errorf("wrong IPToNodeNames\ntest key: %s\ntestname: %s\nlogCtx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(logCtx), msg, ip, expectedValue, value)
t.Fail()
}
}

View File

@@ -17,7 +17,7 @@ var SSTMap = types.RegexMap{
"RegexSSTRequestSuccess": &types.LogRegex{
Regex: regexp.MustCompile("requested state transfer.*Selected"),
InternalRegex: regexp.MustCompile("Member " + regexIdx + " \\(" + regexNodeName + "\\) requested state transfer.*Selected " + regexIdx + " \\(" + regexNodeName2 + "\\)\\("),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
joiner := utils.ShortNodeName(submatches[groupNodeName])
donor := utils.ShortNodeName(submatches[groupNodeName2])
@@ -34,13 +34,13 @@ var SSTMap = types.RegexMap{
sst.SelectionTimestamp = &selectionTimestamp
}
ctx.SSTs[donor] = sst
logCtx.SSTs[donor] = sst
return ctx, func(ctx types.LogCtx) string {
if utils.SliceContains(ctx.OwnNames, joiner) {
return logCtx, func(logCtx types.LogCtx) string {
if utils.SliceContains(logCtx.OwnNames, joiner) {
return donor + utils.Paint(utils.GreenText, " will resync local node")
}
if utils.SliceContains(ctx.OwnNames, donor) {
if utils.SliceContains(logCtx.OwnNames, donor) {
return utils.Paint(utils.GreenText, "local node will resync ") + joiner
}
@@ -52,15 +52,15 @@ var SSTMap = types.RegexMap{
"RegexSSTResourceUnavailable": &types.LogRegex{
Regex: regexp.MustCompile("requested state transfer.*Resource temporarily unavailable"),
InternalRegex: regexp.MustCompile("Member .* \\(" + regexNodeName + "\\) requested state transfer"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
joiner := submatches[groupNodeName]
if utils.SliceContains(ctx.OwnNames, joiner) {
if utils.SliceContains(logCtx.OwnNames, joiner) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "cannot find donor"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "cannot find donor"))
}
return ctx, types.SimpleDisplayer(joiner + utils.Paint(utils.YellowText, " cannot find donor"))
return logCtx, types.SimpleDisplayer(joiner + utils.Paint(utils.YellowText, " cannot find donor"))
},
},
@@ -68,21 +68,21 @@ var SSTMap = types.RegexMap{
"RegexSSTComplete": &types.LogRegex{
Regex: regexp.MustCompile("State transfer to.*complete"),
InternalRegex: regexp.MustCompile(regexIdx + " \\(" + regexNodeName + "\\): State transfer to " + regexIdx + " \\(" + regexNodeName2 + "\\) complete"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
donor := utils.ShortNodeName(submatches[groupNodeName])
joiner := utils.ShortNodeName(submatches[groupNodeName2])
displayType := "SST"
if ctx.SSTs[donor].Type != "" {
displayType = ctx.SSTs[donor].Type
if logCtx.SSTs[donor].Type != "" {
displayType = logCtx.SSTs[donor].Type
}
delete(ctx.SSTs, donor)
delete(logCtx.SSTs, donor)
return ctx, func(ctx types.LogCtx) string {
if utils.SliceContains(ctx.OwnNames, joiner) {
return logCtx, func(logCtx types.LogCtx) string {
if utils.SliceContains(logCtx.OwnNames, joiner) {
return utils.Paint(utils.GreenText, "got "+displayType+" from ") + donor
}
if utils.SliceContains(ctx.OwnNames, donor) {
if utils.SliceContains(logCtx.OwnNames, donor) {
return utils.Paint(utils.GreenText, "finished sending "+displayType+" to ") + joiner
}
@@ -96,81 +96,81 @@ var SSTMap = types.RegexMap{
"RegexSSTCompleteUnknown": &types.LogRegex{
Regex: regexp.MustCompile("State transfer to.*left the group.*complete"),
InternalRegex: regexp.MustCompile(regexIdx + " \\(" + regexNodeName + "\\): State transfer.*\\(left the group\\) complete"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
donor := utils.ShortNodeName(submatches[groupNodeName])
delete(ctx.SSTs, donor)
return ctx, types.SimpleDisplayer(donor + utils.Paint(utils.RedText, " synced ??(node left)"))
delete(logCtx.SSTs, donor)
return logCtx, types.SimpleDisplayer(donor + utils.Paint(utils.RedText, " synced ??(node left)"))
},
},
"RegexSSTFailedUnknown": &types.LogRegex{
Regex: regexp.MustCompile("State transfer to.*left the group.*failed"),
InternalRegex: regexp.MustCompile(regexIdx + " \\(" + regexNodeName + "\\): State transfer.*\\(left the group\\) failed"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
donor := utils.ShortNodeName(submatches[groupNodeName])
delete(ctx.SSTs, donor)
return ctx, types.SimpleDisplayer(donor + utils.Paint(utils.RedText, " failed to sync ??(node left)"))
delete(logCtx.SSTs, donor)
return logCtx, types.SimpleDisplayer(donor + utils.Paint(utils.RedText, " failed to sync ??(node left)"))
},
},
"RegexSSTStateTransferFailed": &types.LogRegex{
Regex: regexp.MustCompile("State transfer to.*failed:"),
InternalRegex: regexp.MustCompile(regexIdx + " \\(" + regexNodeName + "\\): State transfer to " + regexIdx + " \\(" + regexNodeName2 + "\\) failed"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
donor := utils.ShortNodeName(submatches[groupNodeName])
joiner := utils.ShortNodeName(submatches[groupNodeName2])
delete(ctx.SSTs, donor)
return ctx, types.SimpleDisplayer(donor + utils.Paint(utils.RedText, " failed to sync ") + joiner)
delete(logCtx.SSTs, donor)
return logCtx, types.SimpleDisplayer(donor + utils.Paint(utils.RedText, " failed to sync ") + joiner)
},
},
"RegexSSTError": &types.LogRegex{
Regex: regexp.MustCompile("Process completed with error: wsrep_sst"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "SST error"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "SST error"))
},
},
"RegexSSTInitiating": &types.LogRegex{
Regex: regexp.MustCompile("Initiating SST.IST transfer on DONOR side"),
InternalRegex: regexp.MustCompile("DONOR side \\((?P<scriptname>[a-zA-Z0-9-_]*) --role 'donor' --address '" + regexNodeIP + ":(?P<sstport>[0-9]*)\\)"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer("init sst using " + submatches["scriptname"])
return logCtx, types.SimpleDisplayer("init sst using " + submatches["scriptname"])
},
},
"RegexSSTCancellation": &types.LogRegex{
Regex: regexp.MustCompile("Initiating SST cancellation"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "former SST cancelled"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "former SST cancelled"))
},
},
"RegexSSTProceeding": &types.LogRegex{
Regex: regexp.MustCompile("Proceeding with SST"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("JOINER")
ctx.SetSSTTypeMaybe("SST")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("JOINER")
logCtx.SetSSTTypeMaybe("SST")
return ctx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "receiving SST"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "receiving SST"))
},
},
"RegexSSTStreamingTo": &types.LogRegex{
Regex: regexp.MustCompile("Streaming the backup to"),
InternalRegex: regexp.MustCompile("Streaming the backup to joiner at " + regexNodeIP),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("DONOR")
logCtx.SetState("DONOR")
joiner := submatches[groupNodeIP]
return ctx, types.FormatByIPDisplayer(utils.Paint(utils.YellowText, "SST to ")+"%s", joiner, date)
return logCtx, types.FormatByIPDisplayer(utils.Paint(utils.YellowText, "SST to ")+"%s", joiner, date)
},
},
@@ -179,10 +179,10 @@ var SSTMap = types.RegexMap{
// the UUID here is not from a node, it's a cluster state UUID, this is only used to ensure it's correctly parsed
InternalRegex: regexp.MustCompile("IST received: " + regexUUID + ":" + regexSeqno),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
seqno := submatches[groupSeqno]
return ctx, types.SimpleDisplayer(utils.Paint(utils.GreenText, "IST received") + "(seqno:" + seqno + ")")
return logCtx, types.SimpleDisplayer(utils.Paint(utils.GreenText, "IST received") + "(seqno:" + seqno + ")")
},
},
@@ -191,14 +191,14 @@ var SSTMap = types.RegexMap{
// TODO: sometimes, it's a hostname here
InternalRegex: regexp.MustCompile("IST sender starting to serve " + regexNodeIPMethod + " sending [0-9]+-" + regexSeqno),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("DONOR")
ctx.SetSSTTypeMaybe("IST")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("DONOR")
logCtx.SetSSTTypeMaybe("IST")
seqno := submatches[groupSeqno]
joiner := submatches[groupNodeIP]
return ctx, types.FormatByIPDisplayer(utils.Paint(utils.YellowText, "IST to ")+"%s(seqno:"+seqno+")", joiner, date)
return logCtx, types.FormatByIPDisplayer(utils.Paint(utils.YellowText, "IST to ")+"%s(seqno:"+seqno+")", joiner, date)
},
},
@@ -206,8 +206,8 @@ var SSTMap = types.RegexMap{
Regex: regexp.MustCompile("Prepared IST receiver"),
InternalRegex: regexp.MustCompile("Prepared IST receiver( for (?P<startingseqno>[0-9]+)-" + regexSeqno + ")?"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("JOINER")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("JOINER")
seqno := submatches[groupSeqno]
msg := utils.Paint(utils.YellowText, "will receive ")
@@ -215,35 +215,35 @@ var SSTMap = types.RegexMap{
startingseqno := submatches["startingseqno"]
// if it's 0, it will go to SST without a doubt
if startingseqno == "0" {
ctx.SetSSTTypeMaybe("SST")
logCtx.SetSSTTypeMaybe("SST")
msg += "SST"
// not totally correct, but need more logs to get proper pattern
// in some cases it does IST before going with SST
} else {
ctx.SetSSTTypeMaybe("IST")
logCtx.SetSSTTypeMaybe("IST")
msg += "IST"
if seqno != "" {
msg += "(seqno:" + seqno + ")"
}
}
return ctx, types.SimpleDisplayer(msg)
return logCtx, types.SimpleDisplayer(msg)
},
},
"RegexFailedToPrepareIST": &types.LogRegex{
Regex: regexp.MustCompile("Failed to prepare for incremental state transfer"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetSSTTypeMaybe("SST")
return ctx, types.SimpleDisplayer("IST is not applicable")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetSSTTypeMaybe("SST")
return logCtx, types.SimpleDisplayer("IST is not applicable")
},
},
"RegexXtrabackupISTReceived": &types.LogRegex{
Regex: regexp.MustCompile("xtrabackup_ist received from donor"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetSSTTypeMaybe("IST")
return ctx, types.SimpleDisplayer("IST running")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetSSTTypeMaybe("IST")
return logCtx, types.SimpleDisplayer("IST running")
},
Verbosity: types.DebugMySQL, // that one is not really helpful, except for tooling constraints
},
@@ -251,50 +251,50 @@ var SSTMap = types.RegexMap{
// could not find production examples yet, but it did exist in older version there also was "Bypassing state dump"
"RegexBypassSST": &types.LogRegex{
Regex: regexp.MustCompile("Bypassing SST"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetSSTTypeMaybe("IST")
return ctx, types.SimpleDisplayer("IST will be used")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetSSTTypeMaybe("IST")
return logCtx, types.SimpleDisplayer("IST will be used")
},
},
"RegexSocatConnRefused": &types.LogRegex{
Regex: regexp.MustCompile("E connect.*Connection refused"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "socat: connection refused"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "socat: connection refused"))
},
},
// 2023-05-12T02:52:33.767132Z 0 [Note] [MY-000000] [WSREP-SST] Preparing the backup at /var/lib/mysql/sst-xb-tmpdir
"RegexPreparingBackup": &types.LogRegex{
Regex: regexp.MustCompile("Preparing the backup at"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer("preparing SST backup")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer("preparing SST backup")
},
},
"RegexTimeoutReceivingFirstData": &types.LogRegex{
Regex: regexp.MustCompile("Possible timeout in receving first data from donor in gtid/keyring stage"), // typo is in Galera lib
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "timeout from donor in gtid/keyring stage"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "timeout from donor in gtid/keyring stage"))
},
},
"RegexWillNeverReceive": &types.LogRegex{
Regex: regexp.MustCompile("Will never receive state. Need to abort"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "will never receive SST, aborting"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "will never receive SST, aborting"))
},
},
"RegexISTFailed": &types.LogRegex{
Regex: regexp.MustCompile("async IST sender failed to serve"),
InternalRegex: regexp.MustCompile("IST sender failed to serve " + regexNodeIPMethod + ":.*asio error '.*: [0-9]+ \\((?P<error>[\\w\\s]+)\\)"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
joiner := submatches[groupNodeIP]
istError := submatches["error"]
return ctx, types.FormatByIPDisplayer("IST to %s"+utils.Paint(utils.RedText, " failed: ")+istError, joiner, date)
return logCtx, types.FormatByIPDisplayer("IST to %s"+utils.Paint(utils.RedText, " failed: ")+istError, joiner, date)
},
},
}

View File

@@ -11,10 +11,10 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: Member 2.0 (node2) requested state transfer from '*any*'. Selected 0.0 (node1)(SYNCED) as donor.",
input: regexTestState{
Ctx: types.LogCtx{SSTs: map[string]types.SST{}},
LogCtx: types.LogCtx{SSTs: map[string]types.SST{}},
},
expected: regexTestState{
Ctx: types.LogCtx{SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", SelectionTimestamp: timeMustParse("2001-01-01T01:01:01.000000Z")}}},
LogCtx: types.LogCtx{SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", SelectionTimestamp: timeMustParse("2001-01-01T01:01:01.000000Z")}}},
},
expectedOut: "node1 will resync node2",
key: "RegexSSTRequestSuccess",
@@ -23,10 +23,10 @@ func TestSSTRegex(t *testing.T) {
name: "with fqdn",
log: "2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] Member 2.0 (node2.host.com) requested state transfer from '*any*'. Selected 0.0 (node1.host.com)(SYNCED) as donor.",
input: regexTestState{
Ctx: types.LogCtx{SSTs: map[string]types.SST{}},
LogCtx: types.LogCtx{SSTs: map[string]types.SST{}},
},
expected: regexTestState{
Ctx: types.LogCtx{SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", SelectionTimestamp: timeMustParse("2001-01-01T01:01:01.000000Z")}}},
LogCtx: types.LogCtx{SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", SelectionTimestamp: timeMustParse("2001-01-01T01:01:01.000000Z")}}},
},
expectedOut: "node1 will resync node2",
key: "RegexSSTRequestSuccess",
@@ -35,13 +35,13 @@ func TestSSTRegex(t *testing.T) {
name: "joining",
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: Member 2.0 (node2) requested state transfer from '*any*'. Selected 0.0 (node1)(SYNCED) as donor.",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnNames: []string{"node2"},
SSTs: map[string]types.SST{},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnNames: []string{"node2"},
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", SelectionTimestamp: timeMustParse("2001-01-01T01:01:01.000000Z")}},
},
@@ -53,13 +53,13 @@ func TestSSTRegex(t *testing.T) {
name: "donor",
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: Member 2.0 (node2) requested state transfer from '*any*'. Selected 0.0 (node1)(SYNCED) as donor.",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnNames: []string{"node1"},
SSTs: map[string]types.SST{},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnNames: []string{"node1"},
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", SelectionTimestamp: timeMustParse("2001-01-01T01:01:01.000000Z")}},
},
@@ -71,10 +71,10 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01 01:01:01.164 WARN: Member 1.0 (node2) requested state transfer from 'node1', but it is impossible to select State Transfer donor: Resource temporarily unavailable",
input: regexTestState{
Ctx: types.LogCtx{},
LogCtx: types.LogCtx{},
},
expected: regexTestState{
Ctx: types.LogCtx{},
LogCtx: types.LogCtx{},
},
expectedOut: "node2 cannot find donor",
key: "RegexSSTResourceUnavailable",
@@ -83,12 +83,12 @@ func TestSSTRegex(t *testing.T) {
name: "local",
log: "2001-01-01 01:01:01.164 WARN: Member 1.0 (node2) requested state transfer from 'node1', but it is impossible to select State Transfer donor: Resource temporarily unavailable",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnNames: []string{"node2"},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnNames: []string{"node2"},
},
},
@@ -99,12 +99,12 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: 0.0 (node1): State transfer to 2.0 (node2) complete.",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{},
},
},
@@ -115,13 +115,13 @@ func TestSSTRegex(t *testing.T) {
name: "joiner",
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: 0.0 (node1): State transfer to 2.0 (node2) complete.",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnNames: []string{"node2"},
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{},
OwnNames: []string{"node2"},
},
@@ -133,13 +133,13 @@ func TestSSTRegex(t *testing.T) {
name: "joiner ist",
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: 0.0 (node1): State transfer to 2.0 (node2) complete.",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnNames: []string{"node2"},
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "IST"}},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{},
OwnNames: []string{"node2"},
},
@@ -151,13 +151,13 @@ func TestSSTRegex(t *testing.T) {
name: "donor",
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: 0.0 (node1): State transfer to 2.0 (node2) complete.",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnNames: []string{"node1"},
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{},
OwnNames: []string{"node1"},
},
@@ -169,13 +169,13 @@ func TestSSTRegex(t *testing.T) {
name: "donor ist",
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: 0.0 (node1): State transfer to 2.0 (node2) complete.",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnNames: []string{"node1"},
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "IST"}},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{},
OwnNames: []string{"node1"},
},
@@ -187,10 +187,10 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: 0.0 (node1): State transfer to -1.-1 (left the group) complete.",
input: regexTestState{
Ctx: types.LogCtx{},
LogCtx: types.LogCtx{},
},
expected: regexTestState{
Ctx: types.LogCtx{},
LogCtx: types.LogCtx{},
},
expectedOut: "node1 synced ??(node left)",
key: "RegexSSTCompleteUnknown",
@@ -211,13 +211,13 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z WSREP_SST: [INFO] Proceeding with SST.........",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
OwnNames: []string{"node2"},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "SST"}},
OwnNames: []string{"node2"},
},
@@ -245,13 +245,13 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01 1:01:01 140433613571840 [Note] WSREP: async IST sender starting to serve tcp://172.17.0.2:4568 sending 2-116",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
OwnNames: []string{"node1"},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "IST"}},
OwnNames: []string{"node1"},
},
@@ -264,13 +264,13 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] Prepared IST receiver for 114-116, listening at: ssl://172.17.0.2:4568",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
OwnNames: []string{"node2"},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "IST"}},
OwnNames: []string{"node2"},
},
@@ -282,13 +282,13 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] Prepared IST receiver for 0-116, listening at: ssl://172.17.0.2:4568",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
OwnNames: []string{"node2"},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "SST"}},
OwnNames: []string{"node2"},
},
@@ -301,13 +301,13 @@ func TestSSTRegex(t *testing.T) {
name: "mdb variant",
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: Prepared IST receiver, listening at: ssl://172.17.0.2:4568",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
OwnNames: []string{"node2"},
},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "IST"}},
OwnNames: []string{"node2"},
},
@@ -337,14 +337,14 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 1 [Note] WSREP: Failed to prepare for incremental state transfer: Local state UUID (00000000-0000-0000-0000-000000000000) does not match group state UUID (ed16c932-84b3-11ed-998c-8e3ae5bc328f): 1 (Operation not permitted)",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
OwnNames: []string{"node2"},
},
State: "JOINER",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "SST"}},
OwnNames: []string{"node2"},
},
@@ -356,14 +356,14 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 1 [Warning] WSREP: Failed to prepare for incremental state transfer: Local state seqno is undefined: 1 (Operation not permitted)",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
OwnNames: []string{"node2"},
},
State: "JOINER",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "SST"}},
OwnNames: []string{"node2"},
},
@@ -376,14 +376,14 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z WSREP_SST: [INFO] Bypassing SST. Can work it through IST",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
OwnNames: []string{"node2"},
},
State: "JOINER",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "IST"}},
OwnNames: []string{"node2"},
},
@@ -396,14 +396,14 @@ func TestSSTRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [WSREP-SST] xtrabackup_ist received from donor: Running IST",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2"}},
OwnNames: []string{"node2"},
},
State: "JOINER",
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
SSTs: map[string]types.SST{"node1": types.SST{Donor: "node1", Joiner: "node2", Type: "IST"}},
OwnNames: []string{"node2"},
},

View File

@@ -13,18 +13,18 @@ func init() {
}
var (
shiftFunc = func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
shiftFunc = func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
newState := submatches["state2"]
ctx.SetState(newState)
logCtx.SetState(newState)
if newState == "DONOR" || newState == "JOINER" {
ctx.ConfirmSSTMetadata(date)
logCtx.ConfirmSSTMetadata(date)
}
log = utils.PaintForState(submatches["state1"], submatches["state1"]) + " -> " + utils.PaintForState(submatches["state2"], submatches["state2"])
return ctx, types.SimpleDisplayer(log)
return logCtx, types.SimpleDisplayer(log)
}
shiftRegex = regexp.MustCompile("(?P<state1>[A-Z]+) -> (?P<state2>[A-Z]+)")
)
@@ -39,11 +39,11 @@ var StatesMap = types.RegexMap{
"RegexRestoredState": &types.LogRegex{
Regex: regexp.MustCompile("Restored state"),
InternalRegex: shiftRegex,
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
var displayer types.LogDisplayer
ctx, displayer = shiftFunc(submatches, ctx, log, date)
logCtx, displayer = shiftFunc(submatches, logCtx, log, date)
return ctx, types.SimpleDisplayer("(restored)" + displayer(ctx))
return logCtx, types.SimpleDisplayer("(restored)" + displayer(logCtx))
},
},
}

View File

@@ -20,15 +20,15 @@ var ViewsMap = types.RegexMap{
"RegexNodeEstablished": &types.LogRegex{
Regex: regexp.MustCompile("connection established"),
InternalRegex: regexp.MustCompile("established to " + regexNodeHash + " " + regexNodeIPMethod),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ip := submatches[groupNodeIP]
hash := submatches[groupNodeHash]
translate.AddHashToIP(hash, ip, date)
if utils.SliceContains(ctx.OwnIPs, ip) {
return ctx, nil
if utils.SliceContains(logCtx.OwnIPs, ip) {
return logCtx, nil
}
return ctx, types.FormatByHashDisplayer("%s established", hash, date)
return logCtx, types.FormatByHashDisplayer("%s established", hash, date)
},
Verbosity: types.DebugMySQL,
},
@@ -36,26 +36,26 @@ var ViewsMap = types.RegexMap{
"RegexNodeJoined": &types.LogRegex{
Regex: regexp.MustCompile("declaring .* stable"),
InternalRegex: regexp.MustCompile("declaring " + regexNodeHash + " at " + regexNodeIPMethod),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ip := submatches[groupNodeIP]
hash := submatches[groupNodeHash]
translate.AddHashToIP(hash, ip, date)
translate.AddIPToMethod(ip, submatches[groupMethod], date)
return ctx, types.FormatByHashDisplayer("%s"+utils.Paint(utils.GreenText, " joined"), hash, date)
return logCtx, types.FormatByHashDisplayer("%s"+utils.Paint(utils.GreenText, " joined"), hash, date)
},
},
"RegexNodeLeft": &types.LogRegex{
Regex: regexp.MustCompile("forgetting"),
InternalRegex: regexp.MustCompile("forgetting " + regexNodeHash + " \\(" + regexNodeIPMethod),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ip := submatches[groupNodeIP]
hash := submatches[groupNodeHash]
translate.AddHashToIP(hash, ip, date)
translate.AddIPToMethod(ip, submatches[groupMethod], date)
return ctx, types.FormatByHashDisplayer("%s"+utils.Paint(utils.RedText, " left"), hash, date)
return logCtx, types.FormatByHashDisplayer("%s"+utils.Paint(utils.RedText, " left"), hash, date)
},
},
@@ -63,106 +63,106 @@ var ViewsMap = types.RegexMap{
"RegexNewComponent": &types.LogRegex{
Regex: regexp.MustCompile("New COMPONENT:"),
InternalRegex: regexp.MustCompile("New COMPONENT: primary = (?P<primary>.+), bootstrap = (?P<bootstrap>.*), my_idx = .*, memb_num = (?P<memb_num>[0-9]{1,2})"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
primary := submatches["primary"] == "yes"
membNum := submatches["memb_num"]
bootstrap := submatches["bootstrap"] == "yes"
memberCount, err := strconv.Atoi(membNum)
if err != nil {
return ctx, nil
return logCtx, nil
}
ctx.MemberCount = memberCount
logCtx.MemberCount = memberCount
if primary {
// we don't always store PRIMARY because we could have found DONOR/JOINER/SYNCED/DESYNCED just earlier
// and we do not want to override these as they have more value
if !ctx.IsPrimary() {
ctx.SetState("PRIMARY")
if !logCtx.IsPrimary() {
logCtx.SetState("PRIMARY")
}
msg := utils.Paint(utils.GreenText, "PRIMARY") + "(n=" + membNum + ")"
if bootstrap {
msg += ",bootstrap"
}
return ctx, types.SimpleDisplayer(msg)
return logCtx, types.SimpleDisplayer(msg)
}
ctx.SetState("NON-PRIMARY")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "NON-PRIMARY") + "(n=" + membNum + ")")
logCtx.SetState("NON-PRIMARY")
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "NON-PRIMARY") + "(n=" + membNum + ")")
},
},
"RegexNodeSuspect": &types.LogRegex{
Regex: regexp.MustCompile("suspecting node"),
InternalRegex: regexp.MustCompile("suspecting node: " + regexNodeHash),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
hash := submatches[groupNodeHash]
return ctx, types.FormatByHashDisplayer("%s"+utils.Paint(utils.YellowText, " suspected to be down"), hash, date)
return logCtx, types.FormatByHashDisplayer("%s"+utils.Paint(utils.YellowText, " suspected to be down"), hash, date)
},
},
"RegexNodeChangedIdentity": &types.LogRegex{
Regex: regexp.MustCompile("remote endpoint.*changed identity"),
InternalRegex: regexp.MustCompile("remote endpoint " + regexNodeIPMethod + " changed identity " + regexNodeHash + " -> " + strings.Replace(regexNodeHash, groupNodeHash, groupNodeHash+"2", -1)),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
hash := utils.UUIDToShortUUID(submatches[groupNodeHash])
hash2 := utils.UUIDToShortUUID(submatches[groupNodeHash+"2"])
if ip := translate.GetIPFromHash(hash); ip != "" {
translate.AddHashToIP(hash2, ip, date)
}
return ctx, types.FormatByHashDisplayer("%s"+utils.Paint(utils.YellowText, " changed identity"), hash, date)
return logCtx, types.FormatByHashDisplayer("%s"+utils.Paint(utils.YellowText, " changed identity"), hash, date)
},
},
"RegexWsrepUnsafeBootstrap": &types.LogRegex{
Regex: regexp.MustCompile("ERROR.*not be safe to bootstrap"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("CLOSED")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("CLOSED")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "not safe to bootstrap"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "not safe to bootstrap"))
},
},
"RegexWsrepConsistenctyCompromised": &types.LogRegex{
Regex: regexp.MustCompile(".ode consistency compromi.ed"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
ctx.SetState("CLOSED")
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
logCtx.SetState("CLOSED")
return ctx, types.SimpleDisplayer(utils.Paint(utils.RedText, "consistency compromised"))
return logCtx, types.SimpleDisplayer(utils.Paint(utils.RedText, "consistency compromised"))
},
},
"RegexWsrepNonPrimary": &types.LogRegex{
Regex: regexp.MustCompile("failed to reach primary view"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer("received " + utils.Paint(utils.RedText, "non primary"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer("received " + utils.Paint(utils.RedText, "non primary"))
},
},
"RegexBootstrap": &types.LogRegex{
Regex: regexp.MustCompile("gcomm: bootstrapping new group"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "bootstrapping"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "bootstrapping"))
},
},
"RegexSafeToBootstrapSet": &types.LogRegex{
Regex: regexp.MustCompile("safe_to_bootstrap: 1"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "safe_to_bootstrap: 1"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "safe_to_bootstrap: 1"))
},
},
"RegexNoGrastate": &types.LogRegex{
Regex: regexp.MustCompile("Could not open state file for reading.*grastate.dat"),
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "no grastate.dat file"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "no grastate.dat file"))
},
},
"RegexBootstrappingDefaultState": &types.LogRegex{
Regex: regexp.MustCompile("Bootstraping with default state"), // typo is in Galera lib
Handler: func(submatches map[string]string, ctx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return ctx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "bootstrapping(empty grastate)"))
Handler: func(submatches map[string]string, logCtx types.LogCtx, log string, date time.Time) (types.LogCtx, types.LogDisplayer) {
return logCtx, types.SimpleDisplayer(utils.Paint(utils.YellowText, "bootstrapping(empty grastate)"))
},
},
}

View File

@@ -24,13 +24,13 @@ func TestViewsRegex(t *testing.T) {
name: "established to node's own ip",
log: "2001-01-01T01:01:01.000000Z 0 [Note] [MY-000000] [Galera] (60205de0-8884, 'ssl://0.0.0.0:4567') connection established to 5873acd0-baa8 ssl://172.17.0.2:4567",
input: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnIPs: []string{"172.17.0.2"},
},
HashToIP: map[string]string{},
},
expected: regexTestState{
Ctx: types.LogCtx{
LogCtx: types.LogCtx{
OwnIPs: []string{"172.17.0.2"},
},
HashToIP: map[string]string{"5873acd0-baa8": "172.17.0.2"},
@@ -77,8 +77,8 @@ func TestViewsRegex(t *testing.T) {
{
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: New COMPONENT: primary = yes, bootstrap = no, my_idx = 0, memb_num = 2",
expected: regexTestState{
Ctx: types.LogCtx{MemberCount: 2},
State: "PRIMARY",
LogCtx: types.LogCtx{MemberCount: 2},
State: "PRIMARY",
},
expectedOut: "PRIMARY(n=2)",
key: "RegexNewComponent",
@@ -87,8 +87,8 @@ func TestViewsRegex(t *testing.T) {
name: "bootstrap",
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: New COMPONENT: primary = yes, bootstrap = yes, my_idx = 0, memb_num = 2",
expected: regexTestState{
Ctx: types.LogCtx{MemberCount: 2},
State: "PRIMARY",
LogCtx: types.LogCtx{MemberCount: 2},
State: "PRIMARY",
},
expectedOut: "PRIMARY(n=2),bootstrap",
key: "RegexNewComponent",
@@ -100,8 +100,8 @@ func TestViewsRegex(t *testing.T) {
State: "JOINER",
},
expected: regexTestState{
Ctx: types.LogCtx{MemberCount: 2},
State: "JOINER",
LogCtx: types.LogCtx{MemberCount: 2},
State: "JOINER",
},
expectedOut: "PRIMARY(n=2)",
key: "RegexNewComponent",
@@ -110,8 +110,8 @@ func TestViewsRegex(t *testing.T) {
name: "non-primary",
log: "2001-01-01T01:01:01.000000Z 0 [Note] WSREP: New COMPONENT: primary = no, bootstrap = no, my_idx = 0, memb_num = 2",
expected: regexTestState{
Ctx: types.LogCtx{MemberCount: 2},
State: "NON-PRIMARY",
LogCtx: types.LogCtx{MemberCount: 2},
State: "NON-PRIMARY",
},
expectedOut: "NON-PRIMARY(n=2)",
key: "RegexNewComponent",

View File

@@ -37,13 +37,13 @@ type LogCtx struct {
}
func NewLogCtx() LogCtx {
ctx := LogCtx{minVerbosity: Debug}
ctx.InitMaps()
return ctx
logCtx := LogCtx{minVerbosity: Debug}
logCtx.InitMaps()
return logCtx
}
func (ctx *LogCtx) InitMaps() {
ctx.SSTs = map[string]SST{}
func (logCtx *LogCtx) InitMaps() {
logCtx.SSTs = map[string]SST{}
}
// State will return the wsrep state of the current file type
@@ -51,23 +51,23 @@ func (ctx *LogCtx) InitMaps() {
// Not tracking and differentiating by file types led to confusions in most subcommands
// as it would seem that sometimes mysql is restarting after a crash, while actually
// the operator was simply launching a "wsrep-recover" instance while mysql was still running
func (ctx LogCtx) State() string {
switch ctx.FileType {
func (logCtx LogCtx) State() string {
switch logCtx.FileType {
case "post.processing.log":
return ctx.statePostProcessingLog
return logCtx.statePostProcessingLog
case "recovery.log":
return ctx.stateRecoveryLog
return logCtx.stateRecoveryLog
case "backup.log":
return ctx.stateBackupLog
return logCtx.stateBackupLog
case "error.log":
fallthrough
default:
return ctx.stateErrorLog
return logCtx.stateErrorLog
}
}
// SetState will double-check if the STATE exists, and also store it on the correct status
func (ctx *LogCtx) SetState(s string) {
func (logCtx *LogCtx) SetState(s string) {
// NON-PRIMARY and RECOVERY are not a real wsrep state, but it's helpful here
// DONOR and DESYNCED are merged in wsrep, but we are able to distinguish here
@@ -75,68 +75,68 @@ func (ctx *LogCtx) SetState(s string) {
if !utils.SliceContains([]string{"SYNCED", "JOINED", "DONOR", "DESYNCED", "JOINER", "PRIMARY", "NON-PRIMARY", "OPEN", "CLOSED", "DESTROYED", "ERROR", "RECOVERY"}, s) {
return
}
switch ctx.FileType {
switch logCtx.FileType {
case "post.processing.log":
ctx.statePostProcessingLog = s
logCtx.statePostProcessingLog = s
case "recovery.log":
ctx.stateRecoveryLog = s
logCtx.stateRecoveryLog = s
case "backup.log":
ctx.stateBackupLog = s
logCtx.stateBackupLog = s
case "error.log":
fallthrough
default:
ctx.stateErrorLog = s
logCtx.stateErrorLog = s
}
}
func (ctx *LogCtx) HasVisibleEvents(level Verbosity) bool {
return level >= ctx.minVerbosity
func (logCtx *LogCtx) HasVisibleEvents(level Verbosity) bool {
return level >= logCtx.minVerbosity
}
func (ctx *LogCtx) IsPrimary() bool {
return utils.SliceContains([]string{"SYNCED", "DONOR", "DESYNCED", "JOINER", "PRIMARY"}, ctx.State())
func (logCtx *LogCtx) IsPrimary() bool {
return utils.SliceContains([]string{"SYNCED", "DONOR", "DESYNCED", "JOINER", "PRIMARY"}, logCtx.State())
}
// AddOwnName propagates a name into the translation maps using the trusted node's known own hashes and ips
func (ctx *LogCtx) AddOwnName(name string, date time.Time) {
func (logCtx *LogCtx) AddOwnName(name string, date time.Time) {
// used to be a simple "if utils.SliceContains", changed to "is it the last known name?"
// because some names/ips come back and forth, we should keep track of that
name = utils.ShortNodeName(name)
if len(ctx.OwnNames) > 0 && ctx.OwnNames[len(ctx.OwnNames)-1] == name {
if len(logCtx.OwnNames) > 0 && logCtx.OwnNames[len(logCtx.OwnNames)-1] == name {
return
}
ctx.OwnNames = append(ctx.OwnNames, name)
for _, hash := range ctx.OwnHashes {
logCtx.OwnNames = append(logCtx.OwnNames, name)
for _, hash := range logCtx.OwnHashes {
translate.AddHashToNodeName(hash, name, date)
}
for _, ip := range ctx.OwnIPs {
for _, ip := range logCtx.OwnIPs {
translate.AddIPToNodeName(ip, name, date)
}
}
// AddOwnHash propagates a hash into the translation maps
func (ctx *LogCtx) AddOwnHash(hash string, date time.Time) {
if utils.SliceContains(ctx.OwnHashes, hash) {
func (logCtx *LogCtx) AddOwnHash(hash string, date time.Time) {
if utils.SliceContains(logCtx.OwnHashes, hash) {
return
}
ctx.OwnHashes = append(ctx.OwnHashes, hash)
logCtx.OwnHashes = append(logCtx.OwnHashes, hash)
for _, ip := range ctx.OwnIPs {
for _, ip := range logCtx.OwnIPs {
translate.AddHashToIP(hash, ip, date)
}
for _, name := range ctx.OwnNames {
for _, name := range logCtx.OwnNames {
translate.AddHashToNodeName(hash, name, date)
}
}
// AddOwnIP propagates a ip into the translation maps
func (ctx *LogCtx) AddOwnIP(ip string, date time.Time) {
func (logCtx *LogCtx) AddOwnIP(ip string, date time.Time) {
// see AddOwnName comment
if len(ctx.OwnIPs) > 0 && ctx.OwnIPs[len(ctx.OwnIPs)-1] == ip {
if len(logCtx.OwnIPs) > 0 && logCtx.OwnIPs[len(logCtx.OwnIPs)-1] == ip {
return
}
ctx.OwnIPs = append(ctx.OwnIPs, ip)
for _, name := range ctx.OwnNames {
logCtx.OwnIPs = append(logCtx.OwnIPs, ip)
for _, name := range logCtx.OwnNames {
translate.AddIPToNodeName(ip, name, date)
}
}
@@ -145,37 +145,37 @@ func (ctx *LogCtx) AddOwnIP(ip string, date time.Time) {
// into the base
// It is used when merging, so that we do not start from nothing
// It helps when dealing with many small files
func (base *LogCtx) Inherit(ctx LogCtx) {
base.OwnHashes = append(ctx.OwnHashes, base.OwnHashes...)
base.OwnNames = append(ctx.OwnNames, base.OwnNames...)
base.OwnIPs = append(ctx.OwnIPs, base.OwnIPs...)
func (base *LogCtx) Inherit(logCtx LogCtx) {
base.OwnHashes = append(logCtx.OwnHashes, base.OwnHashes...)
base.OwnNames = append(logCtx.OwnNames, base.OwnNames...)
base.OwnIPs = append(logCtx.OwnIPs, base.OwnIPs...)
if base.Version == "" {
base.Version = ctx.Version
base.Version = logCtx.Version
}
base.Conflicts = append(ctx.Conflicts, base.Conflicts...)
base.Conflicts = append(logCtx.Conflicts, base.Conflicts...)
}
func (ctx *LogCtx) SetSSTTypeMaybe(ssttype string) {
for key, sst := range ctx.SSTs {
if len(ctx.SSTs) == 1 || (ctx.State() == "DONOR" && utils.SliceContains(ctx.OwnNames, key)) || (ctx.State() == "JOINER" && utils.SliceContains(ctx.OwnNames, sst.Joiner)) {
func (logCtx *LogCtx) SetSSTTypeMaybe(ssttype string) {
for key, sst := range logCtx.SSTs {
if len(logCtx.SSTs) == 1 || (logCtx.State() == "DONOR" && utils.SliceContains(logCtx.OwnNames, key)) || (logCtx.State() == "JOINER" && utils.SliceContains(logCtx.OwnNames, sst.Joiner)) {
sst.Type = ssttype
ctx.SSTs[key] = sst
logCtx.SSTs[key] = sst
return
}
}
}
func (ctx *LogCtx) ConfirmSSTMetadata(shiftTimestamp time.Time) {
if ctx.State() != "DONOR" && ctx.State() != "JOINER" {
func (logCtx *LogCtx) ConfirmSSTMetadata(shiftTimestamp time.Time) {
if logCtx.State() != "DONOR" && logCtx.State() != "JOINER" {
return
}
for key, sst := range ctx.SSTs {
for key, sst := range logCtx.SSTs {
if sst.MustHaveHappenedLocally(shiftTimestamp) {
if ctx.State() == "DONOR" {
ctx.AddOwnName(key, shiftTimestamp)
if logCtx.State() == "DONOR" {
logCtx.AddOwnName(key, shiftTimestamp)
}
if ctx.State() == "JOINER" {
ctx.AddOwnName(sst.Joiner, shiftTimestamp)
if logCtx.State() == "JOINER" {
logCtx.AddOwnName(sst.Joiner, shiftTimestamp)
}
}
}
@@ -183,7 +183,7 @@ func (ctx *LogCtx) ConfirmSSTMetadata(shiftTimestamp time.Time) {
return
}
func (l LogCtx) MarshalJSON() ([]byte, error) {
func (logCtx *LogCtx) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
FilePath string
FileType string
@@ -202,20 +202,20 @@ func (l LogCtx) MarshalJSON() ([]byte, error) {
MinVerbosity Verbosity
Conflicts Conflicts
}{
FilePath: l.FilePath,
FileType: l.FileType,
OwnIPs: l.OwnIPs,
OwnHashes: l.OwnHashes,
StateErrorLog: l.stateErrorLog,
StateRecoveryLog: l.stateRecoveryLog,
StatePostProcessingLog: l.statePostProcessingLog,
StateBackupLog: l.stateBackupLog,
Version: l.Version,
SSTs: l.SSTs,
MyIdx: l.MyIdx,
MemberCount: l.MemberCount,
Desynced: l.Desynced,
MinVerbosity: l.minVerbosity,
Conflicts: l.Conflicts,
FilePath: logCtx.FilePath,
FileType: logCtx.FileType,
OwnIPs: logCtx.OwnIPs,
OwnHashes: logCtx.OwnHashes,
StateErrorLog: logCtx.stateErrorLog,
StateRecoveryLog: logCtx.stateRecoveryLog,
StatePostProcessingLog: logCtx.statePostProcessingLog,
StateBackupLog: logCtx.stateBackupLog,
Version: logCtx.Version,
SSTs: logCtx.SSTs,
MyIdx: logCtx.MyIdx,
MemberCount: logCtx.MemberCount,
Desynced: logCtx.Desynced,
MinVerbosity: logCtx.minVerbosity,
Conflicts: logCtx.Conflicts,
})
}

View File

@@ -24,18 +24,18 @@ type LogInfo struct {
Log string // the raw log
RegexType RegexType
RegexUsed string
Ctx LogCtx // the context is copied for each logInfo, so that it is easier to handle some info (current state), and this is also interesting to check how it evolved
LogCtx LogCtx // the context is copied for each logInfo, so that it is easier to handle some info (current state), and this is also interesting to check how it evolved
Verbosity Verbosity
RepetitionCount int
extraNotes map[string]string
}
func NewLogInfo(date *Date, displayer LogDisplayer, log string, regex *LogRegex, regexkey string, ctx LogCtx, filetype string) LogInfo {
func NewLogInfo(date *Date, displayer LogDisplayer, log string, regex *LogRegex, regexkey string, logCtx LogCtx, filetype string) LogInfo {
li := LogInfo{
Date: date,
Log: log,
displayer: displayer,
Ctx: ctx,
LogCtx: logCtx,
RegexType: regex.Type,
RegexUsed: regexkey,
Verbosity: regex.Verbosity,
@@ -47,7 +47,7 @@ func NewLogInfo(date *Date, displayer LogDisplayer, log string, regex *LogRegex,
return li
}
func (li *LogInfo) Msg(ctx LogCtx) string {
func (li *LogInfo) Msg(logCtx LogCtx) string {
if li.displayer == nil {
return ""
}
@@ -55,7 +55,7 @@ func (li *LogInfo) Msg(ctx LogCtx) string {
if li.RepetitionCount > 0 {
msg += utils.Paint(utils.BlueText, fmt.Sprintf("(repeated x%d)", li.RepetitionCount))
}
msg += li.displayer(ctx)
msg += li.displayer(logCtx)
for _, note := range li.extraNotes {
msg += utils.Paint(utils.BlueText, fmt.Sprintf("(%s)", note))
}
@@ -67,9 +67,9 @@ func (li *LogInfo) Msg(ctx LogCtx) string {
func (current *LogInfo) IsDuplicatedEvent(base, previous LogInfo) bool {
return base.RegexUsed == previous.RegexUsed &&
base.displayer != nil && previous.displayer != nil && current.displayer != nil &&
base.displayer(base.Ctx) == previous.displayer(previous.Ctx) &&
base.displayer(base.LogCtx) == previous.displayer(previous.LogCtx) &&
previous.RegexUsed == current.RegexUsed &&
previous.displayer(previous.Ctx) == current.displayer(current.Ctx)
previous.displayer(previous.LogCtx) == current.displayer(current.LogCtx)
}
type Date struct {

View File

@@ -20,17 +20,17 @@ type LogRegex struct {
Verbosity Verbosity // To be able to hide details from summaries
}
func (l *LogRegex) Handle(ctx LogCtx, line string, date time.Time) (LogCtx, LogDisplayer) {
if ctx.minVerbosity > l.Verbosity {
ctx.minVerbosity = l.Verbosity
func (l *LogRegex) Handle(logCtx LogCtx, line string, date time.Time) (LogCtx, LogDisplayer) {
if logCtx.minVerbosity > l.Verbosity {
logCtx.minVerbosity = l.Verbosity
}
mergedResults := map[string]string{}
if l.InternalRegex == nil {
return l.Handler(mergedResults, ctx, line, date)
return l.Handler(mergedResults, logCtx, line, date)
}
slice := l.InternalRegex.FindStringSubmatch(line)
if len(slice) == 0 {
return ctx, nil
return logCtx, nil
}
for _, subexpname := range l.InternalRegex.SubexpNames() {
if subexpname == "" { // 1st element is always empty for the complete regex
@@ -38,7 +38,7 @@ func (l *LogRegex) Handle(ctx LogCtx, line string, date time.Time) (LogCtx, LogD
}
mergedResults[subexpname] = slice[l.InternalRegex.SubexpIndex(subexpname)]
}
return l.Handler(mergedResults, ctx, line, date)
return l.Handler(mergedResults, logCtx, line, date)
}
func (l *LogRegex) MarshalJSON() ([]byte, error) {

View File

@@ -31,7 +31,7 @@ func (timeline Timeline) MergeByIdentifier(lt LocalTimeline) {
// identify the node with the easiest to read information
// this is critical part to aggregate logs: this is what enable to merge logs
// ultimately the "identifier" will be used for columns header
node := Identifier(lt[len(lt)-1].Ctx, getlasttime(lt))
node := Identifier(lt[len(lt)-1].LogCtx, getlasttime(lt))
if lt2, ok := timeline[node]; ok {
lt = MergeTimeline(lt2, lt)
}
@@ -41,7 +41,7 @@ func (timeline Timeline) MergeByIdentifier(lt LocalTimeline) {
func (timeline Timeline) MergeByDirectory(path string, lt LocalTimeline) {
node := filepath.Base(filepath.Dir(path))
for _, lt2 := range timeline {
if len(lt2) > 0 && node == filepath.Base(filepath.Dir(lt2[0].Ctx.FilePath)) {
if len(lt2) > 0 && node == filepath.Base(filepath.Dir(lt2[0].LogCtx.FilePath)) {
lt = MergeTimeline(lt2, lt)
}
}
@@ -108,18 +108,18 @@ func MergeTimeline(t1, t2 LocalTimeline) LocalTimeline {
//>t : --O----OOO-- won't try to get things between t1.end and t2.start
// we assume they're identical, they're supposed to be from the same server
t2 = CutTimelineAt(t2, endt1)
// no return here, to avoid repeating the ctx.inherit
// no return here, to avoid repeating the logCtx.inherit
}
// t1: --O--O------
// t2: ------O--O--
t2[len(t2)-1].Ctx.Inherit(t1[len(t1)-1].Ctx)
t2[len(t2)-1].LogCtx.Inherit(t1[len(t1)-1].LogCtx)
return append(t1, t2...)
}
func getfirsttime(l LocalTimeline) time.Time {
for _, event := range l {
if event.Date != nil && (event.Ctx.FileType == "error.log" || event.Ctx.FileType == "") {
if event.Date != nil && (event.LogCtx.FileType == "error.log" || event.LogCtx.FileType == "") {
return event.Date.Time
}
}
@@ -127,7 +127,7 @@ func getfirsttime(l LocalTimeline) time.Time {
}
func getlasttime(l LocalTimeline) time.Time {
for i := len(l) - 1; i >= 0; i-- {
if l[i].Date != nil && (l[i].Ctx.FileType == "error.log" || l[i].Ctx.FileType == "") {
if l[i].Date != nil && (l[i].LogCtx.FileType == "error.log" || l[i].LogCtx.FileType == "") {
return l[i].Date.Time
}
}
@@ -148,13 +148,13 @@ func CutTimelineAt(t LocalTimeline, at time.Time) LocalTimeline {
}
func (t *Timeline) GetLatestContextsByNodes() map[string]LogCtx {
latestctxs := map[string]LogCtx{}
latestlogCtxs := make(map[string]LogCtx, len(*t))
for key, localtimeline := range *t {
latestctxs[key] = localtimeline[len(localtimeline)-1].Ctx
latestlogCtxs[key] = localtimeline[len(localtimeline)-1].LogCtx
}
return latestctxs
return latestlogCtxs
}
// iterateNode is used to search the source node(s) that contains the next chronological events

View File

@@ -11,17 +11,17 @@ import (
// It will also impacts how logs are merged if we have multiple logs per nodes
//
// In order of preference: wsrep_node_name (or galera "node" name), hostname, ip, filepath
func Identifier(ctx LogCtx, date time.Time) string {
if len(ctx.OwnNames) > 0 {
return ctx.OwnNames[len(ctx.OwnNames)-1]
func Identifier(logCtx LogCtx, date time.Time) string {
if len(logCtx.OwnNames) > 0 {
return logCtx.OwnNames[len(logCtx.OwnNames)-1]
}
if len(ctx.OwnIPs) > 0 {
return translate.SimplestInfoFromIP(ctx.OwnIPs[len(ctx.OwnIPs)-1], date)
if len(logCtx.OwnIPs) > 0 {
return translate.SimplestInfoFromIP(logCtx.OwnIPs[len(logCtx.OwnIPs)-1], date)
}
for _, hash := range ctx.OwnHashes {
for _, hash := range logCtx.OwnHashes {
if out := translate.SimplestInfoFromHash(hash, date); out != hash {
return out
}
}
return ctx.FilePath
return logCtx.FilePath
}