From dec7032f669110ac17d823b0c9159f0a9ed86685 Mon Sep 17 00:00:00 2001 From: chenjiandongx Date: Thu, 30 May 2024 19:30:45 +0800 Subject: [PATCH] feat: improve the output format --- formatter/formatter.go | 58 ++++++++++++++++++++++++++++++++++++++++-- formatter/question.go | 10 +++++++- main.go | 2 +- pacp_linux.go | 22 ++++++++-------- pcap_others.go | 17 +++++++------ 5 files changed, 87 insertions(+), 22 deletions(-) diff --git a/formatter/formatter.go b/formatter/formatter.go index 7bef1c6..6ff2b7c 100644 --- a/formatter/formatter.go +++ b/formatter/formatter.go @@ -1,6 +1,10 @@ package formatter import ( + "bytes" + "fmt" + "strconv" + "strings" "time" "github.com/chenjiandongx/dnstrack/codec" @@ -19,11 +23,11 @@ type Formatter interface { Format(msg MessageWrap) (string, bool) } -func New(format, server, typ string) Formatter { +func New(format, server, typ string, n int) Formatter { f := NewFilter(server, typ) switch format { case "question", "q": - return questionFormatter{f} + return questionFormatter{f, n} case "json", "j": return jsonFormatter{f} case "yaml", "y": @@ -32,3 +36,53 @@ func New(format, server, typ string) Formatter { return verboseFormatter{f} } } + +func formatDuration(d time.Duration) string { + s := d.String() + units := []string{"ms", "µs", "ns", "h", "m", "s"} + for _, unit := range units { + if strings.HasSuffix(s, unit) { + v := s[:len(s)-len(unit)] + f, err := strconv.ParseFloat(v, 64) + if err != nil { + return s + } + fs := fmt.Sprintf("%.3f", f) + switch len(fs) { + case 6: + fs = pad(1) + fs + case 5: + fs = pad(2) + fs + case 4: + fs = pad(3) + fs + } + return pad(2-len(unit)) + fs + unit + } + } + return s +} + +func formatIface(s string, maxIfaceLen int) string { + n := maxIfaceLen - len(s) + return pad(n) + s +} + +func formatServer(s string) string { + const maxServerLen = 18 // 172.172.172.172:53 + n := maxServerLen - len(s) + return pad(n) + s +} + +func formatType(s string) string { + const maxTypeLen = 5 // CNAME + n := maxTypeLen - len(s) + return pad(n) + s +} + +func pad(n int) string { + buf := &bytes.Buffer{} + for i := 0; i < n; i++ { + buf.WriteString(" ") + } + return buf.String() +} diff --git a/formatter/question.go b/formatter/question.go index c15abb7..c23e865 100644 --- a/formatter/question.go +++ b/formatter/question.go @@ -7,6 +7,7 @@ import ( type questionFormatter struct { f *Filter + n int } var _ Formatter = (*questionFormatter)(nil) @@ -17,6 +18,13 @@ func (qf questionFormatter) Format(msg MessageWrap) (string, bool) { } q := msg.Msg.QuestionSec - s := fmt.Sprintf("%s\t<%s>@%s\t%s\t%s\t%s", msg.When.Format(time.RFC3339), msg.Device, msg.Server, q.Type, msg.Duration, q.Name) + s := fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s", + msg.When.Format(time.RFC3339), + formatIface(msg.Device, qf.n), + formatServer(msg.Server), + formatType(q.Type), + formatDuration(msg.Duration), + q.Name, + ) return s, true } diff --git a/main.go b/main.go index 76a8ce2..1216fa0 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" ) -const version = "v0.1.0" +const version = "v0.2.0" func NewApp() *cobra.Command { defaultOpts := DefaultOptions() diff --git a/pacp_linux.go b/pacp_linux.go index 251abb3..f5b2bd1 100644 --- a/pacp_linux.go +++ b/pacp_linux.go @@ -23,24 +23,22 @@ type pcapHandler struct { } type PcapClient struct { - ctx context.Context - cancel context.CancelFunc - opt Options - handlers []*pcapHandler - common *CommonClient + ctx context.Context + cancel context.CancelFunc + opt Options + handlers []*pcapHandler + common *CommonClient + maxIfaceLen int } func NewPcapClient(opt Options) (*PcapClient, error) { - client := &PcapClient{ - opt: opt, - common: NewCommonClient(formatter.New(opt.Format, opt.Server, opt.Type)), - } - + client := &PcapClient{opt: opt} client.ctx, client.cancel = context.WithCancel(context.Background()) if err := client.getAvailableDevices(); err != nil { return nil, err } + client.common = NewCommonClient(formatter.New(opt.Format, opt.Server, opt.Type, client.maxIfaceLen)) for _, handler := range client.handlers { go client.listen(handler) } @@ -63,6 +61,10 @@ func (c *PcapClient) getAvailableDevices() error { if err = c.setBPFFilter(handler, bpfFilter); err != nil { return errors.Wrapf(err, "set bpf-filter on device(%s) failed", device.Name) } + + if c.maxIfaceLen < len(device.Name) { + c.maxIfaceLen = len(device.Name) + } c.handlers = append(c.handlers, &pcapHandler{device: device.Name, handle: handler}) } diff --git a/pcap_others.go b/pcap_others.go index 0f527ff..7df33aa 100644 --- a/pcap_others.go +++ b/pcap_others.go @@ -19,21 +19,19 @@ type pcapHandler struct { } type PcapClient struct { - opt Options - handlers []*pcapHandler - common *CommonClient + opt Options + handlers []*pcapHandler + common *CommonClient + maxIfaceLen int } func NewPcapClient(opt Options) (*PcapClient, error) { - client := &PcapClient{ - opt: opt, - common: NewCommonClient(formatter.New(opt.Format, opt.Server, opt.Type)), - } - + client := &PcapClient{opt: opt} if err := client.getAvailableDevices(); err != nil { return nil, err } + client.common = NewCommonClient(formatter.New(opt.Format, opt.Server, opt.Type, client.maxIfaceLen)) for _, handler := range client.handlers { go client.listen(handler) } @@ -53,6 +51,9 @@ func (c *PcapClient) getAvailableDevices() error { return errors.Wrapf(err, "get device(%s) name failed", device.Name) } + if c.maxIfaceLen < len(device.Name) { + c.maxIfaceLen = len(device.Name) + } c.handlers = append(c.handlers, &pcapHandler{ device: device.Name, handle: handler,