diff --git a/flog.go b/flog.go index e3689f7..d6e1f24 100644 --- a/flog.go +++ b/flog.go @@ -14,7 +14,12 @@ import ( // Generate generates the logs with given options func Generate(option *Option) error { splitCount := 1 - delta := time.Duration(0) + created := time.Now() + + delay := time.Duration(0) + if option.Delay > 0 { + delay = time.Duration(option.Delay*float64(time.Second/time.Millisecond)) * time.Millisecond + } logFileName := option.Output writer, err := NewWriter(option.Type, logFileName) @@ -24,16 +29,22 @@ func Generate(option *Option) error { if option.Forever { for { - log := NewLog(option.Format, delta) + if delay > 0 { + time.Sleep(delay) + } + log := NewLog(option.Format, created) writer.Write([]byte(log + "\n")) - delta += time.Duration(option.Sleep*float64(time.Second/time.Millisecond)) * time.Millisecond + created = created.Add(time.Duration(option.Sleep*float64(time.Second/time.Millisecond)) * time.Millisecond) } } if option.Bytes == 0 { // Generates the logs until the certain number of lines is reached for line := 0; line < option.Number; line++ { - log := NewLog(option.Format, delta) + if delay > 0 { + time.Sleep(delay) + } + log := NewLog(option.Format, created) writer.Write([]byte(log + "\n")) if (option.Type != "stdout") && (option.SplitBy > 0) && (line > option.SplitBy*splitCount) { @@ -45,14 +56,16 @@ func Generate(option *Option) error { splitCount++ } - - delta += time.Duration(option.Sleep*float64(time.Second/time.Millisecond)) * time.Millisecond + created = created.Add(time.Duration(option.Sleep*float64(time.Second/time.Millisecond)) * time.Millisecond) } } else { // Generates the logs until the certain size in bytes is reached bytes := 0 for bytes < option.Bytes { - log := NewLog(option.Format, delta) + if delay > 0 { + time.Sleep(delay) + } + log := NewLog(option.Format, created) writer.Write([]byte(log + "\n")) bytes += len(log) @@ -65,8 +78,7 @@ func Generate(option *Option) error { splitCount++ } - - delta += time.Duration(option.Sleep*float64(time.Second/time.Millisecond)) * time.Millisecond + created = created.Add(time.Duration(option.Sleep*float64(time.Second/time.Millisecond)) * time.Millisecond) } } @@ -100,16 +112,16 @@ func NewWriter(logType string, logFileName string) (io.WriteCloser, error) { } // NewLog creates a log for given format -func NewLog(format string, delta time.Duration) string { +func NewLog(format string, t time.Time) string { switch format { case "apache_common": - return NewApacheCommonLog(delta) + return NewApacheCommonLog(t) case "apache_combined": - return NewApacheCombinedLog(delta) + return NewApacheCombinedLog(t) case "apache_error": - return NewApacheErrorLog(delta) + return NewApacheErrorLog(t) case "rfc3164": - return NewRFC3164Log(delta) + return NewRFC3164Log(t) default: return "" } diff --git a/flog_test.go b/flog_test.go index db3ce99..91e9b44 100644 --- a/flog_test.go +++ b/flog_test.go @@ -16,11 +16,12 @@ func ExampleNewLog() { monkey.Patch(time.Now, func() time.Time { return stopped }) defer monkey.Unpatch(time.Now) - fmt.Println(NewLog("apache_common", 0)) - fmt.Println(NewLog("apache_combined", 0)) - fmt.Println(NewLog("apache_error", 0)) - fmt.Println(NewLog("rfc3164", 0)) - fmt.Println(NewLog("unknown", 0)) + created := time.Now() + fmt.Println(NewLog("apache_common", created)) + fmt.Println(NewLog("apache_combined", created)) + fmt.Println(NewLog("apache_error", created)) + fmt.Println(NewLog("rfc3164", created)) + fmt.Println(NewLog("unknown", created)) // Output: // 222.83.191.222 - Kozey7157 697 [2018-04-22T09:30:00Z] "DELETE /innovate/next-generation" 302 24570 // 174.144.199.149 - Mosciski7760 386 [2018-04-22T09:30:00Z] "GET /networks/revolutionary" 204 70360 "https://www.directeyeballs.org/streamline" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7) AppleWebKit/5312 (KHTML, like Gecko) Chrome/37.0.821.0 Mobile Safari/5312" diff --git a/log.go b/log.go index 169648e..cda7d86 100644 --- a/log.go +++ b/log.go @@ -19,13 +19,13 @@ const ( ) // NewApacheCommonLog creates a log string with apache common log format -func NewApacheCommonLog(delta time.Duration) string { +func NewApacheCommonLog(t time.Time) string { return fmt.Sprintf( ApacheCommonLog, gofakeit.IPv4Address(), gofakeit.Username(), gofakeit.Number(0, 1000), - time.Now().Add(delta).Format(time.RFC3339), + t.Format(time.RFC3339), gofakeit.HTTPMethod(), RandResourceURI(), gofakeit.StatusCode(), @@ -34,13 +34,13 @@ func NewApacheCommonLog(delta time.Duration) string { } // NewApacheCombinedLog creates a log string with apache combined log format -func NewApacheCombinedLog(delta time.Duration) string { +func NewApacheCombinedLog(t time.Time) string { return fmt.Sprintf( ApacheCombinedLog, gofakeit.IPv4Address(), gofakeit.Username(), gofakeit.Number(1, 1000), - time.Now().Add(delta).Format(time.RFC3339), + t.Format(time.RFC3339), gofakeit.HTTPMethod(), RandResourceURI(), gofakeit.StatusCode(), @@ -51,10 +51,10 @@ func NewApacheCombinedLog(delta time.Duration) string { } // NewApacheErrorLog creates a log string with apache error log format -func NewApacheErrorLog(delta time.Duration) string { +func NewApacheErrorLog(t time.Time) string { return fmt.Sprintf( ApacheErrorLog, - time.Now().Add(delta).Format(time.RFC3339), + t.Format(time.RFC3339), gofakeit.Word(), gofakeit.LogLevel("apache"), gofakeit.Number(1, 10000), @@ -65,11 +65,11 @@ func NewApacheErrorLog(delta time.Duration) string { } // NewRFC3164Log creates a log string with syslog (RFC3164) format -func NewRFC3164Log(delta time.Duration) string { +func NewRFC3164Log(t time.Time) string { return fmt.Sprintf( RFC3164Log, gofakeit.Number(0, 191), - time.Now().Add(delta).Format(RFC3164), + t.Format(RFC3164), gofakeit.Username(), gofakeit.BuzzWord(), gofakeit.Number(1, 10000), diff --git a/log_test.go b/log_test.go index 5c11b67..e557ddc 100644 --- a/log_test.go +++ b/log_test.go @@ -16,7 +16,8 @@ func ExampleNewApacheCommonLog() { monkey.Patch(time.Now, func() time.Time { return stopped }) defer monkey.Unpatch(time.Now) - fmt.Println(NewApacheCommonLog(0)) + created := time.Now() + fmt.Println(NewApacheCommonLog(created)) // Output: 222.83.191.222 - Kozey7157 697 [2018-04-22T09:30:00Z] "DELETE /innovate/next-generation" 302 24570 } @@ -26,7 +27,8 @@ func ExampleNewApacheCombinedLog() { monkey.Patch(time.Now, func() time.Time { return stopped }) defer monkey.Unpatch(time.Now) - fmt.Println(NewApacheCombinedLog(0)) + created := time.Now() + fmt.Println(NewApacheCombinedLog(created)) // Output: 222.83.191.222 - Kozey7157 119 [2018-04-22T09:30:00Z] "DELETE /innovate/next-generation" 302 81317 "https://www.forwardholistic.biz/mission-critical/synergize/morph/sticky" "Mozilla/5.0 (Windows NT 5.01) AppleWebKit/5320 (KHTML, like Gecko) Chrome/40.0.875.0 Mobile Safari/5320" } @@ -36,7 +38,8 @@ func ExampleNewApacheErrorLog() { monkey.Patch(time.Now, func() time.Time { return stopped }) defer monkey.Unpatch(time.Now) - fmt.Println(NewApacheErrorLog(0)) + created := time.Now() + fmt.Println(NewApacheErrorLog(created)) // Output: [2018-04-22T09:30:00Z] [quia:crit] [pid 4214:tid 6037] [client: 90.151.9.107] If we back up the program, we can get to the SSL sensor through the redundant SAS program! } @@ -46,6 +49,7 @@ func ExampleNewRFC3164Log() { monkey.Patch(time.Now, func() time.Time { return stopped }) defer monkey.Unpatch(time.Now) - fmt.Println(NewRFC3164Log(0)) + created := time.Now() + fmt.Println(NewRFC3164Log(created)) // Output: <24>Apr 22 09:30:00 Moen8727 concept[3160]: If we back up the program, we can get to the SSL sensor through the redundant SAS program! } diff --git a/option.go b/option.go index f483f7a..b13f263 100644 --- a/option.go +++ b/option.go @@ -22,7 +22,8 @@ Options: -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 sleep interval time between lines (in seconds). It does not actually sleep every log generation. + -s, --sleep numeric creation time interval for each log (in seconds). It does not actually sleep. + -d, --delay numeric delay log generation speed (in seconds). -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. @@ -41,6 +42,7 @@ type Option struct { Number int Bytes int Sleep float64 + Delay float64 SplitBy int Overwrite bool Forever bool @@ -71,6 +73,7 @@ func defaultOptions() *Option { Number: 1000, Bytes: 0, Sleep: 0.0, + Delay: 0.0, SplitBy: 0, Overwrite: false, Forever: false, @@ -117,6 +120,14 @@ func ParseSleep(sleep float64) (float64, error) { return sleep, nil } +// ParseDelay validates the given sleep +func ParseDelay(delay float64) (float64, error) { + if delay < 0 { + return 0.0, errors.New("delay can not be negative") + } + return delay, nil +} + // ParseSplitBy validates the given split-by func ParseSplitBy(splitBy int) (int, error) { if splitBy < 0 { @@ -138,7 +149,8 @@ func ParseOptions() *Option { 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, "Sleep interval time between lines. (in seconds)") + 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") overwrite := pflag.BoolP("overwrite", "w", false, "Overwrite the existing log files") forever := pflag.BoolP("loop", "l", false, "Loop output forever until killed") @@ -168,6 +180,9 @@ func ParseOptions() *Option { if opts.Sleep, err = ParseSleep(*sleep); err != nil { errorExit(err) } + if opts.Delay, err = ParseDelay(*delay); err != nil { + errorExit(err) + } if opts.SplitBy, err = ParseSplitBy(*splitBy); err != nil { errorExit(err) } diff --git a/option_test.go b/option_test.go index 09d2c13..ebbdb53 100644 --- a/option_test.go +++ b/option_test.go @@ -58,6 +58,22 @@ func TestParseSleep(t *testing.T) { 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") + a.NoError(err, "there should be no error") + + delay, err = ParseDelay(5.5) + a.Equal(5.5, delay, "delay should be 5.5") + 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") + a.Error(err, "there should be an error when negative is given") +} + func TestParseSplitBy(t *testing.T) { a := assert.New(t)