1
1
mirror of https://github.com/n8n-io/n8n.git synced 2024-12-29 15:14:40 +03:00

refactor(core): Port diagnostics config (#11761)

This commit is contained in:
Iván Ovejero 2024-11-18 14:08:45 +01:00 committed by GitHub
parent 61696c3db3
commit a544b74d87
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 70 additions and 75 deletions

View File

@ -0,0 +1,30 @@
import { Config, Env, Nested } from '../decorators';
@Config
class PostHogConfig {
/** API key for PostHog. */
@Env('N8N_DIAGNOSTICS_POSTHOG_API_KEY')
apiKey: string = 'phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo';
/** API host for PostHog. */
@Env('N8N_DIAGNOSTICS_POSTHOG_API_HOST')
apiHost: string = 'https://ph.n8n.io';
}
@Config
export class DiagnosticsConfig {
/** Whether diagnostics are enabled. */
@Env('N8N_DIAGNOSTICS_ENABLED')
enabled: boolean = false;
/** Diagnostics config for frontend. */
@Env('N8N_DIAGNOSTICS_CONFIG_FRONTEND')
frontendConfig: string = '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://telemetry.n8n.io';
/** Diagnostics config for backend. */
@Env('N8N_DIAGNOSTICS_CONFIG_BACKEND')
backendConfig: string = '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://telemetry.n8n.io';
@Nested
posthogConfig: PostHogConfig;
}

View File

@ -1,6 +1,7 @@
import { CacheConfig } from './configs/cache.config';
import { CredentialsConfig } from './configs/credentials.config';
import { DatabaseConfig } from './configs/database.config';
import { DiagnosticsConfig } from './configs/diagnostics.config';
import { EndpointsConfig } from './configs/endpoints.config';
import { EventBusConfig } from './configs/event-bus.config';
import { ExternalSecretsConfig } from './configs/external-secrets.config';
@ -117,4 +118,7 @@ export class GlobalConfig {
@Nested
pruning: PruningConfig;
@Nested
diagnostics: DiagnosticsConfig;
}

View File

@ -282,6 +282,15 @@ describe('GlobalConfig', () => {
hardDeleteInterval: 15,
softDeleteInterval: 60,
},
diagnostics: {
enabled: false,
frontendConfig: '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://telemetry.n8n.io',
backendConfig: '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://telemetry.n8n.io',
posthogConfig: {
apiKey: 'phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo',
apiHost: 'https://ph.n8n.io',
},
},
};
it('should use all default values when no env variables are defined', () => {

View File

@ -296,43 +296,6 @@ export const schema = {
},
},
diagnostics: {
enabled: {
doc: 'Whether diagnostic mode is enabled.',
format: Boolean,
default: true,
env: 'N8N_DIAGNOSTICS_ENABLED',
},
config: {
posthog: {
apiKey: {
doc: 'API key for PostHog',
format: String,
default: 'phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo',
env: 'N8N_DIAGNOSTICS_POSTHOG_API_KEY',
},
apiHost: {
doc: 'API host for PostHog',
format: String,
default: 'https://ph.n8n.io',
env: 'N8N_DIAGNOSTICS_POSTHOG_API_HOST',
},
},
frontend: {
doc: 'Diagnostics config for frontend.',
format: String,
default: '1zPn9bgWPzlQc0p8Gj1uiK6DOTn;https://telemetry.n8n.io',
env: 'N8N_DIAGNOSTICS_CONFIG_FRONTEND',
},
backend: {
doc: 'Diagnostics config for backend.',
format: String,
default: '1zPn7YoGC3ZXE9zLeTKLuQCB4F6;https://telemetry.n8n.io',
env: 'N8N_DIAGNOSTICS_CONFIG_BACKEND',
},
},
},
defaultLocale: {
doc: 'Default locale for the UI',
format: String,

View File

@ -2,7 +2,6 @@ import type { GlobalConfig } from '@n8n/config';
import { mock } from 'jest-mock-extended';
import type { IWorkflowBase } from 'n8n-workflow';
import config from '@/config';
import { N8N_VERSION } from '@/constants';
import type { WorkflowEntity } from '@/databases/entities/workflow-entity';
import type { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
@ -66,7 +65,7 @@ describe('TelemetryEventRelay', () => {
});
beforeEach(() => {
config.set('diagnostics.enabled', true);
globalConfig.diagnostics.enabled = true;
});
afterEach(() => {
@ -75,7 +74,7 @@ describe('TelemetryEventRelay', () => {
describe('init', () => {
it('with diagnostics enabled, should init telemetry and register listeners', async () => {
config.set('diagnostics.enabled', true);
globalConfig.diagnostics.enabled = true;
const telemetryEventRelay = new TelemetryEventRelay(
eventService,
telemetry,
@ -96,7 +95,7 @@ describe('TelemetryEventRelay', () => {
});
it('with diagnostics disabled, should neither init telemetry nor register listeners', async () => {
config.set('diagnostics.enabled', false);
globalConfig.diagnostics.enabled = false;
const telemetryEventRelay = new TelemetryEventRelay(
eventService,
telemetry,

View File

@ -37,7 +37,7 @@ export class TelemetryEventRelay extends EventRelay {
}
async init() {
if (!config.getEnv('diagnostics.enabled')) return;
if (!this.globalConfig.diagnostics.enabled) return;
await this.telemetry.init();

View File

@ -3,7 +3,6 @@ import { mock } from 'jest-mock-extended';
import { InstanceSettings } from 'n8n-core';
import { PostHog } from 'posthog-node';
import config from '@/config';
import { PostHogClient } from '@/posthog';
import { mockInstance } from '@test/mocking';
@ -20,12 +19,11 @@ describe('PostHog', () => {
const globalConfig = mock<GlobalConfig>({ logging: { level: 'debug' } });
beforeAll(() => {
config.set('diagnostics.config.posthog.apiKey', apiKey);
config.set('diagnostics.config.posthog.apiHost', apiHost);
globalConfig.diagnostics.posthogConfig = { apiKey, apiHost };
});
beforeEach(() => {
config.set('diagnostics.enabled', true);
globalConfig.diagnostics.enabled = true;
jest.resetAllMocks();
});
@ -37,7 +35,7 @@ describe('PostHog', () => {
});
it('does not initialize or track if diagnostics are not enabled', async () => {
config.set('diagnostics.enabled', false);
globalConfig.diagnostics.enabled = false;
const ph = new PostHogClient(instanceSettings, globalConfig);
await ph.init();

View File

@ -4,7 +4,6 @@ import type { FeatureFlags, ITelemetryTrackProperties } from 'n8n-workflow';
import type { PostHog } from 'posthog-node';
import { Service } from 'typedi';
import config from '@/config';
import type { PublicUser } from '@/interfaces';
@Service()
@ -17,14 +16,14 @@ export class PostHogClient {
) {}
async init() {
const enabled = config.getEnv('diagnostics.enabled');
const { enabled, posthogConfig } = this.globalConfig.diagnostics;
if (!enabled) {
return;
}
const { PostHog } = await import('posthog-node');
this.postHog = new PostHog(config.getEnv('diagnostics.config.posthog.apiKey'), {
host: config.getEnv('diagnostics.config.posthog.apiHost'),
this.postHog = new PostHog(posthogConfig.apiKey, {
host: posthogConfig.apiHost,
});
const logLevel = this.globalConfig.logging.level;

View File

@ -103,7 +103,7 @@ export class InstanceRiskReporter implements RiskReporter {
};
settings.telemetry = {
diagnosticsEnabled: config.getEnv('diagnostics.enabled'),
diagnosticsEnabled: this.globalConfig.diagnostics.enabled,
};
return settings;

View File

@ -39,7 +39,7 @@ describe('WorkflowStatisticsService', () => {
});
Object.assign(entityManager, { connection: dataSource });
config.set('diagnostics.enabled', true);
globalConfig.diagnostics.enabled = true;
config.set('deployment.type', 'n8n-testing');
mocked(ownershipService.getWorkflowProjectCached).mockResolvedValue(fakeProject);
mocked(ownershipService.getPersonalProjectOwnerCached).mockResolvedValue(fakeUser);

View File

@ -66,11 +66,11 @@ export class FrontendService {
const restEndpoint = this.globalConfig.endpoints.rest;
const telemetrySettings: ITelemetrySettings = {
enabled: config.getEnv('diagnostics.enabled'),
enabled: this.globalConfig.diagnostics.enabled,
};
if (telemetrySettings.enabled) {
const conf = config.getEnv('diagnostics.config.frontend');
const conf = this.globalConfig.diagnostics.frontendConfig;
const [key, url] = conf.split(';');
if (!key || !url) {
@ -122,15 +122,15 @@ export class FrontendService {
instanceId: this.instanceSettings.instanceId,
telemetry: telemetrySettings,
posthog: {
enabled: config.getEnv('diagnostics.enabled'),
apiHost: config.getEnv('diagnostics.config.posthog.apiHost'),
apiKey: config.getEnv('diagnostics.config.posthog.apiKey'),
enabled: this.globalConfig.diagnostics.enabled,
apiHost: this.globalConfig.diagnostics.posthogConfig.apiHost,
apiKey: this.globalConfig.diagnostics.posthogConfig.apiKey,
autocapture: false,
disableSessionRecording: config.getEnv('deployment.type') !== 'cloud',
debug: this.globalConfig.logging.level === 'debug',
},
personalizationSurveyEnabled:
config.getEnv('personalization.enabled') && config.getEnv('diagnostics.enabled'),
config.getEnv('personalization.enabled') && this.globalConfig.diagnostics.enabled,
defaultLocale: config.getEnv('defaultLocale'),
userManagement: {
quota: this.license.getUsersLimit(),

View File

@ -21,6 +21,10 @@ describe('Telemetry', () => {
const instanceId = 'Telemetry unit test';
const testDateTime = new Date('2022-01-01 00:00:00');
const instanceSettings = mockInstance(InstanceSettings, { instanceId });
const globalConfig = mock<GlobalConfig>({
diagnostics: { enabled: true },
logging: { level: 'info', outputs: ['console'] },
});
beforeAll(() => {
// @ts-expect-error Spying on private method
@ -28,7 +32,6 @@ describe('Telemetry', () => {
jest.useFakeTimers();
jest.setSystemTime(testDateTime);
config.set('diagnostics.enabled', true);
config.set('deployment.type', 'n8n-testing');
});
@ -45,14 +48,7 @@ describe('Telemetry', () => {
const postHog = new PostHogClient(instanceSettings, mock());
await postHog.init();
telemetry = new Telemetry(
mock(),
postHog,
mock(),
instanceSettings,
mock(),
mock<GlobalConfig>({ logging: { level: 'info', outputs: ['console'] } }),
);
telemetry = new Telemetry(mock(), postHog, mock(), instanceSettings, mock(), globalConfig);
// @ts-expect-error Assigning to private property
telemetry.rudderStack = mockRudderStack;
});

View File

@ -5,7 +5,6 @@ import { InstanceSettings } from 'n8n-core';
import type { ITelemetryTrackProperties } from 'n8n-workflow';
import { Container, Service } from 'typedi';
import config from '@/config';
import { LOWEST_SHUTDOWN_PRIORITY, N8N_VERSION } from '@/constants';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
@ -54,10 +53,9 @@ export class Telemetry {
) {}
async init() {
const enabled = config.getEnv('diagnostics.enabled');
const { enabled, backendConfig } = this.globalConfig.diagnostics;
if (enabled) {
const conf = config.getEnv('diagnostics.config.backend');
const [key, dataPlaneUrl] = conf.split(';');
const [key, dataPlaneUrl] = backendConfig.split(';');
if (!key || !dataPlaneUrl) {
this.logger.warn('Diagnostics backend config is invalid');

View File

@ -1,9 +1,9 @@
import { GlobalConfig } from '@n8n/config';
import { mock } from 'jest-mock-extended';
import { NodeConnectionType } from 'n8n-workflow';
import Container from 'typedi';
import { v4 as uuid } from 'uuid';
import config from '@/config';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import { generateNanoId } from '@/databases/utils/generators';
import { INSTANCE_REPORT, WEBHOOK_VALIDATOR_NODE_TYPES } from '@/security-audit/constants';
@ -239,8 +239,7 @@ test('should not report outdated instance when up to date', async () => {
});
test('should report security settings', async () => {
config.set('diagnostics.enabled', true);
Container.get(GlobalConfig).diagnostics.enabled = true;
const testAudit = await securityAuditService.run(['instance']);
const section = getRiskSection(