Some logging improvements

This commit is contained in:
Jan Oberhauser 2021-04-04 13:58:05 +02:00
parent 6269aa3be2
commit e5f4dc951d
6 changed files with 73 additions and 45 deletions

View file

@ -576,7 +576,7 @@ const config = convict({
env: 'N8N_LOG_LEVEL',
},
output: {
doc: 'Where to output logs. Options are: console, file.',
doc: 'Where to output logs. Options are: console, file. Multiple can be separated by comma (",")',
format: String,
default: 'console',
env: 'N8N_LOG_OUTPUT',

View file

@ -1,5 +1,5 @@
import * as winston from 'winston';
import config = require('../config');
import * as winston from 'winston';
import {
ILogger,
@ -8,22 +8,41 @@ import {
class Logger implements ILogger {
private logger: winston.Logger;
constructor() {
const logFormat = winston.format.printf(({ message }) => message) as winston.Logform.Format;
constructor() {
const level = config.get('logs.level');
const output = (config.get('logs.output') as string).split(',').map(output => output.trim());
this.logger = winston.createLogger({
level: config.get('logs.level'),
format: logFormat,
transports: [
new winston.transports.Console(),
],
level,
});
if (config.get('logs.output') === 'file') {
if (output.includes('console')) {
let format: winston.Logform.Format;
if (['debug', 'verbose'].includes(level)) {
format = winston.format.combine(
winston.format.metadata(),
winston.format.timestamp(),
winston.format.colorize({ all: true }),
winston.format.printf(({ level, message, timestamp, metadata }) => {
return `${timestamp} | ${level.padEnd(18)} | ${message}` + (Object.keys(metadata).length ? ` ${JSON.stringify(metadata)}` : '');
}) as winston.Logform.Format,
);
} else {
format = winston.format.printf(({ message }) => message) as winston.Logform.Format;
}
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(
@ -35,31 +54,30 @@ class Logger implements ILogger {
})
);
}
}
log(type: LogTypes, message: string, meta: object = {}) {
this.logger.log(type, message, meta);
}
// Convenience methods below
debug(message: string, meta: object = {}) {
this.logger.log('debug', message, meta);
}
info(message: string, meta: object = {}) {
this.logger.log('info', message, meta);
}
error(message: string, meta: object = {}) {
this.logger.log('error', message, meta);
}
verbose(message: string, meta: object = {}) {
this.logger.log('verbose', message, meta);
}
warn(message: string, meta: object = {}) {
this.logger.log('warn', message, meta);
}
@ -72,6 +90,6 @@ export function getLogger() {
if (activeLoggerInstance === undefined) {
activeLoggerInstance = new Logger();
}
return activeLoggerInstance;
}
}

View file

@ -289,7 +289,7 @@ export function hookFunctionsPreExecute(parentProcessMode?: string): IWorkflowEx
// For busy machines, we may get "Database is locked" errors.
// We do this to prevent crashes and executions ending in `unknown` state.
console.log(`Failed saving execution progress to database for execution ID ${this.executionId}`, err);
Logger.error(`Failed saving execution progress to database for execution ID ${this.executionId}`, err);
}
},
@ -325,8 +325,7 @@ function hookFunctionsSave(parentProcessMode?: string): IWorkflowExecuteHooks {
try {
await WorkflowHelpers.saveStaticDataById(this.workflowData.id as string, newStaticData);
} catch (e) {
// TODO: Add proper logging!
console.error(`There was a problem saving the workflow with id "${this.workflowData.id}" to save changed staticData: ${e.message}`);
Logger.error(`There was a problem saving the workflow with id "${this.workflowData.id}" to save changed staticData: ${e.message}`);
}
}
@ -424,8 +423,7 @@ function hookFunctionsSaveWorker(): IWorkflowExecuteHooks {
try {
await WorkflowHelpers.saveStaticDataById(this.workflowData.id as string, newStaticData);
} catch (e) {
// TODO: Add proper logging!
console.error(`There was a problem saving the workflow with id "${this.workflowData.id}" to save changed staticData: ${e.message}`);
Logger.error(`There was a problem saving the workflow with id "${this.workflowData.id}" to save changed staticData: ${e.message}`);
}
}

View file

@ -17,6 +17,7 @@ import {
IRun,
IRunExecutionData,
ITaskData,
LoggerProxy as Logger,
IWorkflowCredentials,
Workflow,
} from 'n8n-workflow';
@ -86,7 +87,7 @@ export async function executeErrorWorkflow(workflowId: string, workflowErrorData
if (workflowData === undefined) {
// The error workflow could not be found
console.error(`ERROR: Calling Error Workflow for "${workflowErrorData.workflow.id}". Could not find error workflow "${workflowId}"`);
Logger.error(`Calling Error Workflow for "${workflowErrorData.workflow.id}". Could not find error workflow "${workflowId}"`, { workflowId });
return;
}
@ -105,7 +106,7 @@ export async function executeErrorWorkflow(workflowId: string, workflowErrorData
}
if (workflowStartNode === undefined) {
console.error(`ERROR: Calling Error Workflow for "${workflowErrorData.workflow.id}". Could not find "${ERROR_TRIGGER_TYPE}" in workflow "${workflowId}"`);
Logger.error(`Calling Error Workflow for "${workflowErrorData.workflow.id}". Could not find "${ERROR_TRIGGER_TYPE}" in workflow "${workflowId}"`);
return;
}
@ -153,7 +154,7 @@ export async function executeErrorWorkflow(workflowId: string, workflowErrorData
const workflowRunner = new WorkflowRunner();
await workflowRunner.run(runData);
} catch (error) {
console.error(`ERROR: Calling Error Workflow for "${workflowErrorData.workflow.id}": ${error.message}`);
Logger.error(`Calling Error Workflow for "${workflowErrorData.workflow.id}": ${error.message}`, { workflowId: workflowErrorData.workflow.id });
}
}
@ -315,8 +316,7 @@ export async function saveStaticData(workflow: Workflow): Promise <void> {
await saveStaticDataById(workflow.id!, workflow.staticData);
workflow.staticData.__dataChanged = false;
} catch (e) {
// TODO: Add proper logging!
console.error(`There was a problem saving the workflow with id "${workflow.id}" to save changed staticData: ${e.message}`);
Logger.error(`There was a problem saving the workflow with id "${workflow.id}" to save changed staticData: ${e.message}`, { workflowId: workflow.id });
}
}
}

View file

@ -17,25 +17,30 @@ import {
import {
IDataObject,
IExecuteData,
IExecuteWorkflowInfo,
IExecutionError,
ILogger,
INodeExecutionData,
INodeType,
INodeTypeData,
IRun,
IRunExecutionData,
ITaskData,
IWorkflowExecuteAdditionalData,
IWorkflowExecuteHooks,
LoggerProxy,
Workflow,
WorkflowHooks,
} from 'n8n-workflow';
import {
getLogger,
} from '../src/Logger';
import * as config from '../config';
export class WorkflowRunnerProcess {
data: IWorkflowExecutionDataProcessWithExecution | undefined;
logger: ILogger;
startedAt = new Date();
workflow: Workflow | undefined;
workflowExecute: WorkflowExecute | undefined;
@ -53,6 +58,10 @@ export class WorkflowRunnerProcess {
process.on('SIGTERM', WorkflowRunnerProcess.stopProcess);
process.on('SIGINT', WorkflowRunnerProcess.stopProcess);
const logger = this.logger = getLogger();
LoggerProxy.init(logger);
logger.info('Initializing n8n sub-process', { pid: process.pid });
this.data = inputData;
let className: string;
let tempNode: INodeType;
@ -126,10 +135,10 @@ export class WorkflowRunnerProcess {
result = await executeWorkflowFunction(workflowInfo, additionalData, inputData, executionId, workflowData, runData);
} catch (e) {
await sendToParentProcess('finishExecution', { executionId });
// Throw same error we had
throw e;
// Throw same error we had
throw e;
}
await sendToParentProcess('finishExecution', { executionId, result });
const returnData = WorkflowHelpers.getDataLastExecutedNodeData(result);
@ -167,12 +176,7 @@ export class WorkflowRunnerProcess {
parameters,
});
} catch (error) {
// TODO: Add proper logging
console.error(`There was a problem sending hook: "${hook}"`);
console.error('Parameters:');
console.error(parameters);
console.error('Error:');
console.error(error);
this.logger.error(`There was a problem sending hook: "${hook}"`, { parameters, error});
}
}

View file

@ -15,6 +15,7 @@ import {
ITaskDataConnections,
IWaitingForExecution,
IWorkflowExecuteAdditionalData,
LoggerProxy as Logger,
Workflow,
WorkflowExecuteMode,
} from 'n8n-workflow';
@ -500,7 +501,7 @@ export class WorkflowExecute {
if (this.runExecutionData.startData === undefined) {
this.runExecutionData.startData = {};
}
Logger.debug(`Workflow execution (start)`);
let currentExecutionTry = '';
let lastExecutionTry = '';
@ -557,6 +558,7 @@ export class WorkflowExecute {
executionData = this.runExecutionData.executionData!.nodeExecutionStack.shift() as IExecuteData;
executionNode = executionData.node;
Logger.debug(`Process node: "${executionNode.name}" (Start)`);
await this.executeHook('nodeExecuteBefore', [executionNode.name]);
// Get the index of the current run
@ -654,7 +656,9 @@ export class WorkflowExecute {
}
}
Logger.debug(`Process node: "${executionNode.name}" (before: runNode)`);
nodeSuccessData = await workflow.runNode(executionData.node, executionData.data, this.runExecutionData, runIndex, this.additionalData, NodeExecuteFunctions, this.mode);
Logger.debug(`Process node: "${executionNode.name}" (after: runNode - success)`);
if (nodeSuccessData === undefined) {
// Node did not get executed
@ -689,6 +693,8 @@ export class WorkflowExecute {
message: error.message,
stack: error.stack,
};
Logger.debug(`Process node: "${executionNode.name}" (after: runNode - error)`);
}
}
@ -819,8 +825,10 @@ export class WorkflowExecute {
const fullRunData = this.getFullRunData(startedAt);
if (executionError !== undefined) {
Logger.debug(`Workflow execution (end: error)`, { error: executionError });
fullRunData.data.resultData.error = executionError;
} else {
Logger.debug(`Workflow execution (end: success)`);
fullRunData.finished = true;
}