Skip to content

Commit 65fce7e

Browse files
authored
refactor logger and apply to @subql/query (#220)
* refactor logger and apply to @subql/query * use safe strinify from flatted * revert debug in graphile-build-pg plugin
1 parent 344349a commit 65fce7e

File tree

18 files changed

+347
-144
lines changed

18 files changed

+347
-144
lines changed

packages/common/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@
1515
"dependencies": {
1616
"class-transformer": "0.3.1",
1717
"class-validator": "^0.13.1",
18+
"flatted": "^3.1.1",
1819
"graphql": "^15.5.0",
1920
"graphql-tag": "^2.12.0",
2021
"graphql-tools": "^7.0.2",
2122
"js-yaml": "^4.0.0",
23+
"pino": "^6.11.1",
2224
"reflect-metadata": "^0.1.13"
2325
},
2426
"devDependencies": {
25-
"@types/js-yaml": "^4.0.0"
27+
"@types/js-yaml": "^4.0.0",
28+
"@types/pino": "^6.3.6"
2629
}
2730
}

packages/common/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ import 'reflect-metadata';
55

66
export * from './project';
77
export * from './graphql';
8+
export {levelFilter, Logger, LoggerOption} from './logger';

packages/common/src/logger/colors.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2020-2021 OnFinality Limited authors & contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import chalk from 'chalk';
5+
import {LEVELS} from './constants';
6+
7+
export const ctx = new chalk.Instance({level: 3});
8+
const colored = {
9+
default: ctx.white,
10+
60: ctx.bgRed,
11+
50: ctx.red,
12+
40: ctx.yellow,
13+
30: ctx.green,
14+
20: ctx.blue,
15+
10: ctx.grey,
16+
message: ctx.cyan,
17+
};
18+
19+
export function colorizeLevel(level: number) {
20+
if (Number.isInteger(+level)) {
21+
return Object.prototype.hasOwnProperty.call(LEVELS, level)
22+
? colored[level](LEVELS[level])
23+
: colored.default(LEVELS.default);
24+
}
25+
return colored.default(LEVELS.default);
26+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2020-2021 OnFinality Limited authors & contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
export const LEVELS = {
5+
default: 'USERLVL',
6+
60: 'FATAL',
7+
50: 'ERROR',
8+
40: 'WARN',
9+
30: 'INFO',
10+
20: 'DEBUG',
11+
10: 'TRACE',
12+
};
13+
14+
export const LEVELS_MAP = {
15+
trace: 10,
16+
debug: 20,
17+
info: 30,
18+
warn: 40,
19+
error: 50,
20+
fatal: 60,
21+
silent: 999,
22+
};

packages/common/src/logger/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright 2020-2021 OnFinality Limited authors & contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
export * from './logger';
5+
export * from './util';

packages/common/src/logger/logger.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright 2020-2021 OnFinality Limited authors & contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import {stringify} from 'flatted';
5+
import Pino, {LevelWithSilent} from 'pino';
6+
import {colorizeLevel, ctx} from './colors';
7+
8+
export interface LoggerOption {
9+
outputFormat?: 'json' | 'colored';
10+
level?: string;
11+
nestedKey?: string;
12+
}
13+
14+
export class Logger {
15+
private pino: Pino.Logger;
16+
private childLoggers: {[category: string]: Pino.Logger} = {};
17+
18+
constructor({level: logLevel, nestedKey, outputFormat}: LoggerOption) {
19+
this.pino = Pino({
20+
messageKey: 'message',
21+
timestamp: () => `,"timestamp":"${new Date().toISOString()}"`,
22+
nestedKey,
23+
formatters: {
24+
level(label, number) {
25+
return {level: label};
26+
},
27+
},
28+
serializers:
29+
outputFormat === 'json'
30+
? {
31+
payload: (value) => {
32+
if (value instanceof Error) {
33+
return {
34+
type: 'error',
35+
name: value.name,
36+
message: value.message,
37+
stack: value.stack,
38+
};
39+
} else {
40+
return stringify(value);
41+
}
42+
},
43+
}
44+
: {},
45+
prettyPrint: outputFormat !== 'json',
46+
prettifier: function (options) {
47+
// `this` is bound to the pino instance
48+
// Deal with whatever options are supplied.
49+
return function prettifier(inputData: string | object) {
50+
let logObject;
51+
if (typeof inputData === 'string') {
52+
logObject = JSON.parse(inputData);
53+
} else if (isObject(inputData)) {
54+
logObject = inputData;
55+
}
56+
if (!logObject) return inputData;
57+
// implement prettification
58+
const {category, level, message, payload, time} = logObject;
59+
let error = '';
60+
if (payload instanceof Error) {
61+
if (['debug', 'trace'].includes(logLevel)) {
62+
error = `\n${payload.stack}`;
63+
} else {
64+
error = `${payload.name}: ${payload.message}`;
65+
}
66+
}
67+
return `${time} <${ctx.magentaBright(category)}> ${colorizeLevel(level)} ${message} ${error}\n`;
68+
};
69+
70+
function isObject(input) {
71+
return Object.prototype.toString.apply(input) === '[object Object]';
72+
}
73+
},
74+
});
75+
}
76+
77+
getLogger(category: string): Pino.Logger {
78+
if (!this.childLoggers[category]) {
79+
this.childLoggers[category] = this.pino.child({category});
80+
}
81+
return this.childLoggers[category];
82+
}
83+
84+
setLevel(level: LevelWithSilent): void {
85+
this.pino.level = level;
86+
for (const childLogger of Object.values(this.childLoggers)) {
87+
childLogger.level = level;
88+
}
89+
}
90+
}

packages/common/src/logger/util.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright 2020-2021 OnFinality Limited authors & contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import {LevelWithSilent} from 'pino';
5+
import {LEVELS_MAP} from './constants';
6+
7+
export function levelFilter(test: LevelWithSilent, target: LevelWithSilent): boolean {
8+
return LEVELS_MAP[test?.toLowerCase()] >= LEVELS_MAP[target.toLowerCase()];
9+
}

packages/node/src/indexer/sandbox.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
import fs from 'fs';
55
import path from 'path';
66
import { ApiPromise } from '@polkadot/api';
7+
import { levelFilter } from '@subql/common';
78
import { Store } from '@subql/types';
89
import { merge } from 'lodash';
910
import { NodeVM, NodeVMOptions, VMScript } from 'vm2';
1011
import { NodeConfig } from '../configure/NodeConfig';
11-
import { levelFilter } from '../utils/logger';
1212
import { timeout } from '../utils/promise';
1313

1414
export interface SandboxOption {

packages/node/src/utils/logger.ts

Lines changed: 11 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -2,133 +2,30 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import { LoggerService } from '@nestjs/common';
5-
import chalk from 'chalk';
6-
import Pino, { LevelWithSilent, Logger } from 'pino';
5+
import { Logger } from '@subql/common';
6+
import Pino from 'pino';
77
import { argv } from '../yargs';
88

9-
const LEVELS = {
10-
default: 'USERLVL',
11-
60: 'FATAL',
12-
50: 'ERROR',
13-
40: 'WARN',
14-
30: 'INFO',
15-
20: 'DEBUG',
16-
10: 'TRACE',
17-
};
18-
19-
const levelsMap = {
20-
trace: 10,
21-
debug: 20,
22-
info: 30,
23-
warn: 40,
24-
error: 50,
25-
fatal: 60,
26-
silent: 999,
27-
};
28-
29-
const ctx = new chalk.Instance({ level: 3 });
30-
const colored = {
31-
default: ctx.white,
32-
60: ctx.bgRed,
33-
50: ctx.red,
34-
40: ctx.yellow,
35-
30: ctx.green,
36-
20: ctx.blue,
37-
10: ctx.grey,
38-
message: ctx.cyan,
39-
};
40-
41-
function colorizeLevel(level: number) {
42-
if (Number.isInteger(+level)) {
43-
return Object.prototype.hasOwnProperty.call(LEVELS, level)
44-
? colored[level](LEVELS[level])
45-
: colored.default(LEVELS.default);
46-
}
47-
return colored.default(LEVELS.default);
48-
}
49-
50-
const outputFmt = argv('output-fmt');
9+
const outputFmt = argv('output-fmt') as 'json' | 'colored';
5110
const debug = argv('debug');
52-
// TODO: support if loglevel is specified in config file.
5311
const logLevel = argv('log-level') as string | undefined;
5412

55-
const logger = Pino({
56-
messageKey: 'message',
57-
timestamp: () => `,"timestamp":"${new Date().toISOString()}"`,
13+
const logger = new Logger({
14+
level: debug ? 'debug' : logLevel,
15+
outputFormat: outputFmt,
5816
nestedKey: 'payload',
59-
formatters: {
60-
level(label, number) {
61-
return { level: label };
62-
},
63-
},
64-
serializers:
65-
outputFmt === 'json'
66-
? {
67-
payload: (value) => {
68-
if (value instanceof Error) {
69-
return {
70-
type: 'error',
71-
name: value.name,
72-
message: value.message,
73-
stack: value.stack,
74-
};
75-
} else {
76-
return JSON.stringify(value);
77-
}
78-
},
79-
}
80-
: {},
81-
prettyPrint: outputFmt !== 'json',
82-
prettifier: function (options) {
83-
// `this` is bound to the pino instance
84-
// Deal with whatever options are supplied.
85-
return function prettifier(inputData: string | object) {
86-
let logObject;
87-
if (typeof inputData === 'string') {
88-
logObject = JSON.parse(inputData);
89-
} else if (isObject(inputData)) {
90-
logObject = inputData;
91-
}
92-
if (!logObject) return inputData;
93-
// implement prettification
94-
const { category, level, message, payload, time } = logObject;
95-
let error = '';
96-
if (payload instanceof Error) {
97-
if (debug || ['debug', 'trace'].includes(logLevel)) {
98-
error = `\n${payload.stack}`;
99-
} else {
100-
error = `${payload.name}: ${payload.message}`;
101-
}
102-
}
103-
return `${time} <${ctx.magentaBright(category)}> ${colorizeLevel(
104-
level,
105-
)} ${message} ${error}\n`;
106-
};
107-
108-
function isObject(input) {
109-
return Object.prototype.toString.apply(input) === '[object Object]';
110-
}
111-
},
11217
});
11318

114-
const childLoggers: { [category: string]: Logger } = {};
115-
116-
export function getLogger(category: string): Logger {
117-
if (!childLoggers[category]) {
118-
childLoggers[category] = logger.child({ category });
119-
}
120-
return childLoggers[category];
19+
export function getLogger(category: string): Pino.Logger {
20+
return logger.getLogger(category);
12121
}
12222

123-
export function setLevel(level: LevelWithSilent): void {
124-
logger.level = level;
125-
for (const childLogger of Object.values(childLoggers)) {
126-
childLogger.level = level;
127-
}
23+
export function setLevel(level: Pino.LevelWithSilent): void {
24+
logger.setLevel(level);
12825
}
12926

13027
export class NestLogger implements LoggerService {
131-
private logger = logger.child({ category: 'nestjs' });
28+
private logger = logger.getLogger('nestjs');
13229

13330
error(message: any, trace?: string) {
13431
if (trace) {
@@ -146,10 +43,3 @@ export class NestLogger implements LoggerService {
14643
this.logger.warn(message);
14744
}
14845
}
149-
150-
export function levelFilter(
151-
test: LevelWithSilent,
152-
target: LevelWithSilent,
153-
): boolean {
154-
return levelsMap[test?.toLowerCase()] >= levelsMap[target.toLowerCase()];
155-
}

packages/query/.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
DB_USER=postgres
2+
DB_PASS=postgres
3+
DB_DATABASE=postgres
4+
DB_HOST=localhost
5+
DB_PORT=5432
6+
PORT=3001

packages/query/nodemon.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"watch": ["src"],
3+
"ext": "ts",
4+
"ignore": ["src/**/*.spec.ts"],
5+
"exec": "node -r dotenv/config -r tsconfig-paths/register -r ts-node/register src/main.ts"
6+
}

packages/query/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"build": "rm -rf dist && tsc -b",
1313
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
1414
"start": "nest start",
15-
"start:dev": "nest start --watch",
15+
"start:dev": "nodemon",
1616
"start:prod": "node dist/main",
1717
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
1818
"test": "jest",
@@ -35,6 +35,7 @@
3535
"@nestjs/core": "^7.6.5",
3636
"@nestjs/platform-express": "^7.6.5",
3737
"apollo-server-express": "^2.19.2",
38+
"express-pino-logger": "^6.0.0",
3839
"graphile-build": "^4.10.0",
3940
"graphile-build-pg": "^4.10.0",
4041
"graphql": "^15.4.0",
@@ -51,10 +52,12 @@
5152
"@nestjs/schematics": "^7.2.6",
5253
"@nestjs/testing": "^7.6.5",
5354
"@types/express": "^4.17.11",
55+
"@types/express-pino-logger": "^4.0.2",
5456
"@types/jest": "^26.0.20",
5557
"@types/lodash": "^4.14.165",
5658
"@types/rimraf": "^3",
5759
"@types/yargs": "^15.0.11",
60+
"nodemon": "^2.0.7",
5861
"typescript": "^4.1.3"
5962
}
6063
}

0 commit comments

Comments
 (0)