mirror of
https://github.com/immich-app/immich.git
synced 2025-01-06 03:46:47 +01:00
refactor(server): metric repo (#8278)
* refactor * redundant `implements` * simplify * remove `enabled`
This commit is contained in:
parent
c56c04a82b
commit
c45e28ab53
4 changed files with 79 additions and 34 deletions
|
@ -1,13 +1,21 @@
|
||||||
import { MetricOptions } from '@opentelemetry/api';
|
import { MetricOptions } from '@opentelemetry/api';
|
||||||
|
|
||||||
export interface CustomMetricOptions extends MetricOptions {
|
|
||||||
enabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const IMetricRepository = 'IMetricRepository';
|
export const IMetricRepository = 'IMetricRepository';
|
||||||
|
|
||||||
export interface IMetricRepository {
|
export interface MetricGroupOptions {
|
||||||
addToCounter(name: string, value: number, options?: CustomMetricOptions): void;
|
enabled: boolean;
|
||||||
updateGauge(name: string, value: number, options?: CustomMetricOptions): void;
|
}
|
||||||
updateHistogram(name: string, value: number, options?: CustomMetricOptions): void;
|
|
||||||
|
export interface IMetricGroupRepository {
|
||||||
|
addToCounter(name: string, value: number, options?: MetricOptions): void;
|
||||||
|
addToGauge(name: string, value: number, options?: MetricOptions): void;
|
||||||
|
addToHistogram(name: string, value: number, options?: MetricOptions): void;
|
||||||
|
configure(options: MetricGroupOptions): this;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMetricRepository {
|
||||||
|
api: IMetricGroupRepository;
|
||||||
|
host: IMetricGroupRepository;
|
||||||
|
jobs: IMetricGroupRepository;
|
||||||
|
repo: IMetricGroupRepository;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,48 @@
|
||||||
import { Inject } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { MetricOptions } from '@opentelemetry/api';
|
||||||
import { MetricService } from 'nestjs-otel';
|
import { MetricService } from 'nestjs-otel';
|
||||||
import { CustomMetricOptions, IMetricRepository } from 'src/interfaces/metric.interface';
|
import { IMetricGroupRepository, IMetricRepository, MetricGroupOptions } from 'src/interfaces/metric.interface';
|
||||||
|
import { apiMetrics, hostMetrics, jobMetrics, repoMetrics } from 'src/utils/instrumentation';
|
||||||
|
|
||||||
export class MetricRepository implements IMetricRepository {
|
class MetricGroupRepository implements IMetricGroupRepository {
|
||||||
constructor(@Inject(MetricService) private readonly metricService: MetricService) {}
|
private enabled = false;
|
||||||
|
constructor(private readonly metricService: MetricService) {}
|
||||||
|
|
||||||
addToCounter(name: string, value: number, options?: CustomMetricOptions): void {
|
addToCounter(name: string, value: number, options?: MetricOptions): void {
|
||||||
if (options?.enabled === false) {
|
if (this.enabled) {
|
||||||
return;
|
this.metricService.getCounter(name, options).add(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.metricService.getCounter(name, options).add(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGauge(name: string, value: number, options?: CustomMetricOptions): void {
|
addToGauge(name: string, value: number, options?: MetricOptions): void {
|
||||||
if (options?.enabled === false) {
|
if (this.enabled) {
|
||||||
return;
|
this.metricService.getUpDownCounter(name, options).add(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.metricService.getUpDownCounter(name, options).add(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHistogram(name: string, value: number, options?: CustomMetricOptions): void {
|
addToHistogram(name: string, value: number, options?: MetricOptions): void {
|
||||||
if (options?.enabled === false) {
|
if (this.enabled) {
|
||||||
return;
|
this.metricService.getHistogram(name, options).record(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.metricService.getHistogram(name, options).record(value);
|
configure(options: MetricGroupOptions): this {
|
||||||
|
this.enabled = options.enabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MetricRepository implements IMetricRepository {
|
||||||
|
api: MetricGroupRepository;
|
||||||
|
host: MetricGroupRepository;
|
||||||
|
jobs: MetricGroupRepository;
|
||||||
|
repo: MetricGroupRepository;
|
||||||
|
|
||||||
|
constructor(metricService: MetricService) {
|
||||||
|
this.api = new MetricGroupRepository(metricService).configure({ enabled: apiMetrics });
|
||||||
|
this.host = new MetricGroupRepository(metricService).configure({ enabled: hostMetrics });
|
||||||
|
this.jobs = new MetricGroupRepository(metricService).configure({ enabled: jobMetrics });
|
||||||
|
this.repo = new MetricGroupRepository(metricService).configure({ enabled: repoMetrics });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import {
|
||||||
import { IMetricRepository } from 'src/interfaces/metric.interface';
|
import { IMetricRepository } from 'src/interfaces/metric.interface';
|
||||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||||
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
|
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
|
||||||
import { jobMetrics } from 'src/utils/instrumentation';
|
|
||||||
import { ImmichLogger } from 'src/utils/logger';
|
import { ImmichLogger } from 'src/utils/logger';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -96,7 +95,7 @@ export class JobService {
|
||||||
throw new BadRequestException(`Job is already running`);
|
throw new BadRequestException(`Job is already running`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.metricRepository.addToCounter(`immich.queues.${snakeCase(name)}.started`, 1), { enabled: jobMetrics };
|
this.metricRepository.jobs.addToCounter(`immich.queues.${snakeCase(name)}.started`, 1);
|
||||||
|
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case QueueName.VIDEO_CONVERSION: {
|
case QueueName.VIDEO_CONVERSION: {
|
||||||
|
@ -163,20 +162,20 @@ export class JobService {
|
||||||
const { name, data } = item;
|
const { name, data } = item;
|
||||||
|
|
||||||
const queueMetric = `immich.queues.${snakeCase(queueName)}.active`;
|
const queueMetric = `immich.queues.${snakeCase(queueName)}.active`;
|
||||||
this.metricRepository.updateGauge(queueMetric, 1, { enabled: jobMetrics });
|
this.metricRepository.jobs.addToGauge(queueMetric, 1);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const handler = jobHandlers[name];
|
const handler = jobHandlers[name];
|
||||||
const status = await handler(data);
|
const status = await handler(data);
|
||||||
const jobMetric = `immich.jobs.${name.replaceAll('-', '_')}.${status}`;
|
const jobMetric = `immich.jobs.${name.replaceAll('-', '_')}.${status}`;
|
||||||
this.metricRepository.addToCounter(jobMetric, 1, { enabled: jobMetrics });
|
this.metricRepository.jobs.addToCounter(jobMetric, 1);
|
||||||
if (status === JobStatus.SUCCESS || status == JobStatus.SKIPPED) {
|
if (status === JobStatus.SUCCESS || status == JobStatus.SKIPPED) {
|
||||||
await this.onDone(item);
|
await this.onDone(item);
|
||||||
}
|
}
|
||||||
} catch (error: Error | any) {
|
} catch (error: Error | any) {
|
||||||
this.logger.error(`Unable to run job handler (${queueName}/${name}): ${error}`, error?.stack, data);
|
this.logger.error(`Unable to run job handler (${queueName}/${name}): ${error}`, error?.stack, data);
|
||||||
} finally {
|
} finally {
|
||||||
this.metricRepository.updateGauge(queueMetric, -1, { enabled: jobMetrics });
|
this.metricRepository.jobs.addToGauge(queueMetric, -1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,29 @@ import { IMetricRepository } from 'src/interfaces/metric.interface';
|
||||||
|
|
||||||
export const newMetricRepositoryMock = (): jest.Mocked<IMetricRepository> => {
|
export const newMetricRepositoryMock = (): jest.Mocked<IMetricRepository> => {
|
||||||
return {
|
return {
|
||||||
addToCounter: jest.fn(),
|
api: {
|
||||||
updateGauge: jest.fn(),
|
addToCounter: jest.fn(),
|
||||||
updateHistogram: jest.fn(),
|
addToGauge: jest.fn(),
|
||||||
|
addToHistogram: jest.fn(),
|
||||||
|
configure: jest.fn(),
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
addToCounter: jest.fn(),
|
||||||
|
addToGauge: jest.fn(),
|
||||||
|
addToHistogram: jest.fn(),
|
||||||
|
configure: jest.fn(),
|
||||||
|
},
|
||||||
|
jobs: {
|
||||||
|
addToCounter: jest.fn(),
|
||||||
|
addToGauge: jest.fn(),
|
||||||
|
addToHistogram: jest.fn(),
|
||||||
|
configure: jest.fn(),
|
||||||
|
},
|
||||||
|
repo: {
|
||||||
|
addToCounter: jest.fn(),
|
||||||
|
addToGauge: jest.fn(),
|
||||||
|
addToHistogram: jest.fn(),
|
||||||
|
configure: jest.fn(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue