Skip to content

Commit

Permalink
fix: payload
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielMuller committed Oct 23, 2024
1 parent b92b32f commit c568824
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 139 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@serverless-guru/logger",
"version": "1.0.1",
"version": "1.0.2",
"description": "Common logger utility",
"main": "./lib/cjs/index.js",
"types": "./lib/cjs/index.d.ts",
Expand Down
282 changes: 144 additions & 138 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,162 +48,168 @@ class Logger {
context: JSONObject = {},
sensitiveAttributes: StringArray = []
) {
// Default sensitive attributes
const defaultSensitiveAttributes: StringArray = [
"password",
"userid",
"token",
"secret",
"key",
"x-api-key",
"bearer",
"authorization",
];

const arrayToLowerCase = (array: StringArray): StringArray => {
if (Array.isArray(array)) {
return array
.map((el) => {
if (typeof el === "string") {
return el.toLowerCase();
}
return undefined;
})
.filter((el) => typeof el !== "undefined");
}
return [];
};
try {
// Default sensitive attributes
const defaultSensitiveAttributes: StringArray = [
"password",
"userid",
"token",
"secret",
"key",
"x-api-key",
"bearer",
"authorization",
];

const arrayToLowerCase = (array: StringArray): StringArray => {
if (Array.isArray(array)) {
return array
.map((el) => {
if (typeof el === "string") {
return el.toLowerCase();
}
return undefined;
})
.filter((el) => typeof el !== "undefined");
}
return [];
};

// Merge default sensitive attributes with custom ones
const attributesToMask = new Set([...defaultSensitiveAttributes, ...arrayToLowerCase(sensitiveAttributes)]);
// Merge default sensitive attributes with custom ones
const attributesToMask = new Set([...defaultSensitiveAttributes, ...arrayToLowerCase(sensitiveAttributes)]);

// Mask sensitive attributes, remove null
const maskSensitiveAttributes = (key: string, value: JSONObject): JSONObject | string | undefined => {
if (value === null) {
return undefined;
}
if (typeof value === "object" && isEmptyObject(value)) {
return undefined;
}
if (SKIP_MASK === true) {
// Mask sensitive attributes, remove null
const maskSensitiveAttributes = (key: string, value: JSONObject): JSONObject | string | undefined => {
if (value === null) {
return undefined;
}
if (typeof value === "object" && isEmptyObject(value)) {
return undefined;
}
if (SKIP_MASK === true) {
return value;
}
if (attributesToMask.has(key.toLowerCase())) {
return "****";
}
return value;
}
if (attributesToMask.has(key.toLowerCase())) {
return "****";
}
return value;
};

const isEmptyObject = (value: JSONObject): boolean => {
if (value == null) {
return false;
}
if (typeof value !== "object") {
return false;
}
const proto = Object.getPrototypeOf(value);
if (proto !== null && proto !== Object.prototype) {
return false;
}
return isEmpty(value);
};
};

const isEmpty = (obj: JSONObject): boolean => {
for (const prop in obj) {
if (Object.hasOwn(obj, prop)) {
const isEmptyObject = (value: JSONObject): boolean => {
if (value == null) {
return false;
}
}
return true;
};
if (typeof value !== "object") {
return false;
}
const proto = Object.getPrototypeOf(value);
if (proto !== null && proto !== Object.prototype) {
return false;
}
return isEmpty(value);
};

const getPayloadToPrint = (payload: JSONObject | Error): PayloadToPrintResponse => {
if (payload instanceof Error) {
return { gzip: false, error: formatError(payload) };
}
if (level === "warn" && message === MAX_PAYLOAD_MESSAGE) {
return { gzip: false, payload };
}
const stringifiedPayload = JSON.stringify(payload, maskSensitiveAttributes);
if (stringifiedPayload.length > MAX_SIZE && !NO_SKIP) {
this.warn(MAX_PAYLOAD_MESSAGE, { size: stringifiedPayload.length, MAX_SIZE });
return { gzip: false, payload: undefined };
}
if (stringifiedPayload.length > COMPRESS_SIZE && !NO_COMPRESS) {
return { gzip: true, payload: gzipSync(stringifiedPayload).toString("base64") };
}
return { gzip: false, payload };
};
const isEmpty = (obj: JSONObject): boolean => {
for (const prop in obj) {
if (Object.hasOwn(obj, prop)) {
return false;
}
}
return true;
};

const formatError = (error: Error): ErrorLogAttributes => {
return {
name: error.name,
location: getCodeLocation(error.stack),
message: error.message,
stack: error.stack,
cause: error.cause instanceof Error ? formatError(error.cause) : error.cause,
const getPayloadToPrint = (payload: JSONObject | Error | undefined): PayloadToPrintResponse => {
try {
if (payload instanceof Error) {
return { gzip: false, error: formatError(payload) };
}
if (level === "warn" && message === MAX_PAYLOAD_MESSAGE) {
return { gzip: false, payload };
}
const stringifiedPayload = JSON.stringify(payload, maskSensitiveAttributes);
if (stringifiedPayload?.length > MAX_SIZE && !NO_SKIP) {
this.warn(MAX_PAYLOAD_MESSAGE, { size: stringifiedPayload.length, MAX_SIZE });
return { gzip: false, payload: undefined };
}
if (stringifiedPayload?.length > COMPRESS_SIZE && !NO_COMPRESS) {
return { gzip: true, payload: gzipSync(stringifiedPayload).toString("base64") };
}
return { gzip: false, payload };
} catch {
return {};
}
};
};

const getCodeLocation = (stack?: string) => {
if (!stack) {
return "";
}
const formatError = (error: Error): ErrorLogAttributes => {
return {
name: error.name,
location: getCodeLocation(error.stack),
message: error.message,
stack: error.stack,
cause: error.cause instanceof Error ? formatError(error.cause) : error.cause,
};
};

const stackLines = stack.split("\n");
const regex = /\(([^)]*?):(\d+?):(\d+?)\)\\?$/;
const getCodeLocation = (stack?: string) => {
if (!stack) {
return "";
}

for (const item of stackLines) {
const match = regex.exec(item);
const stackLines = stack.split("\n");
const regex = /\(([^)]*?):(\d+?):(\d+?)\)\\?$/;

if (Array.isArray(match)) {
return `${match[1]}:${Number(match[2])}`;
}
}
for (const item of stackLines) {
const match = regex.exec(item);

return "";
};
if (Array.isArray(match)) {
return `${match[1]}:${Number(match[2])}`;
}
}

const getTimestamp = (): number | undefined => {
if (LOG_TS) {
return new Date().getTime();
}
return undefined;
};
return "";
};

const payloadToPrint = getPayloadToPrint(payload);
const getTimestamp = (): number | undefined => {
if (LOG_TS) {
return new Date().getTime();
}
return undefined;
};

const logEntry: LogEntry = {
timestamp: getTimestamp(),
service: this.serviceName,
correlationId: this.correlationId,
message,
context: {
...this.persistentContext,
...(typeof context === "object" && context !== null && Object.keys(context).length ? context : {}),
gzip: payloadToPrint.gzip === true ? true : undefined,
},
payload: payloadToPrint.payload,
error: payloadToPrint.error,
};
const payloadToPrint = getPayloadToPrint(payload);

const logEntry: LogEntry = {
timestamp: getTimestamp(),
service: this.serviceName,
correlationId: this.correlationId,
message,
context: {
...this.persistentContext,
...(typeof context === "object" && context !== null && Object.keys(context).length ? context : {}),
gzip: payloadToPrint.gzip === true ? true : undefined,
},
payload: payloadToPrint.payload,
error: payloadToPrint.error,
};

const stringifiedLogEntry = JSON.stringify(logEntry, maskSensitiveAttributes);
switch (level) {
case "info":
this.console.info(stringifiedLogEntry);
break;
case "debug":
this.console.debug(stringifiedLogEntry);
break;
case "warn":
this.console.warn(stringifiedLogEntry);
break;
case "error":
this.console.error(stringifiedLogEntry);
break;
default:
break;
}
const stringifiedLogEntry = JSON.stringify(logEntry, maskSensitiveAttributes);
switch (level) {
case "info":
this.console.info(stringifiedLogEntry);
break;
case "debug":
this.console.debug(stringifiedLogEntry);
break;
case "warn":
this.console.warn(stringifiedLogEntry);
break;
case "error":
this.console.error(stringifiedLogEntry);
break;
default:
break;
}
} catch {}
}

info(
Expand Down

0 comments on commit c568824

Please sign in to comment.