2018-08-16 06:22:20 +00:00
// Statup
// Copyright (C) 2018. Hunter Long and the project contributors
// Written by Hunter Long <info@socialeck.com> and the project contributors
//
// https://github.com/hunterlong/statup
//
// The licenses for most software and other practical works are designed
// to take away your freedom to share and change the works. By contrast,
// the GNU General Public License is intended to guarantee your freedom to
// share and change all versions of a program--to make sure it remains free
// software for all its users.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2018-06-30 00:57:05 +00:00
package core
2018-06-10 01:31:13 +00:00
import (
"encoding/json"
"fmt"
2018-06-30 00:57:05 +00:00
"github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils"
2018-06-11 00:20:42 +00:00
"strconv"
2018-06-10 01:31:13 +00:00
"time"
2018-06-22 04:02:57 +00:00
"upper.io/db.v3"
2018-06-10 01:31:13 +00:00
)
type Service struct {
2018-08-19 00:37:00 +00:00
* types . Service
2018-07-14 02:37:39 +00:00
}
2018-08-20 07:20:05 +00:00
func ReturnService ( s * types . Service ) * Service {
return & Service { Service : s }
2018-06-10 01:31:13 +00:00
}
2018-06-22 04:02:57 +00:00
func serviceCol ( ) db . Collection {
2018-06-30 00:57:05 +00:00
return DbSession . Collection ( "services" )
2018-06-22 04:02:57 +00:00
}
2018-06-23 00:10:37 +00:00
func SelectService ( id int64 ) * Service {
2018-08-21 06:54:39 +00:00
for _ , s := range CoreApp . Services ( ) {
2018-08-19 00:37:00 +00:00
if s . Id == id {
2018-08-21 06:54:39 +00:00
return s
2018-06-23 00:10:37 +00:00
}
}
return nil
2018-06-10 01:31:13 +00:00
}
2018-08-20 07:20:05 +00:00
func ( c * Core ) SelectAllServices ( ) ( [ ] * types . Service , error ) {
2018-07-14 02:37:39 +00:00
var services [ ] * types . Service
2018-08-20 07:20:05 +00:00
var servs [ ] * types . Service
2018-08-21 08:15:17 +00:00
col := serviceCol ( ) . Find ( ) . OrderBy ( "order_id" )
2018-07-14 02:37:39 +00:00
err := col . All ( & services )
2018-06-30 00:57:05 +00:00
if err != nil {
2018-08-13 16:35:38 +00:00
utils . Log ( 3 , fmt . Sprintf ( "service error: %v" , err ) )
2018-07-12 04:49:18 +00:00
return nil , err
2018-06-30 00:57:05 +00:00
}
2018-08-20 07:20:05 +00:00
for _ , ser := range services {
single := ReturnService ( ser )
single . Start ( )
single . AllCheckins ( )
single . AllFailures ( )
servs = append ( servs , single . Service )
2018-06-22 06:56:44 +00:00
}
2018-08-21 06:54:39 +00:00
CoreApp . SetServices ( servs )
2018-08-20 07:20:05 +00:00
return services , err
}
func ( s * Service ) ToJSON ( ) string {
data , _ := json . Marshal ( s )
return string ( data )
2018-06-10 01:31:13 +00:00
}
func ( s * Service ) AvgTime ( ) float64 {
2018-06-15 04:30:10 +00:00
total , _ := s . TotalHits ( )
if total == 0 {
return float64 ( 0 )
}
sum , _ := s . Sum ( )
2018-06-10 01:31:13 +00:00
avg := sum / float64 ( total ) * 100
2018-06-15 04:30:10 +00:00
amount := fmt . Sprintf ( "%0.0f" , avg * 10 )
val , _ := strconv . ParseFloat ( amount , 10 )
return val
2018-06-10 01:31:13 +00:00
}
2018-08-19 00:37:00 +00:00
func ( s * Service ) Online24 ( ) float32 {
total , _ := s . TotalHits ( )
failed , _ := s . TotalFailures24Hours ( )
2018-06-10 03:44:47 +00:00
if failed == 0 {
s . Online24Hours = 100.00
return s . Online24Hours
}
2018-06-10 04:21:12 +00:00
if total == 0 {
s . Online24Hours = 0
return s . Online24Hours
}
2018-06-10 03:44:47 +00:00
avg := float64 ( failed ) / float64 ( total ) * 100
2018-06-11 00:20:42 +00:00
avg = 100 - avg
if avg < 0 {
avg = 0
}
amount , _ := strconv . ParseFloat ( fmt . Sprintf ( "%0.2f" , avg ) , 10 )
s . Online24Hours = float32 ( amount )
return s . Online24Hours
2018-06-10 03:44:47 +00:00
}
2018-06-24 11:51:07 +00:00
type DateScan struct {
CreatedAt time . Time ` json:"x" `
2018-06-24 20:56:58 +00:00
Value int64 ` json:"y" `
2018-06-24 11:51:07 +00:00
}
2018-08-20 07:20:05 +00:00
func ( s * Service ) lastFailure ( ) * Failure {
limited := s . LimitedFailures ( )
last := limited [ len ( limited ) - 1 ]
return last
2018-07-14 02:37:39 +00:00
}
2018-08-19 00:37:00 +00:00
func ( s * Service ) SmallText ( ) string {
last := s . LimitedFailures ( )
hits , _ := s . LimitedHits ( )
2018-08-19 08:48:02 +00:00
if s . Online {
2018-06-30 03:40:00 +00:00
if len ( last ) == 0 {
return fmt . Sprintf ( "Online since %v" , s . CreatedAt . Format ( "Monday 3:04PM, Jan _2 2006" ) )
} else {
return fmt . Sprintf ( "Online, last failure was %v" , hits [ 0 ] . CreatedAt . Format ( "Monday 3:04PM, Jan _2 2006" ) )
}
}
2018-08-19 08:48:02 +00:00
if len ( last ) > 0 {
2018-08-20 07:20:05 +00:00
lastFailure := s . lastFailure ( )
return fmt . Sprintf ( "%v on %v" , lastFailure . ParseError ( ) , last [ 0 ] . CreatedAt . Format ( "Monday 3:04PM, Jan _2 2006" ) )
2018-08-19 08:48:02 +00:00
} else {
return fmt . Sprintf ( "%v is currently offline" , s . Name )
}
2018-06-30 03:40:00 +00:00
}
2018-07-04 09:00:16 +00:00
func GroupDataBy ( column string , id int64 , tm time . Time , increment string ) string {
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(NOW(), '%%Y-%%m-%%dT%%TZ') GROUP BY 1 ORDER BY created_at ASC;" , column , id , tm . Format ( time . RFC3339 ) )
case "sqlite" :
sql = fmt . Sprintf ( "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:00Z', created_at), AVG(latency)*1000 as value FROM %v WHERE service=%v AND created_at >= '%v' GROUP BY strftime('%%M:00', created_at) ORDER BY created_at ASC;" , column , id , tm . 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' GROUP BY 1 ORDER BY date_trunc ASC;" , increment , column , id , tm . Format ( time . RFC3339 ) )
}
return sql
}
2018-08-19 00:37:00 +00:00
func ( s * Service ) GraphData ( ) string {
2018-07-03 21:39:56 +00:00
var d [ ] * DateScan
since := time . Now ( ) . Add ( time . Hour * - 24 + time . Minute * 0 + time . Second * 0 )
2018-07-04 09:00:16 +00:00
sql := GroupDataBy ( "hits" , s . Id , since , "minute" )
2018-06-30 00:57:05 +00:00
dated , err := DbSession . Query ( db . Raw ( sql ) )
2018-06-24 11:51:07 +00:00
if err != nil {
2018-06-30 00:57:05 +00:00
utils . Log ( 2 , err )
2018-06-25 06:21:18 +00:00
return ""
2018-06-10 01:31:13 +00:00
}
2018-06-24 11:51:07 +00:00
for dated . Next ( ) {
2018-07-03 21:39:56 +00:00
gd := new ( DateScan )
var tt string
2018-06-24 11:51:07 +00:00
var ff float64
2018-07-03 21:39:56 +00:00
err := dated . Scan ( & tt , & ff )
if err != nil {
utils . Log ( 2 , fmt . Sprintf ( "Issue loading chart data for service %v, %v" , s . Name , err ) )
}
gd . CreatedAt , err = time . Parse ( time . RFC3339 , tt )
if err != nil {
utils . Log ( 2 , fmt . Sprintf ( "Issue parsing time %v" , err ) )
}
2018-06-24 11:51:07 +00:00
gd . Value = int64 ( ff )
d = append ( d , gd )
}
2018-06-25 06:21:18 +00:00
data , err := json . Marshal ( d )
2018-06-24 11:51:07 +00:00
if err != nil {
2018-06-30 00:57:05 +00:00
utils . Log ( 2 , err )
2018-06-25 06:21:18 +00:00
return ""
2018-06-24 11:51:07 +00:00
}
2018-06-19 04:48:25 +00:00
return string ( data )
2018-06-10 01:31:13 +00:00
}
2018-08-19 00:37:00 +00:00
func ( s * Service ) AvgUptime ( ) string {
failed , _ := s . TotalFailures ( )
total , _ := s . TotalHits ( )
2018-06-10 01:31:13 +00:00
if failed == 0 {
2018-06-22 04:02:57 +00:00
s . TotalUptime = "100"
2018-06-10 01:31:13 +00:00
return s . TotalUptime
}
2018-06-10 04:21:12 +00:00
if total == 0 {
2018-06-11 00:20:42 +00:00
s . TotalUptime = "0"
2018-06-10 04:21:12 +00:00
return s . TotalUptime
}
2018-06-10 01:31:13 +00:00
percent := float64 ( failed ) / float64 ( total ) * 100
2018-06-11 00:20:42 +00:00
percent = 100 - percent
if percent < 0 {
percent = 0
}
s . TotalUptime = fmt . Sprintf ( "%0.2f" , percent )
2018-06-22 04:02:57 +00:00
if s . TotalUptime == "100.00" {
s . TotalUptime = "100"
}
2018-06-11 00:20:42 +00:00
return s . TotalUptime
2018-06-10 01:31:13 +00:00
}
2018-08-21 03:11:40 +00:00
func ( s * Service ) index ( ) int {
2018-08-21 06:54:39 +00:00
for k , service := range CoreApp . Services ( ) {
2018-08-21 03:11:40 +00:00
if s . Id == service . Id {
return k
2018-08-20 07:20:05 +00:00
}
}
2018-08-21 03:11:40 +00:00
return 0
}
func updateService ( service * Service ) {
service . Start ( )
go service . CheckQueue ( true )
index := service . index ( )
2018-08-21 06:54:39 +00:00
CoreApp . UpdateService ( index , service . Service )
2018-08-20 07:20:05 +00:00
}
func ( u * Service ) Delete ( ) error {
2018-06-22 04:02:57 +00:00
res := serviceCol ( ) . Find ( "id" , u . Id )
2018-06-15 04:30:10 +00:00
err := res . Delete ( )
2018-06-30 00:57:05 +00:00
if err != nil {
utils . Log ( 3 , fmt . Sprintf ( "Failed to delete service %v. %v" , u . Name , err ) )
return err
}
2018-08-19 00:37:00 +00:00
u . Close ( )
2018-08-21 06:54:39 +00:00
CoreApp . RemoveService ( u . index ( ) )
2018-06-19 04:48:25 +00:00
OnDeletedService ( u )
2018-06-15 04:30:10 +00:00
return err
2018-06-11 03:41:02 +00:00
}
2018-08-20 07:20:05 +00:00
func ( u * Service ) Update ( ) error {
u . CreatedAt = time . Now ( )
res := serviceCol ( ) . Find ( "id" , u . Id )
err := res . Update ( u )
2018-07-01 03:54:28 +00:00
if err != nil {
2018-08-20 07:20:05 +00:00
utils . Log ( 3 , fmt . Sprintf ( "Failed to update service %v. %v" , u . Name , err ) )
return err
2018-07-01 03:54:28 +00:00
}
2018-08-21 06:54:39 +00:00
u . Close ( )
2018-08-20 07:20:05 +00:00
updateService ( u )
OnUpdateService ( u )
return err
2018-07-27 02:10:05 +00:00
}
2018-08-20 07:20:05 +00:00
func ( u * Service ) Create ( ) ( int64 , error ) {
2018-06-15 04:30:10 +00:00
u . CreatedAt = time . Now ( )
2018-06-22 04:02:57 +00:00
uuid , err := serviceCol ( ) . Insert ( u )
2018-06-15 04:30:10 +00:00
if uuid == nil {
2018-06-30 00:57:05 +00:00
utils . Log ( 3 , fmt . Sprintf ( "Failed to create service %v. %v" , u . Name , err ) )
2018-06-15 04:30:10 +00:00
return 0 , err
2018-06-10 03:44:47 +00:00
}
2018-06-22 08:48:47 +00:00
u . Id = uuid . ( int64 )
2018-08-19 00:37:00 +00:00
u . Start ( )
2018-08-21 06:54:39 +00:00
CoreApp . AddService ( u . Service )
2018-06-15 04:30:10 +00:00
return uuid . ( int64 ) , err
2018-06-10 01:31:13 +00:00
}
2018-06-11 00:20:42 +00:00
func CountOnline ( ) int {
amount := 0
2018-08-21 06:54:39 +00:00
for _ , s := range CoreApp . Services ( ) {
2018-08-19 00:37:00 +00:00
if s . Online {
2018-06-11 00:20:42 +00:00
amount ++
}
}
return amount
2018-06-25 07:09:31 +00:00
}