func TestRuleTest(t *testing.T) { var rule *Rule // TrendUp rule = &Rule{TrendUp: true} assert.Ok(t, rule.Test(&Metric{}, &Index{Score: 1.2}, nil)) assert.Ok(t, !rule.Test(&Metric{}, &Index{Score: 0.8}, nil)) // TrendDown rule = &Rule{TrendDown: true} assert.Ok(t, rule.Test(&Metric{}, &Index{Score: -1.2}, nil)) assert.Ok(t, !rule.Test(&Metric{}, &Index{Score: 1.2}, nil)) // TrendUp And Value >= X rule = &Rule{TrendUp: true, ThresholdMax: 39} assert.Ok(t, rule.Test(&Metric{Value: 50}, &Index{Score: 1.3}, nil)) assert.Ok(t, !rule.Test(&Metric{Value: 38}, &Index{Score: 1.5}, nil)) assert.Ok(t, !rule.Test(&Metric{Value: 60}, &Index{Score: 0.9}, nil)) // TrendDown And Value <= X rule = &Rule{TrendDown: true, ThresholdMin: 40} assert.Ok(t, rule.Test(&Metric{Value: 10}, &Index{Score: -1.2}, nil)) assert.Ok(t, !rule.Test(&Metric{Value: 41}, &Index{Score: -1.2}, nil)) assert.Ok(t, !rule.Test(&Metric{Value: 12}, &Index{Score: -0.2}, nil)) // (TrendUp And Value >= X) Or TrendDown rule = &Rule{TrendUp: true, TrendDown: true, ThresholdMax: 90} assert.Ok(t, rule.Test(&Metric{Value: 100}, &Index{Score: 1.1}, nil)) assert.Ok(t, rule.Test(&Metric{}, &Index{Score: -1.1}, nil)) assert.Ok(t, !rule.Test(&Metric{}, &Index{Score: -0.1}, nil)) assert.Ok(t, !rule.Test(&Metric{Value: 89}, &Index{Score: 1.3}, nil)) assert.Ok(t, !rule.Test(&Metric{Value: 189}, &Index{Score: 0.3}, nil)) // (TrendUp And Value >= X) Or (TrendDown And Value <= X) rule = &Rule{TrendUp: true, TrendDown: true, ThresholdMax: 90, ThresholdMin: 10} assert.Ok(t, rule.Test(&Metric{Value: 100}, &Index{Score: 1.2}, nil)) assert.Ok(t, rule.Test(&Metric{Value: 9}, &Index{Score: -1.2}, nil)) assert.Ok(t, !rule.Test(&Metric{Value: 12}, &Index{Score: 1.2}, nil)) assert.Ok(t, !rule.Test(&Metric{Value: 102}, &Index{Score: 0.2}, nil)) assert.Ok(t, !rule.Test(&Metric{Value: 2}, &Index{Score: 0.9}, nil)) // Default thresholdMaxs cfg := config.New() cfg.Detector.DefaultThresholdMaxs["fo*"] = 300 rule = &Rule{TrendUp: true} assert.Ok(t, rule.Test(&Metric{Value: 310, Name: "foo"}, &Index{Score: 1.3}, cfg)) assert.Ok(t, !rule.Test(&Metric{Value: 120, Name: "foo"}, &Index{Score: 1.3}, cfg)) // Default thresholdMins cfg = config.New() cfg.Detector.DefaultThresholdMins["fo*"] = 10 rule = &Rule{TrendDown: true} assert.Ok(t, !rule.Test(&Metric{Value: 19, Name: "foo"}, &Index{Score: -1.2}, cfg)) assert.Ok(t, rule.Test(&Metric{Value: 8, Name: "foo"}, &Index{Score: -1.2}, cfg)) // Bug#456: DefaultThresholdMax intercepts the testing for later trendDown. cfg = config.New() cfg.Detector.DefaultThresholdMaxs["fo*"] = 10 rule = &Rule{TrendDown: true} assert.Ok(t, !rule.Test(&Metric{Value: 19, Name: "foo"}, &Index{Score: 0.37}, cfg)) }
func TestHitLimit(t *testing.T) { // Currently disable logging log.Disable() defer log.Enable() //New and add rules. config := config.New() config.Interval = 1 rule1 := &models.Rule{Pattern: "a.*.c.d"} filter := New() filter.addRule(rule1) filter.SetHitLimit(config) for i := 0; i < config.Detector.IntervalHitLimit; i++ { //hit rule when counter < intervalHitLimit rules := filter.MatchedRules(&models.Metric{Name: "a.b.c.d"}) assert.Ok(t, 1 == len(rules)) } //counter over limit, matched rules = 0 rules := filter.MatchedRules(&models.Metric{Name: "a.b.c.d"}) assert.Ok(t, 0 == len(rules)) time.Sleep(time.Second * 2) //after interval counter is cleared, matched rules = 1 rules = filter.MatchedRules(&models.Metric{Name: "a.b.c.d"}) assert.Ok(t, 1 == len(rules)) }
func BenchmarkRuleTest(b *testing.B) { cfg := config.New() m := &Metric{Value: 102} idx := &Index{Score: 1.2} rule := &Rule{TrendUp: true, ThresholdMax: 100} b.ResetTimer() for i := 0; i < b.N; i++ { rule.Test(m, idx, cfg) } }
func TestAlertRecordAlertNotifyAfterConfigDisabled(t *testing.T) { cfg := config.New() cfg.Alerter.NotifyAfter = 0 a := &Alerter{cfg: cfg, alertRecords: safemap.New(), lock: &sync.RWMutex{}} metrics := &models.Metric{Name: "test", Stamp: 0, Value: 80} for i := 0; i <= 100; i++ { metrics.Stamp = uint32(i) util.Must(t, !a.checkAlertCount(metrics)) a.setAlertRecord(metrics) } }
func TestPickTrendingFactor(t *testing.T) { cfg := config.New() d := &Detector{cfg: cfg} rules := []*models.Rule{ &models.Rule{Level: models.RuleLevelLow}, } util.Must(t, d.pickTrendingFactor(rules) == cfg.Detector.TrendingFactorLowLevel) rules = append(rules, &models.Rule{Level: models.RuleLevelMiddle}) util.Must(t, d.pickTrendingFactor(rules) == cfg.Detector.TrendingFactorMiddleLevel) rules = append(rules, &models.Rule{Level: models.RuleLevelHigh}) util.Must(t, d.pickTrendingFactor(rules) == cfg.Detector.TrendingFactorHighLevel) }
func main() { // Arguments fileName := flag.String("c", "config.json", "config file") debug := flag.Bool("d", false, "debug mode") vers := flag.Bool("v", false, "version") flag.Parse() // Version if *vers { fmt.Fprintln(os.Stdout, version.Version) os.Exit(1) } // Logging log.SetName("banshee") if *debug { log.SetLevel(log.DEBUG) } log.Debug("using %s, max %d cpu", runtime.Version(), runtime.GOMAXPROCS(-1)) // Config cfg := config.New() if flag.NFlag() == 0 || (flag.NFlag() == 1 && *debug == true) { log.Warn("no config file specified, using default..") } else { err := cfg.UpdateWithJSONFile(*fileName) if err != nil { log.Fatal("failed to load %s, %s", *fileName, err) } } // Storage options := &storage.Options{ NumGrid: cfg.Period[0], GridLen: cfg.Period[1], } db, err := storage.Open(cfg.Storage.Path, options) if err != nil { log.Fatal("failed to open %s: %v", cfg.Storage.Path, err) } // Cleaner cleaner := cleaner.New(db, cfg.Period[0]*cfg.Period[1]) go cleaner.Start() // Filter filter := filter.New() filter.Init(db) // Alerter alerter := alerter.New(cfg, db, filter) alerter.Start() // Webapp go webapp.Start(cfg, db) // Detector detector := detector.New(cfg, db, filter) detector.Out(alerter.In) detector.Start() }
func TestAlertRecordAlertNotifyAfterConfigSetNotifyAfterToOne(t *testing.T) { cfg := config.New() cfg.Alerter.NotifyAfter = 1 a := &Alerter{cfg: cfg, alertRecords: safemap.New(), lock: &sync.RWMutex{}} metrics := &models.Metric{Name: "test", Stamp: 80, Value: 80} util.Must(t, a.checkAlertCount(metrics)) a.setAlertRecord(metrics) metrics.Stamp = 81 util.Must(t, !a.checkAlertCount(metrics)) a.setAlertRecord(metrics) }
func BenchmarkRuleTestWithDefaultThresholdMaxsNum4(b *testing.B) { cfg := config.New() cfg.Detector.DefaultThresholdMaxs = map[string]float64{ "timer.count_ps.*": 30, "timer.upper_90.*": 500, "counter.*": 10, "timer.mean_90.*": 300, } m := &Metric{Name: "timer.mean_90.foo", Value: 1700} idx := &Index{Name: m.Name, Score: 1.2} rule := Rule{TrendUp: true} b.ResetTimer() for i := 0; i < b.N; i++ { rule.Test(m, idx, cfg) } }
func TestFill0Issue470(t *testing.T) { // Case https://github.com/eleme/banshee/issues/470 cfg := config.New() d := &Detector{cfg: cfg} ms := []*models.Metric{ &models.Metric{Stamp: 80, Value: 80}, &models.Metric{Stamp: 90, Value: 90}, &models.Metric{Stamp: 120, Value: 120}, } start, stop := uint32(60), uint32(150) excepted := []float64{80, 90, 0, 0, 120, 0, 0} actually := d.fill0(ms, start, stop) assert.Ok(t, len(actually) == len(excepted)) for i := 0; i < len(excepted); i++ { assert.Ok(t, excepted[i] == actually[i]) } }
func TestClean(t *testing.T) { // Config cfg := config.New() // Open storage dbFileName := "db-test" db, _ := storage.Open(dbFileName) defer os.RemoveAll(dbFileName) defer db.Close() // Create cleaner c := New(cfg, db) // Add outdated data. // Case fully cleaned: 3 days no new data m1 := &models.Metric{Name: "fully-case", Stamp: uint32(time.Now().Unix() - 3*3600*24 - 1)} // Case outdated metrics cleaned. m2 := &models.Metric{Name: "metric-case", Stamp: uint32(time.Now().Unix() - 7*3600*24 - 100)} m3 := &models.Metric{Name: m2.Name, Stamp: uint32(time.Now().Unix() - 60)} i1 := &models.Index{Name: m1.Name, Stamp: m1.Stamp} i2 := &models.Index{Name: m2.Name, Stamp: m2.Stamp} i3 := &models.Index{Name: m3.Name, Stamp: m3.Stamp} // Put metrics. db.Metric.Put(m1) db.Metric.Put(m2) db.Metric.Put(m3) // Put indexes. db.Index.Put(i1) db.Index.Put(i2) db.Index.Put(i3) c.clean() // m1 should be fully cleaned var err error _, err = db.Index.Get(m1.Name) assert.Ok(t, err == indexdb.ErrNotFound) l, err := db.Metric.Get(m1.Name, 0, uint32(time.Now().Unix())) assert.Ok(t, len(l) == 0) // m2 should be cleaned and m3 shouldn't be cleaned l, err = db.Metric.Get(m2.Name, m2.Stamp, uint32(time.Now().Unix())) assert.Ok(t, len(l) == 1) assert.Ok(t, l[0].Name == m2.Name) assert.Ok(t, l[0].Stamp == m3.Stamp && l[0].Stamp != m2.Stamp) // m2/m3's index shouldn't be cleaned i, err := db.Index.Get(m2.Name) assert.Ok(t, err == nil && i.Name == m2.Name) }
"github.com/eleme/banshee/detector" "github.com/eleme/banshee/filter" "github.com/eleme/banshee/health" "github.com/eleme/banshee/storage" "github.com/eleme/banshee/util/log" "github.com/eleme/banshee/version" "github.com/eleme/banshee/webapp" ) var ( // Arguments debug = flag.Bool("d", false, "debug mode") fileName = flag.String("c", "config.json", "config file path") showVersion = flag.Bool("v", false, "show version") // Variables cfg = config.New() db *storage.DB flt = filter.New() ) func usage() { fmt.Fprintf(os.Stderr, "usage: banshee [-c config] [-d] [-v]\n") flag.PrintDefaults() fmt.Fprintf(os.Stderr, "copyright eleme https://github.com/eleme/banshee.\n") os.Exit(2) } func initLog() { log.SetName("banshee") if *debug { log.SetLevel(log.DEBUG)