mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-14 08:34:07 -08:00
refactor(core): Modernize logger service (#11031)
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Benchmark Docker Image CI / build (push) Waiting to run
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Benchmark Docker Image CI / build (push) Waiting to run
This commit is contained in:
parent
f92637a9fe
commit
3a9c65e1cb
47
packages/@n8n/config/src/configs/logging.config.ts
Normal file
47
packages/@n8n/config/src/configs/logging.config.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { Config, Env, Nested } from '../decorators';
|
||||
import { StringArray } from '../utils';
|
||||
|
||||
@Config
|
||||
class FileLoggingConfig {
|
||||
/**
|
||||
* Max number of log files to keep, or max number of days to keep logs for.
|
||||
* Once the limit is reached, the oldest log files will be rotated out.
|
||||
* If using days, append a `d` suffix. Only for `file` log output.
|
||||
*
|
||||
* @example `N8N_LOG_FILE_COUNT_MAX=7` will keep at most 7 files.
|
||||
* @example `N8N_LOG_FILE_COUNT_MAX=7d` will keep at most 7 days worth of files.
|
||||
*/
|
||||
@Env('N8N_LOG_FILE_COUNT_MAX')
|
||||
fileCountMax: number = 100;
|
||||
|
||||
/** Max size (in MiB) for each log file. Only for `file` log output. */
|
||||
@Env('N8N_LOG_FILE_SIZE_MAX')
|
||||
fileSizeMax: number = 16;
|
||||
|
||||
/** Location of the log files inside `~/.n8n`. Only for `file` log output. */
|
||||
@Env('N8N_LOG_FILE_LOCATION')
|
||||
location: string = 'logs/n8n.log';
|
||||
}
|
||||
|
||||
@Config
|
||||
export class LoggingConfig {
|
||||
/**
|
||||
* Minimum level of logs to output. Logs with this or higher level will be output;
|
||||
* logs with lower levels will not. Exception: `silent` disables all logging.
|
||||
*
|
||||
* @example `N8N_LOG_LEVEL=info` will output `error`, `warn` and `info` logs, but not `debug`.
|
||||
*/
|
||||
@Env('N8N_LOG_LEVEL')
|
||||
level: 'error' | 'warn' | 'info' | 'debug' | 'silent' = 'info';
|
||||
|
||||
/**
|
||||
* Where to output logs to. Options are: `console` or `file` or both in a comma separated list.
|
||||
*
|
||||
* @example `N8N_LOG_OUTPUT=console,file` will output to both console and file.
|
||||
*/
|
||||
@Env('N8N_LOG_OUTPUT')
|
||||
outputs: StringArray<'console' | 'file'> = ['console'];
|
||||
|
||||
@Nested
|
||||
file: FileLoggingConfig;
|
||||
}
|
|
@ -5,6 +5,7 @@ import { EndpointsConfig } from './configs/endpoints.config';
|
|||
import { EventBusConfig } from './configs/event-bus.config';
|
||||
import { ExternalSecretsConfig } from './configs/external-secrets.config';
|
||||
import { ExternalStorageConfig } from './configs/external-storage.config';
|
||||
import { LoggingConfig } from './configs/logging.config';
|
||||
import { NodesConfig } from './configs/nodes.config';
|
||||
import { PublicApiConfig } from './configs/public-api.config';
|
||||
import { ScalingModeConfig } from './configs/scaling-mode.config';
|
||||
|
@ -81,4 +82,7 @@ export class GlobalConfig {
|
|||
|
||||
@Nested
|
||||
queue: ScalingModeConfig;
|
||||
|
||||
@Nested
|
||||
logging: LoggingConfig;
|
||||
}
|
||||
|
|
7
packages/@n8n/config/src/utils.ts
Normal file
7
packages/@n8n/config/src/utils.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
export class StringArray<T extends string> extends Array<T> {
|
||||
constructor(str: string) {
|
||||
super();
|
||||
const parsed = str.split(',') as StringArray<T>;
|
||||
return parsed.every((i) => typeof i === 'string') ? parsed : [];
|
||||
}
|
||||
}
|
|
@ -225,6 +225,15 @@ describe('GlobalConfig', () => {
|
|||
backendDsn: '',
|
||||
frontendDsn: '',
|
||||
},
|
||||
logging: {
|
||||
level: 'info',
|
||||
outputs: ['console'],
|
||||
file: {
|
||||
fileCountMax: 100,
|
||||
fileSizeMax: 16,
|
||||
location: 'logs/n8n.log',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it('should use all default values when no env variables are defined', () => {
|
||||
|
|
|
@ -170,7 +170,7 @@
|
|||
"typedi": "catalog:",
|
||||
"uuid": "catalog:",
|
||||
"validator": "13.7.0",
|
||||
"winston": "3.8.2",
|
||||
"winston": "3.14.2",
|
||||
"ws": "8.17.1",
|
||||
"xml2js": "catalog:",
|
||||
"xmllint-wasm": "3.0.1",
|
||||
|
|
|
@ -5,7 +5,7 @@ import type { InstanceSettings } from 'n8n-core';
|
|||
import config from '@/config';
|
||||
import { N8N_VERSION } from '@/constants';
|
||||
import { License } from '@/license';
|
||||
import type { Logger } from '@/logger';
|
||||
import type { Logger } from '@/logging/logger.service';
|
||||
|
||||
jest.mock('@n8n_io/license-sdk');
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import { N8N_VERSION, TEMPLATES_DIR, inDevelopment, inTest } from '@/constants';
|
|||
import * as Db from '@/db';
|
||||
import { OnShutdown } from '@/decorators/on-shutdown';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { rawBodyReader, bodyParser, corsMiddleware } from '@/middlewares';
|
||||
import { send, sendErrorResponse } from '@/response-helper';
|
||||
import { WaitingForms } from '@/waiting-forms';
|
||||
|
|
|
@ -18,7 +18,7 @@ import type {
|
|||
IExecutionDb,
|
||||
IExecutionsCurrentSummary,
|
||||
} from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { isWorkflowIdValid } from '@/utils';
|
||||
|
||||
import { ConcurrencyControlService } from './concurrency/concurrency-control.service';
|
||||
|
|
|
@ -37,6 +37,7 @@ import { WorkflowRepository } from '@/databases/repositories/workflow.repository
|
|||
import { OnShutdown } from '@/decorators/on-shutdown';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import type { IWorkflowDb } from '@/interfaces';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { ActiveWorkflowsService } from '@/services/active-workflows.service';
|
||||
import { OrchestrationService } from '@/services/orchestration.service';
|
||||
|
@ -47,7 +48,6 @@ import { WorkflowExecutionService } from '@/workflows/workflow-execution.service
|
|||
import { WorkflowStaticDataService } from '@/workflows/workflow-static-data.service';
|
||||
|
||||
import { ExecutionService } from './executions/execution.service';
|
||||
import { Logger } from './logger';
|
||||
|
||||
interface QueuedActivation {
|
||||
activationMode: WorkflowActivateMode;
|
||||
|
|
|
@ -12,7 +12,7 @@ import { UserRepository } from '@/databases/repositories/user.repository';
|
|||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import type { AuthenticatedRequest } from '@/requests';
|
||||
import { JwtService } from '@/services/jwt.service';
|
||||
import { UrlService } from '@/services/url.service';
|
||||
|
|
|
@ -19,7 +19,7 @@ import { ExternalHooks } from '@/external-hooks';
|
|||
import { ExternalSecretsManager } from '@/external-secrets/external-secrets-manager.ee';
|
||||
import { License } from '@/license';
|
||||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { ShutdownService } from '@/shutdown/shutdown.service';
|
||||
|
|
|
@ -4,7 +4,7 @@ import { mock } from 'jest-mock-extended';
|
|||
|
||||
import { main } from '@/commands/db/revert';
|
||||
import type { IrreversibleMigration, ReversibleMigration } from '@/databases/types';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { mockInstance } from '@test/mocking';
|
||||
|
||||
const logger = mockInstance(Logger);
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Container } from 'typedi';
|
|||
import { getConnectionOptions } from '@/databases/config';
|
||||
import type { Migration } from '@/databases/types';
|
||||
import { wrapMigration } from '@/databases/utils/migration-helpers';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
// This function is extracted to make it easier to unit test it.
|
||||
// Mocking turned into a mess due to this command using typeorm and the db
|
||||
|
|
|
@ -365,10 +365,9 @@ export class Start extends BaseCommand {
|
|||
|
||||
if (executions.length === 0) return;
|
||||
|
||||
this.logger.debug(
|
||||
'[Startup] Found enqueued executions to run',
|
||||
executions.map((e) => e.id),
|
||||
);
|
||||
this.logger.debug('[Startup] Found enqueued executions to run', {
|
||||
executionIds: executions.map((e) => e.id),
|
||||
});
|
||||
|
||||
const ownershipService = Container.get(OwnershipService);
|
||||
const workflowRunner = Container.get(WorkflowRunner);
|
||||
|
|
|
@ -11,7 +11,7 @@ import type { ExecutionRepository } from '@/databases/repositories/execution.rep
|
|||
import { InvalidConcurrencyLimitError } from '@/errors/invalid-concurrency-limit.error';
|
||||
import type { EventService } from '@/events/event.service';
|
||||
import type { IExecutingWorkflowData } from '@/interfaces';
|
||||
import type { Logger } from '@/logger';
|
||||
import type { Logger } from '@/logging/logger.service';
|
||||
import type { Telemetry } from '@/telemetry';
|
||||
|
||||
import { ConcurrencyQueue } from '../concurrency-queue';
|
||||
|
|
|
@ -7,7 +7,8 @@ import { InvalidConcurrencyLimitError } from '@/errors/invalid-concurrency-limit
|
|||
import { UnknownExecutionModeError } from '@/errors/unknown-execution-mode.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import type { IExecutingWorkflowData } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import type { LogMetadata } from '@/logging/types';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
|
||||
import { ConcurrencyQueue } from './concurrency-queue';
|
||||
|
@ -170,8 +171,8 @@ export class ConcurrencyControlService {
|
|||
throw new UnknownExecutionModeError(mode);
|
||||
}
|
||||
|
||||
private log(message: string, meta?: object) {
|
||||
this.logger.debug(['[Concurrency Control]', message].join(' '), meta);
|
||||
private log(message: string, metadata?: LogMetadata) {
|
||||
this.logger.debug(['[Concurrency Control]', message].join(' '), metadata);
|
||||
}
|
||||
|
||||
private shouldReport(capacity: number) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { GlobalConfig } from '@n8n/config';
|
||||
import convict from 'convict';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import { LOG_LEVELS } from 'n8n-workflow';
|
||||
import path from 'path';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
|
@ -296,41 +295,6 @@ export const schema = {
|
|||
env: 'EXTERNAL_HOOK_FILES',
|
||||
},
|
||||
|
||||
logs: {
|
||||
level: {
|
||||
doc: 'Log output level',
|
||||
format: LOG_LEVELS,
|
||||
default: 'info',
|
||||
env: 'N8N_LOG_LEVEL',
|
||||
},
|
||||
output: {
|
||||
doc: 'Where to output logs. Options are: console, file. Multiple can be separated by comma (",")',
|
||||
format: String,
|
||||
default: 'console',
|
||||
env: 'N8N_LOG_OUTPUT',
|
||||
},
|
||||
file: {
|
||||
fileCountMax: {
|
||||
doc: 'Maximum number of files to keep.',
|
||||
format: Number,
|
||||
default: 100,
|
||||
env: 'N8N_LOG_FILE_COUNT_MAX',
|
||||
},
|
||||
fileSizeMax: {
|
||||
doc: 'Maximum size for each log file in MB.',
|
||||
format: Number,
|
||||
default: 16,
|
||||
env: 'N8N_LOG_FILE_SIZE_MAX',
|
||||
},
|
||||
location: {
|
||||
doc: 'Log file location; only used if log output is set to file.',
|
||||
format: String,
|
||||
default: path.join(Container.get(InstanceSettings).n8nFolder, 'logs/n8n.log'),
|
||||
env: 'N8N_LOG_FILE_LOCATION',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
push: {
|
||||
backend: {
|
||||
format: ['sse', 'websocket'] as const,
|
||||
|
|
|
@ -14,7 +14,7 @@ import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
|
|||
import { EventService } from '@/events/event.service';
|
||||
import type { PublicUser } from '@/interfaces';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { MfaService } from '@/mfa/mfa.service';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { AuthenticatedRequest, LoginRequest, UserRequest } from '@/requests';
|
||||
|
|
|
@ -14,7 +14,7 @@ import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus'
|
|||
import type { BooleanLicenseFeature, NumericLicenseFeature } from '@/interfaces';
|
||||
import type { FeatureReturnType } from '@/license';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { MfaService } from '@/mfa/mfa.service';
|
||||
import { Push } from '@/push';
|
||||
import type { UserSetupPayload } from '@/requests';
|
||||
|
|
|
@ -12,7 +12,7 @@ import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
|
|||
import { EventService } from '@/events/event.service';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { UserRequest } from '@/requests';
|
||||
import { PasswordUtility } from '@/services/password.utility';
|
||||
|
|
|
@ -16,7 +16,7 @@ import { EventService } from '@/events/event.service';
|
|||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { validateEntity } from '@/generic-helpers';
|
||||
import type { PublicUser } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { MfaService } from '@/mfa/mfa.service';
|
||||
import { AuthenticatedRequest, MeRequest } from '@/requests';
|
||||
import { PasswordUtility } from '@/services/password.utility';
|
||||
|
|
|
@ -15,7 +15,7 @@ import { VariablesService } from '@/environments/variables/variables.service.ee'
|
|||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import type { OAuthRequest } from '@/requests';
|
||||
import { SecretsHelper } from '@/secrets-helpers';
|
||||
import { mockInstance } from '@test/mocking';
|
||||
|
|
|
@ -15,7 +15,7 @@ import { VariablesService } from '@/environments/variables/variables.service.ee'
|
|||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import type { OAuthRequest } from '@/requests';
|
||||
import { SecretsHelper } from '@/secrets-helpers';
|
||||
import { mockInstance } from '@test/mocking';
|
||||
|
|
|
@ -15,7 +15,7 @@ import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
|||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import type { ICredentialsDb } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import type { OAuthRequest } from '@/requests';
|
||||
import { UrlService } from '@/services/url.service';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
|
|
|
@ -9,7 +9,7 @@ import { GlobalScope, Post, RestController } from '@/decorators';
|
|||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { validateEntity } from '@/generic-helpers';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { OwnerRequest } from '@/requests';
|
||||
import { PasswordUtility } from '@/services/password.utility';
|
||||
|
|
|
@ -13,7 +13,7 @@ import { UnprocessableRequestError } from '@/errors/response-errors/unprocessabl
|
|||
import { EventService } from '@/events/event.service';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { MfaService } from '@/mfa/mfa.service';
|
||||
import { PasswordResetRequest } from '@/requests';
|
||||
import { PasswordUtility } from '@/services/password.utility';
|
||||
|
|
|
@ -18,7 +18,7 @@ import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
|||
import { EventService } from '@/events/event.service';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import type { PublicUser } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { listQueryMiddleware } from '@/middlewares';
|
||||
import { AuthenticatedRequest, ListQuery, UserRequest } from '@/requests';
|
||||
import { ProjectService } from '@/services/project.service';
|
||||
|
|
|
@ -7,7 +7,7 @@ import { WorkflowStatisticsRepository } from '@/databases/repositories/workflow-
|
|||
import { Get, Middleware, RestController } from '@/decorators';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import type { IWorkflowStatisticsDataLoaded } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import { StatisticsRequest } from './workflow-statistics.types';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { join, dirname } from 'path';
|
|||
import { Container } from 'typedi';
|
||||
|
||||
import { inProduction } from '@/constants';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
export const touchFile = async (filePath: string): Promise<void> => {
|
||||
await mkdir(dirname(filePath), { recursive: true });
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Service } from 'typedi';
|
|||
|
||||
import { CredentialTypes } from '@/credential-types';
|
||||
import type { ICredentialsOverwrite } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
@Service()
|
||||
export class CredentialsOverwrites {
|
||||
|
|
|
@ -23,7 +23,7 @@ import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
|
|||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { listQueryMiddleware } from '@/middlewares';
|
||||
import { CredentialRequest } from '@/requests';
|
||||
import { NamingService } from '@/services/naming.service';
|
||||
|
|
|
@ -33,7 +33,7 @@ import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
|||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { validateEntity } from '@/generic-helpers';
|
||||
import type { ICredentialsDb } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { userHasScopes } from '@/permissions/check-access';
|
||||
import type { CredentialRequest, ListQuery } from '@/requests';
|
||||
import { CredentialsTester } from '@/services/credentials-tester.service';
|
||||
|
|
|
@ -12,7 +12,7 @@ import { mockInstance, mockEntityManager } from '@test/mocking';
|
|||
|
||||
describe('ExecutionRepository', () => {
|
||||
const entityManager = mockEntityManager(ExecutionEntity);
|
||||
const globalConfig = mockInstance(GlobalConfig);
|
||||
const globalConfig = mockInstance(GlobalConfig, { logging: { outputs: ['console'] } });
|
||||
const binaryDataService = mockInstance(BinaryDataService);
|
||||
const executionRepository = Container.get(ExecutionRepository);
|
||||
const mockDate = new Date('2023-12-28 12:34:56.789Z');
|
||||
|
|
|
@ -47,7 +47,7 @@ import type {
|
|||
IExecutionFlattedDb,
|
||||
IExecutionResponse,
|
||||
} from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { separate } from '@/utils';
|
||||
|
||||
import { ExecutionDataRepository } from './execution-data.repository';
|
||||
|
|
|
@ -3,7 +3,7 @@ import { EventSubscriber } from '@n8n/typeorm';
|
|||
import { ApplicationError, ErrorReporterProxy } from 'n8n-workflow';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import { Project } from '../entities/project';
|
||||
import { User } from '../entities/user';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { QueryRunner, ObjectLiteral } from '@n8n/typeorm';
|
||||
import type { INodeTypes } from 'n8n-workflow';
|
||||
|
||||
import type { Logger } from '@/logger';
|
||||
import type { Logger } from '@/logging/logger.service';
|
||||
|
||||
import type { createSchemaBuilder } from './dsl';
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { Container } from 'typedi';
|
|||
import { inTest } from '@/constants';
|
||||
import { createSchemaBuilder } from '@/databases/dsl';
|
||||
import type { BaseMigration, Migration, MigrationContext, MigrationFn } from '@/databases/types';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
|
||||
const PERSONALIZATION_SURVEY_FILENAME = 'personalizationSurvey.json';
|
||||
|
|
|
@ -11,7 +11,7 @@ import { SharedWorkflowRepository } from '@/databases/repositories/shared-workfl
|
|||
import { TagRepository } from '@/databases/repositories/tag.repository';
|
||||
import { WorkflowTagMappingRepository } from '@/databases/repositories/workflow-tag-mapping.repository';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import {
|
||||
SOURCE_CONTROL_CREDENTIAL_EXPORT_FOLDER,
|
||||
|
|
|
@ -14,7 +14,7 @@ import type {
|
|||
import { Service } from 'typedi';
|
||||
|
||||
import type { User } from '@/databases/entities/user';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
|
||||
import {
|
||||
|
|
|
@ -4,7 +4,7 @@ import path from 'path';
|
|||
import { Container } from 'typedi';
|
||||
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import {
|
||||
SOURCE_CONTROL_GIT_KEY_COMMENT,
|
||||
|
|
|
@ -23,7 +23,7 @@ import { VariablesRepository } from '@/databases/repositories/variables.reposito
|
|||
import { WorkflowTagMappingRepository } from '@/databases/repositories/workflow-tag-mapping.repository';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import type { IWorkflowToImport } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { isUniqueConstraintError } from '@/response-helper';
|
||||
import { assertNever } from '@/utils';
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import Container, { Service } from 'typedi';
|
|||
|
||||
import config from '@/config';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import {
|
||||
SOURCE_CONTROL_SSH_FOLDER,
|
||||
|
|
|
@ -10,7 +10,7 @@ import type { Variables } from '@/databases/entities/variables';
|
|||
import { TagRepository } from '@/databases/repositories/tag.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import {
|
||||
SOURCE_CONTROL_DEFAULT_EMAIL,
|
||||
|
|
|
@ -2,7 +2,7 @@ import { MessageEventBusDestinationTypeNames } from 'n8n-workflow';
|
|||
import { Container } from 'typedi';
|
||||
|
||||
import type { EventDestinations } from '@/databases/entities/event-destinations';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import { MessageEventBusDestinationSentry } from './message-event-bus-destination-sentry.ee';
|
||||
import { MessageEventBusDestinationSyslog } from './message-event-bus-destination-syslog.ee';
|
||||
|
|
|
@ -7,7 +7,7 @@ import { MessageEventBusDestinationTypeNames } from 'n8n-workflow';
|
|||
import syslog from 'syslog-client';
|
||||
import Container from 'typedi';
|
||||
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import { MessageEventBusDestination } from './message-event-bus-destination.ee';
|
||||
import { eventMessageGenericDestinationTestEvent } from '../event-message-classes/event-message-generic';
|
||||
|
|
|
@ -5,7 +5,7 @@ import { v4 as uuid } from 'uuid';
|
|||
|
||||
import { EventDestinationsRepository } from '@/databases/repositories/event-destinations.repository';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import type { EventMessageTypes } from '../event-message-classes';
|
||||
import type { AbstractEventMessage } from '../event-message-classes/abstract-event-message';
|
||||
|
|
|
@ -12,7 +12,7 @@ import Container from 'typedi';
|
|||
import { Worker } from 'worker_threads';
|
||||
|
||||
import { inTest } from '@/constants';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import type { EventMessageTypes } from '../event-message-classes';
|
||||
import { isEventMessageOptions } from '../event-message-classes/abstract-event-message';
|
||||
|
|
|
@ -13,7 +13,7 @@ import { EventDestinationsRepository } from '@/databases/repositories/event-dest
|
|||
import { ExecutionRepository } from '@/databases/repositories/execution.repository';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { OrchestrationService } from '@/services/orchestration.service';
|
||||
|
||||
import { ExecutionRecoveryService } from '../../executions/execution-recovery.service';
|
||||
|
|
|
@ -37,6 +37,10 @@ describe('TelemetryEventRelay', () => {
|
|||
includeQueueMetrics: false,
|
||||
},
|
||||
},
|
||||
logging: {
|
||||
level: 'info',
|
||||
outputs: ['console'],
|
||||
},
|
||||
});
|
||||
const workflowRepository = mock<WorkflowRepository>();
|
||||
const nodeTypes = mock<NodeTypes>();
|
||||
|
|
|
@ -9,7 +9,7 @@ import { ExecutionRepository } from '@/databases/repositories/execution.reposito
|
|||
import { saveExecutionProgress } from '@/execution-lifecycle-hooks/save-execution-progress';
|
||||
import * as fnModule from '@/execution-lifecycle-hooks/to-save-settings';
|
||||
import type { IExecutionResponse } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { mockInstance } from '@test/mocking';
|
||||
|
||||
mockInstance(Logger);
|
||||
|
|
|
@ -4,7 +4,7 @@ import type { IRun, WorkflowExecuteMode } from 'n8n-workflow';
|
|||
import Container from 'typedi';
|
||||
|
||||
import config from '@/config';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
/**
|
||||
* Whenever the execution ID is not available to the binary data service at the
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Container } from 'typedi';
|
|||
|
||||
import { ExecutionRepository } from '@/databases/repositories/execution.repository';
|
||||
import { toSaveSettings } from '@/execution-lifecycle-hooks/to-save-settings';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
export async function saveExecutionProgress(
|
||||
workflowData: IWorkflowBase,
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Container } from 'typedi';
|
|||
|
||||
import { ExecutionRepository } from '@/databases/repositories/execution.repository';
|
||||
import type { IExecutionDb, UpdateExecutionPayload } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { ExecutionMetadataService } from '@/services/execution-metadata.service';
|
||||
import { isWorkflowIdValid } from '@/utils';
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import { NodeCrashedError } from '@/errors/node-crashed.error';
|
|||
import { WorkflowCrashedError } from '@/errors/workflow-crashed.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import type { IExecutionResponse } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { Push } from '@/push';
|
||||
import { getWorkflowHooksMain } from '@/workflow-execute-additional-data'; // @TODO: Dependency cycle
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ import type {
|
|||
IWorkflowDb,
|
||||
} from '@/interfaces';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { WaitTracker } from '@/wait-tracker';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
@ -10,7 +10,7 @@ import type {
|
|||
SecretsProviderSettings,
|
||||
} from '@/interfaces';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { OrchestrationService } from '@/services/orchestration.service';
|
||||
|
||||
import { EXTERNAL_SECRETS_INITIAL_BACKOFF, EXTERNAL_SECRETS_MAX_BACKOFF } from './constants';
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Container } from 'typedi';
|
|||
|
||||
import type { SecretsProviderSettings, SecretsProviderState } from '@/interfaces';
|
||||
import { SecretsProvider } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import { DOCS_HELP_NOTICE, EXTERNAL_SECRETS_NAME_REGEX } from '../constants';
|
||||
import { preferGet } from '../external-secrets-helper.ee';
|
||||
|
|
|
@ -14,7 +14,7 @@ import { SettingsRepository } from '@/databases/repositories/settings.repository
|
|||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import {
|
||||
getCurrentAuthenticationMethod,
|
||||
isEmailCurrentAuthenticationMethod,
|
||||
|
|
|
@ -6,7 +6,7 @@ import Container, { Service } from 'typedi';
|
|||
import config from '@/config';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { OnShutdown } from '@/decorators/on-shutdown';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { LicenseMetricsService } from '@/metrics/license-metrics.service';
|
||||
import { OrchestrationService } from '@/services/orchestration.service';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { WorkflowRepository } from '@/databases/repositories/workflow.repository
|
|||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { UrlService } from '@/services/url.service';
|
||||
|
||||
type LicenseError = Error & { errorId?: keyof typeof LicenseErrors };
|
||||
|
|
|
@ -28,7 +28,7 @@ import {
|
|||
CLI_DIR,
|
||||
inE2ETests,
|
||||
} from '@/constants';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
interface LoadedNodesAndCredentials {
|
||||
nodes: INodeTypeData;
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
import callsites from 'callsites';
|
||||
import { LoggerProxy, type IDataObject, LOG_LEVELS } from 'n8n-workflow';
|
||||
import { basename } from 'path';
|
||||
import { Service } from 'typedi';
|
||||
import { inspect } from 'util';
|
||||
import winston from 'winston';
|
||||
|
||||
import config from '@/config';
|
||||
|
||||
const noOp = () => {};
|
||||
|
||||
@Service()
|
||||
export class Logger {
|
||||
private logger: winston.Logger;
|
||||
|
||||
constructor() {
|
||||
const level = config.getEnv('logs.level');
|
||||
|
||||
this.logger = winston.createLogger({
|
||||
level,
|
||||
silent: level === 'silent',
|
||||
});
|
||||
|
||||
// Change all methods with higher log-level to no-op
|
||||
for (const levelName of LOG_LEVELS) {
|
||||
if (this.logger.levels[levelName] > this.logger.levels[level]) {
|
||||
Object.defineProperty(this, levelName, { value: noOp });
|
||||
}
|
||||
}
|
||||
|
||||
const output = config
|
||||
.getEnv('logs.output')
|
||||
.split(',')
|
||||
.map((line) => line.trim());
|
||||
|
||||
if (output.includes('console')) {
|
||||
let format: winston.Logform.Format;
|
||||
if (level === 'debug') {
|
||||
format = winston.format.combine(
|
||||
winston.format.metadata(),
|
||||
winston.format.timestamp(),
|
||||
winston.format.colorize({ all: true }),
|
||||
|
||||
winston.format.printf(({ level: logLevel, message, timestamp, metadata }) => {
|
||||
return `${timestamp} | ${logLevel.padEnd(18)} | ${message}${
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
Object.keys(metadata).length ? ` ${JSON.stringify(inspect(metadata))}` : ''
|
||||
}`;
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
format = winston.format.printf(({ message }: { message: string }) => message);
|
||||
}
|
||||
|
||||
this.logger.add(
|
||||
new winston.transports.Console({
|
||||
format,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (output.includes('file')) {
|
||||
const fileLogFormat = winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.metadata(),
|
||||
winston.format.json(),
|
||||
);
|
||||
this.logger.add(
|
||||
new winston.transports.File({
|
||||
filename: config.getEnv('logs.file.location'),
|
||||
format: fileLogFormat,
|
||||
maxsize: config.getEnv('logs.file.fileSizeMax') * 1048576, // config * 1mb
|
||||
maxFiles: config.getEnv('logs.file.fileCountMax'),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
LoggerProxy.init(this);
|
||||
}
|
||||
|
||||
private log(level: (typeof LOG_LEVELS)[number], message: string, meta: object = {}): void {
|
||||
const callsite = callsites();
|
||||
// We are using the third array element as the structure is as follows:
|
||||
// [0]: this file
|
||||
// [1]: Should be Logger
|
||||
// [2]: Should point to the caller.
|
||||
// Note: getting line number is useless because at this point
|
||||
// We are in runtime, so it means we are looking at compiled js files
|
||||
const logDetails = {} as IDataObject;
|
||||
if (callsite[2] !== undefined) {
|
||||
logDetails.file = basename(callsite[2].getFileName() || '');
|
||||
const functionName = callsite[2].getFunctionName();
|
||||
if (functionName) {
|
||||
logDetails.function = functionName;
|
||||
}
|
||||
}
|
||||
this.logger.log(level, message, { ...meta, ...logDetails });
|
||||
}
|
||||
|
||||
// Convenience methods below
|
||||
|
||||
error(message: string, meta: object = {}): void {
|
||||
this.log('error', message, meta);
|
||||
}
|
||||
|
||||
warn(message: string, meta: object = {}): void {
|
||||
this.log('warn', message, meta);
|
||||
}
|
||||
|
||||
info(message: string, meta: object = {}): void {
|
||||
this.log('info', message, meta);
|
||||
}
|
||||
|
||||
debug(message: string, meta: object = {}): void {
|
||||
this.log('debug', message, meta);
|
||||
}
|
||||
}
|
145
packages/cli/src/logging/__tests__/logger.service.test.ts
Normal file
145
packages/cli/src/logging/__tests__/logger.service.test.ts
Normal file
|
@ -0,0 +1,145 @@
|
|||
import type { GlobalConfig } from '@n8n/config';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { InstanceSettings } from 'n8n-core';
|
||||
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
describe('Logger', () => {
|
||||
describe('transports', () => {
|
||||
test('if `console` selected, should set console transport', () => {
|
||||
const globalConfig = mock<GlobalConfig>({
|
||||
logging: {
|
||||
level: 'info',
|
||||
outputs: ['console'],
|
||||
},
|
||||
});
|
||||
|
||||
const logger = new Logger(globalConfig, mock<InstanceSettings>());
|
||||
|
||||
const { transports } = logger.getInternalLogger();
|
||||
|
||||
expect(transports).toHaveLength(1);
|
||||
|
||||
const [transport] = transports;
|
||||
|
||||
expect(transport.constructor.name).toBe('Console');
|
||||
});
|
||||
|
||||
test('if `file` selected, should set file transport', () => {
|
||||
const globalConfig = mock<GlobalConfig>({
|
||||
logging: {
|
||||
level: 'info',
|
||||
outputs: ['file'],
|
||||
file: {
|
||||
fileSizeMax: 100,
|
||||
fileCountMax: 16,
|
||||
location: 'logs/n8n.log',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const logger = new Logger(globalConfig, mock<InstanceSettings>({ n8nFolder: '/tmp' }));
|
||||
|
||||
const { transports } = logger.getInternalLogger();
|
||||
|
||||
expect(transports).toHaveLength(1);
|
||||
|
||||
const [transport] = transports;
|
||||
|
||||
expect(transport.constructor.name).toBe('File');
|
||||
});
|
||||
});
|
||||
|
||||
describe('levels', () => {
|
||||
test('if `error` selected, should enable `error` level', () => {
|
||||
const globalConfig = mock<GlobalConfig>({
|
||||
logging: {
|
||||
level: 'error',
|
||||
outputs: ['console'],
|
||||
},
|
||||
});
|
||||
|
||||
const logger = new Logger(globalConfig, mock<InstanceSettings>());
|
||||
|
||||
const internalLogger = logger.getInternalLogger();
|
||||
|
||||
expect(internalLogger.isErrorEnabled()).toBe(true);
|
||||
expect(internalLogger.isWarnEnabled()).toBe(false);
|
||||
expect(internalLogger.isInfoEnabled()).toBe(false);
|
||||
expect(internalLogger.isDebugEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
test('if `warn` selected, should enable `error` and `warn` levels', () => {
|
||||
const globalConfig = mock<GlobalConfig>({
|
||||
logging: {
|
||||
level: 'warn',
|
||||
outputs: ['console'],
|
||||
},
|
||||
});
|
||||
|
||||
const logger = new Logger(globalConfig, mock<InstanceSettings>());
|
||||
|
||||
const internalLogger = logger.getInternalLogger();
|
||||
|
||||
expect(internalLogger.isErrorEnabled()).toBe(true);
|
||||
expect(internalLogger.isWarnEnabled()).toBe(true);
|
||||
expect(internalLogger.isInfoEnabled()).toBe(false);
|
||||
expect(internalLogger.isDebugEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
test('if `info` selected, should enable `error`, `warn`, and `info` levels', () => {
|
||||
const globalConfig = mock<GlobalConfig>({
|
||||
logging: {
|
||||
level: 'info',
|
||||
outputs: ['console'],
|
||||
},
|
||||
});
|
||||
|
||||
const logger = new Logger(globalConfig, mock<InstanceSettings>());
|
||||
|
||||
const internalLogger = logger.getInternalLogger();
|
||||
|
||||
expect(internalLogger.isErrorEnabled()).toBe(true);
|
||||
expect(internalLogger.isWarnEnabled()).toBe(true);
|
||||
expect(internalLogger.isInfoEnabled()).toBe(true);
|
||||
expect(internalLogger.isDebugEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
test('if `debug` selected, should enable all levels', () => {
|
||||
const globalConfig = mock<GlobalConfig>({
|
||||
logging: {
|
||||
level: 'debug',
|
||||
outputs: ['console'],
|
||||
},
|
||||
});
|
||||
|
||||
const logger = new Logger(globalConfig, mock<InstanceSettings>());
|
||||
|
||||
const internalLogger = logger.getInternalLogger();
|
||||
|
||||
expect(internalLogger.isErrorEnabled()).toBe(true);
|
||||
expect(internalLogger.isWarnEnabled()).toBe(true);
|
||||
expect(internalLogger.isInfoEnabled()).toBe(true);
|
||||
expect(internalLogger.isDebugEnabled()).toBe(true);
|
||||
});
|
||||
|
||||
test('if `silent` selected, should disable all levels', () => {
|
||||
const globalConfig = mock<GlobalConfig>({
|
||||
logging: {
|
||||
level: 'silent',
|
||||
outputs: ['console'],
|
||||
},
|
||||
});
|
||||
|
||||
const logger = new Logger(globalConfig, mock<InstanceSettings>());
|
||||
|
||||
const internalLogger = logger.getInternalLogger();
|
||||
|
||||
expect(internalLogger.isErrorEnabled()).toBe(false);
|
||||
expect(internalLogger.isWarnEnabled()).toBe(false);
|
||||
expect(internalLogger.isInfoEnabled()).toBe(false);
|
||||
expect(internalLogger.isDebugEnabled()).toBe(false);
|
||||
expect(internalLogger.silent).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
3
packages/cli/src/logging/constants.ts
Normal file
3
packages/cli/src/logging/constants.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export const noOp = () => {};
|
||||
|
||||
export const LOG_LEVELS = ['error', 'warn', 'info', 'debug', 'silent'] as const;
|
148
packages/cli/src/logging/logger.service.ts
Normal file
148
packages/cli/src/logging/logger.service.ts
Normal file
|
@ -0,0 +1,148 @@
|
|||
import { GlobalConfig } from '@n8n/config';
|
||||
import callsites from 'callsites';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import { LoggerProxy, LOG_LEVELS } from 'n8n-workflow';
|
||||
import path, { basename } from 'node:path';
|
||||
import { Service } from 'typedi';
|
||||
import winston from 'winston';
|
||||
|
||||
import { isObjectLiteral } from '@/utils';
|
||||
|
||||
import { noOp } from './constants';
|
||||
import type { LogLocationMetadata, LogLevel, LogMetadata } from './types';
|
||||
|
||||
@Service()
|
||||
export class Logger {
|
||||
private readonly internalLogger: winston.Logger;
|
||||
|
||||
private readonly level: LogLevel;
|
||||
|
||||
constructor(
|
||||
private readonly globalConfig: GlobalConfig,
|
||||
private readonly instanceSettings: InstanceSettings,
|
||||
) {
|
||||
this.level = this.globalConfig.logging.level;
|
||||
|
||||
const isSilent = this.level === 'silent';
|
||||
|
||||
this.internalLogger = winston.createLogger({
|
||||
level: this.level,
|
||||
silent: isSilent,
|
||||
});
|
||||
|
||||
if (!isSilent) {
|
||||
this.setLevel();
|
||||
|
||||
const { outputs } = this.globalConfig.logging;
|
||||
|
||||
if (outputs.includes('console')) this.setConsoleTransport();
|
||||
if (outputs.includes('file')) this.setFileTransport();
|
||||
}
|
||||
|
||||
LoggerProxy.init(this);
|
||||
}
|
||||
|
||||
private log(level: LogLevel, message: string, metadata: LogMetadata) {
|
||||
const location: LogLocationMetadata = {};
|
||||
|
||||
const caller = callsites().at(2); // zeroth and first are this file, second is caller
|
||||
|
||||
if (caller !== undefined) {
|
||||
location.file = basename(caller.getFileName() ?? '');
|
||||
const fnName = caller.getFunctionName();
|
||||
if (fnName) location.function = fnName;
|
||||
}
|
||||
|
||||
this.internalLogger.log(level, message, { ...metadata, ...location });
|
||||
}
|
||||
|
||||
private setLevel() {
|
||||
const { levels } = this.internalLogger;
|
||||
|
||||
for (const logLevel of LOG_LEVELS) {
|
||||
if (levels[logLevel] > levels[this.level]) {
|
||||
// winston defines `{ error: 0, warn: 1, info: 2, debug: 5 }`
|
||||
// so numerically higher (less severe) log levels become no-op
|
||||
// to prevent overhead from `callsites` calls
|
||||
Object.defineProperty(this, logLevel, { value: noOp });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private setConsoleTransport() {
|
||||
const format =
|
||||
this.level === 'debug'
|
||||
? winston.format.combine(
|
||||
winston.format.metadata(),
|
||||
winston.format.timestamp(),
|
||||
winston.format.colorize({ all: true }),
|
||||
winston.format.printf(({ level, message, timestamp, metadata }) => {
|
||||
const _metadata = this.toPrintable(metadata);
|
||||
return `${timestamp} | ${level.padEnd(18)} | ${message}${_metadata}`;
|
||||
}),
|
||||
)
|
||||
: winston.format.printf(({ message }: { message: string }) => message);
|
||||
|
||||
this.internalLogger.add(new winston.transports.Console({ format }));
|
||||
}
|
||||
|
||||
private toPrintable(metadata: unknown) {
|
||||
if (isObjectLiteral(metadata) && Object.keys(metadata).length > 0) {
|
||||
return ' ' + JSON.stringify(metadata);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private setFileTransport() {
|
||||
const format = winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.metadata(),
|
||||
winston.format.json(),
|
||||
);
|
||||
|
||||
const filename = path.join(
|
||||
this.instanceSettings.n8nFolder,
|
||||
this.globalConfig.logging.file.location,
|
||||
);
|
||||
|
||||
const { fileSizeMax, fileCountMax } = this.globalConfig.logging.file;
|
||||
|
||||
this.internalLogger.add(
|
||||
new winston.transports.File({
|
||||
filename,
|
||||
format,
|
||||
maxsize: fileSizeMax * 1_048_576, // config * 1 MiB in bytes
|
||||
maxFiles: fileCountMax,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// #region Convenience methods
|
||||
|
||||
error(message: string, metadata: LogMetadata = {}) {
|
||||
this.log('error', message, metadata);
|
||||
}
|
||||
|
||||
warn(message: string, metadata: LogMetadata = {}) {
|
||||
this.log('warn', message, metadata);
|
||||
}
|
||||
|
||||
info(message: string, metadata: LogMetadata = {}) {
|
||||
this.log('info', message, metadata);
|
||||
}
|
||||
|
||||
debug(message: string, metadata: LogMetadata = {}) {
|
||||
this.log('debug', message, metadata);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region For testing only
|
||||
|
||||
getInternalLogger() {
|
||||
return this.internalLogger;
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
7
packages/cli/src/logging/types.ts
Normal file
7
packages/cli/src/logging/types.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import type { LOG_LEVELS } from './constants';
|
||||
|
||||
export type LogLevel = (typeof LOG_LEVELS)[number];
|
||||
|
||||
export type LogLocationMetadata = Partial<{ file: string; function: string }>;
|
||||
|
||||
export type LogMetadata = Record<string, unknown> | Error;
|
|
@ -1,3 +1,5 @@
|
|||
import type { GlobalConfig } from '@n8n/config';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import { PostHog } from 'posthog-node';
|
||||
|
||||
|
@ -15,6 +17,8 @@ describe('PostHog', () => {
|
|||
|
||||
const instanceSettings = mockInstance(InstanceSettings, { instanceId });
|
||||
|
||||
const globalConfig = mock<GlobalConfig>({ logging: { level: 'debug' } });
|
||||
|
||||
beforeAll(() => {
|
||||
config.set('diagnostics.config.posthog.apiKey', apiKey);
|
||||
config.set('diagnostics.config.posthog.apiHost', apiHost);
|
||||
|
@ -26,7 +30,7 @@ describe('PostHog', () => {
|
|||
});
|
||||
|
||||
it('inits PostHog correctly', async () => {
|
||||
const ph = new PostHogClient(instanceSettings);
|
||||
const ph = new PostHogClient(instanceSettings, globalConfig);
|
||||
await ph.init();
|
||||
|
||||
expect(PostHog.prototype.constructor).toHaveBeenCalledWith(apiKey, { host: apiHost });
|
||||
|
@ -35,7 +39,7 @@ describe('PostHog', () => {
|
|||
it('does not initialize or track if diagnostics are not enabled', async () => {
|
||||
config.set('diagnostics.enabled', false);
|
||||
|
||||
const ph = new PostHogClient(instanceSettings);
|
||||
const ph = new PostHogClient(instanceSettings, globalConfig);
|
||||
await ph.init();
|
||||
|
||||
ph.track({
|
||||
|
@ -55,7 +59,7 @@ describe('PostHog', () => {
|
|||
test: true,
|
||||
};
|
||||
|
||||
const ph = new PostHogClient(instanceSettings);
|
||||
const ph = new PostHogClient(instanceSettings, globalConfig);
|
||||
await ph.init();
|
||||
|
||||
ph.track({
|
||||
|
@ -75,7 +79,7 @@ describe('PostHog', () => {
|
|||
|
||||
it('gets feature flags', async () => {
|
||||
const createdAt = new Date();
|
||||
const ph = new PostHogClient(instanceSettings);
|
||||
const ph = new PostHogClient(instanceSettings, globalConfig);
|
||||
await ph.init();
|
||||
|
||||
await ph.getFeatureFlags({
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { GlobalConfig } from '@n8n/config';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import type { FeatureFlags, ITelemetryTrackProperties } from 'n8n-workflow';
|
||||
import type { PostHog } from 'posthog-node';
|
||||
|
@ -10,7 +11,10 @@ import type { PublicUser } from '@/interfaces';
|
|||
export class PostHogClient {
|
||||
private postHog?: PostHog;
|
||||
|
||||
constructor(private readonly instanceSettings: InstanceSettings) {}
|
||||
constructor(
|
||||
private readonly instanceSettings: InstanceSettings,
|
||||
private readonly globalConfig: GlobalConfig,
|
||||
) {}
|
||||
|
||||
async init() {
|
||||
const enabled = config.getEnv('diagnostics.enabled');
|
||||
|
@ -23,7 +27,7 @@ export class PostHogClient {
|
|||
host: config.getEnv('diagnostics.config.posthog.apiHost'),
|
||||
});
|
||||
|
||||
const logLevel = config.getEnv('logs.level');
|
||||
const logLevel = this.globalConfig.logging.level;
|
||||
if (logLevel === 'debug') {
|
||||
this.postHog.debug(true);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Container } from 'typedi';
|
|||
import type WebSocket from 'ws';
|
||||
|
||||
import type { User } from '@/databases/entities/user';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { WebSocketPush } from '@/push/websocket.push';
|
||||
import { mockInstance } from '@test/mocking';
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { PushPayload, PushType } from '@n8n/api-types';
|
|||
import { assert, jsonStringify } from 'n8n-workflow';
|
||||
|
||||
import type { User } from '@/databases/entities/user';
|
||||
import type { Logger } from '@/logger';
|
||||
import type { Logger } from '@/logging/logger.service';
|
||||
import type { OnPushMessage } from '@/push/types';
|
||||
import { TypedEmitter } from '@/typed-emitter';
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Service } from 'typedi';
|
||||
|
||||
import type { User } from '@/databases/entities/user';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import SSEChannel from 'sse-channel';
|
||||
|
||||
import { AbstractPush } from './abstract.push';
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Service } from 'typedi';
|
|||
import type WebSocket from 'ws';
|
||||
|
||||
import type { User } from '@/databases/entities/user';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import { AbstractPush } from './abstract.push';
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@ import picocolors from 'picocolors';
|
|||
import Container from 'typedi';
|
||||
|
||||
import { inDevelopment } from '@/constants';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import { ResponseError } from './errors/response-errors/abstract/response.error';
|
||||
import { Logger } from './logger';
|
||||
|
||||
export function sendSuccessResponse(
|
||||
res: Response,
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Service } from 'typedi';
|
|||
import config from '@/config';
|
||||
import { ExecutionRepository } from '@/databases/repositories/execution.repository';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { Redis as SingleNodeClient, Cluster as MultiNodeClient } from 'iore
|
|||
import { Service } from 'typedi';
|
||||
|
||||
import config from '@/config';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { RedisClientService } from '@/services/redis-client.service';
|
||||
|
||||
import type { PubSub } from './pubsub.types';
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { Redis as SingleNodeClient, Cluster as MultiNodeClient } from 'iore
|
|||
import { Service } from 'typedi';
|
||||
|
||||
import config from '@/config';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { RedisClientService } from '@/services/redis-client.service';
|
||||
|
||||
import type { PubSub } from './pubsub.types';
|
||||
|
|
|
@ -11,7 +11,7 @@ import { ExecutionRepository } from '@/databases/repositories/execution.reposito
|
|||
import { OnShutdown } from '@/decorators/on-shutdown';
|
||||
import { MaxStalledCountError } from '@/errors/max-stalled-count.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { OrchestrationService } from '@/services/orchestration.service';
|
||||
|
||||
import { JOB_TYPE_NAME, QUEUE_NAME } from './constants';
|
||||
|
|
|
@ -16,7 +16,7 @@ import { PortTakenError } from '@/errors/port-taken.error';
|
|||
import { ServiceUnavailableError } from '@/errors/response-errors/service-unavailable.error';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import type { ICredentialsOverwrite } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { PrometheusMetricsService } from '@/metrics/prometheus-metrics.service';
|
||||
import { rawBodyReader, bodyParser } from '@/middlewares';
|
||||
import * as ResponseHelper from '@/response-helper';
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Service } from 'typedi';
|
|||
import config from '@/config';
|
||||
import { getN8nPackageJson, inDevelopment } from '@/constants';
|
||||
import type { WorkflowEntity } from '@/databases/entities/workflow-entity';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { isApiEnabled } from '@/public-api';
|
||||
import {
|
||||
ENV_VARS_DOCS_URL,
|
||||
|
|
|
@ -5,7 +5,7 @@ import type { User } from '@/databases/entities/user';
|
|||
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
@Service()
|
||||
export class ActiveWorkflowsService {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { GlobalConfig } from '@n8n/config';
|
||||
import type { AiAssistantSDK } from '@n8n_io/ai-assistant-sdk';
|
||||
import { AiAssistantClient } from '@n8n_io/ai-assistant-sdk';
|
||||
import { assert, type IUser } from 'n8n-workflow';
|
||||
|
@ -14,7 +15,10 @@ import { License } from '../license';
|
|||
export class AiAssistantService {
|
||||
private client: AiAssistantClient | undefined;
|
||||
|
||||
constructor(private readonly licenseService: License) {}
|
||||
constructor(
|
||||
private readonly licenseService: License,
|
||||
private readonly globalConfig: GlobalConfig,
|
||||
) {}
|
||||
|
||||
async init() {
|
||||
const aiAssistantEnabled = this.licenseService.isAiAssistantEnabled();
|
||||
|
@ -25,7 +29,7 @@ export class AiAssistantService {
|
|||
const licenseCert = await this.licenseService.loadCertStr();
|
||||
const consumerId = this.licenseService.getConsumerId();
|
||||
const baseUrl = config.get('aiAssistant.baseUrl');
|
||||
const logLevel = config.getEnv('logs.level');
|
||||
const logLevel = this.globalConfig.logging.level;
|
||||
|
||||
this.client = new AiAssistantClient({
|
||||
licenseCert,
|
||||
|
|
|
@ -22,7 +22,7 @@ import { FeatureNotLicensedError } from '@/errors/feature-not-licensed.error';
|
|||
import type { CommunityPackages } from '@/interfaces';
|
||||
import { License } from '@/license';
|
||||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { toError } from '@/utils';
|
||||
|
||||
import { OrchestrationService } from './orchestration.service';
|
||||
|
|
|
@ -35,7 +35,7 @@ import { Service } from 'typedi';
|
|||
|
||||
import { CredentialTypes } from '@/credential-types';
|
||||
import type { User } from '@/databases/entities/user';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import { getVariablesLimit } from '@/environments/variables/environment-helpers'
|
|||
import { getLdapLoginLabel } from '@/ldap/helpers.ee';
|
||||
import { License } from '@/license';
|
||||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { isApiEnabled } from '@/public-api';
|
||||
import type { CommunityPackagesService } from '@/services/community-packages.service';
|
||||
import { getSamlLoginLabel } from '@/sso/saml/saml-helpers';
|
||||
|
@ -123,7 +123,7 @@ export class FrontendService {
|
|||
apiKey: config.getEnv('diagnostics.config.posthog.apiKey'),
|
||||
autocapture: false,
|
||||
disableSessionRecording: config.getEnv('deployment.type') !== 'cloud',
|
||||
debug: config.getEnv('logs.level') === 'debug',
|
||||
debug: this.globalConfig.logging.level === 'debug',
|
||||
},
|
||||
personalizationSurveyEnabled:
|
||||
config.getEnv('personalization.enabled') && config.getEnv('diagnostics.enabled'),
|
||||
|
@ -153,7 +153,7 @@ export class FrontendService {
|
|||
},
|
||||
},
|
||||
workflowTagsDisabled: config.getEnv('workflowTagsDisabled'),
|
||||
logLevel: config.getEnv('logs.level'),
|
||||
logLevel: this.globalConfig.logging.level,
|
||||
hiringBannerEnabled: config.getEnv('hiringBanner.enabled'),
|
||||
aiAssistant: {
|
||||
enabled: false,
|
||||
|
|
|
@ -11,7 +11,7 @@ import { CredentialsRepository } from '@/databases/repositories/credentials.repo
|
|||
import { TagRepository } from '@/databases/repositories/tag.repository';
|
||||
import * as Db from '@/db';
|
||||
import type { ICredentialsDb } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { replaceInvalidCredentials } from '@/workflow-helpers';
|
||||
|
||||
@Service()
|
||||
|
|
|
@ -4,7 +4,7 @@ import Container, { Service } from 'typedi';
|
|||
|
||||
import config from '@/config';
|
||||
import type { PubSubCommandMap } from '@/events/maps/pub-sub.event-map';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import type { Publisher } from '@/scaling/pubsub/publisher.service';
|
||||
import type { Subscriber } from '@/scaling/pubsub/subscriber.service';
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { jsonParse } from 'n8n-workflow';
|
|||
import os from 'node:os';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { COMMAND_PUBSUB_CHANNEL } from '@/scaling/constants';
|
||||
import type { PubSub } from '@/scaling/pubsub/pubsub.types';
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { WorkflowRepository } from '@/databases/repositories/workflow.repository
|
|||
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
|
||||
import { ExternalSecretsManager } from '@/external-secrets/external-secrets-manager.ee';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { Push } from '@/push';
|
||||
import { CommunityPackagesService } from '@/services/community-packages.service';
|
||||
import { OrchestrationService } from '@/services/orchestration.service';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { jsonParse } from 'n8n-workflow';
|
||||
import Container from 'typedi';
|
||||
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { WORKER_RESPONSE_PUBSUB_CHANNEL } from '@/scaling/constants';
|
||||
import type { PubSub } from '@/scaling/pubsub/pubsub.types';
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Service } from 'typedi';
|
|||
|
||||
import config from '@/config';
|
||||
import { TIME } from '@/constants';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { Publisher } from '@/scaling/pubsub/publisher.service';
|
||||
import { RedisClientService } from '@/services/redis-client.service';
|
||||
import { TypedEmitter } from '@/typed-emitter';
|
||||
|
|
|
@ -6,7 +6,7 @@ import { N8N_VERSION } from '@/constants';
|
|||
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
|
||||
import { ExternalSecretsManager } from '@/external-secrets/external-secrets-manager.ee';
|
||||
import { License } from '@/license';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { COMMAND_PUBSUB_CHANNEL } from '@/scaling/constants';
|
||||
import type { PubSub } from '@/scaling/pubsub/pubsub.types';
|
||||
import { CommunityPackagesService } from '@/services/community-packages.service';
|
||||
|
|
|
@ -6,7 +6,7 @@ import config from '@/config';
|
|||
import { inTest, TIME } from '@/constants';
|
||||
import { ExecutionRepository } from '@/databases/repositories/execution.repository';
|
||||
import { OnShutdown } from '@/decorators/on-shutdown';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
import { OrchestrationService } from './orchestration.service';
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import type { Cluster, RedisOptions } from 'ioredis';
|
|||
import { Service } from 'typedi';
|
||||
|
||||
import { Debounce } from '@/decorators/debounce';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { TypedEmitter } from '@/typed-emitter';
|
||||
|
||||
import type { RedisClientType } from '../scaling/redis/redis.types';
|
||||
|
|
|
@ -7,7 +7,7 @@ import { UserRepository } from '@/databases/repositories/user.repository';
|
|||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import type { Invitation, PublicUser } from '@/interfaces';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import type { PostHogClient } from '@/posthog';
|
||||
import type { UserRequest } from '@/requests';
|
||||
import { UrlService } from '@/services/url.service';
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Service } from 'typedi';
|
|||
import { StatisticsNames } from '@/databases/entities/workflow-statistics';
|
||||
import { WorkflowStatisticsRepository } from '@/databases/repositories/workflow-statistics.repository';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { UserService } from '@/services/user.service';
|
||||
import { TypedEmitter } from '@/typed-emitter';
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { ApplicationError, ErrorReporterProxy, assert } from 'n8n-workflow';
|
|||
import { Container, Service } from 'typedi';
|
||||
|
||||
import { LOWEST_SHUTDOWN_PRIORITY, HIGHEST_SHUTDOWN_PRIORITY } from '@/constants';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
type HandlerFn = () => Promise<void> | void;
|
||||
export type ServiceClass = Class<Record<string, HandlerFn>>;
|
||||
|
|
|
@ -2,7 +2,7 @@ import type express from 'express';
|
|||
import { mock } from 'jest-mock-extended';
|
||||
import type { IdentityProviderInstance, ServiceProviderInstance } from 'samlify';
|
||||
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { UrlService } from '@/services/url.service';
|
||||
import * as samlHelpers from '@/sso/saml/saml-helpers';
|
||||
import { SamlService } from '@/sso/saml/saml.service.ee';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Container } from 'typedi';
|
||||
import type { XMLFileInfo } from 'xmllint-wasm';
|
||||
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
|
||||
let xml: XMLFileInfo;
|
||||
let xmldsigCore: XMLFileInfo;
|
||||
|
|
|
@ -12,7 +12,7 @@ import { SettingsRepository } from '@/databases/repositories/settings.repository
|
|||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { UrlService } from '@/services/url.service';
|
||||
|
||||
import { SAML_PREFERENCES_DB_KEY } from './constants';
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Service } from 'typedi';
|
|||
|
||||
import type { Project } from '@/databases/entities/project';
|
||||
import { SubworkflowPolicyDenialError } from '@/errors/subworkflow-policy-denial.error';
|
||||
import { Logger } from '@/logger';
|
||||
import { Logger } from '@/logging/logger.service';
|
||||
import { AccessService } from '@/services/access.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { UrlService } from '@/services/url.service';
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue