mirror of
https://github.com/OutlineFoundation/outline-server.git
synced 2026-08-04 06:35:06 +00:00
feat(server): stop sharing key usage with metrics server (#1529)
* feat(server): stop sharing key usage with metrics server * Update comment to reflect history.
This commit is contained in:
parent
be02db89f1
commit
a072cc43e1
2 changed files with 6 additions and 78 deletions
|
|
@ -23,7 +23,6 @@ import {
|
|||
CountryUsage,
|
||||
DailyFeatureMetricsReportJson,
|
||||
HourlyServerMetricsReportJson,
|
||||
KeyUsage,
|
||||
MetricsCollectorClient,
|
||||
OutlineSharedMetricsPublisher,
|
||||
UsageMetrics,
|
||||
|
|
@ -83,11 +82,6 @@ describe('OutlineSharedMetricsPublisher', () => {
|
|||
);
|
||||
|
||||
publisher.startSharing();
|
||||
usageMetrics.keyUsage = [
|
||||
{accessKeyId: 'user-0', inboundBytes: 11},
|
||||
{accessKeyId: 'user-1', inboundBytes: 22},
|
||||
{accessKeyId: 'user-0', inboundBytes: 33},
|
||||
];
|
||||
usageMetrics.countryUsage = [
|
||||
{country: 'AA', inboundBytes: 11},
|
||||
{country: 'BB', inboundBytes: 11},
|
||||
|
|
@ -103,9 +97,6 @@ describe('OutlineSharedMetricsPublisher', () => {
|
|||
startUtcMs: startTime,
|
||||
endUtcMs: clock.nowMs,
|
||||
userReports: [
|
||||
{userId: 'M(user-0)', bytesTransferred: 11},
|
||||
{userId: 'M(user-1)', bytesTransferred: 22},
|
||||
{userId: 'M(user-0)', bytesTransferred: 33},
|
||||
{bytesTransferred: 11, countries: ['AA']},
|
||||
{bytesTransferred: 11, countries: ['BB']},
|
||||
{bytesTransferred: 22, countries: ['CC']},
|
||||
|
|
@ -115,10 +106,6 @@ describe('OutlineSharedMetricsPublisher', () => {
|
|||
});
|
||||
|
||||
startTime = clock.nowMs;
|
||||
usageMetrics.keyUsage = [
|
||||
{accessKeyId: 'user-0', inboundBytes: 44},
|
||||
{accessKeyId: 'user-2', inboundBytes: 55},
|
||||
];
|
||||
usageMetrics.countryUsage = [
|
||||
{country: 'EE', inboundBytes: 44},
|
||||
{country: 'FF', inboundBytes: 55},
|
||||
|
|
@ -131,8 +118,6 @@ describe('OutlineSharedMetricsPublisher', () => {
|
|||
startUtcMs: startTime,
|
||||
endUtcMs: clock.nowMs,
|
||||
userReports: [
|
||||
{userId: 'M(user-0)', bytesTransferred: 44},
|
||||
{userId: 'M(user-2)', bytesTransferred: 55},
|
||||
{bytesTransferred: 44, countries: ['EE']},
|
||||
{bytesTransferred: 55, countries: ['FF']},
|
||||
],
|
||||
|
|
@ -157,11 +142,6 @@ describe('OutlineSharedMetricsPublisher', () => {
|
|||
);
|
||||
|
||||
publisher.startSharing();
|
||||
usageMetrics.keyUsage = [
|
||||
{accessKeyId: 'user-0', inboundBytes: 11},
|
||||
{accessKeyId: 'user-1', inboundBytes: 22},
|
||||
{accessKeyId: 'user-0', inboundBytes: 33},
|
||||
];
|
||||
usageMetrics.countryUsage = [
|
||||
{country: 'AA', inboundBytes: 11},
|
||||
{country: 'SY', inboundBytes: 11},
|
||||
|
|
@ -177,9 +157,6 @@ describe('OutlineSharedMetricsPublisher', () => {
|
|||
startUtcMs: startTime,
|
||||
endUtcMs: clock.nowMs,
|
||||
userReports: [
|
||||
{userId: 'M(user-0)', bytesTransferred: 11},
|
||||
{userId: 'M(user-1)', bytesTransferred: 22},
|
||||
{userId: 'M(user-0)', bytesTransferred: 33},
|
||||
{bytesTransferred: 11, countries: ['AA']},
|
||||
{bytesTransferred: 22, countries: ['CC']},
|
||||
{bytesTransferred: 33, countries: ['AA']},
|
||||
|
|
@ -289,19 +266,13 @@ class FakeMetricsCollector implements MetricsCollectorClient {
|
|||
}
|
||||
|
||||
class ManualUsageMetrics implements UsageMetrics {
|
||||
public keyUsage = [] as KeyUsage[];
|
||||
public countryUsage = [] as CountryUsage[];
|
||||
|
||||
getKeyUsage(): Promise<KeyUsage[]> {
|
||||
return Promise.resolve(this.keyUsage);
|
||||
}
|
||||
|
||||
getCountryUsage(): Promise<CountryUsage[]> {
|
||||
return Promise.resolve(this.countryUsage)
|
||||
return Promise.resolve(this.countryUsage);
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.keyUsage = [] as KeyUsage[];
|
||||
this.countryUsage = [] as CountryUsage[];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,12 +27,6 @@ const MS_PER_HOUR = 60 * 60 * 1000;
|
|||
const MS_PER_DAY = 24 * MS_PER_HOUR;
|
||||
const SANCTIONED_COUNTRIES = new Set(['CU', 'KP', 'SY']);
|
||||
|
||||
// Used internally to track key usage.
|
||||
export interface KeyUsage {
|
||||
accessKeyId: string;
|
||||
inboundBytes: number;
|
||||
}
|
||||
|
||||
export interface CountryUsage {
|
||||
country: string;
|
||||
inboundBytes: number;
|
||||
|
|
@ -50,8 +44,7 @@ export interface HourlyServerMetricsReportJson {
|
|||
// JSON format for the published report.
|
||||
// Field renames will break backwards-compatibility.
|
||||
export interface HourlyUserMetricsReportJson {
|
||||
userId?: string;
|
||||
countries?: string[];
|
||||
countries: string[];
|
||||
bytesTransferred: number;
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +71,6 @@ export interface SharedMetricsPublisher {
|
|||
}
|
||||
|
||||
export interface UsageMetrics {
|
||||
getKeyUsage(): Promise<KeyUsage[]>;
|
||||
getCountryUsage(): Promise<CountryUsage[]>;
|
||||
reset();
|
||||
}
|
||||
|
|
@ -89,23 +81,6 @@ export class PrometheusUsageMetrics implements UsageMetrics {
|
|||
|
||||
constructor(private prometheusClient: PrometheusClient) {}
|
||||
|
||||
async getKeyUsage(): Promise<KeyUsage[]> {
|
||||
const timeDeltaSecs = Math.round((Date.now() - this.resetTimeMs) / 1000);
|
||||
// We measure the traffic to and from the target, since that's what we are protecting.
|
||||
const result = await this.prometheusClient.query(
|
||||
`sum(increase(shadowsocks_data_bytes{dir=~"p>t|p<t"}[${timeDeltaSecs}s])) by (access_key)`
|
||||
);
|
||||
const usage = [] as KeyUsage[];
|
||||
for (const entry of result.result) {
|
||||
const accessKeyId = entry.metric['access_key'] || '';
|
||||
const inboundBytes = Math.round(parseFloat(entry.value[1]));
|
||||
if (inboundBytes > 0) {
|
||||
usage.push({accessKeyId, inboundBytes});
|
||||
}
|
||||
}
|
||||
return usage;
|
||||
}
|
||||
|
||||
async getCountryUsage(): Promise<CountryUsage[]> {
|
||||
const timeDeltaSecs = Math.round((Date.now() - this.resetTimeMs) / 1000);
|
||||
// We measure the traffic to and from the target, since that's what we are protecting.
|
||||
|
|
@ -191,9 +166,7 @@ export class OutlineSharedMetricsPublisher implements SharedMetricsPublisher {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
const keyUsagePromise = usageMetrics.getKeyUsage()
|
||||
const countryUsagePromise = usageMetrics.getCountryUsage()
|
||||
await this.reportServerUsageMetrics(await keyUsagePromise, await countryUsagePromise);
|
||||
await this.reportServerUsageMetrics(await usageMetrics.getCountryUsage());
|
||||
usageMetrics.reset();
|
||||
} catch (err) {
|
||||
logging.error(`Failed to report server usage metrics: ${err}`);
|
||||
|
|
@ -227,26 +200,10 @@ export class OutlineSharedMetricsPublisher implements SharedMetricsPublisher {
|
|||
return this.serverConfig.data().metricsEnabled || false;
|
||||
}
|
||||
|
||||
private async reportServerUsageMetrics(keyUsageMetrics: KeyUsage[], countryUsageMetrics: CountryUsage[]): Promise<void> {
|
||||
private async reportServerUsageMetrics(countryUsageMetrics: CountryUsage[]): Promise<void> {
|
||||
const reportEndTimestampMs = this.clock.now();
|
||||
|
||||
const userReports = [] as HourlyUserMetricsReportJson[];
|
||||
// HACK! We use the same backend reporting endpoint for key and country usage.
|
||||
// A row with empty country is for key usage, a row with empty userId is for country usage.
|
||||
// Note that this reports usage twice. If you want the total, filter to rows with non empty countries.
|
||||
for (const keyUsage of keyUsageMetrics) {
|
||||
if (keyUsage.inboundBytes === 0) {
|
||||
continue;
|
||||
}
|
||||
const userId = this.toMetricsId(keyUsage.accessKeyId);
|
||||
if (!userId) {
|
||||
continue;
|
||||
}
|
||||
userReports.push({
|
||||
userId,
|
||||
bytesTransferred: keyUsage.inboundBytes,
|
||||
});
|
||||
}
|
||||
for (const countryUsage of countryUsageMetrics) {
|
||||
if (countryUsage.inboundBytes === 0) {
|
||||
continue;
|
||||
|
|
@ -254,8 +211,8 @@ export class OutlineSharedMetricsPublisher implements SharedMetricsPublisher {
|
|||
if (isSanctionedCountry(countryUsage.country)) {
|
||||
continue;
|
||||
}
|
||||
// Make sure to always set the country to differentiate the row
|
||||
// from key usage rows.
|
||||
// Make sure to always set a country, which is required by the metrics server validation.
|
||||
// It's used to differentiate the row from the legacy key usage rows.
|
||||
const country = countryUsage.country || 'ZZ';
|
||||
userReports.push({
|
||||
bytesTransferred: countryUsage.inboundBytes,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue