mirror of https://github.com/statping/statping
fixed postgres time issue - code cleanup - API timezone updates
parent
aca967caab
commit
f231d39369
|
@ -1,14 +1,6 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b62a3c5b37db602bf1158e921da1a762315a4c37855fd418a14498aa87a342d5"
|
||||
name = "cloud.google.com/go"
|
||||
packages = ["civil"]
|
||||
pruneopts = "UT"
|
||||
revision = "debcad1964693daf8ef4bc06292d7e828e075130"
|
||||
version = "v0.31.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:65796e5fdb94d94bc0ee6bc422aa3541dbe69ed4da275cb5a27f8fa141f4e35c"
|
||||
|
@ -45,31 +37,20 @@
|
|||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0fd9da444782c2defb1352dc098f55b8b42c538787e29e45677a1dc40ff0ab11"
|
||||
name = "github.com/denisenkom/go-mssqldb"
|
||||
packages = [
|
||||
".",
|
||||
"internal/cp",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "4e0d7dc8888fbb59764060e99b7b68e77a6f9698"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e37eb23cfd852df9c65b5dee28456595d7b12479421221a088b6ea7ad95a3570"
|
||||
digest = "1:3806f369b846160fcbde19bdcf93790868defe7c58d1bb6bc8d974c5b8f8dc1e"
|
||||
name = "github.com/go-mail/mail"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "63235f23494bf20d713a585bce40b2a0675c2f77"
|
||||
version = "2.2.0"
|
||||
revision = "f59b9b83a4e522098e3d3eb94e6f81850ad6e973"
|
||||
version = "v2.3.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:adea5a94903eb4384abef30f3d878dc9ff6b6b5b0722da25b82e5169216dfb61"
|
||||
digest = "1:ec6f9bf5e274c833c911923c9193867f3f18788c461f76f05f62bb1510e0ae65"
|
||||
name = "github.com/go-sql-driver/mysql"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "d523deb1b23d913de5bdada721a6071e71283618"
|
||||
version = "v1.4.0"
|
||||
revision = "72cd26f257d44c1114970e19afddcd812016007e"
|
||||
version = "v1.4.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
|
||||
|
@ -112,11 +93,10 @@
|
|||
version = "v1.1.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4d28d632da146ec6e632bdd29676a95e0874f1ad837fff06aef6610b3b6b4728"
|
||||
digest = "1:8fe19266ce82209076d4a81007ff93f40dd349faca4a917aea59d33956bbd4fd"
|
||||
name = "github.com/jinzhu/gorm"
|
||||
packages = [
|
||||
".",
|
||||
"dialects/mssql",
|
||||
"dialects/mysql",
|
||||
"dialects/postgres",
|
||||
"dialects/sqlite",
|
||||
|
@ -211,15 +191,14 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:68344dbfaa4179bb50a583eb8172ace3f1edaf3aebc24e68c03f549f6e6b60dc"
|
||||
digest = "1:1ecf2a49df33be51e757d0033d5d51d5f784f35f68e5a38f797b2d3f03357d71"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"bcrypt",
|
||||
"blowfish",
|
||||
"md4",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "4d3f4d9ffa16a13f451c3b2999e9c49e9750bf06"
|
||||
revision = "3d3f9f413869b949e48070b5bc593aa22cc2b8f2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c25289f43ac4a68d88b02245742347c94f1e108c534dda442188015ff80669b3"
|
||||
|
@ -258,13 +237,13 @@
|
|||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/GeertJohan/go.rice",
|
||||
"github.com/GeertJohan/go.rice/embedded",
|
||||
"github.com/ararog/timeago",
|
||||
"github.com/go-mail/mail",
|
||||
"github.com/go-yaml/yaml",
|
||||
"github.com/gorilla/mux",
|
||||
"github.com/gorilla/sessions",
|
||||
"github.com/jinzhu/gorm",
|
||||
"github.com/jinzhu/gorm/dialects/mssql",
|
||||
"github.com/jinzhu/gorm/dialects/mysql",
|
||||
"github.com/jinzhu/gorm/dialects/postgres",
|
||||
"github.com/jinzhu/gorm/dialects/sqlite",
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
[[constraint]]
|
||||
name = "github.com/go-mail/mail"
|
||||
version = "2.2.0"
|
||||
version = "2.3.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-yaml/yaml"
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1,4 +1,4 @@
|
|||
VERSION=0.79.84
|
||||
VERSION=0.79.85
|
||||
BINARY_NAME=statup
|
||||
GOPATH:=$(GOPATH)
|
||||
GOCMD=go
|
||||
|
|
|
@ -288,7 +288,7 @@ func RunSelectAllMysqlServices(t *testing.T) {
|
|||
|
||||
func RunSelectAllNotifiers(t *testing.T) {
|
||||
var err error
|
||||
notifier.SetDB(core.DbSession)
|
||||
notifier.SetDB(core.DbSession, float32(-8))
|
||||
core.CoreApp.Notifications = notifier.Load()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 8, len(core.CoreApp.Notifications))
|
||||
|
|
|
@ -238,7 +238,7 @@ func (s *Service) Check(record bool) {
|
|||
// recordSuccess will create a new 'hit' record in the database for a successful/online service
|
||||
func recordSuccess(s *Service) {
|
||||
s.Online = true
|
||||
s.LastOnline = time.Now()
|
||||
s.LastOnline = utils.Timezoner(time.Now().UTC(), CoreApp.Timezone)
|
||||
hit := &types.Hit{
|
||||
Service: s.Id,
|
||||
Latency: s.Latency,
|
||||
|
|
|
@ -52,26 +52,32 @@ func LoadConfigFile(directory string) (*DbConfig, error) {
|
|||
// LoadUsingEnv will attempt to load database configs based on environment variables. If DB_CONN is set if will force this function.
|
||||
func LoadUsingEnv() (*DbConfig, error) {
|
||||
Configs = new(DbConfig)
|
||||
Configs.LocalIP = GetLocalIP()
|
||||
if os.Getenv("DB_CONN") == "" {
|
||||
return nil, errors.New("Missing DB_CONN environment variable")
|
||||
return Configs, errors.New("Missing DB_CONN environment variable")
|
||||
}
|
||||
if os.Getenv("DB_CONN") != "sqlite" {
|
||||
if os.Getenv("DB_HOST") == "" {
|
||||
return nil, errors.New("Missing DB_HOST environment variable")
|
||||
return Configs, errors.New("Missing DB_HOST environment variable")
|
||||
}
|
||||
if os.Getenv("DB_USER") == "" {
|
||||
return nil, errors.New("Missing DB_USER environment variable")
|
||||
return Configs, errors.New("Missing DB_USER environment variable")
|
||||
}
|
||||
if os.Getenv("DB_PASS") == "" {
|
||||
return nil, errors.New("Missing DB_PASS environment variable")
|
||||
return Configs, errors.New("Missing DB_PASS environment variable")
|
||||
}
|
||||
if os.Getenv("DB_DATABASE") == "" {
|
||||
return nil, errors.New("Missing DB_DATABASE environment variable")
|
||||
return Configs, errors.New("Missing DB_DATABASE environment variable")
|
||||
}
|
||||
}
|
||||
Configs = EnvToConfig()
|
||||
CoreApp.Name = os.Getenv("NAME")
|
||||
CoreApp.Domain = os.Getenv("DOMAIN")
|
||||
domain := os.Getenv("DOMAIN")
|
||||
if domain == "" {
|
||||
CoreApp.Domain = Configs.LocalIP
|
||||
} else {
|
||||
CoreApp.Domain = os.Getenv("DOMAIN")
|
||||
}
|
||||
CoreApp.DbConnection = Configs.DbConn
|
||||
CoreApp.UseCdn = types.NewNullBool(os.Getenv("USE_CDN") == "true")
|
||||
|
||||
|
@ -121,7 +127,10 @@ func DefaultPort(db string) int64 {
|
|||
|
||||
// EnvToConfig converts environment variables to a DbConfig variable
|
||||
func EnvToConfig() *DbConfig {
|
||||
port := DefaultPort(os.Getenv("DB_PORT"))
|
||||
port := utils.StringInt(os.Getenv("DB_PORT"))
|
||||
if port == 0 {
|
||||
port = DefaultPort(os.Getenv("DB_PORT"))
|
||||
}
|
||||
name := os.Getenv("NAME")
|
||||
if name == "" {
|
||||
name = "Statup"
|
||||
|
|
21
core/core.go
21
core/core.go
|
@ -17,10 +17,12 @@ package core
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/source"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
@ -74,7 +76,7 @@ func InsertNotifierDB() error {
|
|||
return errors.New("database connection has not been created")
|
||||
}
|
||||
}
|
||||
notifier.SetDB(DbSession)
|
||||
notifier.SetDB(DbSession, CoreApp.Timezone)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -151,6 +153,23 @@ func SelectCore() (*Core, error) {
|
|||
return CoreApp, db.Error
|
||||
}
|
||||
|
||||
// GetLocalIP returns the non loopback local IP of the host
|
||||
func GetLocalIP() string {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return "http://localhost"
|
||||
}
|
||||
for _, address := range addrs {
|
||||
// check the address type and if it is not a loopback the display it
|
||||
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||
if ipnet.IP.To4() != nil {
|
||||
return fmt.Sprintf("http://%v", ipnet.IP.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
return "http://localhost"
|
||||
}
|
||||
|
||||
// ServiceOrder will reorder the services based on 'order_id' (Order)
|
||||
type ServiceOrder []types.ServiceInterface
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/mssql"
|
||||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
|
@ -33,8 +32,13 @@ import (
|
|||
var (
|
||||
// DbSession stores the Statup database session
|
||||
DbSession *gorm.DB
|
||||
DbModels []interface{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
DbModels = []interface{}{&types.Service{}, &types.User{}, &types.Hit{}, &types.Failure{}, &types.Message{}, &types.Checkin{}, &types.CheckinHit{}, ¬ifier.Notification{}}
|
||||
}
|
||||
|
||||
// DbConfig stores the config.yml file for the statup configuration
|
||||
type DbConfig types.DbConfig
|
||||
|
||||
|
@ -81,7 +85,12 @@ func checkinHitsDB() *gorm.DB {
|
|||
// HitsBetween returns the gorm database query for a collection of service hits between a time range
|
||||
func (s *Service) HitsBetween(t1, t2 time.Time, group string, column string) *gorm.DB {
|
||||
selector := Dbtimestamp(group, column)
|
||||
return DbSession.Model(&types.Hit{}).Select(selector).Where("service = ? AND created_at BETWEEN ? AND ?", s.Id, t1.UTC().Format(types.TIME_DAY), t2.UTC().Format(types.TIME_DAY))
|
||||
if Configs.DbConn == "postgres" {
|
||||
timeQuery := fmt.Sprintf("service = %v AND created_at BETWEEN '%v.000000' AND '%v.000000'", s.Id, t1.UTC().Format(types.POSTGRES_TIME), t2.UTC().Format(types.POSTGRES_TIME))
|
||||
return DbSession.Model(&types.Hit{}).Select(selector).Where(timeQuery)
|
||||
} else {
|
||||
return DbSession.Model(&types.Hit{}).Select(selector).Where("service = ? AND created_at BETWEEN ? AND ?", s.Id, t1.UTC().Format(types.TIME_DAY), t2.UTC().Format(types.TIME_DAY))
|
||||
}
|
||||
}
|
||||
|
||||
// CloseDB will close the database connection if available
|
||||
|
@ -96,6 +105,13 @@ func (db *DbConfig) Close() error {
|
|||
return DbSession.DB().Close()
|
||||
}
|
||||
|
||||
// AfterFind for Core will set the timezone
|
||||
func (c *Core) AfterFind() (err error) {
|
||||
c.CreatedAt = utils.Timezoner(c.CreatedAt, CoreApp.Timezone)
|
||||
c.UpdatedAt = utils.Timezoner(c.UpdatedAt, CoreApp.Timezone)
|
||||
return
|
||||
}
|
||||
|
||||
// AfterFind for Service will set the timezone
|
||||
func (s *Service) AfterFind() (err error) {
|
||||
s.CreatedAt = utils.Timezoner(s.CreatedAt, CoreApp.Timezone)
|
||||
|
@ -118,12 +134,14 @@ func (f *failure) AfterFind() (err error) {
|
|||
// AfterFind for USer will set the timezone
|
||||
func (u *User) AfterFind() (err error) {
|
||||
u.CreatedAt = utils.Timezoner(u.CreatedAt, CoreApp.Timezone)
|
||||
u.UpdatedAt = utils.Timezoner(u.UpdatedAt, CoreApp.Timezone)
|
||||
return
|
||||
}
|
||||
|
||||
// AfterFind for Checkin will set the timezone
|
||||
func (c *Checkin) AfterFind() (err error) {
|
||||
c.CreatedAt = utils.Timezoner(c.CreatedAt, CoreApp.Timezone)
|
||||
c.UpdatedAt = utils.Timezoner(c.UpdatedAt, CoreApp.Timezone)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -136,6 +154,9 @@ func (c *checkinHit) AfterFind() (err error) {
|
|||
// AfterFind for Message will set the timezone
|
||||
func (u *Message) AfterFind() (err error) {
|
||||
u.CreatedAt = utils.Timezoner(u.CreatedAt, CoreApp.Timezone)
|
||||
u.UpdatedAt = utils.Timezoner(u.UpdatedAt, CoreApp.Timezone)
|
||||
u.StartOn = utils.Timezoner(u.StartOn, CoreApp.Timezone)
|
||||
u.EndOn = utils.Timezoner(u.EndOn, CoreApp.Timezone)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -159,6 +180,7 @@ func (f *failure) BeforeCreate() (err error) {
|
|||
func (u *User) BeforeCreate() (err error) {
|
||||
if u.CreatedAt.IsZero() {
|
||||
u.CreatedAt = time.Now().UTC()
|
||||
u.UpdatedAt = time.Now().UTC()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -167,6 +189,7 @@ func (u *User) BeforeCreate() (err error) {
|
|||
func (u *Message) BeforeCreate() (err error) {
|
||||
if u.CreatedAt.IsZero() {
|
||||
u.CreatedAt = time.Now().UTC()
|
||||
u.UpdatedAt = time.Now().UTC()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -232,7 +255,7 @@ func (db *DbConfig) Connect(retry bool, location string) error {
|
|||
host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort)
|
||||
conn = fmt.Sprintf("%v:%v@tcp(%v)/%v?charset=utf8&parseTime=True&loc=UTC", Configs.DbUser, Configs.DbPass, host, Configs.DbData)
|
||||
case "postgres":
|
||||
conn = fmt.Sprintf("host=%v port=%v user=%v dbname=%v password=%v sslmode=disable", Configs.DbHost, Configs.DbPort, Configs.DbUser, Configs.DbData, Configs.DbPass)
|
||||
conn = fmt.Sprintf("host=%v port=%v user=%v dbname=%v password=%v timezone=UTC sslmode=disable", Configs.DbHost, Configs.DbPort, Configs.DbUser, Configs.DbData, Configs.DbPass)
|
||||
case "mssql":
|
||||
host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort)
|
||||
conn = fmt.Sprintf("sqlserver://%v:%v@%v?database=%v", Configs.DbUser, Configs.DbPass, host, Configs.DbData)
|
||||
|
@ -343,8 +366,8 @@ func (c *DbConfig) CreateCore() *Core {
|
|||
// DropDatabase will DROP each table Statup created
|
||||
func (db *DbConfig) DropDatabase() error {
|
||||
utils.Log(1, "Dropping Database Tables...")
|
||||
//err := DbSession.DropTableIfExists("checkins")
|
||||
err := DbSession.DropTableIfExists("checkin_hits")
|
||||
err := DbSession.DropTableIfExists("checkins")
|
||||
err = DbSession.DropTableIfExists("checkin_hits")
|
||||
err = DbSession.DropTableIfExists("notifications")
|
||||
err = DbSession.DropTableIfExists("core")
|
||||
err = DbSession.DropTableIfExists("failures")
|
||||
|
@ -357,18 +380,18 @@ func (db *DbConfig) DropDatabase() error {
|
|||
|
||||
// CreateDatabase will CREATE TABLES for each of the Statup elements
|
||||
func (db *DbConfig) CreateDatabase() error {
|
||||
var err error
|
||||
utils.Log(1, "Creating Database Tables...")
|
||||
err := DbSession.CreateTable(&types.Checkin{})
|
||||
err = DbSession.CreateTable(&types.CheckinHit{})
|
||||
err = DbSession.CreateTable(¬ifier.Notification{})
|
||||
err = DbSession.Table("core").CreateTable(&types.Core{})
|
||||
err = DbSession.CreateTable(&types.Failure{})
|
||||
err = DbSession.CreateTable(&types.Hit{})
|
||||
err = DbSession.CreateTable(&types.Service{})
|
||||
err = DbSession.CreateTable(&types.User{})
|
||||
err = DbSession.CreateTable(&types.Message{})
|
||||
for _, table := range DbModels {
|
||||
if err := DbSession.CreateTable(table); err.Error != nil {
|
||||
return err.Error
|
||||
}
|
||||
}
|
||||
if err := DbSession.Table("core").CreateTable(&types.Core{}); err.Error != nil {
|
||||
return err.Error
|
||||
}
|
||||
utils.Log(1, "Statup Database Created")
|
||||
return err.Error
|
||||
return err
|
||||
}
|
||||
|
||||
// MigrateDatabase will migrate the database structure to current version.
|
||||
|
@ -385,8 +408,10 @@ func (db *DbConfig) MigrateDatabase() error {
|
|||
if tx.Error != nil {
|
||||
return tx.Error
|
||||
}
|
||||
tx = tx.AutoMigrate(&types.Service{}, &types.User{}, &types.Hit{}, &types.Failure{}, &types.Message{}, &types.Checkin{}, &types.CheckinHit{}, ¬ifier.Notification{}).Table("core").AutoMigrate(&types.Core{})
|
||||
if tx.Error != nil {
|
||||
for _, table := range DbModels {
|
||||
tx = tx.AutoMigrate(table)
|
||||
}
|
||||
if err := tx.Table("core").AutoMigrate(&types.Core{}); err.Error != nil {
|
||||
tx.Rollback()
|
||||
utils.Log(3, fmt.Sprintf("Statup Database could not be migrated: %v", tx.Error))
|
||||
return tx.Error
|
||||
|
|
|
@ -27,9 +27,6 @@ type Hit struct {
|
|||
|
||||
// CreateHit will create a new 'hit' record in the database for a successful/online service
|
||||
func (s *Service) CreateHit(h *types.Hit) (int64, error) {
|
||||
if h.CreatedAt.IsZero() {
|
||||
h.CreatedAt = time.Now().UTC()
|
||||
}
|
||||
db := hitsDB().Create(&h)
|
||||
if db.Error != nil {
|
||||
utils.Log(2, db.Error)
|
||||
|
|
|
@ -31,7 +31,8 @@ var (
|
|||
// AllCommunications holds all the loaded notifiers
|
||||
AllCommunications []types.AllNotifiers
|
||||
// db holds the Statup database connection
|
||||
db *gorm.DB
|
||||
db *gorm.DB
|
||||
timezone float32
|
||||
)
|
||||
|
||||
// Notification contains all the fields for a Statup Notifier.
|
||||
|
@ -89,6 +90,13 @@ type NotificationLog struct {
|
|||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// AfterFind for Notification will set the timezone
|
||||
func (n *Notification) AfterFind() (err error) {
|
||||
n.CreatedAt = utils.Timezoner(n.CreatedAt, timezone)
|
||||
n.UpdatedAt = utils.Timezoner(n.UpdatedAt, timezone)
|
||||
return
|
||||
}
|
||||
|
||||
// AddQueue will add any type of interface (json, string, struct, etc) into the Notifiers queue
|
||||
func (n *Notification) AddQueue(uid int64, msg interface{}) {
|
||||
data := &QueueData{uid, msg}
|
||||
|
@ -106,8 +114,9 @@ func modelDb(n *Notification) *gorm.DB {
|
|||
}
|
||||
|
||||
// SetDB is called by core to inject the database for a notifier to use
|
||||
func SetDB(d *gorm.DB) {
|
||||
func SetDB(d *gorm.DB, zone float32) {
|
||||
db = d
|
||||
timezone = zone
|
||||
}
|
||||
|
||||
// asNotification accepts a Notifier and returns a Notification struct
|
||||
|
@ -243,6 +252,8 @@ func Init(n Notifier) (*Notification, error) {
|
|||
var notify *Notification
|
||||
if err == nil {
|
||||
notify, _ = SelectNotification(n)
|
||||
notify.CreatedAt = utils.Timezoner(notify.CreatedAt, timezone)
|
||||
notify.UpdatedAt = utils.Timezoner(notify.UpdatedAt, timezone)
|
||||
if notify.Delay.Seconds() == 0 {
|
||||
notify.Delay = time.Duration(1 * time.Second)
|
||||
}
|
||||
|
|
|
@ -219,12 +219,18 @@ func (s *Service) DowntimeText() string {
|
|||
func Dbtimestamp(group string, column string) string {
|
||||
var seconds int64
|
||||
switch group {
|
||||
case "minute":
|
||||
seconds = 60
|
||||
case "hour":
|
||||
seconds = 3600
|
||||
case "day":
|
||||
seconds = 86400
|
||||
case "week":
|
||||
seconds = 604800
|
||||
case "month":
|
||||
seconds = 2592000
|
||||
case "year":
|
||||
seconds = 31557600
|
||||
default:
|
||||
seconds = 60
|
||||
}
|
||||
|
@ -271,14 +277,15 @@ func GraphDataRaw(service types.ServiceInterface, start, end time.Time, group st
|
|||
var createdTime time.Time
|
||||
var err error
|
||||
rows.Scan(&createdAt, &value)
|
||||
createdTime, _ = time.Parse(types.TIME, createdAt)
|
||||
if CoreApp.DbConnection == "postgres" {
|
||||
createdTime, err = time.Parse(types.TIME_NANO, createdAt)
|
||||
if err != nil {
|
||||
utils.Log(4, fmt.Errorf("issue parsing time from database: %v to %v", createdAt, types.TIME_NANO))
|
||||
}
|
||||
} else {
|
||||
createdTime, err = time.Parse(types.TIME, createdAt)
|
||||
}
|
||||
gd.CreatedAt = utils.Timezoner(createdTime, CoreApp.Timezone).Format(types.TIME)
|
||||
gd.CreatedAt = utils.Timezoner(createdTime, CoreApp.Timezone).Format(types.CHART_TIME)
|
||||
gd.Value = int64(value * 1000)
|
||||
d = append(d, gd)
|
||||
}
|
||||
|
|
|
@ -83,6 +83,9 @@ func apiServiceDataHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
fields := parseGet(r)
|
||||
grouping := fields.Get("group")
|
||||
if grouping == "" {
|
||||
grouping = "hour"
|
||||
}
|
||||
startField := utils.StringInt(fields.Get("start"))
|
||||
endField := utils.StringInt(fields.Get("end"))
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ package handlers
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/hunterlong/statup/core"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/source"
|
||||
|
@ -30,7 +29,6 @@ import (
|
|||
)
|
||||
|
||||
func dashboardHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Println()
|
||||
if !IsAuthenticated(r) {
|
||||
err := core.ErrorResponse{}
|
||||
executeResponse(w, r, "login.html", err, nil)
|
||||
|
|
|
@ -94,10 +94,10 @@ func servicesViewHandler(w http.ResponseWriter, r *http.Request) {
|
|||
start := end.Add((-24 * 7) * time.Hour).UTC()
|
||||
|
||||
if startField != 0 {
|
||||
start = time.Unix(startField, 0)
|
||||
start = time.Unix(startField, 0).UTC()
|
||||
}
|
||||
if endField != 0 {
|
||||
end = time.Unix(endField, 0)
|
||||
end = time.Unix(endField, 0).UTC()
|
||||
}
|
||||
if group == "" {
|
||||
group = "hour"
|
||||
|
@ -106,11 +106,13 @@ func servicesViewHandler(w http.ResponseWriter, r *http.Request) {
|
|||
data := core.GraphDataRaw(serv, start, end, group, "latency")
|
||||
|
||||
out := struct {
|
||||
Service *core.Service
|
||||
Start string
|
||||
End string
|
||||
Data string
|
||||
}{serv, start.Format(utils.FlatpickrReadable), end.Format(utils.FlatpickrReadable), data.ToString()}
|
||||
Service *core.Service
|
||||
Start string
|
||||
End string
|
||||
StartUnix int64
|
||||
EndUnix int64
|
||||
Data string
|
||||
}{serv, start.Format(utils.FlatpickrReadable), end.Format(utils.FlatpickrReadable), start.Unix(), end.Unix(), data.ToString()}
|
||||
|
||||
executeResponse(w, r, "service.html", out, nil)
|
||||
}
|
||||
|
|
|
@ -29,11 +29,11 @@ func setupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
var data interface{}
|
||||
if os.Getenv("DB_CONN") != "" {
|
||||
data, _ = core.LoadUsingEnv()
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
executeResponse(w, r, "setup.html", data, nil)
|
||||
}
|
||||
|
||||
|
|
|
@ -79,5 +79,5 @@ func injectDatabase() {
|
|||
panic(err)
|
||||
}
|
||||
db.CreateTable(¬ifier.Notification{})
|
||||
notifier.SetDB(db)
|
||||
notifier.SetDB(db, float32(-8))
|
||||
}
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
*/
|
||||
|
||||
var currentLocation = window.location;
|
||||
$("#domain_input").val(currentLocation.origin);
|
||||
var domain = $("#domain_input");
|
||||
if (domain.val() === "") {
|
||||
domain.val(currentLocation.origin);
|
||||
}
|
||||
|
||||
$('select#database_type').on('change', function(){
|
||||
var selected = $('#database_type option:selected').val();
|
||||
|
|
|
@ -21,10 +21,8 @@ import (
|
|||
"github.com/GeertJohan/go.rice"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"gopkg.in/russross/blackfriday.v2"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -68,31 +66,9 @@ func CompileSASS(folder string) error {
|
|||
utils.Log(1, fmt.Sprintf("Compiling SASS %v into %v", scssFile, baseFile))
|
||||
command := fmt.Sprintf("%v %v %v", sassBin, scssFile, baseFile)
|
||||
|
||||
utils.Log(1, fmt.Sprintf("Command: sh -c %v", command))
|
||||
stdout, stderr, err := utils.Command(command)
|
||||
|
||||
testCmd := exec.Command("sh", "-c", command)
|
||||
|
||||
var stdout, stderr []byte
|
||||
var errStdout, errStderr error
|
||||
stdoutIn, _ := testCmd.StdoutPipe()
|
||||
stderrIn, _ := testCmd.StderrPipe()
|
||||
testCmd.Start()
|
||||
|
||||
go func() {
|
||||
stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
stderr, errStderr = copyAndCapture(os.Stderr, stderrIn)
|
||||
}()
|
||||
|
||||
err := testCmd.Wait()
|
||||
if err != nil {
|
||||
utils.Log(3, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if errStdout != nil || errStderr != nil {
|
||||
if stdout != "" || stderr != "" {
|
||||
utils.Log(3, fmt.Sprintf("Failed to compile assets with SASS %v", err))
|
||||
return errors.New("failed to capture stdout or stderr")
|
||||
}
|
||||
|
@ -103,8 +79,7 @@ func CompileSASS(folder string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
outStr, errStr := string(stdout), string(stderr)
|
||||
utils.Log(1, fmt.Sprintf("out: %v | error: %v", outStr, errStr))
|
||||
utils.Log(1, fmt.Sprintf("out: %v | error: %v", stdout, stderr))
|
||||
utils.Log(1, "SASS Compiling is complete!")
|
||||
return nil
|
||||
}
|
||||
|
@ -239,27 +214,3 @@ func MakePublicFolder(folder string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyAndCapture captures the response from a terminal command
|
||||
func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) {
|
||||
var out []byte
|
||||
buf := make([]byte, 1024, 1024)
|
||||
for {
|
||||
n, err := r.Read(buf[:])
|
||||
if n > 0 {
|
||||
d := buf[:n]
|
||||
out = append(out, d...)
|
||||
_, err := w.Write(d)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// Read returns io.EOF at the end of file, which is not an error for us
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
|
||||
AjaxChart(chartdata,{{$s.Id}},{{.Start}},{{.End}},"hour");
|
||||
AjaxChart(chartdata,{{$s.Id}},{{.StartUnix}},{{.EndUnix}},"hour");
|
||||
|
||||
let startDate = $("#service_start").flatpickr({
|
||||
enableTime: false,
|
||||
|
|
|
@ -20,9 +20,11 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
TIME_NANO = "2006-01-02T15:04:05Z"
|
||||
TIME = "2006-01-02 15:04:05"
|
||||
TIME_DAY = "2006-01-02"
|
||||
TIME_NANO = "2006-01-02T15:04:05Z"
|
||||
TIME = "2006-01-02 15:04:05"
|
||||
POSTGRES_TIME = "2006-01-02 15:04"
|
||||
CHART_TIME = "2006-01-02T15:04:05.999999-07:00"
|
||||
TIME_DAY = "2006-01-02"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -46,4 +46,5 @@ type DbConfig struct {
|
|||
Email string `yaml:"-"`
|
||||
Error error `yaml:"-"`
|
||||
Location string `yaml:"location"`
|
||||
LocalIP string `yaml:"-"`
|
||||
}
|
||||
|
|
|
@ -26,6 +26,14 @@ const (
|
|||
FlatpickrReadable = "Mon, 02 Jan 2006"
|
||||
)
|
||||
|
||||
// Timezoner returns the time.Time with the user set timezone
|
||||
func Timezoner(t time.Time, zone float32) time.Time {
|
||||
zoneInt := float32(3600) * zone
|
||||
loc := time.FixedZone("", int(zoneInt))
|
||||
timez := t.In(loc)
|
||||
return timez
|
||||
}
|
||||
|
||||
// FormatDuration converts a time.Duration into a string
|
||||
func FormatDuration(d time.Duration) string {
|
||||
var out string
|
||||
|
|
|
@ -68,14 +68,6 @@ func ToString(s interface{}) string {
|
|||
}
|
||||
}
|
||||
|
||||
// Timezoner returns the time.Time with the user set timezone
|
||||
func Timezoner(t time.Time, zone float32) time.Time {
|
||||
zoneInt := float32(3600) * (zone + 1)
|
||||
loc := time.FixedZone("", int(zoneInt))
|
||||
timez := t.In(loc)
|
||||
return timez
|
||||
}
|
||||
|
||||
// dir returns the current working directory
|
||||
func dir() string {
|
||||
dir, err := os.Getwd()
|
||||
|
|
|
@ -125,7 +125,7 @@ func TestTimezone(t *testing.T) {
|
|||
timestamp := time.Date(2018, 1, 1, 10, 0, 0, 0, loc)
|
||||
timezone := Timezoner(timestamp, zone)
|
||||
assert.Equal(t, "2018-01-01 10:00:00 -0800 PST", timestamp.String())
|
||||
assert.Equal(t, "2018-01-01 15:00:00 -0300 -0300", timezone.String())
|
||||
assert.Equal(t, "2018-01-01 18:00:00 +0000 UTC", timezone.UTC().String())
|
||||
}
|
||||
|
||||
func TestTimestamp_Ago(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue