mirror of https://github.com/statping/statping
				
				
				
			changes n upgrades
							parent
							
								
									cb70a0134d
								
							
						
					
					
						commit
						09bc158e5e
					
				
							
								
								
									
										29
									
								
								failures.go
								
								
								
								
							
							
						
						
									
										29
									
								
								failures.go
								
								
								
								
							|  | @ -1,31 +1,44 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import "time" | import ( | ||||||
|  | 	"github.com/ararog/timeago" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| type Failure struct { | type Failure struct { | ||||||
| 	Id        int | 	Id        int | ||||||
| 	Issue     string | 	Issue     string | ||||||
| 	Service   int | 	Service   int | ||||||
| 	CreatedAt time.Time | 	CreatedAt time.Time | ||||||
|  | 	Ago       string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func SelectAllFailures(id int64) []float64 { | func (s *Service) SelectAllFailures() []*Failure { | ||||||
| 	var tks []float64 | 	var tks []*Failure | ||||||
| 	rows, err := db.Query("SELECT * FROM failures WHERE service=$1 ORDER BY id ASC", id) | 	rows, err := db.Query("SELECT * FROM failures WHERE service=$1 ORDER BY id DESC LIMIT 10", s.Id) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		panic(err) | 		panic(err) | ||||||
| 	} | 	} | ||||||
| 	for rows.Next() { | 	for rows.Next() { | ||||||
| 		var tk Hit | 		var tk Failure | ||||||
| 		err = rows.Scan(&tk.Id, &tk.Metric, &tk.Value, &tk.CreatedAt) | 		err = rows.Scan(&tk.Id, &tk.Issue, &tk.Service, &tk.CreatedAt) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			panic(err) | 			panic(err) | ||||||
| 		} | 		} | ||||||
| 		tks = append(tks, tk.Value) | 
 | ||||||
|  | 		tk.Ago, _ = timeago.TimeAgoWithTime(time.Now(), tk.CreatedAt) | ||||||
|  | 
 | ||||||
|  | 		tks = append(tks, &tk) | ||||||
| 	} | 	} | ||||||
| 	return tks | 	return tks | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func CountFailures() int { | ||||||
|  | 	var amount int | ||||||
|  | 	db.QueryRow("SELECT COUNT(id) FROM failures;").Scan(&amount) | ||||||
|  | 	return amount | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (s *Service) TotalFailures() int { | func (s *Service) TotalFailures() int { | ||||||
| 	var amount int | 	var amount int | ||||||
| 	db.QueryRow("SELECT COUNT(id) FROM failures WHERE service=$1;", s.Id).Scan(&amount) | 	db.QueryRow("SELECT COUNT(id) FROM failures WHERE service=$1;", s.Id).Scan(&amount) | ||||||
|  | @ -36,6 +49,6 @@ func (s *Service) TotalFailures24Hours() int { | ||||||
| 	var amount int | 	var amount int | ||||||
| 	t := time.Now() | 	t := time.Now() | ||||||
| 	x := t.AddDate(0, 0, -1) | 	x := t.AddDate(0, 0, -1) | ||||||
| 	db.QueryRow("SELECT COUNT(id) FROM failures WHERE service=$1 AND created_at>=$2 AND created_at<$3;", s.Id, t, x).Scan(&amount) | 	db.QueryRow("SELECT COUNT(id) FROM failures WHERE service=$1 AND created_at>=$2 AND created_at<$3;", s.Id, x, t).Scan(&amount) | ||||||
| 	return amount | 	return amount | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -21,14 +21,36 @@ HTML,BODY { | ||||||
|     font-size: 26pt; |     font-size: 26pt; | ||||||
|     font-weight: bold; |     font-weight: bold; | ||||||
|     display: block; |     display: block; | ||||||
|  |     color: #3e3e3e; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .text_perfect { | ||||||
|  |     color: #33b418; | ||||||
|  |     text-shadow: 0px 1px 0 #0e6702; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .text_good { | ||||||
|  |     color: #33b418; | ||||||
|  |     text-shadow: 0px 1px 0 #0e6702; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .text_ok { | ||||||
|  |     color: #33b418; | ||||||
|  |     text-shadow: 0px 1px 0 #0e6702; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .text_bad { | ||||||
|  |     color: #33b418; | ||||||
|  |     text-shadow: 0px 1px 0 #0e6702; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .stats_area { | .stats_area { | ||||||
|     text-align: center; |     text-align: center; | ||||||
|  |     color: #a5a5a5; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .offline_bg { | .offline_bg { | ||||||
|     background-color: #c5c5c578 !important; |     background-color: white !important; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .footer { | .footer { | ||||||
|  | @ -41,6 +63,28 @@ HTML,BODY { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | .online_badge { | ||||||
|  |     color: #fff; | ||||||
|  |     background-color: #35b317; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .offline_badge { | ||||||
|  |     color: #fff; | ||||||
|  |     background-color: #c51919; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .progress { | ||||||
|  |     margin-top: -20px; | ||||||
|  |     margin-left: -20px; | ||||||
|  |     margin-bottom: 15px; | ||||||
|  |     width: calc(100% + 40px); | ||||||
|  |     height: 3px; | ||||||
|  |     border-radius: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .card-body { | ||||||
|  |     overflow: hidden; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @media (max-width: 767px) { | @media (max-width: 767px) { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -43,18 +43,18 @@ | ||||||
|     <div class="row stats_area"> |     <div class="row stats_area"> | ||||||
| 
 | 
 | ||||||
|         <div class="col-4"> |         <div class="col-4"> | ||||||
|             <span class="lg_number">69</span> |             <span class="lg_number">{{ .CountServices }}</span> | ||||||
|             24 Hour Hits |             Total Services | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="col-4"> |         <div class="col-4"> | ||||||
|             <span class="lg_number">3921</span> |             <span class="lg_number">{{ .Count24Failures }}</span> | ||||||
|             24 Hour Hits |             Failures last 24 Hours | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="col-4"> |         <div class="col-4"> | ||||||
|             <span class="lg_number">453</span> |             <span class="lg_number">{{ .CountOnline }}</span> | ||||||
|             Total Tokens |             Online Services | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,22 +8,33 @@ | ||||||
|     <link rel="stylesheet" href="/css/base.css"> |     <link rel="stylesheet" href="/css/base.css"> | ||||||
|     <script src="/js/Chart.bundle.min.js"></script> |     <script src="/js/Chart.bundle.min.js"></script> | ||||||
| 
 | 
 | ||||||
|     <title>Statup | Dashboard</title> |     <title>{{.Project}} Status</title> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
| 
 | 
 | ||||||
| <h1 class="text-center">{{.Project}}</h1> | <h1 class="text-center mb-4">{{.Project}}</h1> | ||||||
| 
 | 
 | ||||||
| <div class="container"> | <div class="container"> | ||||||
| 
 | 
 | ||||||
|     <div class="row"> |     <div class="row"> | ||||||
|  | 
 | ||||||
|         {{ range .Services }} |         {{ range .Services }} | ||||||
|             <div class="col-12 mb-4"> |             <div class="col-12 mb-4"> | ||||||
|                 <div class="card"> |                 <div class="card"> | ||||||
|                     <div class="card-body{{if .Online}}{{else}} offline_bg{{end}}"> |                     <div class="card-body{{if .Online}}{{else}} offline_bg{{end}}"> | ||||||
|                         <h3>{{ .Name }} <span class="badge badge-secondary float-right">{{if .Online}} ONLINE {{ else }} OFFLINE {{end}}</span></h3> |  | ||||||
| 
 | 
 | ||||||
|                         <div class="row stats_area mt-3 mb-3"> |                         <div class="progress"> | ||||||
|  |                             <div class="progress-bar {{if .Online24Hours}} bg-success {{else}} bg-danger {{end}}" role="progressbar" style="width: {{.Online24Hours}}%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div> | ||||||
|  |                         </div> | ||||||
|  | 
 | ||||||
|  |                         <h3 class="mt-4">{{ .Name }} | ||||||
|  |                     {{if .Online}} | ||||||
|  |                         <span class="badge online_badge float-right">ONLINE</span> | ||||||
|  |                     {{ else }} | ||||||
|  |                         <span class="badge offline_badge float-right">OFFLINE</span> | ||||||
|  |                     {{end}}</h3> | ||||||
|  | 
 | ||||||
|  |                 <div class="row stats_area mt-5 mb-5"> | ||||||
| 
 | 
 | ||||||
|                             <div class="col-4"> |                             <div class="col-4"> | ||||||
|                                 <span class="lg_number">{{.Online24Hours}}%</span> |                                 <span class="lg_number">{{.Online24Hours}}%</span> | ||||||
|  | @ -39,10 +50,17 @@ | ||||||
|                                 <span class="lg_number">{{.TotalUptime}}%</span> |                                 <span class="lg_number">{{.TotalUptime}}%</span> | ||||||
|                                 Total Uptime |                                 Total Uptime | ||||||
|                             </div> |                             </div> | ||||||
| 
 |  | ||||||
|                         </div> |                         </div> | ||||||
| 
 | 
 | ||||||
|                         <canvas id="service_{{ .Id }}" width="400" height="120"></canvas> |                         <canvas id="service_{{ .Id }}" width="400" height="120"></canvas> | ||||||
|  | 
 | ||||||
|  |                          {{ range .Failures }} | ||||||
|  |                             <blockquote class="blockquote text-right mt-3"> | ||||||
|  |                                 <p class="mb-0">{{.Issue}}</p> | ||||||
|  |                                 <footer class="blockquote-footer">Reported <cite title="Source Title">{{.Ago}}</cite></footer> | ||||||
|  |                             </blockquote> | ||||||
|  |                         {{ end }} | ||||||
|  | 
 | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|  | @ -53,7 +71,7 @@ | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <div class="footer text-center"> | <div class="footer text-center"> | ||||||
|     <a href="https://statup.io" target="_blank">Statup.io Opensource Status Page</a> |     <a href="https://statup.io" target="_blank">Created with Statup.io</a> | <a href="/dashboard">Dashboard</a> | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|  |  | ||||||
|  | @ -52,7 +52,8 @@ | ||||||
|                 <tr> |                 <tr> | ||||||
|                     <th scope="col">#</th> |                     <th scope="col">#</th> | ||||||
|                     <th scope="col">Name</th> |                     <th scope="col">Name</th> | ||||||
|                     <th scope="col">Actions</th> |                     <th scope="col">Status</th> | ||||||
|  |                     <th scope="col"></th> | ||||||
|                 </tr> |                 </tr> | ||||||
|                 </thead> |                 </thead> | ||||||
|                 <tbody> |                 <tbody> | ||||||
|  | @ -60,11 +61,12 @@ | ||||||
|                 <tr> |                 <tr> | ||||||
|                     <th scope="row">{{.Id}}</th> |                     <th scope="row">{{.Id}}</th> | ||||||
|                     <td>{{.Name}}</td> |                     <td>{{.Name}}</td> | ||||||
|                     <td> |                     <td>{{.Online}} <span class="badge badge-danger">OFFLINE</span> </td> | ||||||
|  |                     <td class="text-right"> | ||||||
|                         <div class="btn-group" data-toggle="buttons"> |                         <div class="btn-group" data-toggle="buttons"> | ||||||
|                                 <button class="btn btn-primary" type="submit">View</button> |                                 <a href="/services/{{.Id}}" class="btn btn-primary">View</a> | ||||||
|                                 <button class="btn btn-primary" type="submit">Edit</button> |                                 <a href="/services/{{.Id}}/edit" class="btn btn-primary">Edit</a> | ||||||
|                                 <button class="btn btn-primary" type="submit">Delete</button> |                                 <a href="/services/{{.Id}}/delete" class="btn btn-danger">Delete</a> | ||||||
|                         </div> |                         </div> | ||||||
|                     </td> |                     </td> | ||||||
|                 </tr> |                 </tr> | ||||||
|  | @ -81,8 +83,8 @@ | ||||||
| 
 | 
 | ||||||
|             <form action="/services/create" method="POST"> |             <form action="/services/create" method="POST"> | ||||||
|                 <div class="form-group row"> |                 <div class="form-group row"> | ||||||
|                     <label for="inputEmail3" class="col-sm-2 col-form-label">Name</label> |                     <label for="inputEmail3" class="col-sm-4 col-form-label">Service Name</label> | ||||||
|                     <div class="col-sm-10"> |                     <div class="col-sm-8"> | ||||||
|                         <input type="text" name="name" class="form-control" id="inputEmail3" placeholder="Name"> |                         <input type="text" name="name" class="form-control" id="inputEmail3" placeholder="Name"> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|  | @ -118,7 +120,8 @@ | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="form-group row"> |                 <div class="form-group row"> | ||||||
|                     <div class="col-sm-10"> |                     <div class="col-sm-10"> | ||||||
|                         <button type="submit" class="btn btn-primary">Create</button> |                         <a class="btn btn-primary">Test</a> | ||||||
|  |                         <button type="submit" class="btn btn-success">Create Service</button> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|             </form> |             </form> | ||||||
|  |  | ||||||
|  | @ -1,8 +1,8 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"testing" |  | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	"testing" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestMakeConfig(t *testing.T) { | func TestMakeConfig(t *testing.T) { | ||||||
|  |  | ||||||
							
								
								
									
										42
									
								
								services.go
								
								
								
								
							
							
						
						
									
										42
									
								
								services.go
								
								
								
								
							|  | @ -5,6 +5,7 @@ import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"math/rand" | 	"math/rand" | ||||||
|  | 	"strconv" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -25,9 +26,10 @@ type Service struct { | ||||||
| 	Data           string | 	Data           string | ||||||
| 	Online         bool | 	Online         bool | ||||||
| 	Latency        float64 | 	Latency        float64 | ||||||
| 	Online24Hours  float64 | 	Online24Hours  float32 | ||||||
| 	AvgResponse    string | 	AvgResponse    string | ||||||
| 	TotalUptime    float64 | 	TotalUptime    string | ||||||
|  | 	Failures       []*Failure | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func SelectService(id string) Service { | func SelectService(id string) Service { | ||||||
|  | @ -57,6 +59,7 @@ func SelectAllServices() []*Service { | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			panic(err) | 			panic(err) | ||||||
| 		} | 		} | ||||||
|  | 		tk.Failures = tk.SelectAllFailures() | ||||||
| 		tk.FormatData() | 		tk.FormatData() | ||||||
| 		tks = append(tks, &tk) | 		tks = append(tks, &tk) | ||||||
| 	} | 	} | ||||||
|  | @ -79,7 +82,7 @@ func (s *Service) AvgTime() float64 { | ||||||
| 	return avg | 	return avg | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *Service) Online24() float64 { | func (s *Service) Online24() float32 { | ||||||
| 	total := s.TotalHits() | 	total := s.TotalHits() | ||||||
| 	failed := s.TotalFailures24Hours() | 	failed := s.TotalFailures24Hours() | ||||||
| 	if failed == 0 { | 	if failed == 0 { | ||||||
|  | @ -91,8 +94,13 @@ func (s *Service) Online24() float64 { | ||||||
| 		return s.Online24Hours | 		return s.Online24Hours | ||||||
| 	} | 	} | ||||||
| 	avg := float64(failed) / float64(total) * 100 | 	avg := float64(failed) / float64(total) * 100 | ||||||
| 	s.Online24Hours = avg | 	avg = 100 - avg | ||||||
| 	return avg | 	if avg < 0 { | ||||||
|  | 		avg = 0 | ||||||
|  | 	} | ||||||
|  | 	amount, _ := strconv.ParseFloat(fmt.Sprintf("%0.2f", avg), 10) | ||||||
|  | 	s.Online24Hours = float32(amount) | ||||||
|  | 	return s.Online24Hours | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type GraphJson struct { | type GraphJson struct { | ||||||
|  | @ -116,20 +124,24 @@ func (s *Service) GraphData() string { | ||||||
| 	return s.Data | 	return s.Data | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *Service) AvgUptime() float64 { | func (s *Service) AvgUptime() string { | ||||||
| 	failed := s.TotalFailures() | 	failed := s.TotalFailures() | ||||||
| 	total := s.TotalHits() | 	total := s.TotalHits() | ||||||
| 	if failed == 0 { | 	if failed == 0 { | ||||||
| 		s.TotalUptime = 100.00 | 		s.TotalUptime = "100.00" | ||||||
| 		return s.TotalUptime | 		return s.TotalUptime | ||||||
| 	} | 	} | ||||||
| 	if total == 0 { | 	if total == 0 { | ||||||
| 		s.TotalUptime = 0 | 		s.TotalUptime = "0" | ||||||
| 		return s.TotalUptime | 		return s.TotalUptime | ||||||
| 	} | 	} | ||||||
| 	percent := float64(failed) / float64(total) * 100 | 	percent := float64(failed) / float64(total) * 100 | ||||||
| 	s.TotalUptime = percent | 	percent = 100 - percent | ||||||
| 	return percent | 	if percent < 0 { | ||||||
|  | 		percent = 0 | ||||||
|  | 	} | ||||||
|  | 	s.TotalUptime = fmt.Sprintf("%0.2f", percent) | ||||||
|  | 	return s.TotalUptime | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (u *Service) Create() int { | func (u *Service) Create() int { | ||||||
|  | @ -143,6 +155,16 @@ func (u *Service) Create() int { | ||||||
| 	return lastInsertId | 	return lastInsertId | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func CountOnline() int { | ||||||
|  | 	amount := 0 | ||||||
|  | 	for _, v := range services { | ||||||
|  | 		if v.Online { | ||||||
|  | 			amount++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return amount | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func NewSHA1Hash(n ...int) string { | func NewSHA1Hash(n ...int) string { | ||||||
| 	noRandomCharacters := 32 | 	noRandomCharacters := 32 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								web.go
								
								
								
								
							
							
						
						
									
										16
									
								
								web.go
								
								
								
								
							|  | @ -7,12 +7,6 @@ import ( | ||||||
| 	"strconv" | 	"strconv" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type dashboard struct { |  | ||||||
| 	Services []*Service |  | ||||||
| 	Users    []User |  | ||||||
| 	Core     *Core |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func RunHTTPServer() { | func RunHTTPServer() { | ||||||
| 	fmt.Println("Fusioner HTTP Server running on http://localhost:8080") | 	fmt.Println("Fusioner HTTP Server running on http://localhost:8080") | ||||||
| 	css := http.StripPrefix("/css/", http.FileServer(cssBox.HTTPBox())) | 	css := http.StripPrefix("/css/", http.FileServer(cssBox.HTTPBox())) | ||||||
|  | @ -149,6 +143,14 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 	indexTmpl.Execute(w, out) | 	indexTmpl.Execute(w, out) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | type dashboard struct { | ||||||
|  | 	Services        []*Service | ||||||
|  | 	Core            *Core | ||||||
|  | 	CountOnline     int | ||||||
|  | 	CountServices   int | ||||||
|  | 	Count24Failures int | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func DashboardHandler(w http.ResponseWriter, r *http.Request) { | func DashboardHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 	session, _ := store.Get(r, "apizer_auth") | 	session, _ := store.Get(r, "apizer_auth") | ||||||
| 	if auth, ok := session.Values["authenticated"].(bool); !ok || !auth { | 	if auth, ok := session.Values["authenticated"].(bool); !ok || !auth { | ||||||
|  | @ -170,7 +172,7 @@ func DashboardHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			panic(err) | 			panic(err) | ||||||
| 		} | 		} | ||||||
| 		out := dashboard{services, SelectAllUsers(), core} | 		out := dashboard{services, core, CountOnline(), len(services), CountFailures()} | ||||||
| 		dashboardTmpl.Execute(w, out) | 		dashboardTmpl.Execute(w, out) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Hunter Long
						Hunter Long