Skip to content

Commit 5d509d7

Browse files
committed
Add message statistics
1 parent e0abdc7 commit 5d509d7

File tree

8 files changed

+75
-108
lines changed

8 files changed

+75
-108
lines changed

src/tribler/core/session.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def rust_enhancements(session: Session) -> Generator[None, None, None]:
5959
"""
6060
Attempt to import the IPv8 Rust anonymization backend.
6161
"""
62-
use_fallback = session.config.get("statistics")
62+
use_fallback = False
6363
if_specs = [ifc for ifc in session.config.get("ipv8/interfaces") if ifc["interface"] == "UDPIPv4"]
6464

6565
if not use_fallback:
@@ -71,8 +71,9 @@ def rust_enhancements(session: Session) -> Generator[None, None, None]:
7171
ifc["worker_threads"] = ifc.get("worker_threads", session.config.get("tunnel_community/max_circuits"))
7272
yield
7373
if if_specs:
74+
ipv4_endpoint = session.ipv8.endpoint.interfaces["UDPIPv4"]
75+
session.ipv8.endpoint.get_statistics = ipv4_endpoint.get_statistics
7476
for server in session.socks_servers:
75-
ipv4_endpoint = session.ipv8.endpoint.interfaces["UDPIPv4"]
7677
server.rust_endpoint = ipv4_endpoint if isinstance(ipv4_endpoint, RustEndpoint) else None
7778
except ImportError:
7879
logger.info("Rust endpoint not found (pip install ipv8-rust-tunnels).")
@@ -140,7 +141,7 @@ def __init__(self, config: TriblerConfigManager) -> None:
140141
# IPv8
141142
rescue_keys(self.config)
142143
with rust_enhancements(self):
143-
self.ipv8 = IPv8(self.config.get("ipv8"), enable_statistics=self.config.get("statistics"))
144+
self.ipv8 = IPv8(self.config.get("ipv8"))
144145
self.loader = IPv8CommunityLoader()
145146

146147
# REST
@@ -239,9 +240,14 @@ async def start(self) -> None:
239240
# REST (2/2)
240241
self.rest_manager.get_endpoint("/api/ipv8").initialize(self.ipv8)
241242
self.rest_manager.get_endpoint("/api/statistics").ipv8 = self.ipv8
242-
if self.config.get("statistics"):
243-
self.rest_manager.get_endpoint("/api/ipv8").endpoints["/overlays"].enable_overlay_statistics(True, None,
244-
True)
243+
244+
overlays_endpoint = self.rest_manager.get_endpoint("/api/ipv8").endpoints["/overlays"]
245+
# Enable statistics for IPv8 StatisticsEndpoint
246+
if overlays_endpoint.statistics_supported:
247+
overlays_endpoint.enable_overlay_statistics(True, None, True)
248+
# When using RustEndpoint, statistics are also reported. However, since RustEndpoint
249+
# does not inherit from StatisticsEndpoint, we need to manually set statistics_supported.
250+
overlays_endpoint.statistics_supported = True
245251

246252
async def find_api_server(self) -> tuple[str | None, bytes | None]:
247253
"""

src/tribler/ui/src/components/layouts/Header.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { DialogDescription } from "@radix-ui/react-dialog";
1717
import { Ban, Loader } from "lucide-react";
1818
import { useTranslation } from "react-i18next";
1919
import { ScrollArea } from "../ui/scroll-area";
20-
import { EasyTooltip, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip";
20+
import { EasyTooltip } from "../ui/tooltip";
2121

2222
export function Header() {
2323
const [online, setOnline] = useState<boolean>(true);

src/tribler/ui/src/components/ui/simple-table.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react';
22
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
33
import { getCoreRowModel, useReactTable, flexRender, getFilteredRowModel, getPaginationRowModel, getExpandedRowModel, getSortedRowModel } from '@tanstack/react-table';
4-
import type { ColumnDef, Row, PaginationState, RowSelectionState, ColumnFiltersState, ExpandedState, ColumnDefTemplate, HeaderContext, SortingState, VisibilityState, Header, Column } from '@tanstack/react-table';
4+
import type { ColumnDef, Row, PaginationState, RowSelectionState, ColumnFiltersState, ExpandedState, ColumnDefTemplate, HeaderContext, SortingState, VisibilityState, Header, Column, InitialTableState } from '@tanstack/react-table';
55
import { cn, isMac } from '@/lib/utils';
66
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel } from './select';
77
import { Button } from './button';
@@ -137,6 +137,7 @@ interface ReactTableProps<T extends object> {
137137
storeSortingState?: string;
138138
rowId?: (originalRow: T, index: number, parent?: Row<T>) => string,
139139
selectOnRightClick?: boolean,
140+
initialState?: InitialTableState
140141
}
141142

142143
function SimpleTable<T extends object>({
@@ -158,15 +159,15 @@ function SimpleTable<T extends object>({
158159
expandable,
159160
storeSortingState,
160161
rowId,
161-
selectOnRightClick
162+
selectOnRightClick,
163+
initialState
162164
}: ReactTableProps<T>) {
163165
const [pagination, setPagination] = useState<PaginationState>({
164166
pageIndex: pageIndex ?? 0,
165167
pageSize: pageSize ?? 20,
166168
});
167169
const [rowSelection, setRowSelection] = useState<RowSelectionState>(initialRowSelection || {});
168170
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(filters || [])
169-
const [expanded, setExpanded] = useState<ExpandedState>({});
170171
const [sorting, setSorting] = useState<SortingState>([]);
171172
const [startId, setStartId] = useState<string | undefined>(undefined);
172173
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
@@ -204,7 +205,6 @@ function SimpleTable<T extends object>({
204205
rowSelection,
205206
columnFilters,
206207
columnVisibility,
207-
expanded,
208208
sorting
209209
},
210210
getFilteredRowModel: getFilteredRowModel(),
@@ -214,11 +214,11 @@ function SimpleTable<T extends object>({
214214
onRowSelectionChange: (arg: SetStateAction<RowSelectionState>) => {
215215
if (allowSelect || allowSelectCheckbox || allowMultiSelect) setRowSelection(arg);
216216
},
217-
onExpandedChange: setExpanded,
218217
onSortingChange: setSorting,
219218
getSubRows: (row: any) => row?.subRows,
220219
getRowId: rowId,
221220
autoResetPageIndex: false,
221+
initialState: initialState
222222
});
223223

224224
// If we're on an empty page, reset the pageIndex to 0

src/tribler/ui/src/models/overlay.model.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface Overlay {
4141
export interface OverlayMsgStats {
4242
name?: string;
4343
identifier: number;
44+
handler?: string;
4445
num_up: number;
4546
num_down: number;
4647
bytes_up: number;
@@ -49,6 +50,7 @@ export interface OverlayMsgStats {
4950
first_measured_down: number;
5051
last_measured_up: number;
5152
last_measured_down: number;
53+
subRows?: OverlayMsgStats[];
5254
}
5355

5456
export type OverlayStats = Record<string, Record<string, OverlayMsgStats>>;

src/tribler/ui/src/pages/Debug/IPv8/Details.tsx

+52-34
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,73 @@ import { isErrorDict } from "@/services/reporting";
55
import { OverlayMsgStats } from "@/models/overlay.model";
66
import { ColumnDef } from "@tanstack/react-table";
77
import { useInterval } from '@/hooks/useInterval';
8+
import { formatBytes } from "@/lib/utils";
9+
import { ChevronDown, ChevronRight } from "lucide-react";
810

911

1012
const statisticColumns: ColumnDef<OverlayMsgStats>[] = [
1113
{
1214
accessorKey: "name",
1315
header: getHeader("Name", false),
16+
cell: ({ row }) => {
17+
return (
18+
<div
19+
className="flex text-start items-center"
20+
style={{
21+
paddingLeft: `${row.depth * 2}rem`
22+
}}
23+
>
24+
{row.original.subRows && row.original.subRows.length > 0 && (
25+
<button onClick={row.getToggleExpandedHandler()}>
26+
{row.getIsExpanded()
27+
? <ChevronDown size="16" color="#777"></ChevronDown>
28+
: <ChevronRight size="16" color="#777"></ChevronRight>}
29+
</button>
30+
)}
31+
{row.original.name}
32+
</div>
33+
)
34+
}
1435
},
1536
{
16-
accessorKey: "bytes_up",
17-
header: getHeader("Upload (MB)", false),
37+
accessorKey: "identifier",
38+
header: "Message identifier",
1839
cell: ({ row }) => {
1940
if (row.original.identifier < 0) { return }
20-
return <span>{(row.original.bytes_up / 1024 ** 2).toFixed(3)}</span>
41+
return <span>{row.original.identifier}</span>
42+
},
43+
},
44+
{
45+
accessorKey: "handler",
46+
header: "Handler",
47+
},
48+
{
49+
accessorKey: "bytes_up",
50+
header: getHeader("Upload", false),
51+
cell: ({ row }) => {
52+
return <span>{formatBytes(row.original.bytes_up)}</span>
2153
},
2254
},
2355
{
2456
accessorKey: "bytes_down",
25-
header: getHeader("Download (MB)", false),
57+
header: getHeader("Download", false),
2658
cell: ({ row }) => {
27-
if (row.original.identifier < 0) { return }
28-
return <span>{(row.original.bytes_down / 1024 ** 2).toFixed(3)}</span>
59+
return <span>{formatBytes(row.original.bytes_down)}</span>
2960
},
3061
},
3162
{
3263
accessorKey: "num_up",
3364
header: getHeader("# Msgs sent", false),
3465
cell: ({ row }) => {
35-
if (row.original.identifier < 0) { return }
66+
// if (row.original.identifier < 0) { return }
3667
return <span>{row.original.num_up}</span>
3768
},
3869
},
3970
{
4071
accessorKey: "num_down",
4172
header: getHeader("# Msgs received", false),
4273
cell: ({ row }) => {
43-
if (row.original.identifier < 0) { return }
74+
// if (row.original.identifier < 0) { return }
4475
return <span>{row.original.num_down}</span>
4576
},
4677
},
@@ -57,44 +88,31 @@ export default function Details() {
5788
for (var overlayStats of response) {
5889
for (const [communityName, communityStats] of Object.entries(overlayStats)) {
5990
if (Object.entries(communityStats).length === 0) { break }
91+
let messageStats = []
92+
for (const [msgName, msgStats] of Object.entries(communityStats)) {
93+
let [_, handler] = msgName.split(":", 2);
94+
msgStats.handler = handler;
95+
messageStats.push(msgStats);
96+
}
97+
messageStats.sort((stat1, stat2) => stat1.identifier - stat2.identifier);
6098
stats.push({
6199
name: communityName,
62100
identifier: -1,
63-
num_up: 0,
64-
num_down: 0,
65-
bytes_up: 0,
66-
bytes_down: 0,
101+
num_up: messageStats.reduce((n, stat) => n + stat.num_up, 0),
102+
num_down: messageStats.reduce((n, stat) => n + stat.num_down, 0),
103+
bytes_up: messageStats.reduce((n, stat) => n + stat.bytes_up, 0),
104+
bytes_down: messageStats.reduce((n, stat) => n + stat.bytes_down, 0),
67105
first_measured_up: 0,
68106
first_measured_down: 0,
69107
last_measured_up: 0,
70108
last_measured_down: 0,
109+
subRows: messageStats
71110
});
72-
for (const [msgName, msgStats] of Object.entries(communityStats)) {
73-
msgStats.name = msgName;
74-
stats.push(msgStats);
75-
}
76111
}
77112
}
78113
setStatistics(stats);
79114
}
80115
}, 5000, true);
81116

82-
if (statistics.length === 0) {
83-
return (
84-
<div className="w-3/4 px-4">
85-
<div className="whitespace-pre-wrap">
86-
<br />
87-
The details are not available because the statistics measurement is not enabled.
88-
To enable the statistics measurement, go to:
89-
<br /><br />
90-
Settings -&gt; Debugging -&gt; Network (IPv8) Statistics
91-
<br /><br />
92-
After enabling the checkbox and saving the settings, restart Tribler.
93-
Then the details will be available here.
94-
</div>
95-
</div>
96-
)
97-
}
98-
99-
return <SimpleTable data={statistics} columns={statisticColumns} />
117+
return <SimpleTable data={statistics} columns={statisticColumns} expandable={true} initialState={{expanded: true}} />
100118
}

src/tribler/ui/src/pages/Debug/IPv8/Overlays.tsx

+1-41
Original file line numberDiff line numberDiff line change
@@ -40,46 +40,6 @@ const overlayColumns: ColumnDef<Overlay>[] = [
4040
)
4141
},
4242
},
43-
{
44-
accessorKey: "statistics.bytes_up",
45-
header: getHeader("Upload (MB)", false),
46-
cell: ({ row }) => {
47-
if (Object.keys(row.original.statistics).length === 0) { return 'N/A' }
48-
return <span>{(row.original.statistics.bytes_up / 1024 ** 2).toFixed(3)}</span>
49-
},
50-
},
51-
{
52-
accessorKey: "statistics.bytes_down",
53-
header: getHeader("Download (MB)", false),
54-
cell: ({ row }) => {
55-
if (Object.keys(row.original.statistics).length === 0) { return 'N/A' }
56-
return <span>{(row.original.statistics.bytes_down / 1024 ** 2).toFixed(3)}</span>
57-
},
58-
},
59-
{
60-
accessorKey: "statistics.num_up",
61-
header: getHeader("# Msg sent", false),
62-
cell: ({ row }) => {
63-
if (Object.keys(row.original.statistics).length === 0) { return 'N/A' }
64-
return <span>{row.original.statistics.num_up}</span>
65-
},
66-
},
67-
{
68-
accessorKey: "statistics.num_down",
69-
header: getHeader("# Msg received", false),
70-
cell: ({ row }) => {
71-
if (Object.keys(row.original.statistics).length === 0) { return 'N/A' }
72-
return <span>{row.original.statistics.num_down}</span>
73-
},
74-
},
75-
{
76-
accessorKey: "statistics.diff_time",
77-
header: getHeader("Diff (sec)", false),
78-
cell: ({ row }) => {
79-
if (Object.keys(row.original.statistics).length === 0) { return 'N/A' }
80-
return <span>{row.original.statistics.diff_time.toFixed(3)}</span>
81-
},
82-
},
8343
]
8444

8545
const peerColumns: ColumnDef<Peer>[] = [
@@ -108,7 +68,7 @@ export default function Overlays() {
10868
const response = await ipv8Service.getOverlays();
10969
if (!(response === undefined) && !isErrorDict(response)) {
11070
// We ignore errors and correct with the missing information on the next call
111-
setOverlays(response);
71+
setOverlays(response.filter((overlay) => overlay.overlay_name.endsWith("Community")));
11272
}
11373
}, 5000, true);
11474

src/tribler/ui/src/pages/Debug/IPv8/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ export default function IPv8() {
77
return (
88
<Tabs defaultValue="overlays" className="w-full flex flex-col flex-wrap">
99
<TabsList className="flex-rows-3 border-b">
10-
<TabsTrigger value="overlays">Overlays</TabsTrigger>
11-
<TabsTrigger value="details">Details</TabsTrigger>
10+
<TabsTrigger value="overlays">Peers</TabsTrigger>
11+
<TabsTrigger value="details">Traffic</TabsTrigger>
1212
</TabsList>
1313
<TabsContent value="overlays" className="w-full flex-grow flex-col focus-visible:ring-0">
1414
<Overlays />

src/tribler/ui/src/pages/Settings/Debugging.tsx

-19
Original file line numberDiff line numberDiff line change
@@ -51,25 +51,6 @@ export default function Debugging() {
5151
{t('EnableDevMode')}
5252
</label>
5353
</div>
54-
<div className="flex items-center space-x-2 p-2">
55-
<Checkbox
56-
checked={settings?.statistics}
57-
onCheckedChange={(value) => {
58-
if (settings) {
59-
setSettings({
60-
...settings,
61-
statistics: !!value,
62-
});
63-
}
64-
}}
65-
id="statistics" />
66-
<label
67-
htmlFor="statistics"
68-
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
69-
>
70-
{t('EnableStats')}
71-
</label>
72-
</div>
7354

7455
<SaveButton
7556
onClick={async () => {

0 commit comments

Comments
 (0)