New: Split average response time statistics for queries and grabs

This commit is contained in:
Bogdan
2024-07-21 01:01:03 +03:00
parent 5f3a329ef2
commit 17aa2832ea
5 changed files with 86 additions and 88 deletions

View File

@@ -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}

View File

@@ -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;

View File

@@ -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; }

View File

@@ -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;
}
} }
} }

View File

@@ -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",