feat: Add JSON output

pull/2/head
Karan Sharma 2020-12-13 09:34:53 +05:30
parent d9a70daaf8
commit 7df12b2229
3 changed files with 107 additions and 22 deletions

View File

@ -88,6 +88,12 @@ func main() {
Usage: "Display how long it took for the response to arrive", Usage: "Display how long it took for the response to arrive",
Destination: &hub.QueryFlags.DisplayTimeTaken, Destination: &hub.QueryFlags.DisplayTimeTaken,
}, },
&cli.BoolFlag{
Name: "json",
Aliases: []string{"J"},
Usage: "Set the output format as JSON",
Destination: &hub.QueryFlags.ShowJSON,
},
&cli.BoolFlag{ &cli.BoolFlag{
Name: "verbose", Name: "verbose",
Usage: "Enable verbose logging", Usage: "Enable verbose logging",

View File

@ -29,6 +29,7 @@ type QueryFlags struct {
UseIPv4 bool UseIPv4 bool
UseIPv6 bool UseIPv6 bool
DisplayTimeTaken bool DisplayTimeTaken bool
ShowJSON bool
} }
// NewHub initializes an instance of Hub which holds app wide configuration. // NewHub initializes an instance of Hub which holds app wide configuration.

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"strconv" "strconv"
@ -11,10 +12,58 @@ import (
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
) )
// Output takes a list of `dns.Answers` and based // Output has a list of fields which are produced for the output
// on the output format specified displays the information. type Output struct {
func (hub *Hub) Output(responses []resolvers.Response) { Name string `json:"name"`
// Create SprintXxx functions to mix strings with other non-colorized strings: Type string `json:"type"`
Class string `json:"class"`
TTL string `json:"ttl"`
Address string `json:"address"`
TimeTaken string `json:"rtt"`
}
type Query struct {
Name string `json:"name"`
Type string `json:"type"`
Class string `json:"class"`
}
type Response struct {
Output []Output `json:"answers"`
Queries []Query `json:"queries"`
}
type JSONResponse struct {
Response `json:"responses"`
}
func (hub *Hub) outputJSON(out []Output, msgs []resolvers.Response) {
// get the questions
queries := make([]Query, 0, len(msgs))
for _, m := range msgs {
for _, ques := range m.Message.Question {
q := Query{
Name: ques.Name,
Type: dns.ClassToString[ques.Qtype],
Class: dns.ClassToString[ques.Qclass],
}
queries = append(queries, q)
}
}
resp := JSONResponse{
Response{
Output: out,
Queries: queries,
},
}
res, err := json.Marshal(resp)
if err != nil {
hub.Logger.WithError(err).Error("unable to output data in JSON")
hub.Logger.Exit(-1)
}
fmt.Printf("%s", res)
}
func (hub *Hub) outputTerminal(out []Output) {
green := color.New(color.FgGreen).SprintFunc() green := color.New(color.FgGreen).SprintFunc()
blue := color.New(color.FgBlue).SprintFunc() blue := color.New(color.FgBlue).SprintFunc()
@ -25,25 +74,54 @@ func (hub *Hub) Output(responses []resolvers.Response) {
} }
table.SetHeader(header) table.SetHeader(header)
for _, r := range responses { for _, o := range out {
var res string output := []string{green(o.Name), blue(o.Type), o.Class, o.TTL, o.Address}
for _, a := range r.Message.Answer {
switch t := a.(type) {
case *dns.A:
res = t.A.String()
}
h := a.Header()
name := green(h.Name)
qclass := dns.Class(h.Class).String()
ttl := strconv.FormatInt(int64(h.Ttl), 10) + "s"
qtype := blue(dns.Type(h.Rrtype).String())
output := []string{name, qtype, qclass, ttl, res}
// Print how long it took // Print how long it took
if hub.QueryFlags.DisplayTimeTaken { if hub.QueryFlags.DisplayTimeTaken {
output = append(output, fmt.Sprintf("%dms", r.RTT.Milliseconds())) output = append(output, o.TimeTaken)
} }
table.Append(output) table.Append(output)
} }
}
table.Render() table.Render()
} }
// Output takes a list of `dns.Answers` and based
// on the output format specified displays the information.
func (hub *Hub) Output(responses []resolvers.Response) {
out := collectOutput(responses)
if hub.QueryFlags.ShowJSON {
hub.outputJSON(out, responses)
} else {
hub.outputTerminal(out)
}
}
func collectOutput(responses []resolvers.Response) []Output {
out := make([]Output, 0, len(responses))
// gather Output from the DNS Messages
for _, r := range responses {
var addr string
for _, a := range r.Message.Answer {
switch t := a.(type) {
case *dns.A:
addr = t.A.String()
}
h := a.Header()
name := h.Name
qclass := dns.Class(h.Class).String()
ttl := strconv.FormatInt(int64(h.Ttl), 10) + "s"
qtype := dns.Type(h.Rrtype).String()
rtt := fmt.Sprintf("%dms", r.RTT.Milliseconds())
o := Output{
Name: name,
Type: qtype,
TTL: ttl,
Class: qclass,
Address: addr,
TimeTaken: rtt,
}
out = append(out, o)
}
}
return out
}