Skip to content

Commit 86ed8ec

Browse files
authored
Merge pull request #302 from mackerelio/check-log-ignore-broken-json
[check-log] Ignore broken/unexpected json on reading state
2 parents 4405423 + c14bc29 commit 86ed8ec

File tree

4 files changed

+51
-9
lines changed

4 files changed

+51
-9
lines changed

check-log/lib/check-log.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,14 @@ func (opts *logOpts) searchLog(ctx context.Context, logFile string) (int64, int6
247247
return 0, 0, "", nil
248248
}
249249
stateFile := getStateFile(opts.StateDir, logFile, opts.origArgs)
250-
skipBytes, inode := int64(0), uint(0)
250+
skipBytes, inode, isFirstCheck := int64(0), uint(0), false
251251
if !opts.NoState {
252252
s, err := getBytesToSkip(stateFile)
253253
if err != nil {
254-
return 0, 0, "", err
254+
if err != errValidStateFileNotFound {
255+
return 0, 0, "", err
256+
}
257+
isFirstCheck = true
255258
}
256259
skipBytes = s
257260

@@ -282,10 +285,9 @@ func (opts *logOpts) searchLog(ctx context.Context, logFile string) (int64, int6
282285
return 0, 0, "", err
283286
}
284287

285-
if !opts.NoState && !opts.CheckFirst {
286-
if _, err = os.Stat(stateFile); os.IsNotExist(err) {
287-
skipBytes = stat.Size()
288-
}
288+
// Skip whole file on first check, unless CheckFirst specified
289+
if !opts.NoState && isFirstCheck && !opts.CheckFirst {
290+
skipBytes = stat.Size()
289291
}
290292

291293
rotated := false
@@ -428,7 +430,12 @@ func loadState(fname string) (*state, error) {
428430
return state, err
429431
}
430432
err = json.Unmarshal(b, state)
431-
return state, err
433+
if err != nil {
434+
// this json unmarshal error will be ignored by callers
435+
log.Printf("failed to loadState (will be ignored): %s", err)
436+
return nil, errStateFileCorrupted
437+
}
438+
return state, nil
432439
}
433440

434441
var stateRe = regexp.MustCompile(`^([a-zA-Z]):[/\\]`)
@@ -444,8 +451,15 @@ func getStateFile(stateDir, f string, args []string) string {
444451
)
445452
}
446453

454+
var errValidStateFileNotFound = fmt.Errorf("state file not found, or corrupted")
455+
var errStateFileCorrupted = fmt.Errorf("state file is corrupted")
456+
447457
func getBytesToSkip(f string) (int64, error) {
448458
state, err := loadState(f)
459+
// Do not fallback to old status file when JSON file is corrupted
460+
if err == errStateFileCorrupted {
461+
return 0, errValidStateFileNotFound
462+
}
449463
if err != nil {
450464
return 0, err
451465
}
@@ -464,7 +478,7 @@ func getBytesToSkipOld(f string) (int64, error) {
464478
b, err := ioutil.ReadFile(f)
465479
if err != nil {
466480
if os.IsNotExist(err) {
467-
return 0, nil
481+
return 0, errValidStateFileNotFound
468482
}
469483
return 0, err
470484
}
@@ -478,6 +492,10 @@ func getBytesToSkipOld(f string) (int64, error) {
478492

479493
func getInode(f string) (uint, error) {
480494
state, err := loadState(f)
495+
// ignore corrupted json
496+
if err == errStateFileCorrupted {
497+
return 0, nil
498+
}
481499
if err != nil {
482500
return 0, err
483501
}

check-log/lib/check-log_state_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,28 @@ func TestLoadStateIfAccessDenied(t *testing.T) {
4545
}
4646
}
4747

48+
func TestLoadStateUnexpectedJson(t *testing.T) {
49+
file := "testdata/unexpected_json.json"
50+
s, err := loadState(file)
51+
if err != errStateFileCorrupted {
52+
t.Errorf("loadState(%q) = %v; want errStateFileCorrupted", file, err)
53+
}
54+
if s != nil {
55+
t.Errorf("loadState(%q) = %v; want nil", file, *s)
56+
}
57+
}
58+
59+
func TestLoadStateBrokenJson(t *testing.T) {
60+
file := "testdata/invalid_json.json"
61+
s, err := loadState(file)
62+
if err != errStateFileCorrupted {
63+
t.Errorf("loadState(%q) = %v; want errStateFileCorrupted", file, err)
64+
}
65+
if s != nil {
66+
t.Errorf("loadState(%q) = %v; want nil", file, *s)
67+
}
68+
}
69+
4870
// TODO(lufia): We might be better to test a condition too that file is exist but loadState can't read it.
4971

5072
func TestSaveStateIfFileNotExist(t *testing.T) {
@@ -161,7 +183,7 @@ func TestGetBytesToSkipOld(t *testing.T) {
161183
func TestGetBytesToSkipOldIfFileNotExist(t *testing.T) {
162184
file := "testdata/file_not_found"
163185
n, err := getBytesToSkipOld(file)
164-
if err != nil {
186+
if err != errValidStateFileNotFound {
165187
t.Fatal(err)
166188
}
167189
if want := int64(0); n != want {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"this-is-broken": true
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"skip_bytes": ["this", "is", "wrong"], "but": "valid as json"}

0 commit comments

Comments
 (0)