-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
dump: Rework command to encode #318
Conversation
encode.go
Outdated
fs.PrintDefaults() | ||
} | ||
|
||
return command{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
github.com/tsenart/vegeta.command composite literal uses unkeyed fields
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh, OK, let's comply. Other places are in transgression too.
encode.go
Outdated
return command{ | ||
fs, | ||
func(args []string) error { | ||
fs.Parse(args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error return value of fs.Parse
is not checked
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we introduced @golangci, let's make it happy: _ = fs.Parse()
Dumper [json, csv] (default "json") | ||
-inputs string | ||
Input files (comma separated) (default "stdin") | ||
encode command: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This listing of command's flags in vegeta -h
was alright when commands only took flags but no positional arguments. Since this is changing, I believe we need to re-evaluate.
Either we display the full help out put of each sub command here, or we only display a list of sub command names, and users will have to defer to vegeta subcmd -h
to read more.
What's your take?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will implement this in a follow up PR.
README.md
Outdated
#### `-output` | ||
Specifies the output file to which the dump will be written to. | ||
#### `-from` | ||
Specifies the decoding format of the inputs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be more correct to say "the encoding format of the inputs".
README.md
Outdated
encoding](https://golang.org/pkg/encoding/gob). | ||
|
||
##### `json` | ||
Decodes/encodes results as JSON objects. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be correct, it's JSONLines: http://jsonlines.org/
encode.go
Outdated
|
||
func encodeCmd() command { | ||
var ( | ||
fs = flag.NewFlagSet("encode", flag.ExitOnError) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be flag.NewFlagSet("vegeta encode", ...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? vegeta
is already the main namespace of the binary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consistency with the other sub commands. Also, the different flag sets aren't directly associated in any way. This command could potentially work by itself if the parent didn't exist.
encode.go
Outdated
fs = flag.NewFlagSet("encode", flag.ExitOnError) | ||
from = fs.String("from", "gob", "Input decoding [csv, gob, json]") | ||
to = fs.String("to", "json", "Output encoding [csv, gob, json]") | ||
output = fs.String("output", "", "Output file") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default output should be stdout
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't add up really. We expect output
to be a filename, if we expect stdout
as ivalue it is inconsistent. They don't have the same meaning or refer to the same thing. Arguably we shoul document the default case better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We expect output to be a filename.
Sure, and if you so wished you should be able to pass /dev/stdout
to it and it'd just work. stdout
is in this case a symbolic name that resolves to that path in practice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plus, it documents the behaviour, from the user perspective, it makes it explicit in the output of vegeta encode -h
that the output will be to stdout, instead of that being implicit.
encode.go
Outdated
decFn = vegeta.NewCSVDecoder | ||
case encodingJSON: | ||
decFn = vegeta.NewJSONDecoder | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to rely on the default case to play nice with the pipes as per your comment? The default "gob" could come from the flags outside this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, let's error in if we don't know the given encoding.
encode.go
Outdated
|
||
decs := []vegeta.Decoder{} | ||
|
||
if len(inputs) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have some simpler code to handle this already. i.e. https://github.com/tsenart/vegeta/blob/master/report.go#L33
Because the file
function returns os.Stdin
for the string stdin
. This block of code can become:
srcs := make([]vegeta.Decoder, len(files))
for i, f := range inputs {
in, err := file(f, false)
if err != nil {
return err
}
defer in.Close()
srcs[i] = vegeta.NewDecoder(in)
}
dec := vegeta.NewRoundRobinDecoder(srcs...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the file
function an anti-pattern and don't really understand the gains. os.Create
and os.Open
are so much more expresisve, a fact hidden behind an opaque boolean. Having string literals to refer to the the input and output file handles is unnecesssary indirection imho.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, file
is slightly conflated. We can take out the file creation part from it and use os.Create
directly where needed, thus scoping the symbolic resolution to opening files only, not creating (since you don't create stdout
or stdin
).
func open(file string) (*os.File, error) {
switch file {
case "stdout":
return os.Stdout, nil
case "stdin":
return os.Stdin, nil
default:
return os.Open(file)
}
encode.go
Outdated
decs = append(decs, decFn(os.Stdin)) | ||
} | ||
|
||
in := vegeta.NewRoundRobinDecoder(decs...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering what makes most sense to do. Shall we read results in a round-robin fashion and re-encode each out as they come or should we instead read all of them, sort them and then write them out. Perhaps this should be a flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the upside of the sorting? And sorting per input, over all inputs, by what criteria?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can delegate this to external tools, indeed.
cat results.bin | vegeta encode | jq -s 'sort_by(.timestamp)'
encode.go
Outdated
|
||
var out vegeta.Encoder | ||
|
||
if output != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
output
should never be empty. The default stdout
ought to be set in the flags. Then you can reuse the file
function as in the report command.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally, if you open the output first and then validate the to
value, you don't need encoderFunc
.
var enc vegeta.Encoder
switch to {
case encodingCSV:
enc = vegeta.NewCSVEncoder(out)
case encodingJSON:
enc = vegeta.NewJSONEncoder(out)
case encodingGob:
enc = vegeta.NewEncoder(out)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To your first comment see #318 (comment)
To the second comment I usually try to check all parameters before acquiring system resources (fds, conns, etc.).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To the second comment I usually try to check all parameters before acquiring system resources (fds, conns, etc.).
What does it gain us here?
encode.go
Outdated
out = encFn(os.Stdout) | ||
} | ||
|
||
for { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to handle signals gracefully as in the report command.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will extend!
encode.go
Outdated
} | ||
|
||
return command{fs, func(args []string) error { | ||
fs.Parse(args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error return value of fs.Parse
is not checked
In order to give the command more utility and play well with pipeline idea of the vegeta toolchain we decided per discussion[0] to change the semantics of dump. We offer now a general encode command which can transofrm any input encoding to any of the supported output encodings. We anticipate that in conjunction with advocated auxiliary tools, like\ jq, a wide range of use-cases can be covered without extending vegeta itself. [0] https://github.com/tsenart/vegeta/issues/302#issuecomment-403935450<Paste> Closes #302
abbed82
to
f01a574
Compare
} | ||
|
||
return command{fs, func(args []string) error { | ||
fs.Parse(args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error return value of fs.Parse
is not checked
29734fd
to
a5cd801
Compare
In order to give the command more utility and play well with pipeline idea of the vegeta toolchain we decided per discussion[0] to change the semantics of dump. We offer now a general encode command which can transform any supported input encoding to any supported output encoding. We anticipate that in conjunction with advocated auxiliary tools, like jq, a wide range of use-cases can be covered without extending vegeta itself.
[0] #302 (comment)
Closes #302
Background
Checklist
- [ ] Changed or added code is covered by appropriate tests.