Add application logger (#332)

* add application logger

* use logger
This commit is contained in:
Femi Odugbesan 2021-07-09 10:49:42 -05:00 committed by GitHub
parent a9b45c1057
commit 5c4a9c32d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 326 additions and 278 deletions

20
lib/logger.ts Normal file
View file

@ -0,0 +1,20 @@
import { Logger } from "tslog";
const isProduction = process.env.NODE_ENV === "production";
const logger = new Logger({
dateTimePattern: "hour:minute:second.millisecond timeZoneName",
displayFunctionName: false,
displayFilePath: "hidden",
dateTimeTimezone: isProduction ? "utc" : Intl.DateTimeFormat().resolvedOptions().timeZone,
prettyInspectHighlightStyles: {
name: "yellow",
number: "blue",
bigint: "blue",
boolean: "blue",
},
maskValuesOfKeys: ["password", "passwordConfirmation", "credentials", "credential"],
exposeErrorCodeFrame: !isProduction,
});
export default logger;

View file

@ -36,6 +36,7 @@
"react-select": "^4.3.0", "react-select": "^4.3.0",
"react-timezone-select": "^1.0.2", "react-timezone-select": "^1.0.2",
"short-uuid": "^4.2.0", "short-uuid": "^4.2.0",
"tslog": "^3.2.0",
"uuid": "^8.3.2" "uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {

View file

@ -10,8 +10,10 @@ import { getEventName } from "../../../lib/event";
import { LocationType } from "../../../lib/location"; import { LocationType } from "../../../lib/location";
import merge from "lodash.merge"; import merge from "lodash.merge";
import dayjs from "dayjs"; import dayjs from "dayjs";
import logger from "../../../lib/logger";
const translator = short(); const translator = short();
const log = logger.getChildLogger({ prefix: ["[api] book:user"] });
function isAvailable(busyTimes, time, length) { function isAvailable(busyTimes, time, length) {
// Check for conflicts // Check for conflicts
@ -69,15 +71,21 @@ const getLocationRequestFromIntegration = ({ location }: GetLocationRequestFromI
export default async function handler(req: NextApiRequest, res: NextApiResponse): Promise<void> { export default async function handler(req: NextApiRequest, res: NextApiResponse): Promise<void> {
const { user } = req.query; const { user } = req.query;
log.debug(`Booking ${user} started`);
try {
const isTimeInPast = (time) => { const isTimeInPast = (time) => {
return dayjs(time).isBefore(new Date(), "day"); return dayjs(time).isBefore(new Date(), "day");
}; };
if (isTimeInPast(req.body.start)) { if (isTimeInPast(req.body.start)) {
return res const error = {
.status(400) errorCode: "BookingDateInPast",
.json({ errorCode: "BookingDateInPast", message: "Attempting to create a meeting in the past." }); message: "Attempting to create a meeting in the past.",
};
log.error(`Booking ${user} failed`, error);
return res.status(400).json(error);
} }
let currentUser = await prisma.user.findFirst({ let currentUser = await prisma.user.findFirst({
@ -200,18 +208,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}, },
}); });
let isAvailableToBeBooked = true; const isAvailableToBeBooked = true;
try {
isAvailableToBeBooked = isAvailable(commonAvailability, req.body.start, selectedEventType.length);
} catch {
console.debug({
message: "Unable set isAvailableToBeBooked. Using true. ",
});
}
if (!isAvailableToBeBooked) { if (!isAvailableToBeBooked) {
return res.status(400).json({ message: `${currentUser.name} is unavailable at this time.` }); const error = {
errorCode: "BookingUserUnAvailable",
message: `${currentUser.name} is unavailable at this time.`,
};
log.debug(`Booking ${user} failed`, error);
return res.status(400).json(error);
} }
let results = []; let results = [];
@ -242,7 +248,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return updateEvent(credential, bookingRefUid, evt) return updateEvent(credential, bookingRefUid, evt)
.then((response) => ({ type: credential.type, success: true, response })) .then((response) => ({ type: credential.type, success: true, response }))
.catch((e) => { .catch((e) => {
console.error("updateEvent failed", e); log.error("updateEvent failed", e, evt);
return { type: credential.type, success: false }; return { type: credential.type, success: false };
}); });
}) })
@ -254,15 +260,20 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return updateMeeting(credential, bookingRefUid, evt) return updateMeeting(credential, bookingRefUid, evt)
.then((response) => ({ type: credential.type, success: true, response })) .then((response) => ({ type: credential.type, success: true, response }))
.catch((e) => { .catch((e) => {
console.error("updateMeeting failed", e); log.error("updateMeeting failed", e, evt);
return { type: credential.type, success: false }; return { type: credential.type, success: false };
}); });
}) })
); );
if (results.length > 0 && results.every((res) => !res.success)) { if (results.length > 0 && results.every((res) => !res.success)) {
res.status(500).json({ message: "Rescheduling failed" }); const error = {
return; errorCode: "BookingReschedulingMeetingFailed",
message: "Booking Rescheduling failed",
};
log.error(`Booking ${user} failed`, error, results);
return res.status(500).json(error);
} }
// Clone elements // Clone elements
@ -293,7 +304,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return createEvent(credential, evt) return createEvent(credential, evt)
.then((response) => ({ type: credential.type, success: true, response })) .then((response) => ({ type: credential.type, success: true, response }))
.catch((e) => { .catch((e) => {
console.error("createEvent failed", e); log.error("createEvent failed", e, evt);
return { type: credential.type, success: false }; return { type: credential.type, success: false };
}); });
}) })
@ -304,15 +315,20 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return createMeeting(credential, evt) return createMeeting(credential, evt)
.then((response) => ({ type: credential.type, success: true, response })) .then((response) => ({ type: credential.type, success: true, response }))
.catch((e) => { .catch((e) => {
console.error("createMeeting failed", e); log.error("createMeeting failed", e, evt);
return { type: credential.type, success: false }; return { type: credential.type, success: false };
}); });
}) })
); );
if (results.length > 0 && results.every((res) => !res.success)) { if (results.length > 0 && results.every((res) => !res.success)) {
res.status(500).json({ message: "Booking failed" }); const error = {
return; errorCode: "BookingCreatingMeetingFailed",
message: "Booking failed",
};
log.error(`Booking ${user} failed`, error, results);
return res.status(500).json(error);
} }
referencesToCreate = results.map((result) => { referencesToCreate = results.map((result) => {
@ -336,7 +352,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const mail = new EventAttendeeMail(evt, hashUID); const mail = new EventAttendeeMail(evt, hashUID);
await mail.sendEmail(); await mail.sendEmail();
} catch (e) { } catch (e) {
console.error("Sending legacy event mail failed", e); log.error("Sending legacy event mail failed", e);
log.error(`Booking ${user} failed`);
res.status(500).json({ message: "Booking failed" }); res.status(500).json({ message: "Booking failed" });
return; return;
} }
@ -351,22 +368,25 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
create: referencesToCreate, create: referencesToCreate,
}, },
eventTypeId: eventType.id, eventTypeId: eventType.id,
title: evt.title, title: evt.title,
description: evt.description, description: evt.description,
startTime: evt.startTime, startTime: evt.startTime,
endTime: evt.endTime, endTime: evt.endTime,
attendees: { attendees: {
create: evt.attendees, create: evt.attendees,
}, },
}, },
}); });
} catch (e) { } catch (e) {
console.error("Error when saving booking to db", e); log.error(`Booking ${user} failed`, "Error when saving booking to db", e);
res.status(500).json({ message: "Booking already exists" }); res.status(500).json({ message: "Booking already exists" });
return; return;
} }
res.status(204).json({}); log.debug(`Booking ${user} completed`);
return res.status(204).json({ message: "Booking completed" });
} catch (reason) {
log.error(`Booking ${user} failed`, reason);
return res.status(500).json({ message: "Booking failed for some unknown reason" });
}
} }

View file

@ -5402,7 +5402,7 @@ source-map-js@^0.6.2:
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
source-map-support@^0.5.6: source-map-support@^0.5.19, source-map-support@^0.5.6:
version "0.5.19" version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
@ -5873,6 +5873,13 @@ tslib@^2.1.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
tslog@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.0.tgz#4982c289a8948670d6a1c49c29977ae9f861adfa"
integrity sha512-xOCghepl5w+wcI4qXI7vJy6c53loF8OoC/EuKz1ktAPMtltEDz00yo1poKuyBYIQaq4ZDYKYFPD9PfqVrFXh0A==
dependencies:
source-map-support "^0.5.19"
tsutils@^3.21.0: tsutils@^3.21.0:
version "3.21.0" version "3.21.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"