@once @endonce
Overview Statistics

Statistics

Monitor your server's performance metrics and resource utilization over time.

Loading Telemetry...

Live Telemetry

Processor Utilization

Loading chart...

Network Traffic

Loading chart...

Memory Utilization

Loading chart...

Storage I/O

Loading chart...
@php $statisticsExportRows = []; @endphp

Statistics History

New Report
Creating...
@forelse($this->statistics as $stat) @php $networkStats = $this->getCurrentNetworkStats($stat); $diskStats = $this->getCurrentDiskStats($stat); $cpuPercent = $stat->cpumax > 0 ? ($stat->cpuused / $stat->cpumax * 100) : 0; $memPercent = $stat->memorymax > 0 ? ($stat->memoryused / $stat->memorymax * 100) : 0; $diskPercent = ($stat->diskmax ?? 0) > 0 ? (($stat->diskused ?? 0) / ($stat->diskmax ?? 1) * 100) : 0; $statisticsExportRows[] = [ 'date_time' => $stat->DateTime ? $stat->DateTime->format('M d, Y H:i:s') : '-', 'status' => $stat->vmstatus ? ucfirst($stat->vmstatus) : '-', 'cpu' => number_format($cpuPercent, 1) . '%', 'memory' => number_format($memPercent, 1) . '%', 'disk' => (($stat->diskmax ?? 0) > 0 && ($stat->diskused ?? 0) > 0) ? number_format($diskPercent, 1) . '%' : 'N/A', 'network_in' => Illuminate\Support\Number::fileSize(bytes: $networkStats['netin']), 'network_out' => Illuminate\Support\Number::fileSize(bytes: $networkStats['netout']), 'disk_io' => sprintf( '%s / %s', Illuminate\Support\Number::fileSize(bytes: $diskStats['diskread'] ?? 0), Illuminate\Support\Number::fileSize(bytes: $diskStats['diskwrite'] ?? 0) ), 'uptime' => $stat->uptime > 0 ? $this->formatUptime($stat->uptime) : '-', ]; @endphp @empty @endforelse
Date & Time
Status
CPU
Memory
Disk
Network In
Network Out
Disk I/O
Uptime
Actions
{{ $stat->DateTime?->format('M d, Y') ?? '-' }}
{{ $stat->DateTime?->format('H:i:s') ?? '' }}
@if($stat->vmstatus) {{ ucfirst($stat->vmstatus) }} @else - @endif
{{ number_format($cpuPercent, 1) }}%
{{ number_format($memPercent, 1) }}%
@if(($stat->diskmax ?? 0) > 0 && ($stat->diskused ?? 0) > 0)
{{ number_format($diskPercent, 1) }}%
@else N/A @endif
{{ Illuminate\Support\Number::fileSize(bytes: $networkStats['netin']) }}
@if($networkStats['netin_rate'] > 0)
{{ Illuminate\Support\Number::fileSize(bytes: (int)$networkStats['netin_rate']) }}/s
@endif
{{ Illuminate\Support\Number::fileSize(bytes: $networkStats['netout']) }}
@if($networkStats['netout_rate'] > 0)
{{ Illuminate\Support\Number::fileSize(bytes: (int)$networkStats['netout_rate']) }}/s
@endif
{{ Illuminate\Support\Number::fileSize(bytes: $diskStats['diskread'] ?? 0) }}
{{ Illuminate\Support\Number::fileSize(bytes: $diskStats['diskwrite'] ?? 0) }}
@if($stat->uptime > 0) {{ $this->formatUptime($stat->uptime) }} @else - @endif

No statistics available

Statistics are collected every 5 minutes automatically.

@if($this->statistics->total() > 0)
{{-- Records per page selector --}}
per page
{{-- Page info and navigation --}}
Showing {{ (($this->statistics->currentPage() - 1) * $this->statistics->perPage()) + 1 }} - {{ min($this->statistics->currentPage() * $this->statistics->perPage(), $this->statistics->total()) }} of {{ $this->statistics->total() }} entries @if($this->statistics->hasPages())
{{-- First page --}} {{-- Previous page --}} {{-- Page numbers --}} @php $statsTotalPages = $this->statistics->lastPage(); $statsCurrentPage = $this->statistics->currentPage(); $statsStartPage = max(1, $statsCurrentPage - 2); $statsEndPage = min($statsTotalPages, $statsCurrentPage + 2); @endphp @if($statsStartPage > 1) @if($statsStartPage > 2) ... @endif @endif @for($i = $statsStartPage; $i <= $statsEndPage; $i++) @endfor @if($statsEndPage < $statsTotalPages) @if($statsEndPage < $statsTotalPages - 1) ... @endif @endif {{-- Next page --}} {{-- Last page --}}
@endif
@endif
@php $taskHistoryExportRows = []; @endphp

Task History

@forelse($this->paginatedTaskHistory as $task) @php $startTime = isset($task['starttime']) ? \Carbon\Carbon::createFromTimestamp($task['starttime']) : null; $endTime = isset($task['endtime']) && $task['endtime'] > 0 ? \Carbon\Carbon::createFromTimestamp($task['endtime']) : null; $duration = null; if ($startTime && $endTime) { $duration = $startTime->diffInSeconds($endTime); } elseif ($startTime && isset($task['status']) && $task['status'] === 'running') { $duration = $startTime->diffInSeconds(now()); } $taskUpid = $task['upid'] ?? $task['id'] ?? ''; $taskKey = md5($taskUpid . ($task['starttime'] ?? '')); $isExpanded = in_array($taskUpid, $this->expandedTaskUpids ?? []); $taskHistoryExportRows[] = [ 'type' => $task['type'] ?? 'N/A', 'status' => $task['status'] ?? '-', 'start_time' => $startTime ? $startTime->format('M d, Y H:i:s') : '-', 'end_time' => $endTime ? $endTime->format('M d, Y H:i:s') : '-', 'duration' => $duration !== null ? $this->formatUptime($duration) : '-', ]; @endphp @empty @endforelse
Type
Status
Start Time
End Time
Duration
{{ $task['type'] ?? 'N/A' }} @if(isset($task['status'])) @if($task['status'] === 'OK') Success @else Failure @endif @else - @endif @if($startTime)
{{ $startTime->format('M d, Y') }}
{{ $startTime->format('H:i:s') }}
@else - @endif
@if($endTime)
{{ $endTime->format('M d, Y') }}
{{ $endTime->format('H:i:s') }}
@else - @endif
@if($duration !== null) {{ $this->formatUptime($duration) }} @else - @endif

Task Information

Loading task details...

No detailed information available for this task.

No task history available

Task history will appear here as tasks are executed on the server.

@if(count($this->taskHistory) > 0)
{{-- Records per page selector --}}
per page
{{-- Page info and navigation --}} @php $taskTotalPages = $this->taskHistoryTotalPages; $taskCurrentPage = $taskHistoryCurrentPage; $taskTotalCount = count($this->taskHistory); @endphp
Showing {{ (($taskCurrentPage - 1) * $taskHistoryPerPage) + 1 }} - {{ min($taskCurrentPage * $taskHistoryPerPage, $taskTotalCount) }} of {{ $taskTotalCount }} tasks @if($taskTotalPages > 1)
{{-- First page --}} {{-- Previous page --}} {{-- Page numbers --}} @php $taskStartPage = max(1, $taskCurrentPage - 2); $taskEndPage = min($taskTotalPages, $taskCurrentPage + 2); @endphp @if($taskStartPage > 1) @if($taskStartPage > 2) ... @endif @endif @for($i = $taskStartPage; $i <= $taskEndPage; $i++) @endfor @if($taskEndPage < $taskTotalPages) @if($taskEndPage < $taskTotalPages - 1) ... @endif @endif {{-- Next page --}} {{-- Last page --}}
@endif
@endif
@php $lifecycleEventsExportRows = []; @endphp

Recent Lifecycle Events

@forelse($this->paginatedLifecycleEvents as $index => $event) @php $startTime = isset($event['starttime']) ? \Carbon\Carbon::createFromTimestamp($event['starttime']) : null; $endTime = isset($event['endtime']) && $event['endtime'] > 0 ? \Carbon\Carbon::createFromTimestamp($event['endtime']) : null; $duration = $event['duration'] ?? null; $eventUpid = $event['upid'] ?? $event['timestamp'] ?? ''; $eventKey = md5($eventUpid . ($event['starttime'] ?? '')); $isExpanded = in_array($eventUpid, $this->expandedTaskUpids ?? []); $eventColorMap = [ 'start' => 'text-success', 'shutdown' => 'text-danger', 'reboot' => 'text-info', 'reset' => 'text-warning', 'backup' => 'text-purple-200', ]; $eventColor = $eventColorMap[$event['type']] ?? 'text-base/70'; $lifecycleEventsExportRows[] = [ 'type' => $event['label'] ?? 'N/A', 'status' => ucfirst($event['status'] ?? '-'), 'start_time' => $startTime ? $startTime->format('M d, Y H:i:s') : '-', 'end_time' => $endTime ? $endTime->format('M d, Y H:i:s') : '-', 'duration' => $duration !== null ? $this->formatUptime($duration) : '-', ]; @endphp @empty @endforelse
Type
Status
Start Time
End Time
Duration
{{ $event['label'] ?? 'N/A' }} @if(isset($event['status'])) @if(strtolower($event['status']) === 'ok') Success @elseif(strtolower($event['status']) === 'running') Running @else Failure @endif @else - @endif @if($startTime)
{{ $startTime->format('M d, Y') }}
{{ $startTime->format('H:i:s') }}
@else - @endif
@if($endTime)
{{ $endTime->format('M d, Y') }}
{{ $endTime->format('H:i:s') }}
@else - @endif
@if($duration !== null) {{ $this->formatUptime($duration) }} @else - @endif

Event Information

Type {{ $event['original_type'] ?? 'N/A' }}
Status {{ ucfirst($event['status'] ?? 'Unknown') }}
Event Type {{ $event['label'] ?? 'N/A' }}
@if(isset($event['upid']))
Task ID {{ str_replace([':root@pam!paymenter:', ':root@pam:'], '', $event['upid']) }}
@endif

No lifecycle events available

Lifecycle events will appear here as operations are performed on the server.

@php $lifecycleTotalCount = count($this->chartEvents); @endphp @if($lifecycleTotalCount > 0)
{{-- Records per page selector --}}
per page
{{-- Page info and navigation --}} @php $lifecycleTotalPages = $this->lifecycleEventsTotalPages; $lifecycleCurrentPage = $lifecycleEventsCurrentPage; @endphp
Showing {{ (($lifecycleCurrentPage - 1) * $lifecycleEventsPerPage) + 1 }} - {{ min($lifecycleCurrentPage * $lifecycleEventsPerPage, $lifecycleTotalCount) }} of {{ $lifecycleTotalCount }} events @if($lifecycleTotalPages > 1)
{{-- First page --}} {{-- Previous page --}} {{-- Page numbers --}} @php $lifecycleStartPage = max(1, $lifecycleCurrentPage - 2); $lifecycleEndPage = min($lifecycleTotalPages, $lifecycleCurrentPage + 2); @endphp @if($lifecycleStartPage > 1) @if($lifecycleStartPage > 2) ... @endif @endif @for($i = $lifecycleStartPage; $i <= $lifecycleEndPage; $i++) @endfor @if($lifecycleEndPage < $lifecycleTotalPages) @if($lifecycleEndPage < $lifecycleTotalPages - 1) ... @endif @endif {{-- Next page --}} {{-- Last page --}}
@endif
@endif
@php $historicalComparison = $this->historicalComparison; @endphp

Historical Data Comparison

@if($historicalPeriod === 'custom') @endif
@if($currentPeriod === 'custom') @endif
@if($historicalComparison && !isset($historicalComparison['error'])) @php $current = $historicalComparison['current']; $historical = $historicalComparison['historical']; $diff = $historicalComparison['differences']; @endphp
Metric
Historical ({{ $historical->DateTime->format('M d, Y H:i') }})
Current ({{ $current->DateTime->format('M d, Y H:i') }})
Change
Processor Utilization
{{ number_format($diff['cpu']['historical_percent'], 1) }}% {{ number_format($diff['cpu']['current_percent'], 1) }}% {{ $diff['cpu']['percent_change'] > 0 ? '+' : '' }}{{ number_format($diff['cpu']['percent_change'], 1) }}%
Memory Utilization
{{ number_format($diff['memory']['historical_percent'], 1) }}% {{ number_format($diff['memory']['current_percent'], 1) }}% {{ $diff['memory']['percent_change'] > 0 ? '+' : '' }}{{ number_format($diff['memory']['percent_change'], 1) }}%
Disk Read Rate
{{ $this->formatBytes($diff['disk_read']['historical_rate']) }}/s {{ $this->formatBytes($diff['disk_read']['current_rate']) }}/s {{ $diff['disk_read']['percent_change'] > 0 ? '+' : '' }}{{ number_format($diff['disk_read']['percent_change'], 1) }}%
Disk Write Rate
{{ $this->formatBytes($diff['disk_write']['historical_rate']) }}/s {{ $this->formatBytes($diff['disk_write']['current_rate']) }}/s {{ $diff['disk_write']['percent_change'] > 0 ? '+' : '' }}{{ number_format($diff['disk_write']['percent_change'], 1) }}%
Network Download Rate
{{ $this->formatBytes($diff['network_in']['historical_rate']) }}/s {{ $this->formatBytes($diff['network_in']['current_rate']) }}/s {{ $diff['network_in']['percent_change'] > 0 ? '+' : '' }}{{ number_format($diff['network_in']['percent_change'], 1) }}%
Network Upload Rate
{{ $this->formatBytes($diff['network_out']['historical_rate']) }}/s {{ $this->formatBytes($diff['network_out']['current_rate']) }}/s {{ $diff['network_out']['percent_change'] > 0 ? '+' : '' }}{{ number_format($diff['network_out']['percent_change'], 1) }}%
@elseif($historicalComparison && isset($historicalComparison['error']))

{{ $historicalComparison['message'] }}

@if(isset($historicalComparison['total_stats']))

Total statistics in database: {{ $historicalComparison['total_stats'] }} @if($historicalComparison['total_stats'] == 0) - Statistics are collected automatically every hour. You can also create manual statistics using the "Create Statistics" button above. @elseif($historicalComparison['total_stats'] < 2) - At least 2 statistics are needed for comparison. Wait for more data to be collected or create a manual statistic. @endif

@endif
@else

No comparison data available

Please select periods with available statistics data.

@endif

Network Analysis

Deep visibility into firewall sessions, security threats, and top consumers of bandwidth powered by the Core Router API.

@if($networkAnalysisLoading || ($networkAnalysis['lastUpdated'] === null && $networkAnalysis['error'] === null))

Fetching data from Core Router... reload page

@elseif($networkAnalysis['error'])

{{ $networkAnalysis['error'] }}

Ensure the Core Router API credentials are configured in your environment.

@else
@if(($networkAnalysis['connectionCount'] ?? 0) == 0)
No matching connections tracked for this server.
@else
@foreach($this->paginatedConnections as $index => $connection) @php // Use raw bytes value from backend for reliable numeric sorting $bytesForSort = (int)($connection['bytes'] ?? 0); @endphp @endforeach
Direction
Protocol
Source
Destination
State
Traffic
@php $direction = $connection['direction'] ?? '—'; @endphp @if($direction !== '—')
{{ $direction }}
@else — @endif
@php $protocol = $connection['protocol'] ?? '—'; @endphp @if($protocol !== '—')
{{ $protocol }}
@else — @endif
@php $sourceIP = $connection['source'] ?? '—'; $isSourcePublic = $sourceIP !== '—' && $this->checkIsPublicIP($sourceIP); @endphp
{{ $sourceIP }} @if($isSourcePublic)
@endif
@if(isset($connection['source_port'])) {{ $connection['source_port'] }} @endif
@php $destIP = $connection['destination'] ?? '—'; $isDestPublic = $destIP !== '—' && $this->checkIsPublicIP($destIP); @endphp
{{ $destIP }} @if($isDestPublic)
@endif
@if(isset($connection['destination_port'])) {{ $connection['destination_port'] }} @endif
@php $state = $connection['state'] ?? '—'; @endphp @if($state !== '—')
{{ $state }}
@else — @endif
{{ $connection['bytes_human'] ?? '—' }} @if(isset($connection['packets'])) {{ number_format($connection['packets']) }} packets @endif
{{-- Connections Pagination Controls --}} @if(($networkAnalysis['connectionCount'] ?? 0) > 0)
{{-- Records per page selector --}}
per page
{{-- Page info and navigation --}}
Showing {{ (($connectionsCurrentPage - 1) * $connectionsPerPage) + 1 }} - {{ min($connectionsCurrentPage * $connectionsPerPage, $networkAnalysis['connectionCount'] ?? 0) }} of {{ $networkAnalysis['connectionCount'] ?? 0 }} connections
{{-- First page --}} {{-- Previous page --}} {{-- Page numbers --}} @php $connectionsTotalPages = $this->connectionsTotalPages; $startPage = max(1, $connectionsCurrentPage - 2); $endPage = min($connectionsTotalPages, $connectionsCurrentPage + 2); @endphp @if($startPage > 1) @if($startPage > 2) ... @endif @endif @for($i = $startPage; $i <= $endPage; $i++) @endfor @if($endPage < $connectionsTotalPages) @if($endPage < $connectionsTotalPages - 1) ... @endif @endif {{-- Next page --}} {{-- Last page --}}
@endif
@endif
@if(($networkAnalysis['topConnectionCount'] ?? 0) == 0)
No connection data available.
@else
@foreach($this->paginatedTopConnections as $index => $row) @php $endpointIP = $row['endpoint'] ?? '—'; $port = $row['port'] ?? 0; $connections = $row['count'] ?? 0; $bytes = $row['bytes'] ?? 0; $bytesForSort = $bytes; @endphp @endforeach
Endpoint
Port
Connections
Traffic
@php $isEndpointPublic = $endpointIP !== '—' && $this->checkIsPublicIP($endpointIP); @endphp
{{ $endpointIP }} @if($isEndpointPublic)
@endif
@if(isset($row['port']) && $row['port'] !== '—')
{{ $row['port'] }}
@else — @endif
{{ number_format($row['count']) }}
{{ $row['bytes_human'] }} {{ number_format($row['packets']) }} packets
{{-- Top Connections Pagination Controls --}} @if(($networkAnalysis['topConnectionCount'] ?? 0) > 0)
{{-- Records per page selector --}}
per page
{{-- Page info and navigation --}}
Showing {{ (($topConnectionsCurrentPage - 1) * $topConnectionsPerPage) + 1 }} - {{ min($topConnectionsCurrentPage * $topConnectionsPerPage, $networkAnalysis['topConnectionCount'] ?? 0) }} of {{ $networkAnalysis['topConnectionCount'] ?? 0 }} peers
{{-- First page --}} {{-- Previous page --}} {{-- Page numbers --}} @php $topConnectionsTotalPages = $this->topConnectionsTotalPages; $startPage = max(1, $topConnectionsCurrentPage - 2); $endPage = min($topConnectionsTotalPages, $topConnectionsCurrentPage + 2); @endphp @if($startPage > 1) @if($startPage > 2) ... @endif @endif @for($i = $startPage; $i <= $endPage; $i++) @endfor @if($endPage < $topConnectionsTotalPages) @if($endPage < $topConnectionsTotalPages - 1) ... @endif @endif {{-- Next page --}} {{-- Last page --}}
@endif
@endif
@if(($networkAnalysis['topPortCount'] ?? 0) == 0)
No port statistics are available.
@else
@foreach($this->paginatedTopPorts as $index => $row) @php $port = $row['port'] ?? 0; $connections = $row['connections'] ?? 0; $bytes = $row['bytes'] ?? 0; $bytesForSort = $bytes; @endphp @endforeach
Port
Connections
Traffic
{{ $row['port'] }}
{{ number_format($row['connections']) }}
{{ $row['bytes_human'] }} {{ number_format($row['packets']) }} packets
{{-- Top Ports Pagination Controls --}} @if(($networkAnalysis['topPortCount'] ?? 0) > 0)
{{-- Records per page selector --}}
per page
{{-- Page info and navigation --}}
Showing {{ (($topPortsCurrentPage - 1) * $topPortsPerPage) + 1 }} - {{ min($topPortsCurrentPage * $topPortsPerPage, $networkAnalysis['topPortCount'] ?? 0) }} of {{ $networkAnalysis['topPortCount'] ?? 0 }} ports
{{-- First page --}} {{-- Previous page --}} {{-- Page numbers --}} @php $topPortsTotalPages = $this->topPortsTotalPages; $startPage = max(1, $topPortsCurrentPage - 2); $endPage = min($topPortsTotalPages, $topPortsCurrentPage + 2); @endphp @if($startPage > 1) @if($startPage > 2) ... @endif @endif @for($i = $startPage; $i <= $endPage; $i++) @endfor @if($endPage < $topPortsTotalPages) @if($endPage < $topPortsTotalPages - 1) ... @endif @endif {{-- Next page --}} {{-- Last page --}}
@endif
@endif
@if(empty($networkAnalysis['security']))
No security threats detected. All connections appear to be safe.
@else
@foreach($networkAnalysis['security'] as $warning) @php $conn = $warning['connection'] ?? []; @endphp @php $riskLevel = $warning['risk_level'] ?? 'Medium'; $attackType = $warning['attack_type'] ?? 'Unknown Threat'; $riskDescription = $warning['risk_description'] ?? 'Malicious IP detected from blocklist'; $riskBadgeClass = match($riskLevel) { 'Critical' => 'bg-danger/20 text-danger border-danger/30', 'High' => 'bg-warning/20 text-warning border-warning/30', 'Medium' => 'bg-warning/10 text-warning border-warning/20', 'Low' => 'bg-base/10 text-base/70 border-base/20', default => 'bg-warning/10 text-warning border-warning/20', }; @endphp
Security Threat Detected {{ $warning['type'] }} {{ $riskLevel }} Risk {{ $attackType }} @if(isset($warning['quantity']) && $warning['quantity'] > 1) {{ $warning['quantity'] }}x Repeated @endif

{{ $warning['threat'] }} @if(isset($warning['quantity']) && $warning['quantity'] > 1) ({{ $warning['quantity'] }} similar connection{{ $warning['quantity'] > 1 ? 's' : '' }} detected) @endif

@php $threatIP = $warning['ip'] ?? '—'; $isThreatPublic = $threatIP !== '—' && $this->checkIsPublicIP($threatIP); @endphp
IP Address: {{ $threatIP }} @if($isThreatPublic)
@endif
@endforeach
@endif
@endif
@script @endscript