mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
New: Split average response time statistics for queries and grabs
This commit is contained in:
@@ -32,136 +32,123 @@ import IndexerStatsFilterModal from './IndexerStatsFilterModal';
|
|||||||
import styles from './IndexerStats.css';
|
import styles from './IndexerStats.css';
|
||||||
|
|
||||||
function getAverageResponseTimeData(indexerStats: IndexerStatsIndexer[]) {
|
function getAverageResponseTimeData(indexerStats: IndexerStatsIndexer[]) {
|
||||||
const data = indexerStats.map((indexer) => {
|
const statistics = [...indexerStats].sort((a, b) =>
|
||||||
return {
|
a.averageResponseTime === b.averageResponseTime
|
||||||
label: indexer.indexerName,
|
? b.averageGrabResponseTime - a.averageGrabResponseTime
|
||||||
value: indexer.averageResponseTime,
|
: b.averageResponseTime - a.averageResponseTime
|
||||||
};
|
);
|
||||||
});
|
|
||||||
|
|
||||||
data.sort((a, b) => {
|
return {
|
||||||
return b.value - a.value;
|
labels: statistics.map((indexer) => indexer.indexerName),
|
||||||
});
|
datasets: [
|
||||||
|
{
|
||||||
return data;
|
label: translate('AverageQueries'),
|
||||||
|
data: statistics.map((indexer) => indexer.averageResponseTime),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: translate('AverageGrabs'),
|
||||||
|
data: statistics.map((indexer) => indexer.averageGrabResponseTime),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFailureRateData(indexerStats: IndexerStatsIndexer[]) {
|
function getFailureRateData(indexerStats: IndexerStatsIndexer[]) {
|
||||||
const data = indexerStats.map((indexer) => {
|
const data = indexerStats.map((indexer) => ({
|
||||||
return {
|
label: indexer.indexerName,
|
||||||
label: indexer.indexerName,
|
value:
|
||||||
value:
|
(indexer.numberOfFailedQueries +
|
||||||
(indexer.numberOfFailedQueries +
|
indexer.numberOfFailedRssQueries +
|
||||||
indexer.numberOfFailedRssQueries +
|
indexer.numberOfFailedAuthQueries +
|
||||||
indexer.numberOfFailedAuthQueries +
|
indexer.numberOfFailedGrabs) /
|
||||||
indexer.numberOfFailedGrabs) /
|
(indexer.numberOfQueries +
|
||||||
(indexer.numberOfQueries +
|
indexer.numberOfRssQueries +
|
||||||
indexer.numberOfRssQueries +
|
indexer.numberOfAuthQueries +
|
||||||
indexer.numberOfAuthQueries +
|
indexer.numberOfGrabs),
|
||||||
indexer.numberOfGrabs),
|
}));
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
data.sort((a, b) => {
|
data.sort((a, b) => b.value - a.value);
|
||||||
return b.value - a.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTotalRequestsData(indexerStats: IndexerStatsIndexer[]) {
|
function getTotalRequestsData(indexerStats: IndexerStatsIndexer[]) {
|
||||||
const data = {
|
const statistics = [...indexerStats].sort((a, b) =>
|
||||||
labels: indexerStats.map((indexer) => indexer.indexerName),
|
a.numberOfQueries === b.numberOfQueries
|
||||||
|
? b.numberOfRssQueries - a.numberOfRssQueries
|
||||||
|
: b.numberOfQueries - a.numberOfQueries
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
labels: statistics.map((indexer) => indexer.indexerName),
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: translate('SearchQueries'),
|
label: translate('SearchQueries'),
|
||||||
data: indexerStats.map((indexer) => indexer.numberOfQueries),
|
data: statistics.map((indexer) => indexer.numberOfQueries),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: translate('RssQueries'),
|
label: translate('RssQueries'),
|
||||||
data: indexerStats.map((indexer) => indexer.numberOfRssQueries),
|
data: statistics.map((indexer) => indexer.numberOfRssQueries),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: translate('AuthQueries'),
|
label: translate('AuthQueries'),
|
||||||
data: indexerStats.map((indexer) => indexer.numberOfAuthQueries),
|
data: statistics.map((indexer) => indexer.numberOfAuthQueries),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNumberGrabsData(indexerStats: IndexerStatsIndexer[]) {
|
function getNumberGrabsData(indexerStats: IndexerStatsIndexer[]) {
|
||||||
const data = indexerStats.map((indexer) => {
|
const data = indexerStats.map((indexer) => ({
|
||||||
return {
|
label: indexer.indexerName,
|
||||||
label: indexer.indexerName,
|
value: indexer.numberOfGrabs - indexer.numberOfFailedGrabs,
|
||||||
value: indexer.numberOfGrabs - indexer.numberOfFailedGrabs,
|
}));
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
data.sort((a, b) => {
|
data.sort((a, b) => b.value - a.value);
|
||||||
return b.value - a.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserAgentGrabsData(indexerStats: IndexerStatsUserAgent[]) {
|
function getUserAgentGrabsData(indexerStats: IndexerStatsUserAgent[]) {
|
||||||
const data = indexerStats.map((indexer) => {
|
const data = indexerStats.map((indexer) => ({
|
||||||
return {
|
label: indexer.userAgent ? indexer.userAgent : 'Other',
|
||||||
label: indexer.userAgent ? indexer.userAgent : 'Other',
|
value: indexer.numberOfGrabs,
|
||||||
value: indexer.numberOfGrabs,
|
}));
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
data.sort((a, b) => {
|
data.sort((a, b) => b.value - a.value);
|
||||||
return b.value - a.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserAgentQueryData(indexerStats: IndexerStatsUserAgent[]) {
|
function getUserAgentQueryData(indexerStats: IndexerStatsUserAgent[]) {
|
||||||
const data = indexerStats.map((indexer) => {
|
const data = indexerStats.map((indexer) => ({
|
||||||
return {
|
label: indexer.userAgent ? indexer.userAgent : 'Other',
|
||||||
label: indexer.userAgent ? indexer.userAgent : 'Other',
|
value: indexer.numberOfQueries,
|
||||||
value: indexer.numberOfQueries,
|
}));
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
data.sort((a, b) => {
|
data.sort((a, b) => b.value - a.value);
|
||||||
return b.value - a.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHostGrabsData(indexerStats: IndexerStatsHost[]) {
|
function getHostGrabsData(indexerStats: IndexerStatsHost[]) {
|
||||||
const data = indexerStats.map((indexer) => {
|
const data = indexerStats.map((indexer) => ({
|
||||||
return {
|
label: indexer.host ? indexer.host : 'Other',
|
||||||
label: indexer.host ? indexer.host : 'Other',
|
value: indexer.numberOfGrabs,
|
||||||
value: indexer.numberOfGrabs,
|
}));
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
data.sort((a, b) => {
|
data.sort((a, b) => b.value - a.value);
|
||||||
return b.value - a.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHostQueryData(indexerStats: IndexerStatsHost[]) {
|
function getHostQueryData(indexerStats: IndexerStatsHost[]) {
|
||||||
const data = indexerStats.map((indexer) => {
|
const data = indexerStats.map((indexer) => ({
|
||||||
return {
|
label: indexer.host ? indexer.host : 'Other',
|
||||||
label: indexer.host ? indexer.host : 'Other',
|
value: indexer.numberOfQueries,
|
||||||
value: indexer.numberOfQueries,
|
}));
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
data.sort((a, b) => {
|
data.sort((a, b) => b.value - a.value);
|
||||||
return b.value - a.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@@ -294,7 +281,7 @@ function IndexerStats() {
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.fullWidthChart}>
|
<div className={styles.fullWidthChart}>
|
||||||
<div className={styles.chartContainer}>
|
<div className={styles.chartContainer}>
|
||||||
<BarChart
|
<StackedBarChart
|
||||||
data={getAverageResponseTimeData(item.indexers)}
|
data={getAverageResponseTimeData(item.indexers)}
|
||||||
title={translate('AverageResponseTimesMs')}
|
title={translate('AverageResponseTimesMs')}
|
||||||
stepSize={100}
|
stepSize={100}
|
||||||
|
@@ -2,6 +2,7 @@ export interface IndexerStatsIndexer {
|
|||||||
indexerId: number;
|
indexerId: number;
|
||||||
indexerName: string;
|
indexerName: string;
|
||||||
averageResponseTime: number;
|
averageResponseTime: number;
|
||||||
|
averageGrabResponseTime: number;
|
||||||
numberOfQueries: number;
|
numberOfQueries: number;
|
||||||
numberOfGrabs: number;
|
numberOfGrabs: number;
|
||||||
numberOfRssQueries: number;
|
numberOfRssQueries: number;
|
||||||
|
@@ -15,6 +15,7 @@ namespace NzbDrone.Core.IndexerStats
|
|||||||
public int IndexerId { get; set; }
|
public int IndexerId { get; set; }
|
||||||
public string IndexerName { get; set; }
|
public string IndexerName { get; set; }
|
||||||
public int AverageResponseTime { get; set; }
|
public int AverageResponseTime { get; set; }
|
||||||
|
public int AverageGrabResponseTime { get; set; }
|
||||||
public int NumberOfQueries { get; set; }
|
public int NumberOfQueries { get; set; }
|
||||||
public int NumberOfGrabs { get; set; }
|
public int NumberOfGrabs { get; set; }
|
||||||
public int NumberOfRssQueries { get; set; }
|
public int NumberOfRssQueries { get; set; }
|
||||||
|
@@ -61,13 +61,8 @@ namespace NzbDrone.Core.IndexerStats
|
|||||||
.ThenBy(v => v.Id)
|
.ThenBy(v => v.Id)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var temp = 0;
|
indexerStats.AverageResponseTime = CalculateAverageElapsedTime(sortedEvents.Where(h => h.EventType is HistoryEventType.IndexerRss or HistoryEventType.IndexerQuery).ToArray());
|
||||||
var elapsedTimeEvents = sortedEvents
|
indexerStats.AverageGrabResponseTime = CalculateAverageElapsedTime(sortedEvents.Where(h => h.EventType is HistoryEventType.ReleaseGrabbed).ToArray());
|
||||||
.Where(h => int.TryParse(h.Data.GetValueOrDefault("elapsedTime"), out temp) && h.Data.GetValueOrDefault("cached") != "1")
|
|
||||||
.Select(_ => temp)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
indexerStats.AverageResponseTime = elapsedTimeEvents.Any() ? (int)elapsedTimeEvents.Average() : 0;
|
|
||||||
|
|
||||||
foreach (var historyEvent in sortedEvents)
|
foreach (var historyEvent in sortedEvents)
|
||||||
{
|
{
|
||||||
@@ -176,5 +171,17 @@ namespace NzbDrone.Core.IndexerStats
|
|||||||
HostStatistics = hostStatsList
|
HostStatistics = hostStatsList
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int CalculateAverageElapsedTime(History.History[] sortedEvents)
|
||||||
|
{
|
||||||
|
var temp = 0;
|
||||||
|
|
||||||
|
var elapsedTimeEvents = sortedEvents
|
||||||
|
.Where(h => int.TryParse(h.Data.GetValueOrDefault("elapsedTime"), out temp) && temp > 0 && h.Data.GetValueOrDefault("cached") != "1")
|
||||||
|
.Select(_ => temp)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return elapsedTimeEvents.Any() ? (int)elapsedTimeEvents.Average() : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -88,6 +88,8 @@
|
|||||||
"Author": "Author",
|
"Author": "Author",
|
||||||
"Automatic": "Automatic",
|
"Automatic": "Automatic",
|
||||||
"AutomaticSearch": "Automatic Search",
|
"AutomaticSearch": "Automatic Search",
|
||||||
|
"AverageGrabs": "Average Grabs",
|
||||||
|
"AverageQueries": "Average Queries",
|
||||||
"AverageResponseTimesMs": "Average Indexer Response Times (ms)",
|
"AverageResponseTimesMs": "Average Indexer Response Times (ms)",
|
||||||
"Backup": "Backup",
|
"Backup": "Backup",
|
||||||
"BackupFolderHelpText": "Relative paths will be under {appName}'s AppData directory",
|
"BackupFolderHelpText": "Relative paths will be under {appName}'s AppData directory",
|
||||||
|
Reference in New Issue
Block a user