diff --git a/etcdctl/ctlv3/command/printer.go b/etcdctl/ctlv3/command/printer.go index de35be86c..f5ad15d6d 100644 --- a/etcdctl/ctlv3/command/printer.go +++ b/etcdctl/ctlv3/command/printer.go @@ -49,6 +49,8 @@ func NewPrinter(printerType string, isHex bool) printer { switch printerType { case "simple": return &simplePrinter{isHex: isHex} + case "fields": + return &fieldsPrinter{} case "json": return &jsonPrinter{} case "protobuf": @@ -329,3 +331,127 @@ func printPB(m pbMarshal) { } fmt.Printf(string(b)) } + +type fieldsPrinter struct{} + +func (p *fieldsPrinter) kv(pfx string, kv *spb.KeyValue) { + fmt.Printf("\"%sKey\" : %q\n", pfx, string(kv.Key)) + fmt.Printf("\"%sCreateRevision\" : %d\n", pfx, kv.CreateRevision) + fmt.Printf("\"%sModRevision\" : %d\n", pfx, kv.ModRevision) + fmt.Printf("\"%sVersion\" : %d\n", pfx, kv.Version) + fmt.Printf("\"%sValue\" : %q\n", pfx, string(kv.Value)) + fmt.Printf("\"%sLease\" : %d\n", pfx, string(kv.Lease)) +} + +func (p *fieldsPrinter) hdr(h *pb.ResponseHeader) { + fmt.Println(`"ClusterID" :`, h.ClusterId) + fmt.Println(`"MemberID" :`, h.MemberId) + fmt.Println(`"Revision" :`, h.Revision) + fmt.Println(`"RaftTerm" :`, h.RaftTerm) +} + +func (p *fieldsPrinter) Del(r v3.DeleteResponse) { + p.hdr(r.Header) + fmt.Println(`"Deleted" :`, r.Deleted) + for _, kv := range r.PrevKvs { + p.kv("Prev", kv) + } +} + +func (p *fieldsPrinter) Get(r v3.GetResponse) { + p.hdr(r.Header) + for _, kv := range r.Kvs { + p.kv("", kv) + } + fmt.Println(`"More" :`, r.More) + fmt.Println(`"Count" :`, r.Count) +} + +func (p *fieldsPrinter) Put(r v3.PutResponse) { + p.hdr(r.Header) + if r.PrevKv != nil { + p.kv("Prev", r.PrevKv) + } +} + +func (p *fieldsPrinter) Txn(r v3.TxnResponse) { + p.hdr(r.Header) + fmt.Println(`"Succeeded" :`, r.Succeeded) + for _, resp := range r.Responses { + switch v := resp.Response.(type) { + case *pb.ResponseOp_ResponseDeleteRange: + p.Del((v3.DeleteResponse)(*v.ResponseDeleteRange)) + case *pb.ResponseOp_ResponsePut: + p.Put((v3.PutResponse)(*v.ResponsePut)) + case *pb.ResponseOp_ResponseRange: + p.Get((v3.GetResponse)(*v.ResponseRange)) + default: + fmt.Printf("\"Unknown\" : %q\n", fmt.Sprintf("%+v", v)) + } + } +} + +func (p *fieldsPrinter) Watch(resp v3.WatchResponse) { + p.hdr(&resp.Header) + for _, e := range resp.Events { + fmt.Println(`"Type" : `, e.Type) + if e.PrevKv != nil { + p.kv("Prev", e.PrevKv) + } + p.kv("", e.Kv) + } +} + +func (p *fieldsPrinter) TimeToLive(r v3.LeaseTimeToLiveResponse, keys bool) { + p.hdr(r.ResponseHeader) + fmt.Println(`"ID" :`, r.ID) + fmt.Println(`"TTL" :`, r.TTL) + fmt.Println(`"GrantedTTL" :`, r.GrantedTTL) + for _, k := range r.Keys { + fmt.Printf("\"Key\" : %q\n", string(k)) + } +} + +func (p *fieldsPrinter) MemberList(r v3.MemberListResponse) { + p.hdr(r.Header) + for _, m := range r.Members { + fmt.Println(`"ID" :`, m.ID) + fmt.Printf("\"Name\" : %q\n", m.Name) + for _, u := range m.PeerURLs { + fmt.Printf("\"PeerURL\" : %q\n", u) + } + for _, u := range m.ClientURLs { + fmt.Printf("\"ClientURL\" : %q\n", u) + } + fmt.Println() + } +} + +func (p *fieldsPrinter) EndpointStatus(eps []epStatus) { + for _, ep := range eps { + p.hdr(ep.Resp.Header) + fmt.Printf("\"Version\" : %q\n", ep.Resp.Version) + fmt.Println(`"DBSize" :"`, ep.Resp.DbSize) + fmt.Println(`"Leader" :"`, ep.Resp.Leader) + fmt.Println(`"RaftIndex" :"`, ep.Resp.RaftIndex) + fmt.Println(`"RaftTerm" :"`, ep.Resp.RaftTerm) + fmt.Printf("\"Endpoint\" : %q\n", ep.Ep) + fmt.Println() + } +} + +func (p *fieldsPrinter) Alarm(r v3.AlarmResponse) { + p.hdr(r.Header) + for _, a := range r.Alarms { + fmt.Println(`"MemberID" :`, a.MemberID) + fmt.Println(`"AlarmType" :`, a.Alarm) + fmt.Println() + } +} + +func (p *fieldsPrinter) DBStatus(r dbstatus) { + fmt.Println(`"Hash" :`, r.Hash) + fmt.Println(`"Revision" :`, r.Revision) + fmt.Println(`"Keys" :`, r.TotalKey) + fmt.Println(`"Size" :`, r.TotalSize) +} diff --git a/etcdctl/ctlv3/ctl.go b/etcdctl/ctlv3/ctl.go index 36b0462d3..780e9f7ff 100644 --- a/etcdctl/ctlv3/ctl.go +++ b/etcdctl/ctlv3/ctl.go @@ -45,7 +45,7 @@ var ( func init() { rootCmd.PersistentFlags().StringSliceVar(&globalFlags.Endpoints, "endpoints", []string{"127.0.0.1:2379"}, "gRPC endpoints") - rootCmd.PersistentFlags().StringVarP(&globalFlags.OutputFormat, "write-out", "w", "simple", "set the output format (json, proto, simple, table)") + rootCmd.PersistentFlags().StringVarP(&globalFlags.OutputFormat, "write-out", "w", "simple", "set the output format (fields, json, proto, simple, table)") rootCmd.PersistentFlags().BoolVar(&globalFlags.IsHex, "hex", false, "print byte strings as hex encoded strings") rootCmd.PersistentFlags().DurationVar(&globalFlags.DialTimeout, "dial-timeout", defaultDialTimeout, "dial timeout for client connections")