Replace winston with pino

This commit is contained in:
Tuan Dang
2023-10-31 15:03:36 +02:00
parent 4792e752c2
commit ad4513f926
11 changed files with 833 additions and 1128 deletions

1809
backend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -42,6 +42,9 @@
"passport-github": "^1.1.0",
"passport-gitlab2": "^5.0.0",
"passport-google-oauth20": "^2.0.0",
"pino": "^8.16.1",
"pino-http": "^8.5.1",
"pino-pretty": "^10.2.3",
"posthog-node": "^2.6.0",
"probot": "^12.3.1",
"query-string": "^7.1.3",
@@ -52,8 +55,6 @@
"tweetnacl-util": "^0.15.1",
"typescript": "^4.9.3",
"utility-types": "^3.10.0",
"winston": "^3.8.2",
"winston-loki": "^6.0.6",
"zod": "^3.22.3"
},
"overrides": {
@@ -104,6 +105,7 @@
"@types/nodemailer": "^6.4.6",
"@types/passport": "^1.0.12",
"@types/picomatch": "^2.3.0",
"@types/pino": "^7.0.5",
"@types/supertest": "^2.0.12",
"@types/swagger-jsdoc": "^6.0.1",
"@types/swagger-ui-express": "^4.1.3",

View File

@@ -1,5 +1,5 @@
import mongoose from "mongoose";
import { getLogger } from "../utils/logger";
import { logger } from "../utils/logging";
/**
* Initialize database connection
@@ -18,10 +18,10 @@ export const initDatabaseHelper = async ({
// allow empty strings to pass the required validator
mongoose.Schema.Types.String.checkRequired(v => typeof v === "string");
(await getLogger("database")).info("Database connection established");
logger.info("Database connection established");
} catch (err) {
(await getLogger("database")).error(`Unable to establish Database connection due to the error.\n${err}`);
logger.error(err, "Unable to establish database connection");
}
return mongoose.connection;

View File

@@ -5,6 +5,8 @@ import express from "express";
require("express-async-errors");
import helmet from "helmet";
import cors from "cors";
import { logger } from "./utils/logging";
import httpLogger from "pino-http";
import { DatabaseService } from "./services";
import { EELicenseService, GithubSecretScanningService } from "./ee/services";
import { setUpHealthEndpoint } from "./services/health";
@@ -73,7 +75,7 @@ import {
workspaces as v3WorkspacesRouter
} from "./routes/v3";
import { healthCheck } from "./routes/status";
import { getLogger } from "./utils/logger";
// import { getLogger } from "./utils/logger";
import { RouteNotFoundError } from "./utils/errors";
import { requestErrorHandler } from "./middleware/requestErrorHandler";
import {
@@ -94,12 +96,20 @@ import path from "path";
let handler: null | any = null;
const main = async () => {
const port = await getPort();
await setup();
await EELicenseService.initGlobalFeatureSet();
const app = express();
app.enable("trust proxy");
app.use(httpLogger({
logger,
autoLogging: false
}));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
@@ -164,7 +174,7 @@ const main = async () => {
const nextApp = new NextServer({
dev: false,
dir: nextJsBuildPath,
port: await getPort(),
port,
conf,
hostname: "local",
customServer: false
@@ -255,8 +265,8 @@ const main = async () => {
app.use(requestErrorHandler);
const server = app.listen(await getPort(), async () => {
(await getLogger("backend-main")).info(`Server started listening at port ${await getPort()}`);
const server = app.listen(port, async () => {
logger.info(`Server started listening at port ${port}`);
});
// await createTestUserForDevelopment();

View File

@@ -2,7 +2,7 @@ import * as Sentry from "@sentry/node";
import { ErrorRequestHandler } from "express";
import { TokenExpiredError } from "jsonwebtoken";
import { InternalServerError, UnauthorizedRequestError } from "../utils/errors";
import { getLogger } from "../utils/logger";
import { logger } from "../utils/logging";
import RequestError from "../utils/requestError";
import { ForbiddenError } from "@casl/ability";
@@ -15,10 +15,14 @@ export const requestErrorHandler: ErrorRequestHandler = async (
if (res.headersSent) return next();
const logAndCaptureException = async (error: RequestError) => {
(await getLogger("backend-main")).log(
(<RequestError>error).levelName.toLowerCase(),
`${error.stack}\n${error.message}`
);
// TODO: tie pino error-handling to error types/levels
// (await getLogger("backend-main")).log(
// (<RequestError>error).levelName.toLowerCase(),
// `${error.stack}\n${error.message}`
// );
logger.error(error.stack, error.message);
//* Set Sentry user identification if req.user is populated
if (req.user !== undefined && req.user !== null) {

View File

@@ -1,5 +1,5 @@
import { PostHog } from "posthog-node";
import { getLogger } from "../utils/logger";
import { logger } from "../utils/logging";
import { AuthData } from "../interfaces/middleware";
import {
getNodeEnv,
@@ -22,13 +22,13 @@ class Telemetry {
* Logs telemetry enable/disable notice.
*/
static logTelemetryMessage = async () => {
if(!(await getTelemetryEnabled())){
(await getLogger("backend-main")).info([
"",
[
"To improve, Infisical collects telemetry data about general usage.",
"This helps us understand how the product is doing and guide our product development to create the best possible platform; it also helps us demonstrate growth as we support Infisical as open-source software.",
"To opt into telemetry, you can set `TELEMETRY_ENABLED=true` within the environment variables.",
].join("\n"))
].forEach(line => logger.info(line));
}
}

View File

@@ -1,10 +1,10 @@
import mongoose from "mongoose";
import { createTerminus } from "@godaddy/terminus";
import { getLogger } from "../utils/logger";
import { logger } from "../utils/logging";
export const setUpHealthEndpoint = <T>(server: T) => {
const onSignal = async () => {
(await getLogger("backend-main")).info("Server is starting clean-up");
logger.info("Server is starting clean-up");
return Promise.all([
new Promise((resolve) => {
if (mongoose.connection && mongoose.connection.readyState == 1) {

View File

@@ -16,7 +16,7 @@ import {
getSmtpSecure,
getSmtpUsername,
} from "../config";
import { getLogger } from "../utils/logger";
import { logger } from "../utils/logging";
export const initSmtp = async () => {
const mailOpts: SMTPConnection.Options = {
@@ -84,15 +84,14 @@ export const initSmtp = async () => {
.then(async () => {
Sentry.setUser(null);
Sentry.captureMessage("SMTP - Successfully connected");
(await getLogger("backend-main")).info(
"SMTP - Successfully connected"
);
logger.info("SMTP - Successfully connected");
})
.catch(async (err) => {
Sentry.setUser(null);
Sentry.captureException(
`SMTP - Failed to connect to ${await getSmtpHost()}:${await getSmtpPort()} \n\t${err}`
);
logger.error(err, `SMTP - Failed to connect to ${await getSmtpHost()}:${await getSmtpPort()}`);
});
return transporter;

View File

@@ -1,67 +0,0 @@
/* eslint-disable no-console */
import { createLogger, format, transports } from "winston";
import LokiTransport from "winston-loki";
import { getLokiHost, getNodeEnv } from "../config";
const { combine, colorize, label, printf, splat, timestamp } = format;
const logFormat = (prefix: string) => combine(
timestamp(),
splat(),
label({ label: prefix }),
printf((info) => `${info.timestamp} ${info.label} ${info.level}: ${info.message}`)
);
const createLoggerWithLabel = async (level: string, label: string) => {
const _level = level.toLowerCase() || "info"
//* Always add Console output to transports
const _transports: any[] = [
new transports.Console({
format: combine(
colorize(),
logFormat(label),
// format.json()
),
}),
]
//* Add LokiTransport if it's enabled
if((await getLokiHost()) !== undefined){
_transports.push(
new LokiTransport({
host: await getLokiHost(),
handleExceptions: true,
handleRejections: true,
batching: true,
level: _level,
timeout: 30000,
format: format.combine(
format.json()
),
labels: {
app: process.env.npm_package_name,
version: process.env.npm_package_version,
environment: await getNodeEnv(),
},
onConnectionError: (err: Error)=> console.error("Connection error while connecting to Loki Server.\n", err),
})
)
}
return createLogger({
level: _level,
transports: _transports,
format: format.combine(
logFormat(label),
format.metadata({ fillExcept: ["message", "level", "timestamp", "label"] })
),
});
}
export const getLogger = async (loggerName: "backend-main" | "database") => {
const logger = {
"backend-main": await createLoggerWithLabel("info", "[IFSC:backend-main]"),
"database": await createLoggerWithLabel("info", "[IFSC:database]"),
}
return logger[loggerName]
}

View File

@@ -0,0 +1 @@
export { logger } from "./logger";

View File

@@ -0,0 +1,21 @@
import pino from "pino";
export const logger = pino({
level: process.env.PINO_LOG_LEVEL || "trace",
timestamp: pino.stdTimeFunctions.isoTime,
formatters: {
bindings: (bindings) => {
return {
pid: bindings.pid,
hostname: bindings.hostname
// node_version: process.version
};
},
},
transport: {
target: "pino-pretty",
options: {
colorize: true
}
}
});