forked from LBRYCommunity/lbry-sdk
ver updates to new metrics
This commit is contained in:
parent
08da763327
commit
395518ff76
2 changed files with 193 additions and 92 deletions
|
@ -20,14 +20,11 @@ class ServerConnection {
|
|||
channel = IOWebSocketChannel.connect(this.url);
|
||||
int tick = 1;
|
||||
channel.stream.listen((message) {
|
||||
Map data = json.decode(message);
|
||||
var data = json.decode(message);
|
||||
print(data);
|
||||
Map commands = data['commands'] ?? {};
|
||||
_loadDataController.add(
|
||||
ServerLoadDataPoint(
|
||||
tick,
|
||||
APICallMetrics.from_map(commands['search'] ?? {}),
|
||||
APICallMetrics.from_map(commands['resolve'] ?? {})
|
||||
ServerLoadDataPoint.from_map(
|
||||
tick, data
|
||||
)
|
||||
);
|
||||
tick++;
|
||||
|
@ -52,48 +49,106 @@ class ServerConnection {
|
|||
}
|
||||
|
||||
|
||||
class TimeStats {
|
||||
final int avg, min, max;
|
||||
// percentiles
|
||||
final int five;
|
||||
final int twenty_five;
|
||||
final int fifty;
|
||||
final int seventy_five;
|
||||
final int ninety_five;
|
||||
TimeStats(
|
||||
this.avg, this.min, this.five, this.twenty_five,
|
||||
this.fifty, this.seventy_five, this.ninety_five,
|
||||
this.max
|
||||
);
|
||||
TimeStats.from_list(List l): this(
|
||||
l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7]
|
||||
);
|
||||
TimeStats.from_zeros(): this(
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
);
|
||||
factory TimeStats.from_list_or_zeros(List l) =>
|
||||
l != null ? TimeStats.from_list(l): TimeStats.from_zeros();
|
||||
}
|
||||
|
||||
|
||||
class APICallMetrics {
|
||||
final int started;
|
||||
final int finished;
|
||||
final int total_time;
|
||||
final int execution_time;
|
||||
final int query_time;
|
||||
final int query_count;
|
||||
final int cache_hit;
|
||||
final int avg_wait_time;
|
||||
final int avg_total_time;
|
||||
final int avg_execution_time;
|
||||
final int avg_query_time_per_search;
|
||||
final int avg_query_time_per_query;
|
||||
// total requests received
|
||||
final int receive_count;
|
||||
// sum of these is total responses made
|
||||
final int cache_response_count;
|
||||
final int query_response_count;
|
||||
final int intrp_response_count;
|
||||
final int error_response_count;
|
||||
// stacked values for chart
|
||||
final int cache_response_stack;
|
||||
final int query_response_stack;
|
||||
final int intrp_response_stack;
|
||||
final int error_response_stack;
|
||||
// millisecond timings for non-cache responses
|
||||
final TimeStats response;
|
||||
final TimeStats interrupt;
|
||||
final TimeStats error;
|
||||
// response, interrupt and error each also report the python, wait and sql stats:
|
||||
final TimeStats python;
|
||||
final TimeStats wait;
|
||||
final TimeStats sql;
|
||||
// extended timings for individual sql executions
|
||||
final TimeStats individual_sql;
|
||||
final int individual_sql_count;
|
||||
// actual queries
|
||||
final List<String> errored_queries;
|
||||
final List<String> interrupted_queries;
|
||||
APICallMetrics(
|
||||
this.started, this.finished, this.total_time, this.execution_time,
|
||||
this.query_time, this.query_count, this.cache_hit):
|
||||
avg_wait_time=finished > 0 ? ((total_time - (execution_time + query_time))/finished).round() : 0,
|
||||
avg_total_time=finished > 0 ? (total_time/finished).round() : 0,
|
||||
avg_execution_time=finished > 0 ? (execution_time/finished).round() : 0,
|
||||
avg_query_time_per_search=finished > 0 ? (query_time/finished).round() : 0,
|
||||
avg_query_time_per_query=query_count > 0 ? (query_time/query_count).round() : 0;
|
||||
this.receive_count,
|
||||
this.cache_response_count, this.query_response_count,
|
||||
this.intrp_response_count, this.error_response_count,
|
||||
this.response, this.interrupt, this.error,
|
||||
this.python, this.wait, this.sql,
|
||||
this.individual_sql, this.individual_sql_count,
|
||||
this.errored_queries, this.interrupted_queries
|
||||
):
|
||||
cache_response_stack=cache_response_count+query_response_count+intrp_response_count+error_response_count,
|
||||
query_response_stack=query_response_count+intrp_response_count+error_response_count,
|
||||
intrp_response_stack=intrp_response_count+error_response_count,
|
||||
error_response_stack=error_response_count;
|
||||
APICallMetrics.from_map(Map data): this(
|
||||
data['started'] ?? 0,
|
||||
data['finished'] ?? 0,
|
||||
data['total_time'] ?? 0,
|
||||
data['execution_time'] ?? 0,
|
||||
data['query_time'] ?? 0,
|
||||
data['query_count'] ?? 0,
|
||||
data['cache_hit'] ?? 0,
|
||||
data["receive_count"] ?? 0,
|
||||
data["cache_response_count"] ?? 0,
|
||||
data["query_response_count"] ?? 0,
|
||||
data["intrp_response_count"] ?? 0,
|
||||
data["error_response_count"] ?? 0,
|
||||
TimeStats.from_list_or_zeros(data["response"]),
|
||||
TimeStats.from_list_or_zeros(data["interrupt"]),
|
||||
TimeStats.from_list_or_zeros(data["error"]),
|
||||
TimeStats.from_list_or_zeros(data["python"]),
|
||||
TimeStats.from_list_or_zeros(data["wait"]),
|
||||
TimeStats.from_list_or_zeros(data["sql"]),
|
||||
TimeStats.from_list_or_zeros(data["individual_sql"]),
|
||||
data["individual_sql_count"] ?? 0,
|
||||
List<String>.from(data["errored_queries"] ?? const []),
|
||||
List<String>.from(data["interrupted_queries"] ?? const []),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
class ServerLoadDataPoint {
|
||||
final int tick;
|
||||
final int sessions;
|
||||
final APICallMetrics search;
|
||||
final APICallMetrics resolve;
|
||||
ServerLoadDataPoint(this.tick, this.search, this.resolve);
|
||||
ServerLoadDataPoint.empty():
|
||||
tick = 0,
|
||||
search=APICallMetrics.from_map({}),
|
||||
resolve=APICallMetrics.from_map({});
|
||||
const ServerLoadDataPoint(
|
||||
this.tick, this.sessions, this.search, this.resolve
|
||||
);
|
||||
ServerLoadDataPoint.from_map(int tick, Map data): this(
|
||||
tick, (data['status'] ?? const {})['sessions'] ?? 0,
|
||||
APICallMetrics.from_map((data['api'] ?? const {})['search'] ?? const {}),
|
||||
APICallMetrics.from_map((data['api'] ?? const {})['resolve'] ?? const {})
|
||||
);
|
||||
ServerLoadDataPoint.empty(): this(
|
||||
0, 0, APICallMetrics.from_map(const {}), APICallMetrics.from_map(const {})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,12 @@ class ServerCharts extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
var server = Provider.of<Server>(context, listen: false);
|
||||
return ListView(children: <Widget>[
|
||||
SizedBox(height: 300.0, child: ServerLoadChart(server)),
|
||||
SizedBox(height: 300.0, child: APILoadChart(
|
||||
server, "Search", (ServerLoadDataPoint dataPoint) => dataPoint.search
|
||||
)),
|
||||
//SizedBox(height: 300.0, child: APILoadChart(
|
||||
// server, "Resolve", (ServerLoadDataPoint dataPoint) => dataPoint.resolve
|
||||
//)),
|
||||
SizedBox(height: 300.0, child: ServerPerformanceChart(server)),
|
||||
//SizedBox(height: 220.0, child: ClientLoadChart(server.clientLoadManager)),
|
||||
//SizedBox(height: 220.0, child: ClientPerformanceChart(server.clientLoadManager)),
|
||||
|
@ -22,16 +27,20 @@ class ServerCharts extends StatelessWidget {
|
|||
}
|
||||
|
||||
|
||||
class ServerLoadChart extends StatefulWidget {
|
||||
typedef APICallMetrics APIGetter(ServerLoadDataPoint dataPoint);
|
||||
|
||||
class APILoadChart extends StatefulWidget {
|
||||
final Server server;
|
||||
ServerLoadChart(this.server);
|
||||
final String name;
|
||||
final APIGetter getter;
|
||||
APILoadChart(this.server, this.name, this.getter);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => ServerLoadChartState();
|
||||
State<StatefulWidget> createState() => APILoadChartState();
|
||||
}
|
||||
|
||||
|
||||
class ServerLoadChartState extends State<ServerLoadChart> {
|
||||
class APILoadChartState extends State<APILoadChart> {
|
||||
|
||||
List<charts.Series<ServerLoadDataPoint, int>> seriesData;
|
||||
|
||||
|
@ -39,54 +48,73 @@ class ServerLoadChartState extends State<ServerLoadChart> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
seriesData = [
|
||||
/*
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Search Cache',
|
||||
id: 'Received',
|
||||
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault.lighter,
|
||||
strokeWidthPxFn: (_, __) => 4.0,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => widget.getter(load).receive_count,
|
||||
data: widget.server.serverLoadData,
|
||||
),*/
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Cache',
|
||||
colorFn: (_, __) =>
|
||||
charts.MaterialPalette.green.shadeDefault,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => widget.getter(load).cache_response_stack,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Query',
|
||||
colorFn: (_, __) =>
|
||||
charts.MaterialPalette.blue.shadeDefault,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => widget.getter(load).query_response_stack,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Interrupts',
|
||||
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault.lighter,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => widget.getter(load).intrp_response_stack,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Errors',
|
||||
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => widget.getter(load).error_response_stack,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
/*
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: '${widget.name} Interrupted',
|
||||
colorFn: (_, __) =>
|
||||
charts.MaterialPalette.pink.shadeDefault.lighter,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => widget.getter(load).interrupted,
|
||||
strokeWidthPxFn: (ServerLoadDataPoint load, _) => 5.0,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: '${widget.name} Errored',
|
||||
colorFn: (_, __) =>
|
||||
charts.MaterialPalette.red.shadeDefault.darker,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => widget.getter(load).errored,
|
||||
strokeWidthPxFn: (ServerLoadDataPoint load, _) => 5.0,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: '${widget.name} From Cache',
|
||||
colorFn: (_, __) => charts.MaterialPalette.green.shadeDefault.darker,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.cache_hit,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Search Finish',
|
||||
colorFn: (_, __) =>
|
||||
charts.MaterialPalette.deepOrange.shadeDefault.darker,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.finished,
|
||||
strokeWidthPxFn: (ServerLoadDataPoint load, _) => 5.0,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Search Start',
|
||||
colorFn: (_, __) =>
|
||||
charts.MaterialPalette.deepOrange.shadeDefault.lighter,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.started,
|
||||
strokeWidthPxFn: (ServerLoadDataPoint load, _) => 1.0,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Resolve Cache',
|
||||
colorFn: (_, __) => charts.MaterialPalette.cyan.shadeDefault.darker,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.resolve.cache_hit,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Resolve Finish',
|
||||
colorFn: (_, __) => charts.MaterialPalette.teal.shadeDefault.darker,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.resolve.finished,
|
||||
strokeWidthPxFn: (ServerLoadDataPoint load, _) => 5.0,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Resolve Start',
|
||||
colorFn: (_, __) => charts.MaterialPalette.teal.shadeDefault.lighter,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.resolve.started,
|
||||
strokeWidthPxFn: (ServerLoadDataPoint load, _) => 1.0,
|
||||
measureFn: (ServerLoadDataPoint load, _) => widget.getter(load).cache_hits,
|
||||
strokeWidthPxFn: (ServerLoadDataPoint load, _) => 3.0,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
*/
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -94,7 +122,9 @@ class ServerLoadChartState extends State<ServerLoadChart> {
|
|||
Widget build(BuildContext context) {
|
||||
return StreamBuilder<ServerLoadDataPoint>(
|
||||
stream: widget.server.serverLoadStream,
|
||||
builder: (BuildContext context, _) => BetterLineChart(seriesData)
|
||||
builder: (BuildContext context, _) => BetterLineChart(seriesData,
|
||||
//renderer: new charts.LineRendererConfig<num>(includeArea: true)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -117,27 +147,41 @@ class ServerPerformanceChartState extends State<ServerPerformanceChart> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
seriesData = [
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Waiting 95 Percentile',
|
||||
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault.lighter,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.wait.ninety_five,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Avg. Waiting',
|
||||
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault.darker,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.avg_wait_time,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.wait.avg,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Avg. Executing',
|
||||
colorFn: (_, __) => charts.MaterialPalette.teal.shadeDefault.lighter,
|
||||
colorFn: (_, __) => charts.MaterialPalette.teal.shadeDefault.darker,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.avg_execution_time,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.python.avg,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'SQLite 95 Percentile',
|
||||
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault.lighter,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.sql.ninety_five,
|
||||
data: widget.server.serverLoadData,
|
||||
),
|
||||
charts.Series<ServerLoadDataPoint, int>(
|
||||
id: 'Avg. SQLite',
|
||||
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault.darker,
|
||||
domainFn: (ServerLoadDataPoint load, _) => load.tick,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.avg_query_time_per_search,
|
||||
measureFn: (ServerLoadDataPoint load, _) => load.search.sql.avg,
|
||||
data: widget.server.serverLoadData,
|
||||
)
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -260,11 +304,13 @@ class BetterLineChart extends charts.LineChart {
|
|||
final int itemCount;
|
||||
final Object lastItem;
|
||||
|
||||
BetterLineChart(List<charts.Series<dynamic, int>> seriesList):
|
||||
BetterLineChart(List<charts.Series<dynamic, int>> seriesList, {charts.LineRendererConfig renderer}):
|
||||
itemCount = seriesList[0].data.length,
|
||||
lastItem = seriesList[0].data.last,
|
||||
super(
|
||||
seriesList,
|
||||
animate: false,
|
||||
defaultRenderer: renderer,
|
||||
behaviors: [charts.SeriesLegend()],
|
||||
domainAxis: charts.NumericAxisSpec(
|
||||
viewport: new charts.NumericExtents(
|
||||
|
|
Loading…
Reference in a new issue