func main() { from := flag.String("data-dir", "", "") snapfile := flag.String("start-snap", "", "The base name of snapshot file to start dumping") index := flag.Uint64("start-index", 0, "The index to start dumping") flag.Parse() if *from == "" { log.Fatal("Must provide -data-dir flag.") } if *snapfile != "" && *index != 0 { log.Fatal("start-snap and start-index flags cannot be used together.") } var ( walsnap walpb.Snapshot snapshot *raftpb.Snapshot err error ) isIndex := *index != 0 if isIndex { fmt.Printf("Start dumping log entries from index %d.\n", *index) walsnap.Index = *index } else { if *snapfile == "" { ss := snap.New(snapDir(*from)) snapshot, err = ss.Load() } else { snapshot, err = snap.Read(path.Join(snapDir(*from), *snapfile)) } switch err { case nil: walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term nodes := genIDSlice(snapshot.Metadata.ConfState.Nodes) fmt.Printf("Snapshot:\nterm=%d index=%d nodes=%s\n", walsnap.Term, walsnap.Index, nodes) case snap.ErrNoSnapshot: fmt.Printf("Snapshot:\nempty\n") default: log.Fatalf("Failed loading snapshot: %v", err) } fmt.Println("Start dupmping log entries from snapshot.") } w, err := wal.OpenForRead(walDir(*from), walsnap) if err != nil { log.Fatalf("Failed opening WAL: %v", err) } wmetadata, state, ents, err := w.ReadAll() w.Close() if err != nil && (!isIndex || err != wal.ErrSnapshotNotFound) { log.Fatalf("Failed reading WAL: %v", err) } id, cid := parseWALMetadata(wmetadata) vid := types.ID(state.Vote) fmt.Printf("WAL metadata:\nnodeID=%s clusterID=%s term=%d commitIndex=%d vote=%s\n", id, cid, state.Term, state.Commit, vid) fmt.Printf("WAL entries:\n") fmt.Printf("lastIndex=%d\n", ents[len(ents)-1].Index) fmt.Printf("%4s\t%10s\ttype\tdata\n", "term", "index") for _, e := range ents { msg := fmt.Sprintf("%4d\t%10d", e.Term, e.Index) switch e.Type { case raftpb.EntryNormal: msg = fmt.Sprintf("%s\tnorm", msg) var rr etcdserverpb.InternalRaftRequest if err := rr.Unmarshal(e.Data); err == nil { msg = fmt.Sprintf("%s\t%s", msg, rr.String()) break } var r etcdserverpb.Request if err := r.Unmarshal(e.Data); err == nil { switch r.Method { case "": msg = fmt.Sprintf("%s\tnoop", msg) case "SYNC": msg = fmt.Sprintf("%s\tmethod=SYNC time=%q", msg, time.Unix(0, r.Time)) case "QGET", "DELETE": msg = fmt.Sprintf("%s\tmethod=%s path=%s", msg, r.Method, excerpt(r.Path, 64, 64)) default: msg = fmt.Sprintf("%s\tmethod=%s path=%s val=%s", msg, r.Method, excerpt(r.Path, 64, 64), excerpt(r.Val, 128, 0)) } break } msg = fmt.Sprintf("%s\t???", msg) case raftpb.EntryConfChange: msg = fmt.Sprintf("%s\tconf", msg) var r raftpb.ConfChange if err := r.Unmarshal(e.Data); err != nil { msg = fmt.Sprintf("%s\t???", msg) } else { msg = fmt.Sprintf("%s\tmethod=%s id=%s", msg, r.Type, types.ID(r.NodeID)) } } fmt.Println(msg) } }