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,
|
}, 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", "", "",
|
createTable("sync", "", "",
|
||||||
[]tC{
|
[]tC{
|
||||||
tC{"last_update", "datetime", 0, false, false, ""},
|
tC{"last_update", "datetime", 0, false, false, ""},
|
||||||
|
|
|
@ -35,10 +35,12 @@ type SQLModLogStore struct {
|
||||||
|
|
||||||
func NewModLogStore(acc *qgen.Accumulator) (*SQLModLogStore, error) {
|
func NewModLogStore(acc *qgen.Accumulator) (*SQLModLogStore, error) {
|
||||||
ml := "moderation_logs"
|
ml := "moderation_logs"
|
||||||
|
// TODO: Shorten name of ipaddress column to ip
|
||||||
|
cols := "action, elementID, elementType, ipaddress, actorID, doneAt, extra"
|
||||||
return &SQLModLogStore{
|
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(),
|
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()
|
}, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +93,11 @@ type SQLAdminLogStore struct {
|
||||||
|
|
||||||
func NewAdminLogStore(acc *qgen.Accumulator) (*SQLAdminLogStore, error) {
|
func NewAdminLogStore(acc *qgen.Accumulator) (*SQLAdminLogStore, error) {
|
||||||
al := "administration_logs"
|
al := "administration_logs"
|
||||||
|
cols := "action, elementID, elementType, ipaddress, actorID, doneAt, extra"
|
||||||
return &SQLAdminLogStore{
|
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(),
|
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()
|
}, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,3 +40,13 @@ type RWMutexCounterBucket struct {
|
||||||
counter int
|
counter int
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MutexCounterBucket struct {
|
||||||
|
counter int
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type MutexCounter64Bucket struct {
|
||||||
|
counter int64
|
||||||
|
sync.Mutex
|
||||||
|
}
|
|
@ -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"
|
"sync/atomic"
|
||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
"github.com/Azareal/Gosora/query_gen"
|
qgen "github.com/Azareal/Gosora/query_gen"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ func NewPostCounter() (*DefaultPostCounter, error) {
|
||||||
acc := qgen.NewAcc()
|
acc := qgen.NewAcc()
|
||||||
co := &DefaultPostCounter{
|
co := &DefaultPostCounter{
|
||||||
currentBucket: 0,
|
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.AddScheduledFifteenMinuteTask(co.Tick)
|
||||||
//c.AddScheduledSecondTask(co.Tick)
|
//c.AddScheduledSecondTask(co.Tick)
|
||||||
|
@ -44,7 +44,7 @@ func (co *DefaultPostCounter) Tick() (err error) {
|
||||||
atomic.AddInt64(&co.buckets[oldBucket], -previousViewChunk)
|
atomic.AddInt64(&co.buckets[oldBucket], -previousViewChunk)
|
||||||
err = co.insertChunk(previousViewChunk)
|
err = co.insertChunk(previousViewChunk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(errors.WithStack(err),"post counter")
|
return errors.Wrap(errors.WithStack(err), "post counter")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
"github.com/Azareal/Gosora/query_gen"
|
qgen "github.com/Azareal/Gosora/query_gen"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ func NewDefaultReferrerTracker() (*DefaultReferrerTracker, error) {
|
||||||
refTracker := &DefaultReferrerTracker{
|
refTracker := &DefaultReferrerTracker{
|
||||||
odd: make(map[string]*ReferrerItem),
|
odd: make(map[string]*ReferrerItem),
|
||||||
even: 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.AddScheduledFifteenMinuteTask(refTracker.Tick)
|
||||||
//c.AddScheduledSecondTask(refTracker.Tick)
|
//c.AddScheduledSecondTask(refTracker.Tick)
|
||||||
|
@ -51,7 +51,7 @@ func (ref *DefaultReferrerTracker) Tick() (err error) {
|
||||||
if count != 0 {
|
if count != 0 {
|
||||||
err := ref.insertChunk(referrer, count) // TODO: Bulk insert for speed?
|
err := ref.insertChunk(referrer, count) // TODO: Bulk insert for speed?
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(errors.WithStack(err),"ref counter")
|
return errors.Wrap(errors.WithStack(err), "ref counter")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(referrersToDelete, referrer)
|
delete(referrersToDelete, referrer)
|
||||||
|
@ -69,16 +69,16 @@ func (ref *DefaultReferrerTracker) Tick() (err error) {
|
||||||
count := atomic.SwapInt64(&counter.Count, 0)
|
count := atomic.SwapInt64(&counter.Count, 0)
|
||||||
err := ref.insertChunk(referrer, count) // TODO: Bulk insert for speed?
|
err := ref.insertChunk(referrer, count) // TODO: Bulk insert for speed?
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(errors.WithStack(err),"ref counter")
|
return errors.Wrap(errors.WithStack(err), "ref counter")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err = refLoop(&ref.oddLock,ref.odd)
|
err = refLoop(&ref.oddLock, ref.odd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return refLoop(&ref.evenLock,ref.even)
|
return refLoop(&ref.evenLock, ref.even)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ref *DefaultReferrerTracker) insertChunk(referrer string, count int64) error {
|
func (ref *DefaultReferrerTracker) insertChunk(referrer string, count int64) error {
|
||||||
|
|
|
@ -23,7 +23,7 @@ type DefaultViewCounter struct {
|
||||||
func NewGlobalViewCounter(acc *qgen.Accumulator) (*DefaultViewCounter, error) {
|
func NewGlobalViewCounter(acc *qgen.Accumulator) (*DefaultViewCounter, error) {
|
||||||
co := &DefaultViewCounter{
|
co := &DefaultViewCounter{
|
||||||
currentBucket: 0,
|
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.AddScheduledFifteenMinuteTask(co.Tick) // This is run once every fifteen minutes to match the frequency of the RouteViewCounter
|
||||||
//c.AddScheduledSecondTask(co.Tick)
|
//c.AddScheduledSecondTask(co.Tick)
|
||||||
|
@ -31,6 +31,7 @@ func NewGlobalViewCounter(acc *qgen.Accumulator) (*DefaultViewCounter, error) {
|
||||||
return co, acc.FirstError()
|
return co, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Simplify the atomics used here
|
||||||
func (co *DefaultViewCounter) Tick() (err error) {
|
func (co *DefaultViewCounter) Tick() (err error) {
|
||||||
oldBucket := co.currentBucket
|
oldBucket := co.currentBucket
|
||||||
var nextBucket int64 // 0
|
var nextBucket int64 // 0
|
||||||
|
|
|
@ -354,6 +354,14 @@ type PanelAnalyticsActiveMemory struct {
|
||||||
TimeType string
|
TimeType string
|
||||||
MemType int
|
MemType int
|
||||||
}
|
}
|
||||||
|
type PanelAnalyticsPerf struct {
|
||||||
|
Graph PanelTimeGraph
|
||||||
|
ViewItems []PanelAnalyticsItemUnit
|
||||||
|
TimeRange string
|
||||||
|
Unit string
|
||||||
|
TimeType string
|
||||||
|
PerfType int
|
||||||
|
}
|
||||||
|
|
||||||
type PanelStats struct {
|
type PanelStats struct {
|
||||||
Users int
|
Users int
|
||||||
|
@ -654,6 +662,14 @@ type PanelRegLogsPage struct {
|
||||||
Paginator
|
Paginator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DebugPageTasks struct {
|
||||||
|
HalfSecond int
|
||||||
|
Second int
|
||||||
|
FifteenMinute int
|
||||||
|
Hour int
|
||||||
|
Shutdown int
|
||||||
|
}
|
||||||
|
|
||||||
type DebugPageCache struct {
|
type DebugPageCache struct {
|
||||||
Topics int
|
Topics int
|
||||||
Users int
|
Users int
|
||||||
|
@ -711,8 +727,9 @@ type PanelDebugPage struct {
|
||||||
|
|
||||||
Goroutines int
|
Goroutines int
|
||||||
CPUs int
|
CPUs int
|
||||||
MemStats runtime.MemStats
|
|
||||||
|
|
||||||
|
Tasks DebugPageTasks
|
||||||
|
MemStats runtime.MemStats
|
||||||
Cache DebugPageCache
|
Cache DebugPageCache
|
||||||
Database DebugPageDatabase
|
Database DebugPageDatabase
|
||||||
Disk DebugPageDisk
|
Disk DebugPageDisk
|
||||||
|
|
|
@ -113,25 +113,25 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (header
|
||||||
}
|
}
|
||||||
// TODO: We should probably initialise header.ExtData
|
// 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
|
// ? - 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.StartedAt = time.Now()
|
||||||
}
|
//}
|
||||||
|
|
||||||
header.AddSheet(theme.Name + "/main.css")
|
header.AddSheet(theme.Name + "/main.css")
|
||||||
header.AddSheet(theme.Name + "/panel.css")
|
header.AddSheet(theme.Name + "/panel.css")
|
||||||
if len(theme.Resources) > 0 {
|
if len(theme.Resources) > 0 {
|
||||||
rlist := theme.Resources
|
rlist := theme.Resources
|
||||||
for _, resource := range rlist {
|
for _, res := range rlist {
|
||||||
if resource.Location == "global" || resource.Location == "panel" {
|
if res.Location == "global" || res.Location == "panel" {
|
||||||
extarr := strings.Split(resource.Name, ".")
|
extarr := strings.Split(res.Name, ".")
|
||||||
ext := extarr[len(extarr)-1]
|
ext := extarr[len(extarr)-1]
|
||||||
if ext == "css" {
|
if ext == "css" {
|
||||||
header.AddSheet(resource.Name)
|
header.AddSheet(res.Name)
|
||||||
} else if ext == "js" {
|
} else if ext == "js" {
|
||||||
if resource.Async {
|
if res.Async {
|
||||||
header.AddScriptAsync(resource.Name)
|
header.AddScriptAsync(res.Name)
|
||||||
} else {
|
} 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
|
// 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
|
// ? - 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.StartedAt = time.Now()
|
||||||
}
|
//}
|
||||||
|
|
||||||
//PrepResources(user,header,theme)
|
//PrepResources(user,header,theme)
|
||||||
return header, nil
|
return header, nil
|
||||||
|
@ -237,20 +237,20 @@ func PrepResources(user *User, h *Header, theme *Theme) {
|
||||||
|
|
||||||
if len(theme.Resources) > 0 {
|
if len(theme.Resources) > 0 {
|
||||||
rlist := theme.Resources
|
rlist := theme.Resources
|
||||||
for _, resource := range rlist {
|
for _, res := range rlist {
|
||||||
if resource.Loggedin && !user.Loggedin {
|
if res.Loggedin && !user.Loggedin {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if resource.Location == "global" || resource.Location == "frontend" {
|
if res.Location == "global" || res.Location == "frontend" {
|
||||||
extarr := strings.Split(resource.Name, ".")
|
extarr := strings.Split(res.Name, ".")
|
||||||
ext := extarr[len(extarr)-1]
|
ext := extarr[len(extarr)-1]
|
||||||
if ext == "css" {
|
if ext == "css" {
|
||||||
h.AddSheet(resource.Name)
|
h.AddSheet(res.Name)
|
||||||
} else if ext == "js" {
|
} else if ext == "js" {
|
||||||
if resource.Async {
|
if res.Async {
|
||||||
h.AddScriptAsync(resource.Name)
|
h.AddScriptAsync(res.Name)
|
||||||
} else {
|
} else {
|
||||||
h.AddScript(resource.Name)
|
h.AddScript(res.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,27 @@ func AddShutdownTask(task func() error) {
|
||||||
ShutdownTasks = append(ShutdownTasks, task)
|
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
|
// TODO: Use AddScheduledSecondTask
|
||||||
func HandleExpiredScheduledGroups() error {
|
func HandleExpiredScheduledGroups() error {
|
||||||
rows, err := taskStmts.getExpiredScheduledGroups.Query()
|
rows, err := taskStmts.getExpiredScheduledGroups.Query()
|
||||||
|
|
|
@ -372,10 +372,11 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
||||||
dbVersion := qgen.Builder.DbVersion()
|
dbVersion := qgen.Builder.DbVersion()
|
||||||
var memStats runtime.MemStats
|
var memStats runtime.MemStats
|
||||||
runtime.ReadMemStats(&memStats)
|
runtime.ReadMemStats(&memStats)
|
||||||
|
debugTasks := DebugPageTasks{0,0,0,0,0}
|
||||||
debugCache := DebugPageCache{1, 1, 1, 2, 2, 2, true}
|
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}
|
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}
|
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_debug", "c.PanelDebugPage", dpage)
|
||||||
//t.AddStd("panel_analytics", "c.PanelAnalytics", Panel{basePage, "panel_dashboard_right","panel_dashboard", inter})
|
//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_menus":"Menus",
|
||||||
"panel_menu_widgets":"Widgets",
|
"panel_menu_widgets":"Widgets",
|
||||||
"panel_menu_events":"Events",
|
"panel_menu_events":"Events",
|
||||||
"panel_menu_statistics":"Statistics",
|
"panel_menu_stats":"Statistics",
|
||||||
"panel_menu_statistics_posts":"Posts",
|
"panel_menu_stats_posts":"Posts",
|
||||||
"panel_menu_statistics_topics":"Topics",
|
"panel_menu_stats_topics":"Topics",
|
||||||
"panel_menu_statistics_forums":"Forums",
|
"panel_menu_stats_forums":"Forums",
|
||||||
"panel_menu_statistics_routes":"Routes",
|
"panel_menu_stats_routes":"Routes",
|
||||||
"panel_menu_statistics_agents":"Agents",
|
"panel_menu_stats_agents":"Agents",
|
||||||
"panel_menu_statistics_systems":"Systems",
|
"panel_menu_stats_systems":"Systems",
|
||||||
"panel_menu_statistics_languages":"Languages",
|
"panel_menu_stats_languages":"Languages",
|
||||||
"panel_menu_statistics_referrers":"Referrers",
|
"panel_menu_stats_referrers":"Referrers",
|
||||||
"panel_menu_statistics_memory":"Memory",
|
"panel_menu_stats_memory":"Memory",
|
||||||
"panel_menu_statistics_active_memory":"Active Memory",
|
"panel_menu_stats_active_memory":"Active Memory",
|
||||||
|
"panel_menu_stats_perf":"Performance",
|
||||||
"panel_menu_reports":"Reports",
|
"panel_menu_reports":"Reports",
|
||||||
"panel_menu_logs":"Logs",
|
"panel_menu_logs":"Logs",
|
||||||
"panel_menu_logs_registrations":"Registrations",
|
"panel_menu_logs_registrations":"Registrations",
|
||||||
|
@ -975,56 +976,60 @@
|
||||||
"panel_pages_title":"Title",
|
"panel_pages_title":"Title",
|
||||||
"panel_pages_edit_update_button":"Update Page",
|
"panel_pages_edit_update_button":"Update Page",
|
||||||
|
|
||||||
"panel_statistics_views_head_suffix":" Views",
|
"panel_stats_views_head_suffix":" Views",
|
||||||
"panel_statistics_user_agents_head":"User Agents",
|
"panel_stats_user_agents_head":"User Agents",
|
||||||
"panel_statistics_forums_head":"Forums",
|
"panel_stats_forums_head":"Forums",
|
||||||
"panel_statistics_languages_head":"Languages",
|
"panel_stats_languages_head":"Languages",
|
||||||
"panel_statistics_post_counts_head":"Post Counts",
|
"panel_stats_post_counts_head":"Post Counts",
|
||||||
"panel_statistics_referrers_head":"Referrers",
|
"panel_stats_referrers_head":"Referrers",
|
||||||
"panel_statistics_routes_head":"Routes",
|
"panel_stats_routes_head":"Routes",
|
||||||
"panel_statistics_operating_systems_head":"Operating Systems",
|
"panel_stats_operating_systems_head":"Operating Systems",
|
||||||
"panel_statistics_topic_counts_head":"Topic Counts",
|
"panel_stats_topic_counts_head":"Topic Counts",
|
||||||
"panel_statistics_requests_head":"Requests",
|
"panel_stats_requests_head":"Requests",
|
||||||
"panel_statistics_memory_head":"Memory Usage",
|
"panel_stats_memory_head":"Memory Usage",
|
||||||
"panel_statistics_active_memory_head":"Active Memory",
|
"panel_stats_active_memory_head":"Active Memory",
|
||||||
|
"panel_stats_perf_head":"Performance",
|
||||||
|
|
||||||
"panel_statistics_spam_hide":"Hide Spam",
|
"panel_stats_spam_hide":"Hide Spam",
|
||||||
"panel_statistics_spam_show":"Show Spam",
|
"panel_stats_spam_show":"Show Spam",
|
||||||
"panel_statistics_memory_type_total":"Total",
|
"panel_stats_memory_type_total":"Total",
|
||||||
"panel_statistics_memory_type_stack":"Stack",
|
"panel_stats_memory_type_stack":"Stack",
|
||||||
"panel_statistics_memory_type_heap":"Heap",
|
"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_stats_time_range_one_year":"1 year",
|
||||||
"panel_statistics_time_range_three_months":"3 months",
|
"panel_stats_time_range_three_months":"3 months",
|
||||||
"panel_statistics_time_range_one_month":"1 month",
|
"panel_stats_time_range_one_month":"1 month",
|
||||||
"panel_statistics_time_range_one_week":"1 week",
|
"panel_stats_time_range_one_week":"1 week",
|
||||||
"panel_statistics_time_range_two_days":"2 days",
|
"panel_stats_time_range_two_days":"2 days",
|
||||||
"panel_statistics_time_range_one_day":"1 day",
|
"panel_stats_time_range_one_day":"1 day",
|
||||||
"panel_statistics_time_range_twelve_hours":"12 hours",
|
"panel_stats_time_range_twelve_hours":"12 hours",
|
||||||
"panel_statistics_time_range_six_hours":"6 hours",
|
"panel_stats_time_range_six_hours":"6 hours",
|
||||||
|
|
||||||
"panel_statistics_post_counts_chart_aria":"Post Chart",
|
"panel_stats_post_counts_chart_aria":"Post Chart",
|
||||||
"panel_statistics_topic_counts_chart_aria":"Topic Chart",
|
"panel_stats_topic_counts_chart_aria":"Topic Chart",
|
||||||
"panel_statistics_requests_chart_aria":"Requests Chart",
|
"panel_stats_requests_chart_aria":"Requests Chart",
|
||||||
"panel_statistics_memory_chart_aria":"Memory Use Chart",
|
"panel_stats_memory_chart_aria":"Memory Use Chart",
|
||||||
"panel_statistics_details_head":"Details",
|
"panel_stats_details_head":"Details",
|
||||||
"panel_statistics_post_counts_table_aria":"Post Table, this has the same information as the post chart",
|
"panel_stats_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_stats_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_stats_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_stats_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_stats_memory_table_aria":"Memory Use Table, this has the same information as the memory use chart",
|
||||||
"panel_statistics_views_suffix":" views",
|
"panel_stats_views_suffix":" views",
|
||||||
"panel_statistics_posts_suffix":" posts",
|
"panel_stats_posts_suffix":" posts",
|
||||||
"panel_statistics_topics_suffix":" topics",
|
"panel_stats_topics_suffix":" topics",
|
||||||
|
|
||||||
"panel_statistics_user_agents_no_user_agents":"No user agents 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_statistics_forums_no_forums":"No forum view counts 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_statistics_languages_no_languages":"No language could be found in the selected time range",
|
"panel_stats_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_stats_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_stats_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_stats_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_stats_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_memory_no_memory":"No memory chunks could be found in the selected time range",
|
||||||
|
|
||||||
"panel_logs_menu_head":"Logs",
|
"panel_logs_menu_head":"Logs",
|
||||||
"panel_logs_reg_head":"Registrations",
|
"panel_logs_reg_head":"Registrations",
|
||||||
|
@ -1173,6 +1178,13 @@
|
||||||
"panel_debug_goroutine_count_label":"Goroutines",
|
"panel_debug_goroutine_count_label":"Goroutines",
|
||||||
"panel_debug_cpu_count_label":"CPUs",
|
"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":"Memory Statistics",
|
||||||
"panel_debug_memory_stats_sys":"Sys",
|
"panel_debug_memory_stats_sys":"Sys",
|
||||||
"panel_debug_memory_stats_heapsys":"HeapSys",
|
"panel_debug_memory_stats_heapsys":"HeapSys",
|
||||||
|
|
|
@ -49,6 +49,7 @@ func init() {
|
||||||
addPatch(29, patch29)
|
addPatch(29, patch29)
|
||||||
addPatch(30, patch30)
|
addPatch(30, patch30)
|
||||||
addPatch(31, patch31)
|
addPatch(31, patch31)
|
||||||
|
addPatch(32, patch32)
|
||||||
}
|
}
|
||||||
|
|
||||||
func patch0(scanner *bufio.Scanner) (err error) {
|
func patch0(scanner *bufio.Scanner) (err error) {
|
||||||
|
@ -892,3 +893,15 @@ func patch31(scanner *bufio.Scanner) error {
|
||||||
}
|
}
|
||||||
return nil
|
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 Kilobyte = 1024;
|
||||||
const Megabyte = Kilobyte * 1024;
|
const Megabyte = Kilobyte * 1024;
|
||||||
const Gigabyte = Megabyte * 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: Fully localise this
|
||||||
// TODO: Load rawLabels and seriesData dynamically rather than potentially fiddling with nonces for the CSP?
|
// 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("buildStatsChart");
|
||||||
console.log("seriesData:",seriesData);
|
console.log("seriesData:",seriesData);
|
||||||
let labels = [];
|
let labels = [];
|
||||||
|
@ -122,7 +183,8 @@ function buildStatsChart(rawLabels, seriesData, timeRange, legendNames, bytes =
|
||||||
if(legendNames.length > 0) config.plugins = [
|
if(legendNames.length > 0) config.plugins = [
|
||||||
Chartist.plugins.legend({legendNames: legendNames})
|
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', {
|
Chartist.Line('.ct_chart', {
|
||||||
labels: labels,
|
labels: labels,
|
||||||
series: seriesData,
|
series: seriesData,
|
||||||
|
|
|
@ -258,6 +258,7 @@ func panelRoutes() *RouteGroup {
|
||||||
View("panel.AnalyticsActiveMemory", "/panel/analytics/active-memory/").Before("ParseForm"),
|
View("panel.AnalyticsActiveMemory", "/panel/analytics/active-memory/").Before("ParseForm"),
|
||||||
View("panel.AnalyticsTopics", "/panel/analytics/topics/").Before("ParseForm"),
|
View("panel.AnalyticsTopics", "/panel/analytics/topics/").Before("ParseForm"),
|
||||||
View("panel.AnalyticsForums", "/panel/analytics/forums/").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.Groups", "/panel/groups/"),
|
||||||
View("panel.GroupsEdit", "/panel/groups/edit/", "extraData"),
|
View("panel.GroupsEdit", "/panel/groups/edit/", "extraData"),
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
|
co "github.com/Azareal/Gosora/common/counters"
|
||||||
)
|
)
|
||||||
|
|
||||||
var successJSONBytes = []byte(`{"success":1}`)
|
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)
|
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)
|
err := renderTemplate3(tmplName, tmplName, w, r, header, pi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
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
|
s := h.Stylesheets
|
||||||
h.Stylesheets = nil
|
h.Stylesheets = nil
|
||||||
c.PrepResources(&h.CurrentUser, h, h.Theme)
|
c.PrepResources(&h.CurrentUser, h, h.Theme)
|
||||||
|
@ -134,9 +135,11 @@ func renderTemplate3(tmplName string, hookName string, w http.ResponseWriter, r
|
||||||
}
|
}
|
||||||
|
|
||||||
FootHeaders(w, h)
|
FootHeaders(w, h)
|
||||||
if h.CurrentUser.IsAdmin {
|
since := time.Since(h.StartedAt)
|
||||||
h.Elapsed1 = time.Since(h.StartedAt).String()
|
//if h.CurrentUser.IsAdmin {
|
||||||
}
|
h.Elapsed1 = since.String()
|
||||||
|
//}
|
||||||
|
co.PerfCounter.Push(since)
|
||||||
if c.RunPreRenderHook("pre_render_"+hookName, w, r, &h.CurrentUser, pi) {
|
if c.RunPreRenderHook("pre_render_"+hookName, w, r, &h.CurrentUser, pi) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
p "github.com/Azareal/Gosora/common/phrases"
|
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
|
// TODO: Move this to another file, probably common/pages.go
|
||||||
|
@ -25,11 +25,11 @@ type AnalyticsTimeRange struct {
|
||||||
|
|
||||||
func analyticsTimeRange(rawTimeRange string) (*AnalyticsTimeRange, error) {
|
func analyticsTimeRange(rawTimeRange string) (*AnalyticsTimeRange, error) {
|
||||||
tRange := &AnalyticsTimeRange{
|
tRange := &AnalyticsTimeRange{
|
||||||
Quantity: 6,
|
Quantity: 6,
|
||||||
Unit: "hour",
|
Unit: "hour",
|
||||||
Slices: 12,
|
Slices: 12,
|
||||||
SliceWidth: 60 * 30,
|
SliceWidth: 60 * 30,
|
||||||
Range: "six-hours",
|
Range: "six-hours",
|
||||||
}
|
}
|
||||||
|
|
||||||
switch rawTimeRange {
|
switch rawTimeRange {
|
||||||
|
@ -198,6 +198,50 @@ func analyticsRowsToAverageMap2(rows *sql.Rows, labelList []int64, avgMap map[in
|
||||||
return avgMap, rows.Err()
|
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) {
|
func PreAnalyticsDetail(w http.ResponseWriter, r *http.Request, user *c.User) (*c.BasePanelPage, c.RouteError) {
|
||||||
bp, ferr := buildBasePage(w, r, user, "analytics", "analytics")
|
bp, ferr := buildBasePage(w, r, user, "analytics", "analytics")
|
||||||
if ferr != nil {
|
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")
|
c.DebugLog("in panel.AnalyticsViews")
|
||||||
// TODO: Add some sort of analytics store / iterator?
|
// 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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
@ -232,8 +276,8 @@ func AnalyticsViews(w http.ResponseWriter, r *http.Request, user c.User) c.Route
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewList := make([]int64,len(revLabelList))
|
viewList := make([]int64, len(revLabelList))
|
||||||
viewItems := make([]c.PanelAnalyticsItem,len(revLabelList))
|
viewItems := make([]c.PanelAnalyticsItem, len(revLabelList))
|
||||||
for i, value := range revLabelList {
|
for i, value := range revLabelList {
|
||||||
viewList[i] = viewMap[value]
|
viewList[i] = viewMap[value]
|
||||||
viewItems[i] = c.PanelAnalyticsItem{Time: value, Count: viewMap[value]}
|
viewItems[i] = c.PanelAnalyticsItem{Time: value, Count: viewMap[value]}
|
||||||
|
@ -263,7 +307,7 @@ func AnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user c.User, ro
|
||||||
|
|
||||||
c.DebugLog("in panel.AnalyticsRouteViews")
|
c.DebugLog("in panel.AnalyticsRouteViews")
|
||||||
// TODO: Validate the route is valid
|
// 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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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")
|
c.DebugLog("in panel.AnalyticsAgentViews")
|
||||||
// TODO: Verify the agent is valid
|
// 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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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")
|
c.DebugLog("in panel.AnalyticsForumViews")
|
||||||
// TODO: Verify the agent is valid
|
// 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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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")
|
c.DebugLog("in panel.AnalyticsSystemViews")
|
||||||
// TODO: Verify the OS name is valid
|
// 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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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")
|
c.DebugLog("in panel.AnalyticsLanguageViews")
|
||||||
// TODO: Verify the language code is valid
|
// 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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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")
|
c.DebugLog("in panel.AnalyticsReferrerViews")
|
||||||
// TODO: Verify the agent is valid
|
// 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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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)
|
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
|
||||||
|
|
||||||
c.DebugLog("in panel.AnalyticsTopics")
|
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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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)
|
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
|
||||||
|
|
||||||
c.DebugLog("in panel.AnalyticsPosts")
|
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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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)
|
revLabelList, labelList, avgMap := analyticsTimeRangeToLabelList(timeRange)
|
||||||
|
|
||||||
c.DebugLog("in panel.AnalyticsMemory")
|
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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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)
|
revLabelList, labelList, avgMap := analyticsTimeRangeToLabelList(timeRange)
|
||||||
|
|
||||||
c.DebugLog("in panel.AnalyticsActiveMemory")
|
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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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})
|
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) {
|
func analyticsRowsToRefMap(rows *sql.Rows) (map[string]int, error) {
|
||||||
nameMap := make(map[string]int)
|
nameMap := make(map[string]int)
|
||||||
defer rows.Close()
|
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)
|
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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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)
|
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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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)
|
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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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)
|
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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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)
|
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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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)
|
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 {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return c.InternalError(err, w, r)
|
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?
|
// TODO: Fetch the adapter from Builder rather than getting it from a global?
|
||||||
goroutines := runtime.NumGoroutine()
|
goroutines := runtime.NumGoroutine()
|
||||||
cpus := runtime.NumCPU()
|
cpus := runtime.NumCPU()
|
||||||
|
|
||||||
|
debugTasks := c.DebugPageTasks{c.ScheduledHalfSecondTaskCount(),c.ScheduledSecondTaskCount(),c.ScheduledFifteenMinuteTaskCount(),c.ScheduledHourTaskCount(),c.ShutdownTaskCount()}
|
||||||
var memStats runtime.MemStats
|
var memStats runtime.MemStats
|
||||||
runtime.ReadMemStats(&memStats)
|
runtime.ReadMemStats(&memStats)
|
||||||
|
|
||||||
|
@ -113,10 +115,11 @@ func Debug(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||||
if fErr != nil {
|
if fErr != nil {
|
||||||
return c.InternalError(fErr,w,r)
|
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}
|
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})
|
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_dashboard_right", "debug_page", "panel_debug", pi})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
[poll] int DEFAULT 0 not null,
|
||||||
[data] nvarchar (200) DEFAULT '' not null,
|
[data] nvarchar (200) DEFAULT '' not null,
|
||||||
primary key([tid]),
|
primary key([tid]),
|
||||||
|
fulltext key([title]),
|
||||||
fulltext key([content])
|
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_originID` (`originID`);;
|
||||||
ALTER TABLE `attachments` ADD INDEX `i_path` (`path`);;
|
ALTER TABLE `attachments` ADD INDEX `i_path` (`path`);;
|
||||||
ALTER TABLE `activity_stream_matches` ADD INDEX `i_watcher` (`watcher`);;
|
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 `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`,`constraints`) VALUES ('activation_type','1','list','1-3');
|
||||||
INSERT INTO `settings`(`name`,`content`,`type`) VALUES ('bigpost_min_words','250','int');
|
INSERT INTO `settings`(`name`,`content`,`type`) VALUES ('bigpost_min_words','250','int');
|
||||||
|
|
|
@ -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,
|
`poll` int DEFAULT 0 not null,
|
||||||
`data` varchar(200) DEFAULT '' not null,
|
`data` varchar(200) DEFAULT '' not null,
|
||||||
primary key(`tid`),
|
primary key(`tid`),
|
||||||
|
fulltext key(`title`),
|
||||||
fulltext key(`content`)
|
fulltext key(`content`)
|
||||||
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
|
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
|
|
@ -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,
|
`poll` int DEFAULT 0 not null,
|
||||||
`data` varchar (200) DEFAULT '' not null,
|
`data` varchar (200) DEFAULT '' not null,
|
||||||
primary key(`tid`),
|
primary key(`tid`),
|
||||||
|
fulltext key(`title`),
|
||||||
fulltext key(`content`)
|
fulltext key(`content`)
|
||||||
);
|
);
|
|
@ -1,10 +1,10 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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">
|
<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="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_statistics_memory_type_stack"}}</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_statistics_memory_type_heap"}}</option>
|
<option value="2"{{if eq .MemType 2}} selected{{end}}>{{lang "panel_stats_memory_type_heap"}}</option>
|
||||||
</select>
|
</select>
|
||||||
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
||||||
{{template "panel_analytics_time_range_month.html" . }}
|
{{template "panel_analytics_time_range_month.html" . }}
|
||||||
|
@ -12,19 +12,19 @@
|
||||||
</div>
|
</div>
|
||||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/active-memory/" method="get"></form>
|
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/active-memory/" method="get"></form>
|
||||||
<div id="panel_analytics_memory" class="colstack_graph_holder">
|
<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>
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<div class="rowitem">
|
||||||
<h1>{{lang "panel_statistics_details_head"}}</h1>
|
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||||
</div>
|
</div>
|
||||||
</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}}
|
{{range .ViewItems}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<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>
|
<span class="panel_compacttext to_right">{{.Count}}{{.Unit}}</span>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
{{template "panel_analytics_script_memory.html" . }}
|
{{template "panel_analytics_script_memory.html" . }}
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
{{range .ItemList}}
|
{{range .ItemList}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<div class="rowitem panel_compactrow editable_parent">
|
||||||
<a href="/panel/analytics/agent/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
|
<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>
|
</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>
|
</div>
|
||||||
{{template "panel_analytics_script.html" . }}
|
{{template "panel_analytics_script.html" . }}
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<div class="rowitem">
|
||||||
<h1>{{lang "panel_statistics_forums_head"}}</h1>
|
<h1>{{lang "panel_stats_forums_head"}}</h1>
|
||||||
{{template "panel_analytics_time_range.html" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
{{range .ItemList}}
|
{{range .ItemList}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<div class="rowitem panel_compactrow editable_parent">
|
||||||
<a href="/panel/analytics/forum/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
|
<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>
|
</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>
|
</div>
|
||||||
{{template "panel_analytics_script.html" . }}
|
{{template "panel_analytics_script.html" . }}
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<div class="rowitem">
|
||||||
<h1>{{lang "panel_statistics_languages_head"}}</h1>
|
<h1>{{lang "panel_stats_languages_head"}}</h1>
|
||||||
{{template "panel_analytics_time_range.html" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
{{range .ItemList}}
|
{{range .ItemList}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<div class="rowitem panel_compactrow editable_parent">
|
||||||
<a href="/panel/analytics/lang/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
|
<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>
|
</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>
|
</div>
|
||||||
{{template "panel_analytics_script.html" . }}
|
{{template "panel_analytics_script.html" . }}
|
|
@ -1,24 +1,24 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<div class="rowitem">
|
||||||
<h1>{{lang "panel_statistics_memory_head"}}</h1>
|
<h1>{{lang "panel_stats_memory_head"}}</h1>
|
||||||
{{template "panel_analytics_time_range_month.html" . }}
|
{{template "panel_analytics_time_range_month.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/memory/" method="get"></form>
|
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/memory/" method="get"></form>
|
||||||
<div id="panel_analytics_memory" class="colstack_graph_holder">
|
<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>
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<div class="rowitem">
|
||||||
<h1>{{lang "panel_statistics_details_head"}}</h1>
|
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||||
</div>
|
</div>
|
||||||
</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}}
|
{{range .ViewItems}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<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_{{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>
|
<span class="panel_compacttext to_right">{{.Count}}{{.Unit}}</span>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
{{template "panel_analytics_script_memory.html" . }}
|
{{template "panel_analytics_script_memory.html" . }}
|
|
@ -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="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/posts/" method="get"></form>
|
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/posts/" method="get"></form>
|
||||||
<div id="panel_analytics_posts" class="colstack_graph_holder">
|
<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>
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<div class="rowitem">
|
||||||
<h1>{{lang "panel_statistics_details_head"}}</h1>
|
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||||
</div>
|
</div>
|
||||||
</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}}
|
{{range .ViewItems}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<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_{{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>
|
</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>
|
</div>
|
||||||
{{template "panel_analytics_script.html" . }}
|
{{template "panel_analytics_script.html" . }}
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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">
|
<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="0"{{if not .ShowSpam}} selected{{end}}>{{lang "panel_stats_spam_hide"}}</option>
|
||||||
<option value="1"{{if .ShowSpam}} selected{{end}}>{{lang "panel_statistics_spam_show"}}</option>
|
<option value="1"{{if .ShowSpam}} selected{{end}}>{{lang "panel_stats_spam_show"}}</option>
|
||||||
</select>
|
</select>
|
||||||
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
||||||
{{template "panel_analytics_time_range.html" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
{{range .ItemList}}
|
{{range .ItemList}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<div class="rowitem panel_compactrow editable_parent">
|
||||||
<a href="/panel/analytics/referrer/{{.Agent}}" class="panel_upshift">{{.Agent}}</a>
|
<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>
|
</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>
|
</div>
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,13 +9,13 @@
|
||||||
<div class="ct_chart"></div>
|
<div class="ct_chart"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="colstack_item colstack_head">
|
<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>
|
||||||
<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}}
|
{{range .ViewItems}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<div class="rowitem panel_compactrow editable_parent">
|
||||||
<a class="panel_upshift unix_to_24_hour_time">{{.Time}}</a>
|
<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>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<div class="rowitem">
|
||||||
<h1>{{lang "panel_statistics_routes_head"}}</h1>
|
<h1>{{lang "panel_stats_routes_head"}}</h1>
|
||||||
{{template "panel_analytics_time_range.html" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
{{range .ItemList}}
|
{{range .ItemList}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<div class="rowitem panel_compactrow editable_parent">
|
||||||
<a href="/panel/analytics/route/{{.Route}}" class="panel_upshift">{{.Route}}</a>
|
<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>
|
</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>
|
</div>
|
||||||
{{template "panel_analytics_script.html" . }}
|
{{template "panel_analytics_script.html" . }}
|
|
@ -1,21 +1,21 @@
|
||||||
<script>
|
<script>
|
||||||
let rawLabels = [{{range .Graph.Labels}}
|
let rawLabels = [{{range .Graph.Labels}}
|
||||||
{{.}},{{end}}
|
{{.}},{{end}}
|
||||||
];
|
];
|
||||||
let seriesData = [{{range .Graph.Series}}[{{range .}}
|
let seriesData = [{{range .Graph.Series}}[{{range .}}
|
||||||
{{.}},{{end}}
|
{{.}},{{end}}
|
||||||
],{{end}}
|
],{{end}}
|
||||||
];
|
];
|
||||||
let legendNames = [{{range .Graph.Legends}}
|
let legendNames = [{{range .Graph.Legends}}
|
||||||
{{.}},{{end}}
|
{{.}},{{end}}
|
||||||
];
|
];
|
||||||
|
|
||||||
addInitHook("after_phrases", () => {
|
addInitHook("after_phrases", () => {
|
||||||
addInitHook("end_init", () => {
|
addInitHook("end_init", () => {
|
||||||
addInitHook("analytics_loaded", () => {
|
addInitHook("analytics_loaded", () => {
|
||||||
memStuff(window, document, Chartist);
|
memStuff(window, document, Chartist);
|
||||||
buildStatsChart(rawLabels, seriesData, "{{.TimeRange}}",legendNames,true);
|
buildStatsChart(rawLabels, seriesData, "{{.TimeRange}}",legendNames,1);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
|
@ -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="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
{{range .ItemList}}
|
{{range .ItemList}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<div class="rowitem panel_compactrow editable_parent">
|
||||||
<a href="/panel/analytics/system/{{.Agent}}" class="panel_upshift">{{.FriendlyAgent}}</a>
|
<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>
|
</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>
|
</div>
|
||||||
{{template "panel_analytics_script.html" . }}
|
{{template "panel_analytics_script.html" . }}
|
|
@ -1,11 +1,11 @@
|
||||||
<select form="timeRangeForm" class="timeRangeSelector to_right autoSubmitRedirect" name="timeRange">
|
<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="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_statistics_time_range_three_months"}}</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_statistics_time_range_one_month"}}</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_statistics_time_range_one_week"}}</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_statistics_time_range_two_days"}}</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_statistics_time_range_one_day"}}</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_statistics_time_range_twelve_hours"}}</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_statistics_time_range_six_hours"}}</option>
|
<option value="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>{{lang "panel_stats_time_range_six_hours"}}</option>
|
||||||
</select>
|
</select>
|
||||||
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
|
@ -1,9 +1,9 @@
|
||||||
<select form="timeRangeForm" class="timeRangeSelector to_right autoSubmitRedirect" name="timeRange">
|
<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-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_statistics_time_range_one_week"}}</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_statistics_time_range_two_days"}}</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_statistics_time_range_one_day"}}</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_statistics_time_range_twelve_hours"}}</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_statistics_time_range_six_hours"}}</option>
|
<option value="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>{{lang "panel_stats_time_range_six_hours"}}</option>
|
||||||
</select>
|
</select>
|
||||||
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
<noscript><input form="timeRangeForm" type="submit" /></noscript>
|
|
@ -1,23 +1,23 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<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" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/topics/" method="get"></form>
|
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/topics/" method="get"></form>
|
||||||
<div id="panel_analytics_topics" class="colstack_graph_holder">
|
<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>
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<div class="rowitem">
|
||||||
<h1>{{lang "panel_statistics_details_head"}}</h1>
|
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||||
</div>
|
</div>
|
||||||
</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}}
|
{{range .ViewItems}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<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}}{{lang "panel_statistics_topics_suffix"}}</span>
|
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_topics_suffix"}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<div class="rowitem">
|
||||||
<h1>{{lang "panel_statistics_requests_head"}}</h1>
|
<h1>{{lang "panel_stats_requests_head"}}</h1>
|
||||||
{{template "panel_analytics_time_range.html" . }}
|
{{template "panel_analytics_time_range.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/views/" method="get"></form>
|
<form id="timeRangeForm" name="timeRangeForm" action="/panel/analytics/views/" method="get"></form>
|
||||||
<div id="panel_analytics_views" class="colstack_graph_holder">
|
<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>
|
||||||
<div class="colstack_item colstack_head">
|
<div class="colstack_item colstack_head">
|
||||||
<div class="rowitem">
|
<div class="rowitem">
|
||||||
<h1>{{lang "panel_statistics_details_head"}}</h1>
|
<h1>{{lang "panel_stats_details_head"}}</h1>
|
||||||
</div>
|
</div>
|
||||||
</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}}
|
{{range .ViewItems}}
|
||||||
<div class="rowitem panel_compactrow editable_parent">
|
<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}}{{lang "panel_statistics_views_suffix"}}</span>
|
<span class="panel_compacttext to_right">{{.Count}}{{lang "panel_stats_views_suffix"}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,6 +24,22 @@
|
||||||
{{template "panel_debug_stat.html" .CPUs}}
|
{{template "panel_debug_stat.html" .CPUs}}
|
||||||
{{template "panel_debug_stat_q.html"}}
|
{{template "panel_debug_stat_q.html"}}
|
||||||
</div>
|
</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"}}
|
{{template "panel_debug_subhead.html" "panel_debug_memory_stats"}}
|
||||||
<div id="panel_debug" class="colstack_grid">
|
<div id="panel_debug" class="colstack_grid">
|
||||||
{{template "panel_debug_stat_head.html" "panel_debug_memory_stats_sys"}}
|
{{template "panel_debug_stat_head.html" "panel_debug_memory_stats_sys"}}
|
||||||
|
|
|
@ -35,38 +35,41 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="colstack_item rowmenu">
|
<div class="colstack_item rowmenu">
|
||||||
<div class="rowitem passive">
|
<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>
|
</div>
|
||||||
{{if eq .Zone "analytics"}}
|
{{if eq .Zone "analytics"}}
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="rowitem passive">
|
<div class="rowitem passive">
|
||||||
|
|
|
@ -35,38 +35,41 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="colstack_item rowmenu">
|
<div class="colstack_item rowmenu">
|
||||||
<div class="rowitem passive">
|
<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>
|
</div>
|
||||||
{{if eq .Zone "analytics"}}
|
{{if eq .Zone "analytics"}}
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
||||||
<div class="rowitem passive submenu">
|
<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>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="rowitem passive">
|
<div class="rowitem passive">
|
||||||
|
|
Loading…
Reference in New Issue