initial perf anaytics
add tasks to debug page ignore .git on debug page for speed add perfchunks table Renamed phrases (changed statistics to stats): panel_menu_stats panel_menu_stats_posts panel_menu_stats_topics panel_menu_stats_forums panel_menu_stats_routes panel_menu_stats_agents panel_menu_stats_systems panel_menu_stats_languages panel_menu_stats_referrers panel_menu_stats_memory panel_menu_stats_active_memory panel_menu_stats_perf panel_stats_views_head_suffix panel_stats_user_agents_head panel_stats_forums_head panel_stats_languages_head panel_stats_post_counts_head panel_stats_referrers_head panel_stats_routes_head panel_stats_operating_systems_head panel_stats_topic_counts_head panel_stats_requests_head panel_stats_memory_head panel_stats_active_memory_head panel_stats_spam_hide panel_stats_spam_show panel_stats_memory_type_total panel_stats_memory_type_stack panel_stats_memory_type_heap panel_stats_time_range_one_year panel_stats_time_range_three_months panel_stats_time_range_one_month panel_stats_time_range_one_week panel_stats_time_range_two_days panel_stats_time_range_one_day panel_stats_time_range_twelve_hours panel_stats_time_range_six_hours panel_stats_post_counts_chart_aria panel_stats_topic_counts_chart_aria panel_stats_requests_chart_aria panel_stats_memory_chart_aria panel_stats_details_head panel_stats_post_counts_table_aria panel_stats_topic_counts_table_aria panel_stats_route_views_table_aria panel_stats_requests_table_aria panel_stats_memory_table_aria panel_stats_views_suffix panel_stats_posts_suffix panel_stats_topics_suffix panel_stats_user_agents_no_user_agents panel_stats_forums_no_forums panel_stats_languages_no_languages panel_stats_post_counts_no_post_counts panel_stats_referrers_no_referrers panel_stats_routes_no_routes panel_stats_operating_systems_no_operating_systems panel_stats_memory_no_memory Added phrases: panel_debug_tasks panel_debug_tasks_half_second panel_debug_tasks_second panel_debug_tasks_fifteen_minute panel_debug_tasks_hour panel_debug_tasks_shutdown panel_stats_perf_head panel_stats_perf_low panel_stats_perf_high panel_stats_perf_avg You will need to run the updater / patcher for this commit.
This commit is contained in:
parent
24cef43439
commit
459d745cb1
@ -733,6 +733,15 @@ func createTables(adapter qgen.Adapter) (err error) {
|
||||
}, nil,
|
||||
)
|
||||
|
||||
createTable("perfchunks", "", "",
|
||||
[]tC{
|
||||
tC{"low", "int", 0, false, false, "0"},
|
||||
tC{"high", "int", 0, false, false, "0"},
|
||||
tC{"avg", "int", 0, false, false, "0"},
|
||||
tC{"createdAt", "datetime", 0, false, false, ""},
|
||||
}, nil,
|
||||
)
|
||||
|
||||
createTable("sync", "", "",
|
||||
[]tC{
|
||||
tC{"last_update", "datetime", 0, false, false, ""},
|
||||
|
@ -35,10 +35,12 @@ type SQLModLogStore struct {
|
||||
|
||||
func NewModLogStore(acc *qgen.Accumulator) (*SQLModLogStore, error) {
|
||||
ml := "moderation_logs"
|
||||
// TODO: Shorten name of ipaddress column to ip
|
||||
cols := "action, elementID, elementType, ipaddress, actorID, doneAt, extra"
|
||||
return &SQLModLogStore{
|
||||
create: acc.Insert(ml).Columns("action, elementID, elementType, ipaddress, actorID, doneAt, extra").Fields("?,?,?,?,?,UTC_TIMESTAMP(),?").Prepare(),
|
||||
create: acc.Insert(ml).Columns(cols).Fields("?,?,?,?,?,UTC_TIMESTAMP(),?").Prepare(),
|
||||
count: acc.Count(ml).Prepare(),
|
||||
getOffset: acc.Select(ml).Columns("action, elementID, elementType, ipaddress, actorID, doneAt, extra").Orderby("doneAt DESC").Limit("?,?").Prepare(),
|
||||
getOffset: acc.Select(ml).Columns(cols).Orderby("doneAt DESC").Limit("?,?").Prepare(),
|
||||
}, acc.FirstError()
|
||||
}
|
||||
|
||||
@ -91,10 +93,11 @@ type SQLAdminLogStore struct {
|
||||
|
||||
func NewAdminLogStore(acc *qgen.Accumulator) (*SQLAdminLogStore, error) {
|
||||
al := "administration_logs"
|
||||
cols := "action, elementID, elementType, ipaddress, actorID, doneAt, extra"
|
||||
return &SQLAdminLogStore{
|
||||
create: acc.Insert(al).Columns("action, elementID, elementType, ipaddress, actorID, doneAt, extra").Fields("?,?,?,?,?,UTC_TIMESTAMP(),?").Prepare(),
|
||||
create: acc.Insert(al).Columns(cols).Fields("?,?,?,?,?,UTC_TIMESTAMP(),?").Prepare(),
|
||||
count: acc.Count(al).Prepare(),
|
||||
getOffset: acc.Select(al).Columns("action, elementID, elementType, ipaddress, actorID, doneAt, extra").Orderby("doneAt DESC").Limit("?,?").Prepare(),
|
||||
getOffset: acc.Select(al).Columns(cols).Orderby("doneAt DESC").Limit("?,?").Prepare(),
|
||||
}, acc.FirstError()
|
||||
}
|
||||
|
||||
|
@ -40,3 +40,13 @@ type RWMutexCounterBucket struct {
|
||||
counter int
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
type MutexCounterBucket struct {
|
||||
counter int
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type MutexCounter64Bucket struct {
|
||||
counter int64
|
||||
sync.Mutex
|
||||
}
|
113
common/counters/performance.go
Normal file
113
common/counters/performance.go
Normal file
@ -0,0 +1,113 @@
|
||||
package counters
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"math"
|
||||
|
||||
c "github.com/Azareal/Gosora/common"
|
||||
qgen "github.com/Azareal/Gosora/query_gen"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var PerfCounter *DefaultPerfCounter
|
||||
|
||||
type PerfCounterBucket struct {
|
||||
low *MutexCounter64Bucket
|
||||
high *MutexCounter64Bucket
|
||||
avg *MutexCounter64Bucket
|
||||
}
|
||||
|
||||
// TODO: Track perf on a per route basis
|
||||
type DefaultPerfCounter struct {
|
||||
buckets []PerfCounterBucket
|
||||
|
||||
insert *sql.Stmt
|
||||
}
|
||||
|
||||
func NewDefaultPerfCounter(acc *qgen.Accumulator) (*DefaultPerfCounter, error) {
|
||||
co := &DefaultPerfCounter{
|
||||
buckets: []PerfCounterBucket{
|
||||
PerfCounterBucket{
|
||||
low: &MutexCounter64Bucket{counter: 0},
|
||||
high: &MutexCounter64Bucket{counter: 0},
|
||||
avg: &MutexCounter64Bucket{counter: 0},
|
||||
},
|
||||
},
|
||||
insert: acc.Insert("perfchunks").Columns("low,high,avg,createdAt").Fields("?,?,?,UTC_TIMESTAMP()").Prepare(),
|
||||
}
|
||||
|
||||
c.AddScheduledFifteenMinuteTask(co.Tick)
|
||||
//c.AddScheduledSecondTask(co.Tick)
|
||||
c.AddShutdownTask(co.Tick)
|
||||
return co, acc.FirstError()
|
||||
}
|
||||
|
||||
func (co *DefaultPerfCounter) Tick() error {
|
||||
getCounter := func(b *MutexCounter64Bucket) int64 {
|
||||
return atomic.SwapInt64(&b.counter, 0)
|
||||
}
|
||||
for _, b := range co.buckets {
|
||||
low := atomic.SwapInt64(&b.low.counter, math.MaxInt64)
|
||||
if low == math.MaxInt64 {
|
||||
low = 0
|
||||
}
|
||||
high := getCounter(b.high)
|
||||
avg := getCounter(b.avg)
|
||||
|
||||
err := co.insertChunk(low, high, avg) // TODO: Bulk insert for speed?
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.WithStack(err), "perf counter")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (co *DefaultPerfCounter) insertChunk(low, high, avg int64) error {
|
||||
if low == 0 && high == 0 && avg == 0 {
|
||||
return nil
|
||||
}
|
||||
c.DebugLogf("Inserting a pchunk with low %d, high %d, avg %d", low, high, avg)
|
||||
_, err := co.insert.Exec(low, high, avg)
|
||||
return err
|
||||
}
|
||||
|
||||
func (co *DefaultPerfCounter) Push(dur time.Duration) {
|
||||
id := 0
|
||||
b := co.buckets[id]
|
||||
//c.DebugDetail("co.buckets[", id, "]: ", b)
|
||||
micro := dur.Microseconds()
|
||||
|
||||
low := b.low
|
||||
if micro < low.counter {
|
||||
low.Lock()
|
||||
if micro < low.counter {
|
||||
atomic.StoreInt64(&low.counter,micro)
|
||||
}
|
||||
low.Unlock()
|
||||
}
|
||||
|
||||
high := b.high
|
||||
if micro > high.counter {
|
||||
high.Lock()
|
||||
if micro > high.counter {
|
||||
atomic.StoreInt64(&high.counter,micro)
|
||||
}
|
||||
high.Unlock()
|
||||
}
|
||||
|
||||
avg := b.avg
|
||||
// TODO: Sync semantics are slightly loose but it should be close enough for our purposes here
|
||||
if micro != avg.counter {
|
||||
t := false
|
||||
avg.Lock()
|
||||
if avg.counter == 0 {
|
||||
t = atomic.CompareAndSwapInt64(&avg.counter, 0, micro)
|
||||
}
|
||||
if !t && micro != avg.counter {
|
||||
atomic.StoreInt64(&avg.counter,(micro+avg.counter) / 2)
|
||||
}
|
||||
avg.Unlock()
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
c "github.com/Azareal/Gosora/common"
|
||||
"github.com/Azareal/Gosora/query_gen"
|
||||
qgen "github.com/Azareal/Gosora/query_gen"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -22,7 +22,7 @@ func NewPostCounter() (*DefaultPostCounter, error) {
|
||||
acc := qgen.NewAcc()
|
||||
co := &DefaultPostCounter{
|
||||
currentBucket: 0,
|
||||
insert: acc.Insert("postchunks").Columns("count, createdAt").Fields("?,UTC_TIMESTAMP()").Prepare(),
|
||||
insert: acc.Insert("postchunks").Columns("count,createdAt").Fields("?,UTC_TIMESTAMP()").Prepare(),
|
||||
}
|
||||
c.AddScheduledFifteenMinuteTask(co.Tick)
|
||||
//c.AddScheduledSecondTask(co.Tick)
|
||||
@ -44,7 +44,7 @@ func (co *DefaultPostCounter) Tick() (err error) {
|
||||
atomic.AddInt64(&co.buckets[oldBucket], -previousViewChunk)
|
||||
err = co.insertChunk(previousViewChunk)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.WithStack(err),"post counter")
|
||||
return errors.Wrap(errors.WithStack(err), "post counter")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
c "github.com/Azareal/Gosora/common"
|
||||
"github.com/Azareal/Gosora/query_gen"
|
||||
qgen "github.com/Azareal/Gosora/query_gen"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -35,7 +35,7 @@ func NewDefaultReferrerTracker() (*DefaultReferrerTracker, error) {
|
||||
refTracker := &DefaultReferrerTracker{
|
||||
odd: make(map[string]*ReferrerItem),
|
||||
even: make(map[string]*ReferrerItem),
|
||||
insert: acc.Insert("viewchunks_referrers").Columns("count, createdAt, domain").Fields("?,UTC_TIMESTAMP(),?").Prepare(), // TODO: Do something more efficient than doing a query for each referrer
|
||||
insert: acc.Insert("viewchunks_referrers").Columns("count,createdAt,domain").Fields("?,UTC_TIMESTAMP(),?").Prepare(), // TODO: Do something more efficient than doing a query for each referrer
|
||||
}
|
||||
c.AddScheduledFifteenMinuteTask(refTracker.Tick)
|
||||
//c.AddScheduledSecondTask(refTracker.Tick)
|
||||
@ -51,7 +51,7 @@ func (ref *DefaultReferrerTracker) Tick() (err error) {
|
||||
if count != 0 {
|
||||
err := ref.insertChunk(referrer, count) // TODO: Bulk insert for speed?
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.WithStack(err),"ref counter")
|
||||
return errors.Wrap(errors.WithStack(err), "ref counter")
|
||||
}
|
||||
}
|
||||
delete(referrersToDelete, referrer)
|
||||
@ -69,16 +69,16 @@ func (ref *DefaultReferrerTracker) Tick() (err error) {
|
||||
count := atomic.SwapInt64(&counter.Count, 0)
|
||||
err := ref.insertChunk(referrer, count) // TODO: Bulk insert for speed?
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.WithStack(err),"ref counter")
|
||||
return errors.Wrap(errors.WithStack(err), "ref counter")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
err = refLoop(&ref.oddLock,ref.odd)
|
||||
err = refLoop(&ref.oddLock, ref.odd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return refLoop(&ref.evenLock,ref.even)
|
||||
return refLoop(&ref.evenLock, ref.even)
|
||||
}
|
||||
|
||||
func (ref *DefaultReferrerTracker) insertChunk(referrer string, count int64) error {
|
||||
|
@ -23,7 +23,7 @@ type DefaultViewCounter struct {
|
||||
func NewGlobalViewCounter(acc *qgen.Accumulator) (*DefaultViewCounter, error) {
|
||||
co := &DefaultViewCounter{
|
||||
currentBucket: 0,
|
||||
insert: acc.Insert("viewchunks").Columns("count, createdAt, route").Fields("?,UTC_TIMESTAMP(),''").Prepare(),
|
||||
insert: acc.Insert("viewchunks").Columns("count,createdAt,route").Fields("?,UTC_TIMESTAMP(),''").Prepare(),
|
||||
}
|
||||
c.AddScheduledFifteenMinuteTask(co.Tick) // This is run once every fifteen minutes to match the frequency of the RouteViewCounter
|
||||
//c.AddScheduledSecondTask(co.Tick)
|
||||
@ -31,6 +31,7 @@ func NewGlobalViewCounter(acc *qgen.Accumulator) (*DefaultViewCounter, error) {
|
||||
return co, acc.FirstError()
|
||||
}
|
||||
|
||||
// TODO: Simplify the atomics used here
|
||||
func (co *DefaultViewCounter) Tick() (err error) {
|
||||
oldBucket := co.currentBucket
|
||||
var nextBucket int64 // 0
|
||||
|
@ -354,6 +354,14 @@ type PanelAnalyticsActiveMemory struct {
|
||||
TimeType string
|
||||
MemType int
|
||||
}
|
||||
type PanelAnalyticsPerf struct {
|
||||
Graph PanelTimeGraph
|
||||
ViewItems []PanelAnalyticsItemUnit
|
||||
TimeRange string
|
||||
Unit string
|
||||
TimeType string
|
||||
PerfType int
|
||||
}
|
||||
|
||||
type PanelStats struct {
|
||||
Users int
|
||||
@ -654,6 +662,14 @@ type PanelRegLogsPage struct {
|
||||
Paginator
|
||||
}
|
||||
|
||||
type DebugPageTasks struct {
|
||||
HalfSecond int
|
||||
Second int
|
||||
FifteenMinute int
|
||||
Hour int
|
||||
Shutdown int
|
||||
}
|
||||
|
||||
type DebugPageCache struct {
|
||||
Topics int
|
||||
Users int
|
||||
@ -711,8 +727,9 @@ type PanelDebugPage struct {
|
||||
|
||||
Goroutines int
|
||||
CPUs int
|
||||
MemStats runtime.MemStats
|
||||
|
||||
Tasks DebugPageTasks
|
||||
MemStats runtime.MemStats
|
||||
Cache DebugPageCache
|
||||
Database DebugPageDatabase
|
||||
Disk DebugPageDisk
|
||||
|
@ -113,25 +113,25 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (header
|
||||
}
|
||||
// TODO: We should probably initialise header.ExtData
|
||||
// ? - Should we only show this in debug mode? It might be useful for detecting issues in production, if we show it there as-well
|
||||
if user.IsAdmin {
|
||||
//if user.IsAdmin {
|
||||
header.StartedAt = time.Now()
|
||||
}
|
||||
//}
|
||||
|
||||
header.AddSheet(theme.Name + "/main.css")
|
||||
header.AddSheet(theme.Name + "/panel.css")
|
||||
if len(theme.Resources) > 0 {
|
||||
rlist := theme.Resources
|
||||
for _, resource := range rlist {
|
||||
if resource.Location == "global" || resource.Location == "panel" {
|
||||
extarr := strings.Split(resource.Name, ".")
|
||||
for _, res := range rlist {
|
||||
if res.Location == "global" || res.Location == "panel" {
|
||||
extarr := strings.Split(res.Name, ".")
|
||||
ext := extarr[len(extarr)-1]
|
||||
if ext == "css" {
|
||||
header.AddSheet(resource.Name)
|
||||
header.AddSheet(res.Name)
|
||||
} else if ext == "js" {
|
||||
if resource.Async {
|
||||
header.AddScriptAsync(resource.Name)
|
||||
if res.Async {
|
||||
header.AddScriptAsync(res.Name)
|
||||
} else {
|
||||
header.AddScript(resource.Name)
|
||||
header.AddScript(res.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -224,9 +224,9 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Head
|
||||
|
||||
// An optimisation so we don't populate StartedAt for users who shouldn't see the stat anyway
|
||||
// ? - Should we only show this in debug mode? It might be useful for detecting issues in production, if we show it there as-well
|
||||
if user.IsAdmin {
|
||||
//if user.IsAdmin {
|
||||
header.StartedAt = time.Now()
|
||||
}
|
||||
//}
|
||||
|
||||
//PrepResources(user,header,theme)
|
||||
return header, nil
|
||||
@ -237,20 +237,20 @@ func PrepResources(user *User, h *Header, theme *Theme) {
|
||||
|
||||
if len(theme.Resources) > 0 {
|
||||
rlist := theme.Resources
|
||||
for _, resource := range rlist {
|
||||
if resource.Loggedin && !user.Loggedin {
|
||||
for _, res := range rlist {
|
||||
if res.Loggedin && !user.Loggedin {
|
||||
continue
|
||||
}
|
||||
if resource.Location == "global" || resource.Location == "frontend" {
|
||||
extarr := strings.Split(resource.Name, ".")
|
||||
if res.Location == "global" || res.Location == "frontend" {
|
||||
extarr := strings.Split(res.Name, ".")
|
||||
ext := extarr[len(extarr)-1]
|
||||
if ext == "css" {
|
||||
h.AddSheet(resource.Name)
|
||||
h.AddSheet(res.Name)
|
||||
} else if ext == "js" {
|
||||
if resource.Async {
|
||||
h.AddScriptAsync(resource.Name)
|
||||
if res.Async {
|
||||
h.AddScriptAsync(res.Name)
|
||||
} else {
|
||||
h.AddScript(resource.Name)
|
||||
h.AddScript(res.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,27 @@ func AddShutdownTask(task func() error) {
|
||||
ShutdownTasks = append(ShutdownTasks, task)
|
||||
}
|
||||
|
||||
// ScheduledHalfSecondTaskCount is not concurrency safe
|
||||
func ScheduledHalfSecondTaskCount() int {
|
||||
return len(ScheduledHalfSecondTasks)
|
||||
}
|
||||
// ScheduledSecondTaskCount is not concurrency safe
|
||||
func ScheduledSecondTaskCount() int {
|
||||
return len(ScheduledSecondTasks)
|
||||
}
|
||||
// ScheduledFifteenMinuteTaskCount is not concurrency safe
|
||||
func ScheduledFifteenMinuteTaskCount() int {
|
||||
return len(ScheduledFifteenMinuteTasks)
|
||||
}
|
||||
// ScheduledHourTaskCount is not concurrency safe
|
||||
func ScheduledHourTaskCount() int {
|
||||
return len(ScheduledHourTasks)
|
||||
}
|
||||
// ShutdownTaskCount is not concurrency safe
|
||||
func ShutdownTaskCount() int {
|
||||
return len(ShutdownTasks)
|
||||
}
|
||||
|
||||
// TODO: Use AddScheduledSecondTask
|
||||
func HandleExpiredScheduledGroups() error {
|
||||
rows, err := taskStmts.getExpiredScheduledGroups.Query()
|
||||
|
@ -372,10 +372,11 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
||||
dbVersion := qgen.Builder.DbVersion()
|
||||
var memStats runtime.MemStats
|
||||
runtime.ReadMemStats(&memStats)
|
||||
debugTasks := DebugPageTasks{0,0,0,0,0}
|
||||
debugCache := DebugPageCache{1, 1, 1, 2, 2, 2, true}
|
||||
debugDatabase := DebugPageDatabase{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||
debugDisk := DebugPageDisk{1, 1, 1, 1, 1, 1}
|
||||
dpage := PanelDebugPage{basePage, goVersion, dbVersion, "0s", 1, qgen.Builder.GetAdapter().GetName(), 1, 1, memStats, debugCache, debugDatabase, debugDisk}
|
||||
dpage := PanelDebugPage{basePage, goVersion, dbVersion, "0s", 1, qgen.Builder.GetAdapter().GetName(), 1, 1, debugTasks, memStats, debugCache, debugDatabase, debugDisk}
|
||||
t.AddStd("panel_debug", "c.PanelDebugPage", dpage)
|
||||
//t.AddStd("panel_analytics", "c.PanelAnalytics", Panel{basePage, "panel_dashboard_right","panel_dashboard", inter})
|
||||
|
||||
|
573
gen_router.go
573
gen_router.go
File diff suppressed because it is too large
Load Diff
@ -795,17 +795,18 @@
|
||||
"panel_menu_menus":"Menus",
|
||||
"panel_menu_widgets":"Widgets",
|
||||
"panel_menu_events":"Events",
|
||||
"panel_menu_statistics":"Statistics",
|
||||
"panel_menu_statistics_posts":"Posts",
|
||||
"panel_menu_statistics_topics":"Topics",
|
||||
"panel_menu_statistics_forums":"Forums",
|
||||
"panel_menu_statistics_routes":"Routes",
|
||||
"panel_menu_statistics_agents":"Agents",
|
||||
"panel_menu_statistics_systems":"Systems",
|
||||
"panel_menu_statistics_languages":"Languages",
|
||||
"panel_menu_statistics_referrers":"Referrers",
|
||||
"panel_menu_statistics_memory":"Memory",
|
||||
"panel_menu_statistics_active_memory":"Active Memory",
|
||||
"panel_menu_stats":"Statistics",
|
||||
"panel_menu_stats_posts":"Posts",
|
||||
"panel_menu_stats_topics":"Topics",
|
||||
"panel_menu_stats_forums":"Forums",
|
||||
"panel_menu_stats_routes":"Routes",
|
||||
"panel_menu_stats_agents":"Agents",
|
||||
"panel_menu_stats_systems":"Systems",
|
||||
"panel_menu_stats_languages":"Languages",
|
||||
"panel_menu_stats_referrers":"Referrers",
|
||||
"panel_menu_stats_memory":"Memory",
|
||||
"panel_menu_stats_active_memory":"Active Memory",
|
||||
"panel_menu_stats_perf":"Performance",
|
||||
"panel_menu_reports":"Reports",
|
||||
"panel_menu_logs":"Logs",
|
||||
"panel_menu_logs_registrations":"Registrations",
|
||||
@ -975,56 +976,60 @@
|
||||
"panel_pages_title":"Title",
|
||||
"panel_pages_edit_update_button":"Update Page",
|
||||
|
||||
"panel_statistics_views_head_suffix":" Views",
|
||||
"panel_statistics_user_agents_head":"User Agents",
|
||||
"panel_statistics_forums_head":"Forums",
|
||||
"panel_statistics_languages_head":"Languages",
|
||||
"panel_statistics_post_counts_head":"Post Counts",
|
||||
"panel_statistics_referrers_head":"Referrers",
|
||||
"panel_statistics_routes_head":"Routes",
|
||||
"panel_statistics_operating_systems_head":"Operating Systems",
|
||||
"panel_statistics_topic_counts_head":"Topic Counts",
|
||||
"panel_statistics_requests_head":"Requests",
|
||||
"panel_statistics_memory_head":"Memory Usage",
|
||||
"panel_statistics_active_memory_head":"Active Memory",
|
||||
"panel_stats_views_head_suffix":" Views",
|
||||
"panel_stats_user_agents_head":"User Agents",
|
||||
"panel_stats_forums_head":"Forums",
|
||||
"panel_stats_languages_head":"Languages",
|
||||
"panel_stats_post_counts_head":"Post Counts",
|
||||
"panel_stats_referrers_head":"Referrers",
|
||||
"panel_stats_routes_head":"Routes",
|
||||
"panel_stats_operating_systems_head":"Operating Systems",
|
||||
"panel_stats_topic_counts_head":"Topic Counts",
|
||||
"panel_stats_requests_head":"Requests",
|
||||
"panel_stats_memory_head":"Memory Usage",
|
||||
"panel_stats_active_memory_head":"Active Memory",
|
||||
"panel_stats_perf_head":"Performance",
|
||||
|
||||
"panel_statistics_spam_hide":"Hide Spam",
|
||||
"panel_statistics_spam_show":"Show Spam",
|
||||
"panel_statistics_memory_type_total":"Total",
|
||||
"panel_statistics_memory_type_stack":"Stack",
|
||||
"panel_statistics_memory_type_heap":"Heap",
|
||||
"panel_stats_spam_hide":"Hide Spam",
|
||||
"panel_stats_spam_show":"Show Spam",
|
||||
"panel_stats_memory_type_total":"Total",
|
||||
"panel_stats_memory_type_stack":"Stack",
|
||||
"panel_stats_memory_type_heap":"Heap",
|
||||
"panel_stats_perf_low":"Low",
|
||||
"panel_stats_perf_high":"High",
|
||||
"panel_stats_perf_avg":"Average",
|
||||
|
||||
"panel_statistics_time_range_one_year":"1 year",
|
||||
"panel_statistics_time_range_three_months":"3 months",
|
||||
"panel_statistics_time_range_one_month":"1 month",
|
||||
"panel_statistics_time_range_one_week":"1 week",
|
||||
"panel_statistics_time_range_two_days":"2 days",
|
||||
"panel_statistics_time_range_one_day":"1 day",
|
||||
"panel_statistics_time_range_twelve_hours":"12 hours",
|
||||
"panel_statistics_time_range_six_hours":"6 hours",
|
||||
"panel_stats_time_range_one_year":"1 year",
|
||||
"panel_stats_time_range_three_months":"3 months",
|
||||
"panel_stats_time_range_one_month":"1 month",
|
||||
"panel_stats_time_range_one_week":"1 week",
|
||||
"panel_stats_time_range_two_days":"2 days",
|
||||
"panel_stats_time_range_one_day":"1 day",
|
||||
"panel_stats_time_range_twelve_hours":"12 hours",
|
||||
"panel_stats_time_range_six_hours":"6 hours",
|
||||
|
||||
"panel_statistics_post_counts_chart_aria":"Post Chart",
|
||||
"panel_statistics_topic_counts_chart_aria":"Topic Chart",
|
||||
"panel_statistics_requests_chart_aria":"Requests Chart",
|
||||
"panel_statistics_memory_chart_aria":"Memory Use Chart",
|
||||
"panel_statistics_details_head":"Details",
|
||||
"panel_statistics_post_counts_table_aria":"Post Table, this has the same information as the post chart",
|
||||
"panel_statistics_topic_counts_table_aria":"Topic Table, this has the same information as the topic chart",
|
||||
"panel_statistics_route_views_table_aria":"View Table, this has the same information as the view chart",
|
||||
"panel_statistics_requests_table_aria":"View Table, this has the same information as the view chart",
|
||||
"panel_statistics_memory_table_aria":"Memory Use Table, this has the same information as the memory use chart",
|
||||
"panel_statistics_views_suffix":" views",
|
||||
"panel_statistics_posts_suffix":" posts",
|
||||
"panel_statistics_topics_suffix":" topics",
|
||||
"panel_stats_post_counts_chart_aria":"Post Chart",
|
||||
"panel_stats_topic_counts_chart_aria":"Topic Chart",
|
||||
"panel_stats_requests_chart_aria":"Requests Chart",
|
||||
"panel_stats_memory_chart_aria":"Memory Use Chart",
|
||||
"panel_stats_details_head":"Details",
|
||||
"panel_stats_post_counts_table_aria":"Post Table, this has the same information as the post chart",
|
||||
"panel_stats_topic_counts_table_aria":"Topic Table, this has the same information as the topic chart",
|
||||
"panel_stats_route_views_table_aria":"View Table, this has the same information as the view chart",
|
||||
"panel_stats_requests_table_aria":"View Table, this has the same information as the view chart",
|
||||
"panel_stats_memory_table_aria":"Memory Use Table, this has the same information as the memory use chart",
|
||||
"panel_stats_views_suffix":" views",
|
||||
"panel_stats_posts_suffix":" posts",
|
||||
"panel_stats_topics_suffix":" topics",
|
||||
|
||||
"panel_statistics_user_agents_no_user_agents":"No user agents could be found in the selected time range",
|
||||
"panel_statistics_forums_no_forums":"No forum view counts could be found in the selected time range",
|
||||
"panel_statistics_languages_no_languages":"No language could be found in the selected time range",
|
||||
"panel_statistics_post_counts_no_post_counts":"No posts could be found in the selected time range",
|
||||
"panel_statistics_referrers_no_referrers":"No referrers could be found in the selected time range",
|
||||
"panel_statistics_routes_no_routes":"No route view counts could be found in the selected time range",
|
||||
"panel_statistics_operating_systems_no_operating_systems":"No operating systems could be found in the selected time range",
|
||||
"panel_statistics_memory_no_memory":"No memory chunks could be found in the selected time range",
|
||||
"panel_stats_user_agents_no_user_agents":"No user agents could be found in the selected time range",
|
||||
"panel_stats_forums_no_forums":"No forum view counts could be found in the selected time range",
|
||||
"panel_stats_languages_no_languages":"No language could be found in the selected time range",
|
||||
"panel_stats_post_counts_no_post_counts":"No posts could be found in the selected time range",
|
||||
"panel_stats_referrers_no_referrers":"No referrers could be found in the selected time range",
|
||||
"panel_stats_routes_no_routes":"No route view counts could be found in the selected time range",
|
||||
"panel_stats_operating_systems_no_operating_systems":"No operating systems could be found in the selected time range",
|
||||
"panel_stats_memory_no_memory":"No memory chunks could be found in the selected time range",
|
||||
|
||||
"panel_logs_menu_head":"Logs",
|
||||
"panel_logs_reg_head":"Registrations",
|
||||
@ -1173,6 +1178,13 @@
|
||||
"panel_debug_goroutine_count_label":"Goroutines",
|
||||
"panel_debug_cpu_count_label":"CPUs",
|
||||
|
||||
"panel_debug_tasks":"Tasks",
|
||||
"panel_debug_tasks_half_second":"Half Second",
|
||||
"panel_debug_tasks_second":"Second",
|
||||
"panel_debug_tasks_fifteen_minute":"Fifteen Minute",
|
||||
"panel_debug_tasks_hour":"Hourly",
|
||||
"panel_debug_tasks_shutdown":"Shutdown",
|
||||
|
||||
"panel_debug_memory_stats":"Memory Statistics",
|
||||
"panel_debug_memory_stats_sys":"Sys",
|
||||
"panel_debug_memory_stats_heapsys":"HeapSys",
|
||||
|
@ -49,6 +49,7 @@ func init() {
|
||||
addPatch(29, patch29)
|
||||
addPatch(30, patch30)
|
||||
addPatch(31, patch31)
|
||||
addPatch(32, patch32)
|
||||
}
|
||||
|
||||
func patch0(scanner *bufio.Scanner) (err error) {
|
||||
@ -892,3 +893,15 @@ func patch31(scanner *bufio.Scanner) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func patch32(scanner *bufio.Scanner) error {
|
||||
return execStmt(qgen.Builder.CreateTable("perfchunks", "", "",
|
||||
[]tC{
|
||||
tC{"low", "int", 0, false, false, "0"},
|
||||
tC{"high", "int", 0, false, false, "0"},
|
||||
tC{"avg", "int", 0, false, false, "0"},
|
||||
tC{"createdAt", "datetime", 0, false, false, ""},
|
||||
}, nil,
|
||||
))
|
||||
}
|
@ -38,6 +38,46 @@ function memStuff(window, document, Chartist) {
|
||||
};
|
||||
}
|
||||
|
||||
function perfStuff(window, document, Chartist) {
|
||||
'use strict';
|
||||
|
||||
Chartist.plugins = Chartist.plugins || {};
|
||||
Chartist.plugins.perfUnits = function(options) {
|
||||
options = Chartist.extend({}, {}, options);
|
||||
|
||||
return function perfUnits(chart) {
|
||||
if(!chart instanceof Chartist.Line) return;
|
||||
|
||||
chart.on('created', function() {
|
||||
console.log("running created")
|
||||
const vbits = document.getElementsByClassName("ct-vertical");
|
||||
if(vbits==null) return;
|
||||
|
||||
let tbits = [];
|
||||
for(let i = 0; i < vbits.length; i++) {
|
||||
tbits[i] = vbits[i].innerHTML;
|
||||
}
|
||||
console.log("tbits:",tbits);
|
||||
|
||||
const calc = (places) => {
|
||||
if(places==3) return;
|
||||
|
||||
const matcher = vbits[0].innerHTML;
|
||||
let allMatch = true;
|
||||
for(let i = 0; i < tbits.length; i++) {
|
||||
let val = convertPerfUnit(tbits[i], places);
|
||||
if(val!=matcher) allMatch = false;
|
||||
vbits[i].innerHTML = val;
|
||||
}
|
||||
|
||||
if(allMatch) calc(places + 1);
|
||||
}
|
||||
calc(0);
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const Kilobyte = 1024;
|
||||
const Megabyte = Kilobyte * 1024;
|
||||
const Gigabyte = Megabyte * 1024;
|
||||
@ -60,9 +100,30 @@ function convertByteUnit(bytes, places = 0) {
|
||||
}
|
||||
}
|
||||
|
||||
let ms = 1000;
|
||||
let sec = ms * 1000;
|
||||
let min = sec * 60;
|
||||
let hour = min * 60;
|
||||
let day = hour * 24;
|
||||
function convertPerfUnit(quan, places = 0) {
|
||||
let out;
|
||||
if(quan >= day) out = [quan / day, "d"];
|
||||
else if(quan >= hour) out = [quan / hour, "h"];
|
||||
else if(quan >= min) out = [quan / min, "m"];
|
||||
else if(quan >= sec) out = [quan / sec, "s"];
|
||||
else if(quan >= ms) out = [quan / ms, "ms"];
|
||||
else out = [quan,"μs"];
|
||||
|
||||
if(places==0) return Math.ceil(out[0]) + out[1];
|
||||
else {
|
||||
let ex = Math.pow(10, places);
|
||||
return (Math.round(out[0], ex) / ex) + out[1];
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Fully localise this
|
||||
// TODO: Load rawLabels and seriesData dynamically rather than potentially fiddling with nonces for the CSP?
|
||||
function buildStatsChart(rawLabels, seriesData, timeRange, legendNames, bytes = false) {
|
||||
function buildStatsChart(rawLabels, seriesData, timeRange, legendNames, typ=0) {
|
||||
console.log("buildStatsChart");
|
||||
console.log("seriesData:",seriesData);
|
||||
let labels = [];
|
||||
@ -122,7 +183,8 @@ function buildStatsChart(rawLabels, seriesData, timeRange, legendNames, bytes =
|
||||
if(legendNames.length > 0) config.plugins = [
|
||||
Chartist.plugins.legend({legendNames: legendNames})
|
||||
];
|
||||
if(bytes) config.plugins.push(Chartist.plugins.byteUnits());
|
||||
if(typ==1) config.plugins.push(Chartist.plugins.byteUnits());
|
||||
else if(typ==2) config.plugins.push(Chartist.plugins.perfUnits());
|
||||
Chartist.Line('.ct_chart', {
|
||||
labels: labels,
|
||||
series: seriesData,
|
||||
|
@ -258,6 +258,7 @@ func panelRoutes() *RouteGroup {
|
||||
View("panel.AnalyticsActiveMemory", "/panel/analytics/active-memory/").Before("ParseForm"),
|
||||
View("panel.AnalyticsTopics", "/panel/analytics/topics/").Before("ParseForm"),
|
||||
View("panel.AnalyticsForums", "/panel/analytics/forums/").Before("ParseForm"),
|
||||
View("panel.AnalyticsPerf", "/panel/analytics/perf/").Before("ParseForm"),
|
||||
|
||||
View("panel.Groups", "/panel/groups/"),
|
||||
View("panel.GroupsEdit", "/panel/groups/edit/", "extraData"),
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
c "github.com/Azareal/Gosora/common"
|
||||
co "github.com/Azareal/Gosora/common/counters"
|
||||
)
|
||||
|
||||
var successJSONBytes = []byte(`{"success":1}`)
|
||||
@ -89,7 +90,7 @@ func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, hea
|
||||
return renderTemplate2(tmplName, tmplName, w, r, header, pi)
|
||||
}
|
||||
|
||||
func renderTemplate2(tmplName string, hookName string, w http.ResponseWriter, r *http.Request, header *c.Header, pi interface{}) c.RouteError {
|
||||
func renderTemplate2(tmplName, hookName string, w http.ResponseWriter, r *http.Request, header *c.Header, pi interface{}) c.RouteError {
|
||||
err := renderTemplate3(tmplName, tmplName, w, r, header, pi)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
@ -114,7 +115,7 @@ func FootHeaders(w http.ResponseWriter, header *c.Header) {
|
||||
}
|
||||
}
|
||||
|
||||
func renderTemplate3(tmplName string, hookName string, w http.ResponseWriter, r *http.Request, h *c.Header, pi interface{}) error {
|
||||
func renderTemplate3(tmplName, hookName string, w http.ResponseWriter, r *http.Request, h *c.Header, pi interface{}) error {
|
||||
s := h.Stylesheets
|
||||
h.Stylesheets = nil
|
||||
c.PrepResources(&h.CurrentUser, h, h.Theme)
|
||||
@ -134,9 +135,11 @@ func renderTemplate3(tmplName string, hookName string, w http.ResponseWriter, r
|
||||
}
|
||||
|
||||
FootHeaders(w, h)
|
||||
if h.CurrentUser.IsAdmin {
|
||||
h.Elapsed1 = time.Since(h.StartedAt).String()
|
||||
}
|
||||
since := time.Since(h.StartedAt)
|
||||
//if h.CurrentUser.IsAdmin {
|
||||
h.Elapsed1 = since.String()
|
||||
//}
|
||||
co.PerfCounter.Push(since)
|
||||
if c.RunPreRenderHook("pre_render_"+hookName, w, r, &h.CurrentUser, pi) {
|
||||
return nil
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
c "github.com/Azareal/Gosora/common"
|
||||
p "github.com/Azareal/Gosora/common/phrases"
|
||||
"github.com/Azareal/Gosora/query_gen"
|
||||
qgen "github.com/Azareal/Gosora/query_gen"
|
||||
)
|
||||
|
||||
// TODO: Move this to another file, probably common/pages.go
|
||||
@ -25,11 +25,11 @@ type AnalyticsTimeRange struct {
|
||||
|
||||
func analyticsTimeRange(rawTimeRange string) (*AnalyticsTimeRange, error) {
|
||||
tRange := &AnalyticsTimeRange{
|
||||
Quantity: 6,
|
||||
Unit: "hour",
|
||||
Slices: 12,
|
||||
Quantity: 6,
|
||||
Unit: "hour",
|
||||
Slices: 12,
|
||||
SliceWidth: 60 * 30,
|
||||
Range: "six-hours",
|
||||
Range: "six-hours",
|
||||
}
|
||||
|
||||
switch rawTimeRange {
|
||||
@ -198,6 +198,50 @@ func analyticsRowsToAverageMap2(rows *sql.Rows, labelList []int64, avgMap map[in
|
||||
return avgMap, rows.Err()
|
||||
}
|
||||
|
||||
func analyticsRowsToAverageMap3(rows *sql.Rows, labelList []int64, avgMap map[int64]int64, typ int) (map[int64]int64, error) {
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var low, high, avg int64
|
||||
var createdAt time.Time
|
||||
err := rows.Scan(&low, &high, &avg, &createdAt)
|
||||
if err != nil {
|
||||
return avgMap, err
|
||||
}
|
||||
unixCreatedAt := createdAt.Unix()
|
||||
// TODO: Bulk log this
|
||||
if c.Dev.SuperDebug {
|
||||
log.Print("low: ", low)
|
||||
log.Print("high: ", high)
|
||||
log.Print("avg: ", avg)
|
||||
log.Print("createdAt: ", createdAt)
|
||||
log.Print("unixCreatedAt: ", unixCreatedAt)
|
||||
}
|
||||
var dat int64
|
||||
switch typ {
|
||||
case 0:
|
||||
dat = low
|
||||
case 1:
|
||||
dat = high
|
||||
default:
|
||||
dat = avg
|
||||
}
|
||||
pAvgMap := make(map[int64]pAvg)
|
||||
for _, value := range labelList {
|
||||
if unixCreatedAt > value {
|
||||
prev := pAvgMap[value]
|
||||
prev.Avg += dat
|
||||
prev.Tot++
|
||||
pAvgMap[value] = prev
|
||||
break
|
||||
}
|
||||
}
|
||||
for key, pAvg := range pAvgMap {
|
||||
avgMap[key] = pAvg.Avg / pAvg.Tot
|
||||
}
|
||||
}
|
||||
return avgMap, rows.Err()
|
||||
}
|
||||
|
||||
func PreAnalyticsDetail(w http.ResponseWriter, r *http.Request, user *c.User) (*c.BasePanelPage, c.RouteError) {
|
||||
bp, ferr := buildBasePage(w, r, user, "analytics", "analytics")
|
||||
if ferr != nil {
|
||||
@ -223,7 +267,7 @@ func AnalyticsViews(w http.ResponseWriter, r *http.Request, user c.User) c.Route
|
||||
|
||||
c.DebugLog("in panel.AnalyticsViews")
|
||||
// TODO: Add some sort of analytics store / iterator?
|
||||
rows, err := qgen.NewAcc().Select("viewchunks").Columns("count, createdAt").Where("route = ''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("viewchunks").Columns("count,createdAt").Where("route=''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -232,13 +276,13 @@ func AnalyticsViews(w http.ResponseWriter, r *http.Request, user c.User) c.Route
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
viewList := make([]int64,len(revLabelList))
|
||||
viewItems := make([]c.PanelAnalyticsItem,len(revLabelList))
|
||||
viewList := make([]int64, len(revLabelList))
|
||||
viewItems := make([]c.PanelAnalyticsItem, len(revLabelList))
|
||||
for i, value := range revLabelList {
|
||||
viewList[i] = viewMap[value]
|
||||
viewItems[i] = c.PanelAnalyticsItem{Time: value, Count: viewMap[value]}
|
||||
}
|
||||
|
||||
|
||||
graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList}
|
||||
c.DebugLogf("graph: %+v\n", graph)
|
||||
var ttime string
|
||||
@ -263,7 +307,7 @@ func AnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user c.User, ro
|
||||
|
||||
c.DebugLog("in panel.AnalyticsRouteViews")
|
||||
// TODO: Validate the route is valid
|
||||
rows, err := qgen.NewAcc().Select("viewchunks").Columns("count, createdAt").Where("route = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(route)
|
||||
rows, err := qgen.NewAcc().Select("viewchunks").Columns("count,createdAt").Where("route=?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(route)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -300,7 +344,7 @@ func AnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user c.User, ag
|
||||
|
||||
c.DebugLog("in panel.AnalyticsAgentViews")
|
||||
// TODO: Verify the agent is valid
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_agents").Columns("count, createdAt").Where("browser = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(agent)
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_agents").Columns("count,createdAt").Where("browser=?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(agent)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -343,7 +387,7 @@ func AnalyticsForumViews(w http.ResponseWriter, r *http.Request, user c.User, sf
|
||||
|
||||
c.DebugLog("in panel.AnalyticsForumViews")
|
||||
// TODO: Verify the agent is valid
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_forums").Columns("count, createdAt").Where("forum = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(fid)
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_forums").Columns("count,createdAt").Where("forum=?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(fid)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -382,7 +426,7 @@ func AnalyticsSystemViews(w http.ResponseWriter, r *http.Request, user c.User, s
|
||||
|
||||
c.DebugLog("in panel.AnalyticsSystemViews")
|
||||
// TODO: Verify the OS name is valid
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_systems").Columns("count, createdAt").Where("system = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(system)
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_systems").Columns("count,createdAt").Where("system=?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(system)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -421,7 +465,7 @@ func AnalyticsLanguageViews(w http.ResponseWriter, r *http.Request, user c.User,
|
||||
|
||||
c.DebugLog("in panel.AnalyticsLanguageViews")
|
||||
// TODO: Verify the language code is valid
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_langs").Columns("count, createdAt").Where("lang = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(lang)
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_langs").Columns("count,createdAt").Where("lang=?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(lang)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -460,7 +504,7 @@ func AnalyticsReferrerViews(w http.ResponseWriter, r *http.Request, user c.User,
|
||||
|
||||
c.DebugLog("in panel.AnalyticsReferrerViews")
|
||||
// TODO: Verify the agent is valid
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_referrers").Columns("count, createdAt").Where("domain = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(domain)
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_referrers").Columns("count,createdAt").Where("domain=?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(domain)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -491,7 +535,7 @@ func AnalyticsTopics(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
|
||||
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
|
||||
|
||||
c.DebugLog("in panel.AnalyticsTopics")
|
||||
rows, err := qgen.NewAcc().Select("topicchunks").Columns("count, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("topicchunks").Columns("count,createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -524,7 +568,7 @@ func AnalyticsPosts(w http.ResponseWriter, r *http.Request, user c.User) c.Route
|
||||
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
|
||||
|
||||
c.DebugLog("in panel.AnalyticsPosts")
|
||||
rows, err := qgen.NewAcc().Select("postchunks").Columns("count, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("postchunks").Columns("count,createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -557,7 +601,7 @@ func AnalyticsMemory(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
|
||||
revLabelList, labelList, avgMap := analyticsTimeRangeToLabelList(timeRange)
|
||||
|
||||
c.DebugLog("in panel.AnalyticsMemory")
|
||||
rows, err := qgen.NewAcc().Select("memchunks").Columns("count, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("memchunks").Columns("count,createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -593,7 +637,7 @@ func AnalyticsActiveMemory(w http.ResponseWriter, r *http.Request, user c.User)
|
||||
revLabelList, labelList, avgMap := analyticsTimeRangeToLabelList(timeRange)
|
||||
|
||||
c.DebugLog("in panel.AnalyticsActiveMemory")
|
||||
rows, err := qgen.NewAcc().Select("memchunks").Columns("stack, heap, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("memchunks").Columns("stack,heap,createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -626,6 +670,51 @@ func AnalyticsActiveMemory(w http.ResponseWriter, r *http.Request, user c.User)
|
||||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_analytics_right", "analytics", "panel_analytics_active_memory", pi})
|
||||
}
|
||||
|
||||
func AnalyticsPerf(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||
basePage, ferr := PreAnalyticsDetail(w, r, &user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
|
||||
if err != nil {
|
||||
return c.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
revLabelList, labelList, avgMap := analyticsTimeRangeToLabelList(timeRange)
|
||||
|
||||
c.DebugLog("in panel.AnalyticsPerf")
|
||||
rows, err := qgen.NewAcc().Select("perfchunks").Columns("low,high,avg,createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
var typ int
|
||||
switch r.FormValue("type") {
|
||||
case "0":
|
||||
typ = 0
|
||||
case "1":
|
||||
typ = 1
|
||||
default:
|
||||
typ = 2
|
||||
}
|
||||
avgMap, err = analyticsRowsToAverageMap3(rows, labelList, avgMap, typ)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
// TODO: Adjust for the missing chunks in week and month
|
||||
var avgList []int64
|
||||
var avgItems []c.PanelAnalyticsItemUnit
|
||||
for _, value := range revLabelList {
|
||||
avgList = append(avgList, avgMap[value])
|
||||
cv, cu := c.ConvertByteUnit(float64(avgMap[value]))
|
||||
avgItems = append(avgItems, c.PanelAnalyticsItemUnit{Time: value, Unit: cu, Count: int64(cv)})
|
||||
}
|
||||
graph := c.PanelTimeGraph{Series: [][]int64{avgList}, Labels: labelList}
|
||||
c.DebugLogf("graph: %+v\n", graph)
|
||||
pi := c.PanelAnalyticsPerf{graph, avgItems, timeRange.Range, timeRange.Unit, "time", typ}
|
||||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_analytics_right", "analytics", "panel_analytics_performance", pi})
|
||||
}
|
||||
|
||||
func analyticsRowsToRefMap(rows *sql.Rows) (map[string]int, error) {
|
||||
nameMap := make(map[string]int)
|
||||
defer rows.Close()
|
||||
@ -736,7 +825,7 @@ func AnalyticsForums(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
|
||||
}
|
||||
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
|
||||
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_forums").Columns("count, forum, createdAt").Where("forum != ''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_forums").Columns("count,forum,createdAt").Where("forum!=''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -820,7 +909,7 @@ func AnalyticsRoutes(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
|
||||
}
|
||||
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
|
||||
|
||||
rows, err := qgen.NewAcc().Select("viewchunks").Columns("count, route, createdAt").Where("route != ''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("viewchunks").Columns("count,route,createdAt").Where("route!=''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -892,7 +981,7 @@ func AnalyticsAgents(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
|
||||
}
|
||||
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
|
||||
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_agents").Columns("count, browser, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_agents").Columns("count,browser,createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -978,7 +1067,7 @@ func AnalyticsSystems(w http.ResponseWriter, r *http.Request, user c.User) c.Rou
|
||||
}
|
||||
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
|
||||
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_systems").Columns("count, system, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_systems").Columns("count,system,createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -1042,7 +1131,7 @@ func AnalyticsLanguages(w http.ResponseWriter, r *http.Request, user c.User) c.R
|
||||
}
|
||||
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
|
||||
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_langs").Columns("count, lang, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_langs").Columns("count,lang,createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
@ -1125,7 +1214,7 @@ func AnalyticsReferrers(w http.ResponseWriter, r *http.Request, user c.User) c.R
|
||||
return c.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_referrers").Columns("count, domain").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
rows, err := qgen.NewAcc().Select("viewchunks_referrers").Columns("count,domain").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ func Debug(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||
// TODO: Fetch the adapter from Builder rather than getting it from a global?
|
||||
goroutines := runtime.NumGoroutine()
|
||||
cpus := runtime.NumCPU()
|
||||
|
||||
debugTasks := c.DebugPageTasks{c.ScheduledHalfSecondTaskCount(),c.ScheduledSecondTaskCount(),c.ScheduledFifteenMinuteTaskCount(),c.ScheduledHourTaskCount(),c.ShutdownTaskCount()}
|
||||
var memStats runtime.MemStats
|
||||
runtime.ReadMemStats(&memStats)
|
||||
|
||||
@ -113,10 +115,11 @@ func Debug(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||
if fErr != nil {
|
||||
return c.InternalError(fErr,w,r)
|
||||
}
|
||||
gitSize, _ := c.DirSize("./.git")
|
||||
//gitSize, _ := c.DirSize("./.git")
|
||||
gitSize := 0
|
||||
|
||||
debugDisk := c.DebugPageDisk{staticSize,attachSize,uploadsSize,logsSize,backupsSize,gitSize}
|
||||
|
||||
pi := c.PanelDebugPage{basePage, goVersion, dbVersion, uptime, openConnCount, qgen.Builder.GetAdapter().GetName(), goroutines, cpus, memStats, debugCache, debugDatabase, debugDisk}
|
||||
pi := c.PanelDebugPage{basePage, goVersion, dbVersion, uptime, openConnCount, qgen.Builder.GetAdapter().GetName(), goroutines, cpus,debugTasks, memStats, debugCache, debugDatabase, debugDisk}
|
||||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_dashboard_right", "debug_page", "panel_debug", pi})
|
||||
}
|
||||
|
6
schema/mssql/query_perfchunks.sql
Normal file
6
schema/mssql/query_perfchunks.sql
Normal file
@ -0,0 +1,6 @@
|
||||
CREATE TABLE [perfchunks] (
|
||||
[low] int DEFAULT 0 not null,
|
||||
[high] int DEFAULT 0 not null,
|
||||
[avg] int DEFAULT 0 not null,
|
||||
[createdAt] datetime not null
|
||||
);
|
@ -21,5 +21,6 @@ CREATE TABLE [topics] (
|
||||
[poll] int DEFAULT 0 not null,
|
||||
[data] nvarchar (200) DEFAULT '' not null,
|
||||
primary key([tid]),
|
||||
fulltext key([title]),
|
||||
fulltext key([content])
|
||||
);
|
@ -6,9 +6,6 @@ ALTER TABLE `emails` ADD INDEX `i_uid` (`uid`);;
|
||||
ALTER TABLE `attachments` ADD INDEX `i_originID` (`originID`);;
|
||||
ALTER TABLE `attachments` ADD INDEX `i_path` (`path`);;
|
||||
ALTER TABLE `activity_stream_matches` ADD INDEX `i_watcher` (`watcher`);;
|
||||
ALTER TABLE `topics` ADD FULLTEXT(`title`);
|
||||
ALTER TABLE `topics` ADD FULLTEXT(`content`);
|
||||
ALTER TABLE `replies` ADD FULLTEXT(`content`);
|
||||
INSERT INTO `sync`(`last_update`) VALUES (UTC_TIMESTAMP());
|
||||
INSERT INTO `settings`(`name`,`content`,`type`,`constraints`) VALUES ('activation_type','1','list','1-3');
|
||||
INSERT INTO `settings`(`name`,`content`,`type`) VALUES ('bigpost_min_words','250','int');
|
||||
|
6
schema/mysql/query_perfchunks.sql
Normal file
6
schema/mysql/query_perfchunks.sql
Normal file
@ -0,0 +1,6 @@
|
||||
CREATE TABLE `perfchunks` (
|
||||
`low` int DEFAULT 0 not null,
|
||||
`high` int DEFAULT 0 not null,
|
||||
`avg` int DEFAULT 0 not null,
|
||||
`createdAt` datetime not null
|
||||
);
|
@ -21,5 +21,6 @@ CREATE TABLE `topics` (
|
||||
`poll` int DEFAULT 0 not null,
|
||||
`data` varchar(200) DEFAULT '' not null,
|
||||
primary key(`tid`),
|
||||
fulltext key(`title`),
|
||||
fulltext key(`content`)
|
||||
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
|
6
schema/pgsql/query_perfchunks.sql
Normal file
6
schema/pgsql/query_perfchunks.sql
Normal file
@ -0,0 +1,6 @@
|
||||
CREATE TABLE "perfchunks" (
|
||||
`low` int DEFAULT 0 not null,
|
||||
`high` int DEFAULT 0 not null,
|
||||
`avg` int DEFAULT 0 not null,
|
||||
`createdAt` timestamp not null
|
||||
);
|
@ -21,5 +21,6 @@ CREATE TABLE "topics" (
|
||||
`poll` int DEFAULT 0 not null,
|
||||
`data` varchar (200) DEFAULT '' not null,
|
||||
primary key(`tid`),
|
||||
fulltext key(`title`),
|
||||
fulltext key(`content`)
|
||||
);
|
@ -1,10 +1,10 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_active_memory_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_active_memory_head"}}</h1>
|
||||
<select form="timeRangeForm" class="typeSelector to_right autoSubmitRedirect" name="mtype">
|
||||
<option value="0"{{if eq .MemType 0}} selected{{end}}>{{lang "panel_statistics_memory_type_total"}}</option>
|
||||
<option value="1"{{if eq .MemType 1}} selected{{end}}>{{lang "panel_statistics_memory_type_stack"}}</option>
|
||||
<option value="2"{{if eq .MemType 2}} selected{{end}}>{{lang "panel_statistics_memory_type_heap"}}</option>
|
||||
<option value="0"{{if eq .MemType 0}} selected{{end}}>{{lang "panel_stats_memory_type_total"}}</option>
|
||||
<option value="1"{{if eq .MemType 1}} selected{{end}}>{{lang "panel_stats_memory_type_stack"}}</option>
|
||||
<option value="2"{{if eq .MemType 2}} selected{{end}}>{{lang "panel_stats_memory_type_heap"}}</option>
|
||||
</select>
|
||||
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
||||
{{template "panel_analytics_time_range_month.html" . }}
|
||||
@ -12,19 +12,19 @@
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/active-memory/" method="get"></form>
|
||||
<div id="panel_analytics_memory" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_statistics_memory_chart_aria"}}"></div>
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_memory_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_details_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_memory_table" class="colstack_item rowlist" aria-label="{{lang "panel_statistics_memory_table_aria"}}">
|
||||
<div id="panel_analytics_memory_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_memory_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}to_24_hour_time{{else}}to_date{{end}}">{{.Time}}</a>
|
||||
<a class="panel_upshift unix_to_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}24_hour_time{{else}}date{{end}}">{{.Time}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{.Unit}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_statistics_memory_no_memory"}}</div>{{end}}
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_memory_no_memory"}}</div>{{end}}
|
||||
</div>
|
||||
{{template "panel_analytics_script_memory.html" . }}
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{.FriendlyAgent}}{{lang "panel_statistics_views_head_suffix"}}</h1>
|
||||
<h1>{{.FriendlyAgent}}{{lang "panel_stats_views_head_suffix"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_user_agents_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_user_agents_head"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
@ -12,8 +12,8 @@
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a href="/panel/analytics/agent/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_statistics_views_suffix"}}</span>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_statistics_user_agents_no_user_agents"}}</div>{{end}}
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_user_agents_no_user_agents"}}</div>{{end}}
|
||||
</div>
|
||||
{{template "panel_analytics_script.html" . }}
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{.FriendlyAgent}}{{lang "panel_statistics_views_head_suffix"}}</h1>
|
||||
<h1>{{.FriendlyAgent}}{{lang "panel_stats_views_head_suffix"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_forums_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_forums_head"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
@ -12,8 +12,8 @@
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a href="/panel/analytics/forum/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_statistics_views_suffix"}}</span>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_statistics_forums_no_forums"}}</div>{{end}}
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_forums_no_forums"}}</div>{{end}}
|
||||
</div>
|
||||
{{template "panel_analytics_script.html" . }}
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{.FriendlyAgent}}{{lang "panel_statistics_views_head_suffix"}}</h1>
|
||||
<h1>{{.FriendlyAgent}}{{lang "panel_stats_views_head_suffix"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_languages_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_languages_head"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
@ -12,8 +12,8 @@
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a href="/panel/analytics/lang/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_statistics_views_suffix"}}</span>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_statistics_languages_no_languages"}}</div>{{end}}
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_languages_no_languages"}}</div>{{end}}
|
||||
</div>
|
||||
{{template "panel_analytics_script.html" . }}
|
@ -1,24 +1,24 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_memory_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_memory_head"}}</h1>
|
||||
{{template "panel_analytics_time_range_month.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/memory/" method="get"></form>
|
||||
<div id="panel_analytics_memory" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_statistics_memory_chart_aria"}}"></div>
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_memory_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_details_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_memory_table" class="colstack_item rowlist" aria-label="{{lang "panel_statistics_memory_table_aria"}}">
|
||||
<div id="panel_analytics_memory_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_memory_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}to_24_hour_time{{else}}to_date{{end}}">{{.Time}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{.Unit}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_statistics_memory_no_memory"}}</div>{{end}}
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_memory_no_memory"}}</div>{{end}}
|
||||
</div>
|
||||
{{template "panel_analytics_script_memory.html" . }}
|
30
templates/panel_analytics_performance.html
Normal file
30
templates/panel_analytics_performance.html
Normal file
@ -0,0 +1,30 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_perf_head"}}</h1>
|
||||
<select form="timeRangeForm" class="typeSelector to_right autoSubmitRedirect" name="type">
|
||||
<option value="0"{{if eq .PerfType 0}} selected{{end}}>{{lang "panel_stats_perf_low"}}</option>
|
||||
<option value="1"{{if eq .PerfType 1}} selected{{end}}>{{lang "panel_stats_perf_high"}}</option>
|
||||
<option value="2"{{if eq .PerfType 2}} selected{{end}}>{{lang "panel_stats_perf_avg"}}</option>
|
||||
</select>
|
||||
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
||||
{{template "panel_analytics_time_range_month.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/perf/" method="get"></form>
|
||||
<div id="panel_analytics_memory" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_perf_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_perf_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_perf_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_to_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}24_hour_time{{else}}date{{end}}">{{.Time}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{.Unit}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_perf_no_perf"}}</div>{{end}}
|
||||
</div>
|
||||
{{template "panel_analytics_script_perf.html" . }}
|
@ -1,24 +1,24 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_post_counts_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_post_counts_head"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/posts/" method="get"></form>
|
||||
<div id="panel_analytics_posts" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_statistics_post_counts_chart_aria"}}"></div>
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_post_counts_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_details_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_posts_table" class="colstack_item rowlist" aria-label="{{lang "panel_statistics_post_counts_table_aria"}}">
|
||||
<div id="panel_analytics_posts_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_post_counts_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}to_24_hour_time{{else}}to_date{{end}}">{{.Time}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_statistics_posts_suffix"}}</span>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_posts_suffix"}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_statistics_post_counts_no_post_counts"}}</div>{{end}}
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_post_counts_no_post_counts"}}</div>{{end}}
|
||||
</div>
|
||||
{{template "panel_analytics_script.html" . }}
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{.Agent}}{{lang "panel_statistics_views_head_suffix"}}</h1>
|
||||
<h1>{{.Agent}}{{lang "panel_stats_views_head_suffix"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,9 +1,9 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_referrers_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_referrers_head"}}</h1>
|
||||
<select form="timeRangeForm" class="spamSelector to_right autoSubmitRedirect" name="spam">
|
||||
<option value="0"{{if not .ShowSpam}} selected{{end}}>{{lang "panel_statistics_spam_hide"}}</option>
|
||||
<option value="1"{{if .ShowSpam}} selected{{end}}>{{lang "panel_statistics_spam_show"}}</option>
|
||||
<option value="0"{{if not .ShowSpam}} selected{{end}}>{{lang "panel_stats_spam_hide"}}</option>
|
||||
<option value="1"{{if .ShowSpam}} selected{{end}}>{{lang "panel_stats_spam_show"}}</option>
|
||||
</select>
|
||||
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
@ -14,7 +14,7 @@
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a href="/panel/analytics/referrer/{{.Agent}}" class="panel_upshift">{{.Agent}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_statistics_views_suffix"}}</span>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_statistics_referrers_no_referrers"}}</div>{{end}}
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_referrers_no_referrers"}}</div>{{end}}
|
||||
</div>
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{.Route}}{{lang "panel_statistics_views_head_suffix"}}</h1>
|
||||
<h1>{{.Route}}{{lang "panel_stats_views_head_suffix"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
@ -9,13 +9,13 @@
|
||||
<div class="ct_chart"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><a>{{lang "panel_statistics_details_head"}}</a></div>
|
||||
<div class="rowitem"><a>{{lang "panel_stats_details_head"}}</a></div>
|
||||
</div>
|
||||
<div id="panel_analytics_views_table" class="colstack_item rowlist" aria-label="{{lang "panel_statistics_route_views_table_aria"}}">
|
||||
<div id="panel_analytics_views_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_route_views_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_to_24_hour_time">{{.Time}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_statistics_views_suffix"}}</span>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_routes_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_routes_head"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
@ -12,8 +12,8 @@
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a href="/panel/analytics/route/{{.Route}}" class="panel_upshift">{{.Route}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_statistics_views_suffix"}}</span>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_statistics_routes_no_routes"}}</div>{{end}}
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_routes_no_routes"}}</div>{{end}}
|
||||
</div>
|
||||
{{template "panel_analytics_script.html" . }}
|
@ -1,21 +1,21 @@
|
||||
<script>
|
||||
let rawLabels = [{{range .Graph.Labels}}
|
||||
{{.}},{{end}}
|
||||
];
|
||||
let seriesData = [{{range .Graph.Series}}[{{range .}}
|
||||
{{.}},{{end}}
|
||||
],{{end}}
|
||||
];
|
||||
let legendNames = [{{range .Graph.Legends}}
|
||||
{{.}},{{end}}
|
||||
];
|
||||
let rawLabels = [{{range .Graph.Labels}}
|
||||
{{.}},{{end}}
|
||||
];
|
||||
let seriesData = [{{range .Graph.Series}}[{{range .}}
|
||||
{{.}},{{end}}
|
||||
],{{end}}
|
||||
];
|
||||
let legendNames = [{{range .Graph.Legends}}
|
||||
{{.}},{{end}}
|
||||
];
|
||||
|
||||
addInitHook("after_phrases", () => {
|
||||
addInitHook("end_init", () => {
|
||||
addInitHook("analytics_loaded", () => {
|
||||
memStuff(window, document, Chartist);
|
||||
buildStatsChart(rawLabels, seriesData, "{{.TimeRange}}",legendNames,true);
|
||||
});
|
||||
addInitHook("after_phrases", () => {
|
||||
addInitHook("end_init", () => {
|
||||
addInitHook("analytics_loaded", () => {
|
||||
memStuff(window, document, Chartist);
|
||||
buildStatsChart(rawLabels, seriesData, "{{.TimeRange}}",legendNames,1);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
21
templates/panel_analytics_script_perf.html
Normal file
21
templates/panel_analytics_script_perf.html
Normal file
@ -0,0 +1,21 @@
|
||||
<script>
|
||||
let rawLabels = [{{range .Graph.Labels}}
|
||||
{{.}},{{end}}
|
||||
];
|
||||
let seriesData = [{{range .Graph.Series}}[{{range .}}
|
||||
{{.}},{{end}}
|
||||
],{{end}}
|
||||
];
|
||||
let legendNames = [{{range .Graph.Legends}}
|
||||
{{.}},{{end}}
|
||||
];
|
||||
|
||||
addInitHook("after_phrases", () => {
|
||||
addInitHook("end_init", () => {
|
||||
addInitHook("analytics_loaded", () => {
|
||||
perfStuff(window, document, Chartist);
|
||||
buildStatsChart(rawLabels, seriesData, "{{.TimeRange}}",legendNames,2);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{.FriendlyAgent}}{{lang "panel_statistics_views_head_suffix"}}</h1>
|
||||
<h1>{{.FriendlyAgent}}{{lang "panel_stats_views_head_suffix"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_operating_systems_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_operating_systems_head"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
@ -12,8 +12,8 @@
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a href="/panel/analytics/system/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_statistics_views_suffix"}}</span>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_statistics_operating_systems_no_operating_systems"}}</div>{{end}}
|
||||
{{else}}<div class="rowitem passive rowmsg">{{lang "panel_stats_operating_systems_no_operating_systems"}}</div>{{end}}
|
||||
</div>
|
||||
{{template "panel_analytics_script.html" . }}
|
@ -1,11 +1,11 @@
|
||||
<select form="timeRangeForm" class="timeRangeSelector to_right autoSubmitRedirect" name="timeRange">
|
||||
<option value="one-year"{{if eq .TimeRange "one-year"}} selected{{end}}>{{lang "panel_statistics_time_range_one_year"}}</option>
|
||||
<option value="three-months"{{if eq .TimeRange "three-months"}} selected{{end}}>{{lang "panel_statistics_time_range_three_months"}}</option>
|
||||
<option value="one-month"{{if eq .TimeRange "one-month"}} selected{{end}}>{{lang "panel_statistics_time_range_one_month"}}</option>
|
||||
<option value="one-week"{{if eq .TimeRange "one-week"}} selected{{end}}>{{lang "panel_statistics_time_range_one_week"}}</option>
|
||||
<option value="two-days"{{if eq .TimeRange "two-days"}} selected{{end}}>{{lang "panel_statistics_time_range_two_days"}}</option>
|
||||
<option value="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>{{lang "panel_statistics_time_range_one_day"}}</option>
|
||||
<option value="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>{{lang "panel_statistics_time_range_twelve_hours"}}</option>
|
||||
<option value="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>{{lang "panel_statistics_time_range_six_hours"}}</option>
|
||||
<option value="one-year"{{if eq .TimeRange "one-year"}} selected{{end}}>{{lang "panel_stats_time_range_one_year"}}</option>
|
||||
<option value="three-months"{{if eq .TimeRange "three-months"}} selected{{end}}>{{lang "panel_stats_time_range_three_months"}}</option>
|
||||
<option value="one-month"{{if eq .TimeRange "one-month"}} selected{{end}}>{{lang "panel_stats_time_range_one_month"}}</option>
|
||||
<option value="one-week"{{if eq .TimeRange "one-week"}} selected{{end}}>{{lang "panel_stats_time_range_one_week"}}</option>
|
||||
<option value="two-days"{{if eq .TimeRange "two-days"}} selected{{end}}>{{lang "panel_stats_time_range_two_days"}}</option>
|
||||
<option value="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>{{lang "panel_stats_time_range_one_day"}}</option>
|
||||
<option value="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>{{lang "panel_stats_time_range_twelve_hours"}}</option>
|
||||
<option value="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>{{lang "panel_stats_time_range_six_hours"}}</option>
|
||||
</select>
|
||||
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
@ -1,9 +1,9 @@
|
||||
<select form="timeRangeForm" class="timeRangeSelector to_right autoSubmitRedirect" name="timeRange">
|
||||
<option value="one-month"{{if eq .TimeRange "one-month"}} selected{{end}}>{{lang "panel_statistics_time_range_one_month"}}</option>
|
||||
<option value="one-week"{{if eq .TimeRange "one-week"}} selected{{end}}>{{lang "panel_statistics_time_range_one_week"}}</option>
|
||||
<option value="two-days"{{if eq .TimeRange "two-days"}} selected{{end}}>{{lang "panel_statistics_time_range_two_days"}}</option>
|
||||
<option value="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>{{lang "panel_statistics_time_range_one_day"}}</option>
|
||||
<option value="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>{{lang "panel_statistics_time_range_twelve_hours"}}</option>
|
||||
<option value="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>{{lang "panel_statistics_time_range_six_hours"}}</option>
|
||||
<option value="one-month"{{if eq .TimeRange "one-month"}} selected{{end}}>{{lang "panel_stats_time_range_one_month"}}</option>
|
||||
<option value="one-week"{{if eq .TimeRange "one-week"}} selected{{end}}>{{lang "panel_stats_time_range_one_week"}}</option>
|
||||
<option value="two-days"{{if eq .TimeRange "two-days"}} selected{{end}}>{{lang "panel_stats_time_range_two_days"}}</option>
|
||||
<option value="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>{{lang "panel_stats_time_range_one_day"}}</option>
|
||||
<option value="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>{{lang "panel_stats_time_range_twelve_hours"}}</option>
|
||||
<option value="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>{{lang "panel_stats_time_range_six_hours"}}</option>
|
||||
</select>
|
||||
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
@ -1,23 +1,23 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_topic_counts_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_topic_counts_head"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/topics/" method="get"></form>
|
||||
<div id="panel_analytics_topics" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_statistics_topic_counts_chart_aria"}}"></div>
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_topic_counts_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_details_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_topics_table" class="colstack_item rowlist" aria-label="{{lang "panel_statistics_topic_counts_table_aria"}}">
|
||||
<div id="panel_analytics_topics_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_topic_counts_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}to_24_hour_time{{else}}to_date{{end}}">{{.Time}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_statistics_topics_suffix"}}</span>
|
||||
<a class="panel_upshift unix_to_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}24_hour_time{{else}}date{{end}}">{{.Time}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_topics_suffix"}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
@ -1,23 +1,23 @@
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_requests_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_requests_head"}}</h1>
|
||||
{{template "panel_analytics_time_range.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/views/" method="get"></form>
|
||||
<div id="panel_analytics_views" class="colstack_graph_holder">
|
||||
<div class="ct_chart" aria-label="{{lang "panel_statistics_requests_chart_aria"}}"></div>
|
||||
<div class="ct_chart" aria-label="{{lang "panel_stats_requests_chart_aria"}}"></div>
|
||||
</div>
|
||||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "panel_statistics_details_head"}}</h1>
|
||||
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="panel_analytics_views_table" class="colstack_item rowlist" aria-label="{{lang "panel_statistics_requests_table_aria"}}">
|
||||
<div id="panel_analytics_views_table" class="colstack_item rowlist" aria-label="{{lang "panel_stats_requests_table_aria"}}">
|
||||
{{range .ViewItems}}
|
||||
<div class="rowitem panel_compactrow editable_parent">
|
||||
<a class="panel_upshift unix_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}to_24_hour_time{{else}}to_date{{end}}">{{.Time}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_statistics_views_suffix"}}</span>
|
||||
<a class="panel_upshift unix_to_{{if or (or (or (eq $.TimeRange "six-hours") (eq $.TimeRange "twelve-hours")) (eq $.TimeRange "one-day")) (eq $.TimeRange "two-days")}}24_hour_time{{else}}date{{end}}">{{.Time}}</a>
|
||||
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
@ -24,6 +24,22 @@
|
||||
{{template "panel_debug_stat.html" .CPUs}}
|
||||
{{template "panel_debug_stat_q.html"}}
|
||||
</div>
|
||||
{{template "panel_debug_subhead.html" "panel_debug_tasks"}}
|
||||
<div id="panel_debug" class="colstack_grid">
|
||||
{{template "panel_debug_stat_head.html" "panel_debug_tasks_half_second"}}
|
||||
{{template "panel_debug_stat_head.html" "panel_debug_tasks_second"}}
|
||||
{{template "panel_debug_stat_head.html" "panel_debug_tasks_fifteen_minute"}}
|
||||
{{template "panel_debug_stat.html" .Tasks.HalfSecond}}
|
||||
{{template "panel_debug_stat.html" .Tasks.Second}}
|
||||
{{template "panel_debug_stat.html" .Tasks.FifteenMinute}}
|
||||
|
||||
{{template "panel_debug_stat_head.html" "panel_debug_tasks_hour"}}
|
||||
{{template "panel_debug_stat_head.html" "panel_debug_tasks_shutdown"}}
|
||||
{{template "panel_debug_stat_head_q.html"}}
|
||||
{{template "panel_debug_stat.html" .Tasks.Hour}}
|
||||
{{template "panel_debug_stat.html" .Tasks.Shutdown}}
|
||||
{{template "panel_debug_stat_q.html"}}
|
||||
</div>
|
||||
{{template "panel_debug_subhead.html" "panel_debug_memory_stats"}}
|
||||
<div id="panel_debug" class="colstack_grid">
|
||||
{{template "panel_debug_stat_head.html" "panel_debug_memory_stats_sys"}}
|
||||
|
@ -35,38 +35,41 @@
|
||||
</div>
|
||||
<div class="colstack_item rowmenu">
|
||||
<div class="rowitem passive">
|
||||
<a href="/panel/analytics/views/">{{lang "panel_menu_statistics"}}</a>
|
||||
<a href="/panel/analytics/views/">{{lang "panel_menu_stats"}}</a>
|
||||
</div>
|
||||
{{if eq .Zone "analytics"}}
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/posts/">{{lang "panel_menu_statistics_posts"}}</a>
|
||||
<a href="/panel/analytics/posts/">{{lang "panel_menu_stats_posts"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/topics/">{{lang "panel_menu_statistics_topics"}}</a>
|
||||
<a href="/panel/analytics/topics/">{{lang "panel_menu_stats_topics"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/forums/">{{lang "panel_menu_statistics_forums"}}</a>
|
||||
<a href="/panel/analytics/forums/">{{lang "panel_menu_stats_forums"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/routes/">{{lang "panel_menu_statistics_routes"}}</a>
|
||||
<a href="/panel/analytics/routes/">{{lang "panel_menu_stats_routes"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/agents/">{{lang "panel_menu_statistics_agents"}}</a>
|
||||
<a href="/panel/analytics/agents/">{{lang "panel_menu_stats_agents"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/systems/">{{lang "panel_menu_statistics_systems"}}</a>
|
||||
<a href="/panel/analytics/systems/">{{lang "panel_menu_stats_systems"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/langs/">{{lang "panel_menu_statistics_languages"}}</a>
|
||||
<a href="/panel/analytics/langs/">{{lang "panel_menu_stats_languages"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/referrers/">{{lang "panel_menu_statistics_referrers"}}</a>
|
||||
<a href="/panel/analytics/referrers/">{{lang "panel_menu_stats_referrers"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/memory/">{{lang "panel_menu_statistics_memory"}}</a>
|
||||
<a href="/panel/analytics/memory/">{{lang "panel_menu_stats_memory"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/active-memory/">{{lang "panel_menu_statistics_active_memory"}}</a>
|
||||
<a href="/panel/analytics/active-memory/">{{lang "panel_menu_stats_active_memory"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/perf/">{{lang "panel_menu_stats_perf"}}</a>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="rowitem passive">
|
||||
|
@ -35,38 +35,41 @@
|
||||
</div>
|
||||
<div class="colstack_item rowmenu">
|
||||
<div class="rowitem passive">
|
||||
<a href="/panel/analytics/views/">{{lang "panel_menu_statistics"}}</a>
|
||||
<a href="/panel/analytics/views/">{{lang "panel_menu_stats"}}</a>
|
||||
</div>
|
||||
{{if eq .Zone "analytics"}}
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/posts/">{{lang "panel_menu_statistics_posts"}}</a>
|
||||
<a href="/panel/analytics/posts/">{{lang "panel_menu_stats_posts"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/topics/">{{lang "panel_menu_statistics_topics"}}</a>
|
||||
<a href="/panel/analytics/topics/">{{lang "panel_menu_stats_topics"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/forums/">{{lang "panel_menu_statistics_forums"}}</a>
|
||||
<a href="/panel/analytics/forums/">{{lang "panel_menu_stats_forums"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/routes/">{{lang "panel_menu_statistics_routes"}}</a>
|
||||
<a href="/panel/analytics/routes/">{{lang "panel_menu_stats_routes"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/agents/">{{lang "panel_menu_statistics_agents"}}</a>
|
||||
<a href="/panel/analytics/agents/">{{lang "panel_menu_stats_agents"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/systems/">{{lang "panel_menu_statistics_systems"}}</a>
|
||||
<a href="/panel/analytics/systems/">{{lang "panel_menu_stats_systems"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/langs/">{{lang "panel_menu_statistics_languages"}}</a>
|
||||
<a href="/panel/analytics/langs/">{{lang "panel_menu_stats_languages"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/referrers/">{{lang "panel_menu_statistics_referrers"}}</a>
|
||||
<a href="/panel/analytics/referrers/">{{lang "panel_menu_stats_referrers"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/memory/">{{lang "panel_menu_statistics_memory"}}</a>
|
||||
<a href="/panel/analytics/memory/">{{lang "panel_menu_stats_memory"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/active-memory/">{{lang "panel_menu_statistics_active_memory"}}</a>
|
||||
<a href="/panel/analytics/active-memory/">{{lang "panel_menu_stats_active_memory"}}</a>
|
||||
</div>
|
||||
<div class="rowitem passive submenu">
|
||||
<a href="/panel/analytics/perf/">{{lang "panel_menu_stats_perf"}}</a>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="rowitem passive">
|
||||
|
Loading…
Reference in New Issue
Block a user