Skip to content

Commit fce7a74

Browse files
committed
feat(options): support duration string for sleep/delay options
1 parent c48e1ac commit fce7a74

File tree

4 files changed

+107
-48
lines changed

4 files changed

+107
-48
lines changed

README.md

+22-8
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,25 @@ There are useful options. (`flog --help`)
4141

4242
```console
4343
Options:
44-
-f, --format string choose log format. ("apache_common"|"apache_combined"|"apache_error"|"rfc3164"|"rfc5424"|"common_log"|"json") (default "apache_common")
44+
-f, --format string log format. available formats:
45+
- apache_common (default)
46+
- apache_combined
47+
- apache_error
48+
- rfc3164
49+
- rfc5424
50+
- json
4551
-o, --output string output filename. Path-like is allowed. (default "generated.log")
46-
-t, --type string log output type. ("stdout"|"log"|"gz") (default "stdout")
52+
-t, --type string log output type. available types:
53+
- stdout (default)
54+
- log
55+
- gz
4756
-n, --number integer number of lines to generate.
4857
-b, --bytes integer size of logs to generate (in bytes).
4958
"bytes" will be ignored when "number" is set.
50-
-s, --sleep numeric fix creation time interval for each log (in seconds). It does not actually sleep.
51-
-d, --delay numeric delay log generation speed (in seconds).
59+
-s, --sleep duration fix creation time interval for each log (default unit "seconds"). It does not actually sleep.
60+
examples: 10, 20ms, 5s, 1m
61+
-d, --delay duration delay log generation speed (default unit "seconds").
62+
examples: 10, 20ms, 5s, 1m
5263
-p, --split-by integer set the maximum number of lines or maximum size in bytes of a log file.
5364
with "number" option, the logs will be split whenever the maximum number of lines is reached.
5465
with "byte" option, the logs will be split whenever the maximum size in bytes is reached.
@@ -60,16 +71,19 @@ Options:
6071
# Generate 1000 lines of logs to stdout
6172
flog
6273

74+
# Generate 200 lines of logs with a time interval of 10s for each log. It doesn't actually sleep while generating
75+
flog -s 10s -n 200
76+
6377
# Generate a single log file with 1000 lines of logs, then overwrite existing log file
6478
flog -t log -w
6579

66-
# Generate a single log gzip file with 3000 lines of logs every 10 seconds
67-
flog -t gz -o log.gz -n 3000 -s 10
80+
# Generate a single log gzip file with 3000 lines of logs every 300ms. It actually sleep (delay) while generating
81+
flog -t gz -o log.gz -n 3000 -d 10s
6882

69-
# Generate logs up to 10MB and split the log files every 1MB in "web/log/apache.log" path with apache combined format
83+
# Generate logs up to 10MB and split log files every 1MB in "web/log/*.log" path with "apache combined" format
7084
flog -t log -f apache_combined -o web/log/apache.log -b 10485760 -p 1048576
7185

72-
# Generate logs in rfc3164 format infinitely
86+
# Generate logs in rfc3164 format infinitely until killed
7387
flog -f rfc3164 -l
7488
```
7589

flog.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ func Generate(option *Option) error {
2222
)
2323

2424
if option.Delay > 0 {
25-
interval = time.Duration(option.Delay * float64(time.Second))
25+
interval = option.Delay
2626
delay = interval
2727
}
2828
if option.Sleep > 0 {
29-
interval = time.Duration(option.Sleep * float64(time.Second))
29+
interval = option.Sleep
3030
}
3131

3232
logFileName := option.Output
@@ -39,7 +39,7 @@ func Generate(option *Option) error {
3939
for {
4040
time.Sleep(delay)
4141
log := NewLog(option.Format, created)
42-
writer.Write([]byte(log + "\n"))
42+
_, _ = writer.Write([]byte(log + "\n"))
4343
created = created.Add(interval)
4444
}
4545
}
@@ -49,10 +49,10 @@ func Generate(option *Option) error {
4949
for line := 0; line < option.Number; line++ {
5050
time.Sleep(delay)
5151
log := NewLog(option.Format, created)
52-
writer.Write([]byte(log + "\n"))
52+
_, _ = writer.Write([]byte(log + "\n"))
5353

5454
if (option.Type != "stdout") && (option.SplitBy > 0) && (line > option.SplitBy*splitCount) {
55-
writer.Close()
55+
_ = writer.Close()
5656
fmt.Println(logFileName, "is created.")
5757

5858
logFileName = NewSplitFileName(option.Output, splitCount)
@@ -68,11 +68,11 @@ func Generate(option *Option) error {
6868
for bytes < option.Bytes {
6969
time.Sleep(delay)
7070
log := NewLog(option.Format, created)
71-
writer.Write([]byte(log + "\n"))
71+
_, _ = writer.Write([]byte(log + "\n"))
7272

7373
bytes += len(log)
7474
if (option.Type != "stdout") && (option.SplitBy > 0) && (bytes > option.SplitBy*splitCount+1) {
75-
writer.Close()
75+
_ = writer.Close()
7676
fmt.Println(logFileName, "is created.")
7777

7878
logFileName = NewSplitFileName(option.Output, splitCount)
@@ -85,7 +85,7 @@ func Generate(option *Option) error {
8585
}
8686

8787
if option.Type != "stdout" {
88-
writer.Close()
88+
_ = writer.Close()
8989
fmt.Println(logFileName, "is created.")
9090
}
9191
return nil

option.go

+48-20
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,40 @@ import (
44
"errors"
55
"fmt"
66
"os"
7+
"strconv"
8+
"strings"
9+
"time"
710

811
"github.com/spf13/pflag"
912
)
1013

11-
const version = "0.4.2"
14+
const version = "0.4.3"
1215
const usage = `flog is a fake log generator for common log formats
1316
1417
Usage: flog [options]
1518
1619
Version: %s
1720
1821
Options:
19-
-f, --format string choose log format. ("apache_common"|"apache_combined"|"apache_error"|"rfc3164"|"rfc5424"|"json") (default "apache_common")
22+
-f, --format string log format. available formats:
23+
- apache_common (default)
24+
- apache_combined
25+
- apache_error
26+
- rfc3164
27+
- rfc5424
28+
- json
2029
-o, --output string output filename. Path-like is allowed. (default "generated.log")
21-
-t, --type string log output type. ("stdout"|"log"|"gz") (default "stdout")
30+
-t, --type string log output type. available types:
31+
- stdout (default)
32+
- log
33+
- gz
2234
-n, --number integer number of lines to generate.
2335
-b, --bytes integer size of logs to generate (in bytes).
2436
"bytes" will be ignored when "number" is set.
25-
-s, --sleep numeric fix creation time interval for each log (in seconds). It does not actually sleep.
26-
-d, --delay numeric delay log generation speed (in seconds).
37+
-s, --sleep duration fix creation time interval for each log (default unit "seconds"). It does not actually sleep.
38+
examples: 10, 20ms, 5s, 1m
39+
-d, --delay duration delay log generation speed (default unit "seconds").
40+
examples: 10, 20ms, 5s, 1m
2741
-p, --split-by integer set the maximum number of lines or maximum size in bytes of a log file.
2842
with "number" option, the logs will be split whenever the maximum number of lines is reached.
2943
with "byte" option, the logs will be split whenever the maximum size in bytes is reached.
@@ -41,8 +55,8 @@ type Option struct {
4155
Type string
4256
Number int
4357
Bytes int
44-
Sleep float64
45-
Delay float64
58+
Sleep time.Duration
59+
Delay time.Duration
4660
SplitBy int
4761
Overwrite bool
4862
Forever bool
@@ -113,19 +127,33 @@ func ParseBytes(bytes int) (int, error) {
113127
}
114128

115129
// ParseSleep validates the given sleep
116-
func ParseSleep(sleep float64) (float64, error) {
130+
func ParseSleep(sleepString string) (time.Duration, error) {
131+
if strings.ContainsAny(sleepString, "nsuµmh") {
132+
return time.ParseDuration(sleepString)
133+
}
134+
sleep, err := strconv.ParseFloat(sleepString, 64)
135+
if err != nil {
136+
return 0, err
137+
}
117138
if sleep < 0 {
118-
return 0.0, errors.New("sleep can not be negative")
139+
return 0.0, errors.New("sleep time must be positive")
119140
}
120-
return sleep, nil
141+
return time.Duration(sleep * float64(time.Second)), nil
121142
}
122143

123144
// ParseDelay validates the given sleep
124-
func ParseDelay(delay float64) (float64, error) {
145+
func ParseDelay(delayString string) (time.Duration, error) {
146+
if strings.ContainsAny(delayString, "nsuµmh") {
147+
return time.ParseDuration(delayString)
148+
}
149+
delay, err := strconv.ParseFloat(delayString, 64)
150+
if err != nil {
151+
return 0, err
152+
}
125153
if delay < 0 {
126-
return 0.0, errors.New("delay can not be negative")
154+
return 0.0, errors.New("delay time must be positive")
127155
}
128-
return delay, nil
156+
return time.Duration(delay * float64(time.Second)), nil
129157
}
130158

131159
// ParseSplitBy validates the given split-by
@@ -142,16 +170,16 @@ func ParseOptions() *Option {
142170

143171
opts := defaultOptions()
144172

145-
help := pflag.BoolP("help", "h", false, "Show usage")
173+
help := pflag.BoolP("help", "h", false, "Show this help message")
146174
version := pflag.BoolP("version", "v", false, "Show version")
147175
format := pflag.StringP("format", "f", opts.Format, "Log format")
148-
output := pflag.StringP("output", "o", opts.Output, "Output filename. Path-like filename is allowed")
176+
output := pflag.StringP("output", "o", opts.Output, "Path-like output filename")
149177
logType := pflag.StringP("type", "t", opts.Type, "Log output type")
150178
number := pflag.IntP("number", "n", opts.Number, "Number of lines to generate")
151179
bytes := pflag.IntP("bytes", "b", opts.Bytes, "Size of logs to generate. (in bytes)")
152-
sleep := pflag.Float64P("sleep", "s", opts.Sleep, "Creation time interval for each log (in seconds)")
153-
delay := pflag.Float64P("delay", "d", opts.Delay, "Delay log generation speed (in seconds)")
154-
splitBy := pflag.IntP("split", "p", opts.SplitBy, "Set the maximum number of lines or maximum size in bytes of a log file")
180+
sleepString := pflag.StringP("sleep", "s", "0s", "Creation time interval (default unit: seconds)")
181+
delayString := pflag.StringP("delay", "d", "0s", "Log generation speed (default unit: seconds)")
182+
splitBy := pflag.IntP("split", "p", opts.SplitBy, "Maximum number of lines or size of a log file")
155183
overwrite := pflag.BoolP("overwrite", "w", false, "Overwrite the existing log files")
156184
forever := pflag.BoolP("loop", "l", false, "Loop output forever until killed")
157185

@@ -177,10 +205,10 @@ func ParseOptions() *Option {
177205
if opts.Bytes, err = ParseBytes(*bytes); err != nil {
178206
errorExit(err)
179207
}
180-
if opts.Sleep, err = ParseSleep(*sleep); err != nil {
208+
if opts.Sleep, err = ParseSleep(*sleepString); err != nil {
181209
errorExit(err)
182210
}
183-
if opts.Delay, err = ParseDelay(*delay); err != nil {
211+
if opts.Delay, err = ParseDelay(*delayString); err != nil {
184212
errorExit(err)
185213
}
186214
if opts.SplitBy, err = ParseSplitBy(*splitBy); err != nil {

option_test.go

+29-12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"testing"
5+
"time"
56

67
"github.com/stretchr/testify/assert"
78
)
@@ -45,32 +46,48 @@ func TestParseBytes(t *testing.T) {
4546
func TestParseSleep(t *testing.T) {
4647
a := assert.New(t)
4748

48-
sleep, err := ParseSleep(10)
49-
a.Equal(10.0, sleep, "sleep should be 10")
49+
sleep, err := ParseSleep("10")
50+
a.Equal(10*time.Second, sleep, "sleep should be 10s")
5051
a.NoError(err, "there should be no error")
5152

52-
sleep, err = ParseSleep(5.5)
53-
a.Equal(5.5, sleep, "sleep should be 5.5")
53+
sleep, err = ParseSleep("20ms")
54+
a.Equal(20*time.Millisecond, sleep, "sleep should be 20ms")
5455
a.NoError(err, "there should be no error")
5556

56-
sleep, err = ParseSleep(-10)
57-
a.Equal(0.0, sleep, "sleep should be 0 when negative is given")
57+
sleep, err = ParseSleep("3s")
58+
a.Equal(3*time.Second, sleep, "sleep should be 3s")
59+
a.NoError(err, "there should be no error")
60+
61+
sleep, err = ParseSleep("5.5")
62+
a.Equal(time.Duration(5.5*float64(time.Second)), sleep, "sleep should be 5.5s")
63+
a.NoError(err, "there should be no error")
64+
65+
sleep, err = ParseSleep("-10")
66+
a.Equal(time.Duration(0), sleep, "sleep should be 0 when negative is given")
5867
a.Error(err, "there should be an error when negative is given")
5968
}
6069

6170
func TestParseDelay(t *testing.T) {
6271
a := assert.New(t)
6372

64-
delay, err := ParseDelay(10)
65-
a.Equal(10.0, delay, "delay should be 10")
73+
delay, err := ParseDelay("10")
74+
a.Equal(10*time.Second, delay, "delay should be 10s")
75+
a.NoError(err, "there should be no error")
76+
77+
delay, err = ParseDelay("20ms")
78+
a.Equal(20*time.Millisecond, delay, "delay should be 20ms")
79+
a.NoError(err, "there should be no error")
80+
81+
delay, err = ParseDelay("3s")
82+
a.Equal(3*time.Second, delay, "delay should be 3s")
6683
a.NoError(err, "there should be no error")
6784

68-
delay, err = ParseDelay(5.5)
69-
a.Equal(5.5, delay, "delay should be 5.5")
85+
delay, err = ParseDelay("5.5")
86+
a.Equal(time.Duration(5.5*float64(time.Second)), delay, "delay should be 5.5s")
7087
a.NoError(err, "there should be no error")
7188

72-
delay, err = ParseDelay(-10)
73-
a.Equal(0.0, delay, "delay should be 0 when negative is given")
89+
delay, err = ParseDelay("-10")
90+
a.Equal(time.Duration(0), delay, "delay should be 0 when negative is given")
7491
a.Error(err, "there should be an error when negative is given")
7592
}
7693

0 commit comments

Comments
 (0)