Crashes are now saved in the database
This commit is contained in:
parent
604dc3c755
commit
2e9ad4bf6f
@ -14,7 +14,7 @@ type ClientErrorReport struct {
|
||||
hasCreator
|
||||
}
|
||||
|
||||
// StreamClientErrorReports returns a stream of all characters.
|
||||
// StreamClientErrorReports returns a stream of all client error reports.
|
||||
func StreamClientErrorReports() <-chan *ClientErrorReport {
|
||||
channel := make(chan *ClientErrorReport, nano.ChannelBufferSize)
|
||||
|
||||
@ -29,10 +29,9 @@ func StreamClientErrorReports() <-chan *ClientErrorReport {
|
||||
return channel
|
||||
}
|
||||
|
||||
// AllClientErrorReports returns a slice of all characters.
|
||||
// AllClientErrorReports returns a slice of all client error reports.
|
||||
func AllClientErrorReports() []*ClientErrorReport {
|
||||
all := make([]*ClientErrorReport, 0, DB.Collection("ClientErrorReport").Count())
|
||||
|
||||
stream := StreamClientErrorReports()
|
||||
|
||||
for obj := range stream {
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/aerogo/api"
|
||||
)
|
||||
|
||||
// Force interface implementations
|
||||
var (
|
||||
_ api.Newable = (*ClientErrorReport)(nil)
|
||||
)
|
||||
|
39
arn/Crash.go
Normal file
39
arn/Crash.go
Normal file
@ -0,0 +1,39 @@
|
||||
package arn
|
||||
|
||||
import "github.com/aerogo/nano"
|
||||
|
||||
// Crash contains data about server crashes.
|
||||
type Crash struct {
|
||||
Error string `json:"error"`
|
||||
Stack string `json:"stack"`
|
||||
|
||||
hasID
|
||||
hasCreator
|
||||
}
|
||||
|
||||
// StreamCrashes returns a stream of all crashes.
|
||||
func StreamCrashes() <-chan *Crash {
|
||||
channel := make(chan *Crash, nano.ChannelBufferSize)
|
||||
|
||||
go func() {
|
||||
for obj := range DB.All("Crash") {
|
||||
channel <- obj.(*Crash)
|
||||
}
|
||||
|
||||
close(channel)
|
||||
}()
|
||||
|
||||
return channel
|
||||
}
|
||||
|
||||
// AllCrashes returns a slice of all crashes.
|
||||
func AllCrashes() []*Crash {
|
||||
all := make([]*Crash, 0, DB.Collection("Crash").Count())
|
||||
stream := StreamCrashes()
|
||||
|
||||
for obj := range stream {
|
||||
all = append(all, obj)
|
||||
}
|
||||
|
||||
return all
|
||||
}
|
13
arn/CrashAPI.go
Normal file
13
arn/CrashAPI.go
Normal file
@ -0,0 +1,13 @@
|
||||
package arn
|
||||
|
||||
import "github.com/aerogo/api"
|
||||
|
||||
// Force interface implementations
|
||||
var (
|
||||
_ api.Savable = (*Crash)(nil)
|
||||
)
|
||||
|
||||
// Save saves the crash in the database.
|
||||
func (crash *Crash) Save() {
|
||||
DB.Set("Crash", crash.ID, crash)
|
||||
}
|
@ -25,6 +25,7 @@ var DB = Node.Namespace("arn").RegisterTypes(
|
||||
(*AnimeCharacters)(nil),
|
||||
(*AnimeRelations)(nil),
|
||||
(*AnimeList)(nil),
|
||||
(*Crash)(nil),
|
||||
(*Character)(nil),
|
||||
(*ClientErrorReport)(nil),
|
||||
(*Company)(nil),
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/aerogo/aero"
|
||||
"github.com/animenotifier/notify.moe/arn"
|
||||
)
|
||||
|
||||
// Recover recovers from panics and shows them as the response body.
|
||||
@ -27,11 +28,28 @@ func Recover(next aero.Handler) aero.Handler {
|
||||
}
|
||||
|
||||
stack := make([]byte, 4096)
|
||||
length := runtime.Stack(stack, true)
|
||||
length := runtime.Stack(stack, false)
|
||||
stackString := string(stack[:length])
|
||||
fmt.Fprint(os.Stderr, stackString)
|
||||
|
||||
message := err.Error() + "<br><br>" + strings.ReplaceAll(stackString, "\n", "<br>")
|
||||
// Save crash in database
|
||||
crash := &arn.Crash{
|
||||
Error: err.Error(),
|
||||
Stack: stackString,
|
||||
}
|
||||
|
||||
crash.ID = arn.GenerateID("Crash")
|
||||
crash.Created = arn.DateTimeUTC()
|
||||
user := arn.GetUserFromContext(ctx)
|
||||
|
||||
if user != nil {
|
||||
crash.CreatedBy = user.ID
|
||||
}
|
||||
|
||||
crash.Save()
|
||||
|
||||
// Send HTML
|
||||
message := "<div class='crash'>" + err.Error() + "<br><br>" + strings.ReplaceAll(stackString, "\n", "<br>") + "</div>"
|
||||
_ = ctx.Error(http.StatusInternalServerError, message)
|
||||
}()
|
||||
|
||||
|
@ -2,6 +2,7 @@ component AdminTabs
|
||||
.tabs
|
||||
Tab("Server", "server", "/admin")
|
||||
Tab("WebDev", "html5", "/admin/webdev")
|
||||
Tab("Crashes", "exclamation", "/admin/crashes")
|
||||
Tab("Client errors", "exclamation", "/admin/errors/client")
|
||||
Tab("Registrations", "user-plus", "/admin/registrations")
|
||||
Tab("Purchases", "shopping-cart", "/admin/purchases")
|
||||
|
26
pages/admin/crashes.go
Normal file
26
pages/admin/crashes.go
Normal file
@ -0,0 +1,26 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/aerogo/aero"
|
||||
"github.com/animenotifier/notify.moe/arn"
|
||||
"github.com/animenotifier/notify.moe/components"
|
||||
)
|
||||
|
||||
const maxCrashes = 80
|
||||
|
||||
// Crashes shows client-side errors.
|
||||
func Crashes(ctx aero.Context) error {
|
||||
crashes := arn.AllCrashes()
|
||||
|
||||
sort.Slice(crashes, func(i, j int) bool {
|
||||
return crashes[i].Created > crashes[j].Created
|
||||
})
|
||||
|
||||
if len(crashes) > maxCrashes {
|
||||
crashes = crashes[:maxCrashes]
|
||||
}
|
||||
|
||||
return ctx.HTML(components.Crashes(crashes))
|
||||
}
|
19
pages/admin/crashes.pixy
Normal file
19
pages/admin/crashes.pixy
Normal file
@ -0,0 +1,19 @@
|
||||
component Crashes(crashes []*arn.Crash)
|
||||
AdminTabs
|
||||
h1.mountable Server-side crashes
|
||||
|
||||
table
|
||||
tbody
|
||||
each crash in crashes
|
||||
tr.mountable
|
||||
td
|
||||
a(href="/api/crash/" + crash.ID, target="_blank")= crash.Error
|
||||
td
|
||||
each line in strings.Split(crash.Stack, "\n")
|
||||
p= line
|
||||
td.utc-date(data-date=crash.Created)
|
||||
td.edit-log-user
|
||||
if crash.CreatedBy != ""
|
||||
Avatar(crash.Creator())
|
||||
else
|
||||
span anonymous
|
@ -16,6 +16,8 @@ import (
|
||||
// privateTypes are types that are not available for download.
|
||||
var privateTypes = []string{
|
||||
"Analytics",
|
||||
"Crash",
|
||||
"ClientErrorReport",
|
||||
"EditLogEntry",
|
||||
"EmailToUser",
|
||||
"FacebookToUser",
|
||||
|
@ -77,6 +77,7 @@ func Register(app *aero.Application) {
|
||||
page.Get(app, "/admin", admin.Get)
|
||||
page.Get(app, "/admin/webdev", admin.WebDev)
|
||||
page.Get(app, "/admin/registrations", admin.UserRegistrations)
|
||||
page.Get(app, "/admin/crashes", admin.Crashes)
|
||||
page.Get(app, "/admin/errors/client", admin.ClientErrors)
|
||||
page.Get(app, "/admin/purchases", admin.PurchaseHistory)
|
||||
page.Get(app, "/admin/payments", admin.PaymentHistory)
|
||||
|
Loading…
Reference in New Issue
Block a user