From c441f95a2c46267fba1feb307fd28960ed9373a8 Mon Sep 17 00:00:00 2001 From: ehlxr Date: Fri, 22 Nov 2019 18:11:26 +0800 Subject: [PATCH] update at 2019-11-22 18:11:26 by ehlxr --- go.mod | 1 + main.go | 147 ++++++++++++++------------------------------ pkg/limiter.go | 49 +++++++++++++++ pkg/limiter_test.go | 20 ++++++ pkg/parser.go | 55 +++++++++++++++++ pkg/version.go | 30 +++++++++ version | 2 +- 7 files changed, 202 insertions(+), 102 deletions(-) create mode 100644 pkg/limiter.go create mode 100644 pkg/limiter_test.go create mode 100644 pkg/parser.go create mode 100644 pkg/version.go diff --git a/go.mod b/go.mod index 35f7989..2884b25 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/hpcloud/tail v1.0.1-0.20180514194441-a1dbeea552b7 github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4 golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 // indirect + golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect unknwon.dev/clog/v2 v2.0.0-beta.5 diff --git a/main.go b/main.go index 6462c49..b67487f 100644 --- a/main.go +++ b/main.go @@ -1,60 +1,52 @@ package main import ( - "encoding/base64" "fmt" + "github.com/ehlxr/monitor/pkg" "github.com/hpcloud/tail" - "github.com/jessevdk/go-flags" "strings" + "time" log "unknwon.dev/clog/v2" dt "github.com/JetBlink/dingtalk-notify-go-sdk" - "os" "regexp" ) var ( - AppName string - Version string - BuildTime string - GitCommit string - GoVersion string - - versionTpl = `%s -Name: %s -Version: %s -BuildTime: %s -GitCommit: %s -GoVersion: %s - -` - bannerBase64 = "DQogX18gIF9fICBfX19fXyAgXyAgXyAgX19fXyAgX19fXyAgX19fX18gIF9fX18gDQooICBcLyAgKSggIF8gICkoIFwoICkoXyAgXykoXyAgXykoICBfICApKCAgXyBcDQogKSAgICAoICApKF8pKCAgKSAgKCAgXykoXyAgICkoICAgKShfKSggICkgICAvDQooXy9cL1xfKShfX19fXykoXylcXykoX19fXykgKF9fKSAoX19fX18pKF8pXF8pDQo=" - - opts struct { - AppName string `short:"n" long:"monitor-app-name" env:"MONITOR_APP_NAME" description:"The name of the application being monitored, which will be added to the content before"` - File string `short:"f" long:"monitor-file" env:"MONITOR_FILE" description:"The file to be monitored" required:"true"` - KeyWord string `short:"k" long:"search-keyword" env:"SEARCH_KEYWORD" description:"Keyword to be search for" default:"ERRO"` - KeyWordIgnoreCase bool `short:"c" long:"keyword-case-sensitive" env:"KEYWORD_IGNORE_CASE" description:"Whether Keyword ignore case"` - Version bool `short:"v" long:"version" description:"Show version info"` - Robot robot `group:"DingTalk Robot Options" namespace:"robot" env-namespace:"ROBOT" ` - } + dingTalk *dt.Robot + limiter *pkg.LimiterServer ) -type robot struct { - Token string `short:"t" long:"token" env:"TOKEN" description:"DingTalk robot access token" required:"true"` - Secret string `short:"s" long:"secret" env:"SECRET" description:"DingTalk robot secret"` - AtMobiles []string `short:"m" long:"at-mobiles" env:"AT_MOBILES" env-delim:"," description:"The mobile of the person will be at"` - IsAtAll bool `short:"a" long:"at-all" env:"AT_ALL" description:"Whether at everyone"` -} - func init() { - initLog() + err := log.NewConsole() + if err != nil { + panic("unable to create new logger: " + err.Error()) + } } func main() { - parseArg() + pkg.ParseArg() - tf, err := tail.TailFile(opts.File, + dingTalk = dt.NewRobot(pkg.Opts.Robot.Token, pkg.Opts.Robot.Secret) + limiter = pkg.NewLimiterServer(1*time.Minute, 20) + + tailFile() +} + +func sendMsg(content string) { + if err := dingTalk.SendTextMessage( + fmt.Sprintf("%s\n%s", pkg.Opts.AppName, content), + pkg.Opts.Robot.AtMobiles, + pkg.Opts.Robot.IsAtAll, + ); err != nil { + log.Error("%+v", err) + } + + log.Info("send message <%s> success", content) +} + +func tailFile() { + tf, err := tail.TailFile(pkg.Opts.File, tail.Config{ ReOpen: true, Follow: true, @@ -63,79 +55,32 @@ func main() { if err != nil { log.Fatal("Tail file %+v", err) } - log.Info("monitor app <%s> file <%s>, filter by <%s>, ignore case <%v>...", - opts.AppName, - opts.File, - opts.KeyWord, - opts.KeyWordIgnoreCase) - dingTalk := dt.NewRobot(opts.Robot.Token, opts.Robot.Secret) - - if opts.KeyWordIgnoreCase { - opts.KeyWord = strings.ToLower(opts.KeyWord) + if pkg.Opts.KeyWordIgnoreCase { + pkg.Opts.KeyWord = strings.ToLower(pkg.Opts.KeyWord) } + + log.Info("monitor app <%s> file <%s>, filter by <%s>, ignore case <%v>...", + pkg.Opts.AppName, + pkg.Opts.File, + pkg.Opts.KeyWord, + pkg.Opts.KeyWordIgnoreCase) + for line := range tf.Lines { text := line.Text - if opts.KeyWordIgnoreCase { + if pkg.Opts.KeyWordIgnoreCase { text = strings.ToLower(text) } - if ok, _ := regexp.Match(opts.KeyWord, []byte(text)); ok { + if ok, _ := regexp.Match(pkg.Opts.KeyWord, []byte(text)); ok { + if limiter.IsAvailable() { + limiter.Increase() - if err = dingTalk.SendTextMessage( - // opts.AppName, - fmt.Sprintf("%s\n%s", opts.AppName, line.Text), - opts.Robot.AtMobiles, - opts.Robot.IsAtAll, - ); err != nil { - log.Error("%+v", err) - continue + sendMsg(line.Text) + } else { + log.Error("dingTalk 1 m allow send 20 msg. msg %v discarded.", + line.Text) } - - log.Info("send message <%s> success", line.Text) } } } - -func initLog() { - err := log.NewConsole() - if err != nil { - panic("unable to create new logger: " + err.Error()) - } -} - -func parseArg() { - parser := flags.NewParser(&opts, flags.HelpFlag|flags.PassDoubleDash) - parser.NamespaceDelimiter = "-" - - if AppName != "" { - parser.Name = AppName - } - - if _, err := parser.Parse(); err != nil { - if opts.Version { - // -v - printVersion() - os.Exit(0) - } - - if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp { - // -h - _, _ = fmt.Fprintln(os.Stdout, err) - os.Exit(0) - } - - // err - _, _ = fmt.Fprintln(os.Stderr, err) - - parser.WriteHelp(os.Stderr) - - os.Exit(1) - } -} - -// printVersion Print out version information -func printVersion() { - banner, _ := base64.StdEncoding.DecodeString(bannerBase64) - fmt.Printf(versionTpl, banner, AppName, Version, BuildTime, GitCommit, GoVersion) -} diff --git a/pkg/limiter.go b/pkg/limiter.go new file mode 100644 index 0000000..6c80958 --- /dev/null +++ b/pkg/limiter.go @@ -0,0 +1,49 @@ +package pkg + +import ( + "sync" + "time" + log "unknwon.dev/clog/v2" +) + +type LimiterServer struct { + Interval time.Duration + MaxCount int + Lock sync.Mutex + ReqCount int +} + +func NewLimiterServer(interval time.Duration, maxCount int) *LimiterServer { + limiter := &LimiterServer{ + Interval: interval, + MaxCount: maxCount, + } + + go func() { + ticker := time.NewTicker(interval) + for { + <-ticker.C + limiter.Lock.Lock() + log.Info("Reset LimiterServer Count...") + + limiter.ReqCount = 0 + limiter.Lock.Unlock() + } + }() + + return limiter +} + +func (limiter *LimiterServer) Increase() { + limiter.Lock.Lock() + defer limiter.Lock.Unlock() + + limiter.ReqCount += 1 +} + +func (limiter *LimiterServer) IsAvailable() bool { + limiter.Lock.Lock() + defer limiter.Lock.Unlock() + + return limiter.ReqCount < limiter.MaxCount +} diff --git a/pkg/limiter_test.go b/pkg/limiter_test.go new file mode 100644 index 0000000..3da6542 --- /dev/null +++ b/pkg/limiter_test.go @@ -0,0 +1,20 @@ +package pkg + +import ( + "testing" + "time" +) + +func TestLimiter(t *testing.T) { + limiter := NewLimiterServer(1*time.Second, 5) + + for { + if limiter.IsAvailable() { + limiter.Increase() + + t.Log("hello...", limiter.ReqCount) + } else { + return + } + } +} diff --git a/pkg/parser.go b/pkg/parser.go new file mode 100644 index 0000000..4ea046b --- /dev/null +++ b/pkg/parser.go @@ -0,0 +1,55 @@ +package pkg + +import ( + "fmt" + "github.com/jessevdk/go-flags" + "os" +) + +var ( + Opts struct { + AppName string `short:"n" long:"monitor-app-name" env:"MONITOR_APP_NAME" description:"The name of the application being monitored, which will be added to the content before"` + File string `short:"f" long:"monitor-file" env:"MONITOR_FILE" description:"The file to be monitored" required:"true"` + KeyWord string `short:"k" long:"search-keyword" env:"SEARCH_KEYWORD" description:"Keyword to be search for" default:"ERRO"` + KeyWordIgnoreCase bool `short:"c" long:"keyword-case-sensitive" env:"KEYWORD_IGNORE_CASE" description:"Whether Keyword ignore case"` + Version bool `short:"v" long:"version" description:"Show version info"` + Robot Robot `group:"DingTalk Robot Options" namespace:"robot" env-namespace:"ROBOT" ` + } +) + +type Robot struct { + Token string `short:"t" long:"token" env:"TOKEN" description:"DingTalk robot access token" required:"true"` + Secret string `short:"s" long:"secret" env:"SECRET" description:"DingTalk robot secret"` + AtMobiles []string `short:"m" long:"at-mobiles" env:"AT_MOBILES" env-delim:"," description:"The mobile of the person will be at"` + IsAtAll bool `short:"a" long:"at-all" env:"AT_ALL" description:"Whether at everyone"` +} + +func ParseArg() { + parser := flags.NewParser(&Opts, flags.HelpFlag|flags.PassDoubleDash) + parser.NamespaceDelimiter = "-" + + if AppName != "" { + parser.Name = AppName + } + + if _, err := parser.Parse(); err != nil { + if Opts.Version { + // -v + PrintVersion() + os.Exit(0) + } + + if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp { + // -h + _, _ = fmt.Fprintln(os.Stdout, err) + os.Exit(0) + } + + // err + _, _ = fmt.Fprintln(os.Stderr, err) + + parser.WriteHelp(os.Stderr) + + os.Exit(1) + } +} diff --git a/pkg/version.go b/pkg/version.go new file mode 100644 index 0000000..222698a --- /dev/null +++ b/pkg/version.go @@ -0,0 +1,30 @@ +package pkg + +import ( + "encoding/base64" + "fmt" +) + +var ( + AppName string + Version string + BuildTime string + GitCommit string + GoVersion string + + versionTpl = `%s +Name: %s +Version: %s +BuildTime: %s +GitCommit: %s +GoVersion: %s + +` + bannerBase64 = "DQogX18gIF9fICBfX19fXyAgXyAgXyAgX19fXyAgX19fXyAgX19fX18gIF9fX18gDQooICBcLyAgKSggIF8gICkoIFwoICkoXyAgXykoXyAgXykoICBfICApKCAgXyBcDQogKSAgICAoICApKF8pKCAgKSAgKCAgXykoXyAgICkoICAgKShfKSggICkgICAvDQooXy9cL1xfKShfX19fXykoXylcXykoX19fXykgKF9fKSAoX19fX18pKF8pXF8pDQo=" +) + +// PrintVersion Print out version information +func PrintVersion() { + banner, _ := base64.StdEncoding.DecodeString(bannerBase64) + fmt.Printf(versionTpl, banner, AppName, Version, BuildTime, GitCommit, GoVersion) +} diff --git a/version b/version index 8ce995b..a92e827 100644 --- a/version +++ b/version @@ -1 +1 @@ -v0.0.3 \ No newline at end of file +v0.0.4 \ No newline at end of file