diff --git a/Makefile b/Makefile index ac9f31c3..fb323894 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION=0.67 +VERSION=0.68 BINARY_NAME=statup GOPATH:=$(GOPATH) GOCMD=go diff --git a/core/configs.go b/core/configs.go index a569086e..e7eb87cc 100644 --- a/core/configs.go +++ b/core/configs.go @@ -31,7 +31,7 @@ type ErrorResponse struct { // LoadConfig will attempt to load the 'config.yml' file in a specific directory func LoadConfig(directory string) (*DbConfig, error) { - var configs *types.DbConfig + var configs *DbConfig if os.Getenv("DB_CONN") != "" { utils.Log(1, "DB_CONN environment variable was found, waiting for database...") return LoadUsingEnv() @@ -44,7 +44,7 @@ func LoadConfig(directory string) (*DbConfig, error) { if err != nil { return nil, err } - Configs = &DbConfig{configs} + Configs = configs return Configs, err } @@ -79,7 +79,7 @@ func LoadUsingEnv() (*DbConfig, error) { CoreApp.UseCdn = true } - dbConfig := &DbConfig{&types.DbConfig{ + dbConfig := &DbConfig{ DbConn: os.Getenv("DB_CONN"), DbHost: os.Getenv("DB_HOST"), DbUser: os.Getenv("DB_USER"), @@ -92,7 +92,7 @@ func LoadUsingEnv() (*DbConfig, error) { Username: "admin", Password: "admin", Email: "info@localhost.com", - }} + } err := dbConfig.Connect(true, utils.Directory) if err != nil { diff --git a/core/database.go b/core/database.go index 6cc3ff57..fe34a5f4 100644 --- a/core/database.go +++ b/core/database.go @@ -34,9 +34,7 @@ var ( DbSession *gorm.DB ) -type DbConfig struct { - *types.DbConfig -} +type DbConfig types.DbConfig // failuresDB returns the 'failures' database column func failuresDB() *gorm.DB { @@ -199,8 +197,8 @@ func (db *DbConfig) waitForDb() error { // this function is currently set to delete records 7+ days old every 60 minutes func DatabaseMaintence() { for range time.Tick(60 * time.Minute) { - utils.Log(1, "Checking for database records older than 7 days...") - since := time.Now().AddDate(0, 0, -7) + utils.Log(1, "Checking for database records older than 3 months...") + since := time.Now().AddDate(0, -3, 0).UTC() DeleteAllSince("failures", since) DeleteAllSince("hits", since) } @@ -223,7 +221,7 @@ func (c *DbConfig) Update() error { utils.Log(4, err) return err } - data, err := yaml.Marshal(c.DbConfig) + data, err := yaml.Marshal(c) if err != nil { utils.Log(3, err) return err @@ -243,7 +241,7 @@ func (c *DbConfig) Save() (*DbConfig, error) { } c.ApiKey = utils.NewSHA1Hash(16) c.ApiSecret = utils.NewSHA1Hash(16) - data, err := yaml.Marshal(c.DbConfig) + data, err := yaml.Marshal(c) if err != nil { utils.Log(3, err) return nil, err @@ -275,23 +273,6 @@ func (c *DbConfig) CreateCore() *Core { return CoreApp } -// SeedDatabase will insert many elements into the database. This is only ran in Dev/Test move -//func (db *DbConfig) SeedDatabase() (string, string, error) { -// utils.Log(1, "Seeding Database with Dummy Data...") -// dir := utils.Directory -// var cmd string -// switch db.DbConn { -// case "sqlite": -// cmd = fmt.Sprintf("cat %v/dev/sqlite_seed.sql | sqlite3 %v/statup.db", dir, dir) -// case "mysql": -// cmd = fmt.Sprintf("mysql -h %v -P %v -u %v --password=%v %v < %v/dev/mysql_seed.sql", Configs.DbHost, 3306, Configs.DbUser, Configs.DbPass, Configs.DbData, dir) -// case "postgres": -// cmd = fmt.Sprintf("PGPASSWORD=%v psql -U %v -h %v -d %v -1 -f %v/dev/postgres_seed.sql", db.DbPass, db.DbUser, db.DbHost, db.DbData, dir) -// } -// out, outErr, err := utils.Command(cmd) -// return out, outErr, err -//} - // DropDatabase will DROP each table Statup created func (db *DbConfig) DropDatabase() error { utils.Log(1, "Dropping Database Tables...") diff --git a/core/sample.go b/core/sample.go index 0ca38a81..3a6a5f2a 100644 --- a/core/sample.go +++ b/core/sample.go @@ -91,16 +91,18 @@ func InsertSampleData() error { // InsertSampleHits will create a couple new hits for the sample services func InsertSampleHits() error { - since := time.Now().Add((-24 * 7) * time.Hour) + since := time.Now().Add((-24 * 7) * time.Hour).UTC() for i := int64(1); i <= 5; i++ { service := SelectService(i) utils.Log(1, fmt.Sprintf("Adding %v sample hit records to service %v", 360, service.Name)) createdAt := since + alpha := float64(1.05) - for hi := int64(1); hi <= 1860; hi++ { + for hi := int64(1); hi <= 168; hi++ { + alpha += 0.01 rand.Seed(time.Now().UnixNano()) - latency := rand.Float64() - createdAt = createdAt.Add(3 * time.Minute).UTC() + latency := rand.Float64() * alpha + createdAt = createdAt.Add(1 * time.Hour) hit := &types.Hit{ Service: service.Id, CreatedAt: createdAt, @@ -112,6 +114,39 @@ func InsertSampleHits() error { return nil } +func sampleGraphData(i float64, upward *bool) float64 { + alpha := 0.0003 + if *upward { + i += 0.3 + if i >= 6500 { + i += 0.1 + *upward = false + } else if i >= 4500 { + i += 3 + } else if i >= 2300 { + i += 1 + } else if i >= 1150 { + i += 2 + } else if i >= 500 { + i += 1 + } + } else { + i -= 0.3 + if i <= 6500 { + i -= 0.1 + } else if i <= 4500 { + i -= 3 + } else if i <= 2300 { + i -= 1 + } else if i <= 1150 { + i -= 2 + } else if i <= 500 { + i -= 1 + } + } + return i * alpha +} + func insertSampleCore() error { core := &types.Core{ Name: "Statup Sample Data", diff --git a/core/services.go b/core/services.go index 25adcc00..dd4c212d 100644 --- a/core/services.go +++ b/core/services.go @@ -166,27 +166,6 @@ func (s *Service) DowntimeText() string { return fmt.Sprintf("%v has been offline for %v", s.Name, utils.DurationReadable(s.Downtime())) } -// GroupDataBy returns a SQL query as a string to group a column by a time -func GroupDataBy(column string, id int64, start, end time.Time, seconds int64) string { - incrementTime := "second" - if seconds == 60 { - incrementTime = "minute" - } else if seconds == 3600 { - incrementTime = "hour" - } - var sql string - switch CoreApp.DbConnection { - case "mysql": - sql = fmt.Sprintf("SELECT CONCAT(date_format(created_at, '%%Y-%%m-%%dT%%H:%%i:00Z')) AS created_at, AVG(latency)*1000 AS value FROM %v WHERE service=%v AND DATE_FORMAT(created_at, '%%Y-%%m-%%dT%%TZ') BETWEEN DATE_FORMAT('%v', '%%Y-%%m-%%dT%%TZ') AND DATE_FORMAT('%v', '%%Y-%%m-%%dT%%TZ') GROUP BY 1 ORDER BY created_at ASC;", column, id, start.UTC().Format(time.RFC3339), end.UTC().Format(time.RFC3339)) - case "sqlite": - sql = fmt.Sprintf("SELECT datetime((strftime('%%s', created_at) / %v) * %v, 'unixepoch'), AVG(latency)*1000 as value FROM %v WHERE service=%v AND created_at BETWEEN '%v' AND '%v' GROUP BY 1 ORDER BY created_at ASC;", seconds, seconds, column, id, start.UTC().Format(time.RFC3339), end.UTC().Format(time.RFC3339)) - case "postgres": - sql = fmt.Sprintf("SELECT date_trunc('%v', created_at), AVG(latency)*1000 AS value FROM %v WHERE service=%v AND created_at >= '%v' AND created_at <= '%v' GROUP BY 1 ORDER BY date_trunc ASC;", incrementTime, column, id, start.UTC().Format(time.RFC3339), end.UTC().Format(time.RFC3339)) - } - fmt.Println(sql) - return sql -} - func Dbtimestamp(seconds int64) string { incrementTime := "second" if seconds == 60 { diff --git a/handlers/index.go b/handlers/index.go index 63b30f43..05fddf0f 100644 --- a/handlers/index.go +++ b/handlers/index.go @@ -56,7 +56,7 @@ func DesktopInit(ip string, port int) { RunHTTPServer(ip, port) } - config := &core.DbConfig{DbConfig: &types.DbConfig{ + config := &core.DbConfig{ DbConn: "sqlite", Project: "Statup", Description: "Statup running as an App!", @@ -66,7 +66,7 @@ func DesktopInit(ip string, port int) { Email: "user@email.com", Error: nil, Location: utils.Directory, - }} + } config, err = config.Save() if err != nil { diff --git a/handlers/services.go b/handlers/services.go index b30b7f10..cdfba01c 100644 --- a/handlers/services.go +++ b/handlers/services.go @@ -53,8 +53,6 @@ func renderServiceChartHandler(w http.ResponseWriter, r *http.Request) { end = now.New(end).EndOfDay().UTC() } - fmt.Println("start: ", start.String(), "end: ", end.String()) - service := core.SelectService(utils.StringInt(vars["id"])) data := core.GraphDataRaw(service, start, end).ToString() @@ -186,8 +184,8 @@ func servicesViewHandler(w http.ResponseWriter, r *http.Request) { return } - end := time.Now() - start := end.Add((-24 * 7) * time.Hour) + end := time.Now().UTC() + start := end.Add((-24 * 7) * time.Hour).UTC() if startField != 0 { start = time.Unix(startField, 0) diff --git a/handlers/setup.go b/handlers/setup.go index 54365be8..b4884e2a 100644 --- a/handlers/setup.go +++ b/handlers/setup.go @@ -77,7 +77,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { dir := utils.Directory - config := &core.DbConfig{DbConfig: &types.DbConfig{ + config := &core.DbConfig{ DbConn: dbConn, DbHost: dbHost, DbUser: dbUser, @@ -92,7 +92,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { Email: email, Error: nil, Location: utils.Directory, - }} + } core.Configs, err = config.Save() if err != nil { diff --git a/notifiers/email.go b/notifiers/email.go index 711c94bf..841272fb 100644 --- a/notifiers/email.go +++ b/notifiers/email.go @@ -19,11 +19,12 @@ import ( "bytes" "crypto/tls" "fmt" + "github.com/go-mail/mail" "github.com/hunterlong/statup/core/notifier" "github.com/hunterlong/statup/types" "github.com/hunterlong/statup/utils" - "gopkg.in/gomail.v2" "html/template" + "net/smtp" ) const ( @@ -33,7 +34,7 @@ const ( ) var ( - mailer *gomail.Dialer + mailer *mail.Dialer ) type Email struct { @@ -97,18 +98,6 @@ func (u *Email) Send(msg interface{}) error { return nil } -func (u *Email) OnTest(n notifier.Notification) (bool, error) { - email := &EmailOutgoing{ - To: emailer.GetValue("var2"), - Subject: "Test Email", - Template: MESSAGE, - Data: nil, - From: emailer.GetValue("var1"), - } - u.AddQueue(email) - return true, nil -} - type EmailOutgoing struct { To string Subject string @@ -158,11 +147,23 @@ func (u *Email) OnSave() error { return nil } +// OnTest triggers when this notifier has been saved +func (u *Email) OnTest() error { + host := fmt.Sprintf("%v:%v", u.Host, u.Port) + dial, err := smtp.Dial(host) + if err != nil { + utils.Log(3, err) + return err + } + auth := smtp.PlainAuth("", u.Username, u.Password, host) + return dial.Auth(auth) +} + func (u *Email) dialSend(email *EmailOutgoing) error { - mailer = gomail.NewPlainDialer(emailer.Host, emailer.Port, emailer.Username, emailer.Password) + mailer = mail.NewDialer(emailer.Host, emailer.Port, emailer.Username, emailer.Password) mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true} emailSource(email) - m := gomail.NewMessage() + m := mail.NewMessage() m.SetHeader("From", email.From) m.SetHeader("To", email.To) m.SetHeader("Subject", email.Subject) diff --git a/source/tmpl/service.html b/source/tmpl/service.html index e173d15a..8bccf586 100644 --- a/source/tmpl/service.html +++ b/source/tmpl/service.html @@ -281,7 +281,7 @@ xAxes: [{ type: 'time', gridLines: { - display:true + display: true } }] },