revert individual settings for metrics, now only enable/disable

This commit is contained in:
Daniel Dietzler 2023-12-28 19:49:32 +01:00
parent ac4c57247e
commit 0232655da2
No known key found for this signature in database
GPG Key ID: A1C0B97CD8E18DFF
11 changed files with 33 additions and 230 deletions

View File

@ -3717,19 +3717,9 @@
} }
}, },
"/metrics": { "/metrics": {
"put": { "get": {
"operationId": "getMetrics", "operationId": "getMetrics",
"parameters": [], "parameters": [],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SystemConfigMetricsDto"
}
}
},
"required": true
},
"responses": { "responses": {
"200": { "200": {
"content": { "content": {
@ -8103,48 +8093,6 @@
], ],
"type": "object" "type": "object"
}, },
"MetricServerInfoConfig": {
"properties": {
"cpuCount": {
"type": "boolean"
},
"cpuModel": {
"type": "boolean"
},
"memory": {
"type": "boolean"
},
"version": {
"type": "boolean"
}
},
"required": [
"cpuCount",
"cpuModel",
"memory",
"version"
],
"type": "object"
},
"MetricsAssetCountConfig": {
"properties": {
"image": {
"type": "boolean"
},
"total": {
"type": "boolean"
},
"video": {
"type": "boolean"
}
},
"required": [
"image",
"video",
"total"
],
"type": "object"
},
"ModelType": { "ModelType": {
"enum": [ "enum": [
"facial-recognition", "facial-recognition",
@ -9373,20 +9321,12 @@
}, },
"SystemConfigMetricsDto": { "SystemConfigMetricsDto": {
"properties": { "properties": {
"assetCount": {
"$ref": "#/components/schemas/MetricsAssetCountConfig"
},
"enabled": { "enabled": {
"type": "boolean" "type": "boolean"
},
"serverInfo": {
"$ref": "#/components/schemas/MetricServerInfoConfig"
} }
}, },
"required": [ "required": [
"enabled", "enabled"
"serverInfo",
"assetCount"
], ],
"type": "object" "type": "object"
}, },

View File

@ -1,31 +1,3 @@
import { IsBoolean } from 'class-validator';
// TODO I feel like it must be possible to generate those from MetricsServerInfo and MetricsAssetCount
export class MetricServerInfoConfig {
@IsBoolean()
cpuCount!: boolean;
@IsBoolean()
cpuModel!: boolean;
@IsBoolean()
memory!: boolean;
@IsBoolean()
version!: boolean;
}
export class MetricsAssetCountConfig {
@IsBoolean()
image!: boolean;
@IsBoolean()
video!: boolean;
@IsBoolean()
total!: boolean;
}
class MetricsServerInfo { class MetricsServerInfo {
cpuCount!: number; cpuCount!: number;
cpuModel!: string; cpuModel!: string;

View File

@ -1,12 +1,11 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import _ from 'lodash';
import { serverVersion } from '../domain.constant'; import { serverVersion } from '../domain.constant';
import { JobName } from '../job'; import { JobName } from '../job';
import { ISystemConfigRepository } from '../repositories'; import { ISystemConfigRepository } from '../repositories';
import { IJobRepository } from '../repositories/job.repository'; import { IJobRepository } from '../repositories/job.repository';
import { IMetricsRepository } from '../repositories/metrics.repository'; import { IMetricsRepository } from '../repositories/metrics.repository';
import { FeatureFlag, SystemConfigCore, SystemConfigMetricsDto } from '../system-config'; import { FeatureFlag, SystemConfigCore } from '../system-config';
import { Metrics, MetricsDto } from './metrics.dto'; import { MetricsDto } from './metrics.dto';
@Injectable() @Injectable()
export class MetricsService { export class MetricsService {
@ -27,15 +26,14 @@ export class MetricsService {
} }
async handleSendMetrics() { async handleSendMetrics() {
const metricsConfig = await this.configCore.getConfig().then((config) => config.metrics); const metrics = await this.getMetrics();
const metrics = await this.getMetrics(metricsConfig);
await this.repository.sendMetrics(metrics); await this.repository.sendMetrics(metrics);
return true; return true;
} }
async getMetrics(config: SystemConfigMetricsDto) { async getMetrics() {
const metrics: Metrics = new MetricsDto(); const metrics = new MetricsDto();
metrics.serverInfo = { metrics.serverInfo = {
cpuCount: this.repository.getCpuCount(), cpuCount: this.repository.getCpuCount(),
@ -50,22 +48,6 @@ export class MetricsService {
total: await this.repository.getAssetCount(), total: await this.repository.getAssetCount(),
}; };
return _.pick(metrics, this.getKeys(config)); return metrics;
}
private getKeys(config: SystemConfigMetricsDto) {
const result = [];
const keys = _.keys(config) as Array<keyof SystemConfigMetricsDto>;
for (const key of keys) {
const subConfig = _.get(config, key);
if (typeof subConfig === 'boolean') {
continue;
}
const keys = _.keys(_.pickBy(subConfig)).map((value) => `${key}.${value}`);
result.push(...keys);
}
return result;
} }
} }

View File

@ -9,5 +9,5 @@ export interface IMetricsRepository {
getMemory(): number; getMemory(): number;
getImageCount(): Promise<number>; getImageCount(): Promise<number>;
getVideoCount(): Promise<number>; getVideoCount(): Promise<number>;
sendMetrics(payload: Partial<MetricsDto>): Promise<void>; sendMetrics(payload: MetricsDto): Promise<void>;
} }

View File

@ -1,18 +1,6 @@
import { MetricServerInfoConfig, MetricsAssetCountConfig } from '@app/domain'; import { IsBoolean } from 'class-validator';
import { Type } from 'class-transformer';
import { IsBoolean, IsObject, ValidateNested } from 'class-validator';
export class SystemConfigMetricsDto { export class SystemConfigMetricsDto {
@IsBoolean() @IsBoolean()
enabled!: boolean; enabled!: boolean;
@Type(() => MetricServerInfoConfig)
@ValidateNested()
@IsObject()
serverInfo!: MetricServerInfoConfig;
@Type(() => MetricsAssetCountConfig)
@ValidateNested()
@IsObject()
assetCount!: MetricsAssetCountConfig;
} }

View File

@ -84,17 +84,6 @@ export const defaults = Object.freeze<SystemConfig>({
}, },
metrics: { metrics: {
enabled: false, enabled: false,
serverInfo: {
cpuCount: true,
cpuModel: true,
memory: true,
version: true,
},
assetCount: {
image: true,
video: true,
total: true,
},
}, },
reverseGeocoding: { reverseGeocoding: {
enabled: true, enabled: true,

View File

@ -1,5 +1,5 @@
import { Metrics, MetricsService, SystemConfigMetricsDto } from '@app/domain'; import { Metrics, MetricsService } from '@app/domain';
import { Body, Controller, Put } from '@nestjs/common'; import { Controller, Get } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { Authenticated } from '../app.guard'; import { Authenticated } from '../app.guard';
import { UseValidation } from '../app.utils'; import { UseValidation } from '../app.utils';
@ -11,8 +11,8 @@ import { UseValidation } from '../app.utils';
export class MetricsController { export class MetricsController {
constructor(private service: MetricsService) {} constructor(private service: MetricsService) {}
@Put() @Get()
getMetrics(@Body() dto: SystemConfigMetricsDto): Promise<Partial<Metrics>> { getMetrics(): Promise<Partial<Metrics>> {
return this.service.getMetrics(dto); return this.service.getMetrics();
} }
} }

View File

@ -67,13 +67,6 @@ export enum SystemConfigKey {
MAP_DARK_STYLE = 'map.darkStyle', MAP_DARK_STYLE = 'map.darkStyle',
METRICS_ENABLED = 'metrics.enabled', METRICS_ENABLED = 'metrics.enabled',
METRICS_SERVER_INFO_CPU_COUNT = 'metrics.serverInfo.cpuCount',
METRICS_SERVER_INFO_CPU_MODEL = 'metrics.serverInfo.cpuModel',
METRICS_SERVER_INFO_MEMORY = 'metrics.serverInfo.memory',
METRICS_SERVER_INFO_VERSION = 'metrics.serverInfo.version',
METRICS_ASSET_COUNT_IMAGE = 'metrics.assetCount.image',
METRICS_ASSET_COUNT_VIDEO = 'metrics.assetCount.video',
METRICS_ASSET_COUNT_TOTAL = 'metrics.assetCount.total',
REVERSE_GEOCODING_ENABLED = 'reverseGeocoding.enabled', REVERSE_GEOCODING_ENABLED = 'reverseGeocoding.enabled',
@ -207,17 +200,6 @@ export interface SystemConfig {
}; };
metrics: { metrics: {
enabled: boolean; enabled: boolean;
serverInfo: {
cpuCount: boolean;
cpuModel: boolean;
memory: boolean;
version: boolean;
};
assetCount: {
image: boolean;
video: boolean;
total: boolean;
};
}; };
reverseGeocoding: { reverseGeocoding: {
enabled: boolean; enabled: boolean;

View File

@ -10,7 +10,7 @@ import { AssetEntity, AssetType } from '../entities';
@Injectable() @Injectable()
export class MetricsRepository implements IMetricsRepository { export class MetricsRepository implements IMetricsRepository {
constructor(@InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>) {} constructor(@InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>) {}
async sendMetrics(payload: Partial<MetricsDto>): Promise<void> { async sendMetrics(payload: MetricsDto): Promise<void> {
await axios.post('IMMICH-DATA-DOMAIN', payload); await axios.post('IMMICH-DATA-DOMAIN', payload);
} }

View File

@ -7,7 +7,6 @@
import { api, SystemConfigMetricsDto } from '@api'; import { api, SystemConfigMetricsDto } from '@api';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
import SettingAccordion from '../setting-accordion.svelte';
import SettingButtonsRow from '../setting-buttons-row.svelte'; import SettingButtonsRow from '../setting-buttons-row.svelte';
import SettingSwitch from '../setting-switch.svelte'; import SettingSwitch from '../setting-switch.svelte';
import type { ResetOptions } from '$lib/utils/dipatch'; import type { ResetOptions } from '$lib/utils/dipatch';
@ -19,8 +18,6 @@
let savedConfig: SystemConfigMetricsDto; let savedConfig: SystemConfigMetricsDto;
let defaultConfig: SystemConfigMetricsDto; let defaultConfig: SystemConfigMetricsDto;
$: sharedMetrics = getSharedMetrics(config);
const handleReset = (detail: ResetOptions) => { const handleReset = (detail: ResetOptions) => {
if (detail.default) { if (detail.default) {
resetToDefault(); resetToDefault();
@ -44,8 +41,6 @@
...current, ...current,
metrics: { metrics: {
enabled: config.enabled, enabled: config.enabled,
serverInfo: config.serverInfo,
assetCount: config.assetCount,
}, },
}, },
}); });
@ -83,8 +78,8 @@
}); });
} }
function getSharedMetrics(systemConfigMetricsDto: SystemConfigMetricsDto) { function getSharedMetrics() {
return api.metricsApi.getMetrics({ systemConfigMetricsDto }).then((response) => response.data); return api.metricsApi.getMetrics().then((response) => response.data);
} }
</script> </script>
@ -92,61 +87,16 @@
{#await refreshConfig() then} {#await refreshConfig() then}
<div in:fade={{ duration: 500 }}> <div in:fade={{ duration: 500 }}>
<form autocomplete="off" on:submit|preventDefault> <form autocomplete="off" on:submit|preventDefault>
<div class="flex flex-col gap-4">
<SettingSwitch title="ENABLED" {disabled} subtitle="Enable sharing metrics" bind:checked={config.enabled} />
<SettingAccordion title="Server Info Metrics" subtitle="Manage which server infos the instance should share">
<div class="ml-4 mt-4 flex flex-col gap-4"> <div class="ml-4 mt-4 flex flex-col gap-4">
<SettingSwitch <SettingSwitch
title="CPU Count" title="ENABLED"
disabled={disabled || !config.enabled} {disabled}
bind:checked={config.serverInfo.cpuCount} subtitle="Enable sharing of anonymous usage data"
bind:checked={config.enabled}
/> />
<SettingSwitch
title="CPU Model"
disabled={disabled || !config.enabled}
bind:checked={config.serverInfo.cpuModel}
/>
<SettingSwitch
title="Memory"
disabled={disabled || !config.enabled}
bind:checked={config.serverInfo.memory}
/>
<SettingSwitch
title="Version"
disabled={disabled || !config.enabled}
bind:checked={config.serverInfo.version}
/>
</div></SettingAccordion
>
<SettingAccordion title="Asset Count Metrics" subtitle="Manage which asset counts the instance should share">
<div class="ml-4 mt-4 flex flex-col gap-4">
<SettingSwitch
title="Image Count"
disabled={disabled || !config.enabled}
bind:checked={config.assetCount.image}
/>
<SettingSwitch
title="Video Count"
disabled={disabled || !config.enabled}
bind:checked={config.assetCount.video}
/>
<SettingSwitch
title="Total Assets Count"
disabled={disabled || !config.enabled}
bind:checked={config.assetCount.total}
/>
</div></SettingAccordion
>
{#if config.enabled} {#if config.enabled}
{#await sharedMetrics} {#await getSharedMetrics()}
<LoadingSpinner /> <LoadingSpinner />
{:then metrics} {:then metrics}
<div class="mt-2 rounded-lg bg-gray-200 p-4 text-xs dark:bg-gray-700 dark:text-immich-dark-fg"> <div class="mt-2 rounded-lg bg-gray-200 p-4 text-xs dark:bg-gray-700 dark:text-immich-dark-fg">

View File

@ -64,6 +64,13 @@
<section id="setting-content" class="flex place-content-center sm:mx-4"> <section id="setting-content" class="flex place-content-center sm:mx-4">
<section class="w-full pb-28 sm:w-5/6 md:w-[850px]"> <section class="w-full pb-28 sm:w-5/6 md:w-[850px]">
<SettingAccordion
title="Anonymous Usage Data Settings"
subtitle="Manage if you want to share anonymous usage data with Immich"
>
<MetricsSettings disabled={$featureFlags.configFile} config={configs.metrics} />
</SettingAccordion>
<SettingAccordion <SettingAccordion
title="Job Settings" title="Job Settings"
subtitle="Manage job concurrency" subtitle="Manage job concurrency"
@ -88,13 +95,6 @@
<MapSettings disabled={$featureFlags.configFile} config={configs} /> <MapSettings disabled={$featureFlags.configFile} config={configs} />
</SettingAccordion> </SettingAccordion>
<SettingAccordion
title="Metrics Settings"
subtitle="Manage which - if any - metrics you want to share with Immich"
>
<MetricsSettings disabled={$featureFlags.configFile} config={configs.metrics} />
</SettingAccordion>
<SettingAccordion title="OAuth Authentication" subtitle="Manage the login with OAuth settings"> <SettingAccordion title="OAuth Authentication" subtitle="Manage the login with OAuth settings">
<OAuthSettings disabled={$featureFlags.configFile} oauthConfig={configs.oauth} /> <OAuthSettings disabled={$featureFlags.configFile} oauthConfig={configs.oauth} />
</SettingAccordion> </SettingAccordion>