Skip to content

Commit

Permalink
feat(options): support duration string for sleep/delay options
Browse files Browse the repository at this point in the history
  • Loading branch information
mingrammer committed Aug 1, 2020
1 parent c48e1ac commit fce7a74
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 48 deletions.
30 changes: 22 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,25 @@ There are useful options. (`flog --help`)

```console
Options:
-f, --format string choose log format. ("apache_common"|"apache_combined"|"apache_error"|"rfc3164"|"rfc5424"|"common_log"|"json") (default "apache_common")
-f, --format string log format. available formats:
- apache_common (default)
- apache_combined
- apache_error
- rfc3164
- rfc5424
- json
-o, --output string output filename. Path-like is allowed. (default "generated.log")
-t, --type string log output type. ("stdout"|"log"|"gz") (default "stdout")
-t, --type string log output type. available types:
- stdout (default)
- log
- gz
-n, --number integer number of lines to generate.
-b, --bytes integer size of logs to generate (in bytes).
"bytes" will be ignored when "number" is set.
-s, --sleep numeric fix creation time interval for each log (in seconds). It does not actually sleep.
-d, --delay numeric delay log generation speed (in seconds).
-s, --sleep duration fix creation time interval for each log (default unit "seconds"). It does not actually sleep.
examples: 10, 20ms, 5s, 1m
-d, --delay duration delay log generation speed (default unit "seconds").
examples: 10, 20ms, 5s, 1m
-p, --split-by integer set the maximum number of lines or maximum size in bytes of a log file.
with "number" option, the logs will be split whenever the maximum number of lines is reached.
with "byte" option, the logs will be split whenever the maximum size in bytes is reached.
Expand All @@ -60,16 +71,19 @@ Options:
# Generate 1000 lines of logs to stdout
flog

# Generate 200 lines of logs with a time interval of 10s for each log. It doesn't actually sleep while generating
flog -s 10s -n 200

# Generate a single log file with 1000 lines of logs, then overwrite existing log file
flog -t log -w

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

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

# Generate logs in rfc3164 format infinitely
# Generate logs in rfc3164 format infinitely until killed
flog -f rfc3164 -l
```

Expand Down
16 changes: 8 additions & 8 deletions flog.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ func Generate(option *Option) error {
)

if option.Delay > 0 {
interval = time.Duration(option.Delay * float64(time.Second))
interval = option.Delay
delay = interval
}
if option.Sleep > 0 {
interval = time.Duration(option.Sleep * float64(time.Second))
interval = option.Sleep
}

logFileName := option.Output
Expand All @@ -39,7 +39,7 @@ func Generate(option *Option) error {
for {
time.Sleep(delay)
log := NewLog(option.Format, created)
writer.Write([]byte(log + "\n"))
_, _ = writer.Write([]byte(log + "\n"))
created = created.Add(interval)
}
}
Expand All @@ -49,10 +49,10 @@ func Generate(option *Option) error {
for line := 0; line < option.Number; line++ {
time.Sleep(delay)
log := NewLog(option.Format, created)
writer.Write([]byte(log + "\n"))
_, _ = writer.Write([]byte(log + "\n"))

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

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

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

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

if option.Type != "stdout" {
writer.Close()
_ = writer.Close()
fmt.Println(logFileName, "is created.")
}
return nil
Expand Down
68 changes: 48 additions & 20 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,40 @@ import (
"errors"
"fmt"
"os"
"strconv"
"strings"
"time"

"github.com/spf13/pflag"
)

const version = "0.4.2"
const version = "0.4.3"
const usage = `flog is a fake log generator for common log formats
Usage: flog [options]
Version: %s
Options:
-f, --format string choose log format. ("apache_common"|"apache_combined"|"apache_error"|"rfc3164"|"rfc5424"|"json") (default "apache_common")
-f, --format string log format. available formats:
- apache_common (default)
- apache_combined
- apache_error
- rfc3164
- rfc5424
- json
-o, --output string output filename. Path-like is allowed. (default "generated.log")
-t, --type string log output type. ("stdout"|"log"|"gz") (default "stdout")
-t, --type string log output type. available types:
- stdout (default)
- log
- gz
-n, --number integer number of lines to generate.
-b, --bytes integer size of logs to generate (in bytes).
"bytes" will be ignored when "number" is set.
-s, --sleep numeric fix creation time interval for each log (in seconds). It does not actually sleep.
-d, --delay numeric delay log generation speed (in seconds).
-s, --sleep duration fix creation time interval for each log (default unit "seconds"). It does not actually sleep.
examples: 10, 20ms, 5s, 1m
-d, --delay duration delay log generation speed (default unit "seconds").
examples: 10, 20ms, 5s, 1m
-p, --split-by integer set the maximum number of lines or maximum size in bytes of a log file.
with "number" option, the logs will be split whenever the maximum number of lines is reached.
with "byte" option, the logs will be split whenever the maximum size in bytes is reached.
Expand All @@ -41,8 +55,8 @@ type Option struct {
Type string
Number int
Bytes int
Sleep float64
Delay float64
Sleep time.Duration
Delay time.Duration
SplitBy int
Overwrite bool
Forever bool
Expand Down Expand Up @@ -113,19 +127,33 @@ func ParseBytes(bytes int) (int, error) {
}

// ParseSleep validates the given sleep
func ParseSleep(sleep float64) (float64, error) {
func ParseSleep(sleepString string) (time.Duration, error) {
if strings.ContainsAny(sleepString, "nsuµmh") {
return time.ParseDuration(sleepString)
}
sleep, err := strconv.ParseFloat(sleepString, 64)
if err != nil {
return 0, err
}
if sleep < 0 {
return 0.0, errors.New("sleep can not be negative")
return 0.0, errors.New("sleep time must be positive")
}
return sleep, nil
return time.Duration(sleep * float64(time.Second)), nil
}

// ParseDelay validates the given sleep
func ParseDelay(delay float64) (float64, error) {
func ParseDelay(delayString string) (time.Duration, error) {
if strings.ContainsAny(delayString, "nsuµmh") {
return time.ParseDuration(delayString)
}
delay, err := strconv.ParseFloat(delayString, 64)
if err != nil {
return 0, err
}
if delay < 0 {
return 0.0, errors.New("delay can not be negative")
return 0.0, errors.New("delay time must be positive")
}
return delay, nil
return time.Duration(delay * float64(time.Second)), nil
}

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

opts := defaultOptions()

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

Expand All @@ -177,10 +205,10 @@ func ParseOptions() *Option {
if opts.Bytes, err = ParseBytes(*bytes); err != nil {
errorExit(err)
}
if opts.Sleep, err = ParseSleep(*sleep); err != nil {
if opts.Sleep, err = ParseSleep(*sleepString); err != nil {
errorExit(err)
}
if opts.Delay, err = ParseDelay(*delay); err != nil {
if opts.Delay, err = ParseDelay(*delayString); err != nil {
errorExit(err)
}
if opts.SplitBy, err = ParseSplitBy(*splitBy); err != nil {
Expand Down
41 changes: 29 additions & 12 deletions option_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -45,32 +46,48 @@ func TestParseBytes(t *testing.T) {
func TestParseSleep(t *testing.T) {
a := assert.New(t)

sleep, err := ParseSleep(10)
a.Equal(10.0, sleep, "sleep should be 10")
sleep, err := ParseSleep("10")
a.Equal(10*time.Second, sleep, "sleep should be 10s")
a.NoError(err, "there should be no error")

sleep, err = ParseSleep(5.5)
a.Equal(5.5, sleep, "sleep should be 5.5")
sleep, err = ParseSleep("20ms")
a.Equal(20*time.Millisecond, sleep, "sleep should be 20ms")
a.NoError(err, "there should be no error")

sleep, err = ParseSleep(-10)
a.Equal(0.0, sleep, "sleep should be 0 when negative is given")
sleep, err = ParseSleep("3s")
a.Equal(3*time.Second, sleep, "sleep should be 3s")
a.NoError(err, "there should be no error")

sleep, err = ParseSleep("5.5")
a.Equal(time.Duration(5.5*float64(time.Second)), sleep, "sleep should be 5.5s")
a.NoError(err, "there should be no error")

sleep, err = ParseSleep("-10")
a.Equal(time.Duration(0), sleep, "sleep should be 0 when negative is given")
a.Error(err, "there should be an error when negative is given")
}

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

delay, err := ParseDelay(10)
a.Equal(10.0, delay, "delay should be 10")
delay, err := ParseDelay("10")
a.Equal(10*time.Second, delay, "delay should be 10s")
a.NoError(err, "there should be no error")

delay, err = ParseDelay("20ms")
a.Equal(20*time.Millisecond, delay, "delay should be 20ms")
a.NoError(err, "there should be no error")

delay, err = ParseDelay("3s")
a.Equal(3*time.Second, delay, "delay should be 3s")
a.NoError(err, "there should be no error")

delay, err = ParseDelay(5.5)
a.Equal(5.5, delay, "delay should be 5.5")
delay, err = ParseDelay("5.5")
a.Equal(time.Duration(5.5*float64(time.Second)), delay, "delay should be 5.5s")
a.NoError(err, "there should be no error")

delay, err = ParseDelay(-10)
a.Equal(0.0, delay, "delay should be 0 when negative is given")
delay, err = ParseDelay("-10")
a.Equal(time.Duration(0), delay, "delay should be 0 when negative is given")
a.Error(err, "there should be an error when negative is given")
}

Expand Down

0 comments on commit fce7a74

Please sign in to comment.