From ceec382899b8f2f2faa4a5161ced2fa266e9cc4a Mon Sep 17 00:00:00 2001 From: David Thyresson Date: Tue, 14 Mar 2023 11:19:36 -0400 Subject: [PATCH 1/3] Support additional log data without custom attribute --- .../src/__tests__/logFormatter.test.ts | 118 +++++++++++++----- packages/api-server/src/logFormatter/index.ts | 112 +++++++++++------ 2 files changed, 158 insertions(+), 72 deletions(-) diff --git a/packages/api-server/src/__tests__/logFormatter.test.ts b/packages/api-server/src/__tests__/logFormatter.test.ts index 4f71aa127583..b3ef1bdb43e5 100644 --- a/packages/api-server/src/__tests__/logFormatter.test.ts +++ b/packages/api-server/src/__tests__/logFormatter.test.ts @@ -4,63 +4,63 @@ const logFormatter = LogFormatter() describe('LogFormatter', () => { describe('Formats log levels as emoji', () => { - test('Formats Trace level', () => { + it('Formats Trace level', () => { expect(logFormatter({ level: 10 })).toMatch('๐Ÿงต') }) - test('Formats Debug level', () => { + it('Formats Debug level', () => { expect(logFormatter({ level: 20 })).toMatch('๐Ÿ›') }) - test('Formats Info level', () => { + it('Formats Info level', () => { expect(logFormatter({ level: 30 })).toMatch('๐ŸŒฒ') }) - test('Formats Warn level', () => { + it('Formats Warn level', () => { expect(logFormatter({ level: 40 })).toMatch('๐Ÿšฆ') }) - test('Formats Error level', () => { + it('Formats Error level', () => { expect(logFormatter({ level: 50 })).toMatch('๐Ÿšจ') }) }) describe('Formats log messages', () => { - test('Formats newline-delimited json data with a message', () => { + it('Formats newline-delimited json data with a message', () => { expect( logFormatter({ level: 10, message: 'Message in a bottle' }) ).toMatch('Message in a bottle') }) - test('Formats newline-delimited json data with a msg', () => { + it('Formats newline-delimited json data with a msg', () => { expect(logFormatter({ level: 10, msg: 'Message in a bottle' })).toMatch( 'Message in a bottle' ) }) - test('Formats a text message', () => { + it('Formats a text message', () => { expect(logFormatter('Handles text data')).toMatch('Handles text data') }) - test('Formats Get Method and Status Code', () => { + it('Formats Get Method and Status Code', () => { const logData = { level: 10, method: 'GET', statusCode: 200 } expect(logFormatter(logData)).toMatch('GET') expect(logFormatter(logData)).toMatch('200') }) - test('Formats Post Method and Status Code', () => { + it('Formats Post Method and Status Code', () => { const logData = { level: 10, method: 'POST', statusCode: 200 } expect(logFormatter(logData)).toMatch('POST') expect(logFormatter(logData)).toMatch('200') }) - test('Should not format Status Code without a Method', () => { + it('Should not format Status Code without a Method', () => { expect(logFormatter({ level: 10, statusCode: 200 })).not.toMatch('200') }) }) describe('Formats GraphQL injected log data from useRedwoodLogger plugin', () => { - test('Handles query', () => { + it('Handles query', () => { expect( logFormatter({ level: 10, @@ -71,13 +71,13 @@ describe('LogFormatter', () => { ).toMatch('"id": 1') }) - test('Handles operation name', () => { + it('Handles operation name', () => { expect( logFormatter({ level: 10, operationName: 'GET_BLOG_POST_BY_ID' }) ).toMatch('GET_BLOG_POST_BY_ID') }) - test('Handles GraphQL data', () => { + it('Handles GraphQL data', () => { expect( logFormatter({ level: 10, @@ -86,7 +86,7 @@ describe('LogFormatter', () => { ).toMatch('My Blog Post') }) - test('Handles browser user agent', () => { + it('Handles browser user agent', () => { const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15' expect( @@ -98,19 +98,19 @@ describe('LogFormatter', () => { }) }) - describe('Unknown log data', () => { - test('Should not include an unknown log data attribute', () => { - expect( - logFormatter({ - level: 10, - unknown: 'I should not see this', - }) - ).not.toMatch('I should not see this') - }) - }) + // describe('Unknown log data', () => { + // it('Should not include an unknown log data attribute', () => { + // expect( + // logFormatter({ + // level: 10, + // unknown: 'I should not see this', + // }) + // ).not.toMatch('I should not see this') + // }) + // }) describe('Custom log data', () => { - test('Should include the custom log attribute text', () => { + it('Should include the custom log attribute text', () => { expect( logFormatter({ level: 10, @@ -119,7 +119,7 @@ describe('LogFormatter', () => { ).toMatch('I should see this') }) - test('Should include the custom log attribute info a custom emoji and label', () => { + it('Should include the custom log attribute info a custom emoji and label', () => { expect( logFormatter({ level: 10, @@ -128,7 +128,7 @@ describe('LogFormatter', () => { ).toMatch('๐Ÿ—’ Custom') }) - test('Should include the custom log attribute info with nested text message', () => { + it('Should include the custom log attribute info with nested text message', () => { expect( logFormatter({ level: 10, @@ -140,7 +140,7 @@ describe('LogFormatter', () => { }) }) - test('Should include the custom log attribute info with a number attribute', () => { + it('Should include the custom log attribute info with a number attribute', () => { expect( logFormatter({ level: 10, @@ -152,7 +152,7 @@ describe('LogFormatter', () => { ).toMatch('100') }) - test('Should include the custom log attribute info with a nested object attribute', () => { + it('Should include the custom log attribute info with a nested object attribute', () => { expect( logFormatter({ level: 10, @@ -164,7 +164,7 @@ describe('LogFormatter', () => { ).toMatch('"foo": "bar"') }) - test('Should include the custom log attribute info with a nested object attribute', () => { + it('Should include the custom log attribute info with a nested object attribute', () => { expect( logFormatter({ level: 10, @@ -176,7 +176,7 @@ describe('LogFormatter', () => { ).toMatch('"foo": "bar"') }) - test('Should format error stack traces', () => { + it('Should format error stack traces', () => { expect( logFormatter({ level: 50, @@ -189,7 +189,7 @@ describe('LogFormatter', () => { ).toMatch(/at some line number/) }) - test('Should format error and include the error type', () => { + it('Should format error and include the error type', () => { expect( logFormatter({ level: 50, @@ -202,4 +202,56 @@ describe('LogFormatter', () => { }) ).toMatch(/GraphQL Error Info/) }) + + describe('When there are additional options', () => { + it('Should format and include additional options without custom tag', () => { + expect( + logFormatter({ + level: 10, + apiVersion: '4.2.1', + environment: 'staging', + }) + ).toMatch('"apiVersion": "4.2.1"') + + expect( + logFormatter({ + level: 10, + apiVersion: '4.2.1', + environment: 'staging', + }) + ).toMatch('"environment": "staging"') + }) + + it('Should format and include additional nested options without custom tag', () => { + expect( + logFormatter({ + level: 10, + deploy: { + environment: 'staging', + version: '4.2.1', + }, + }) + ).toMatch('"deploy"') + + expect( + logFormatter({ + level: 10, + deploy: { + environment: 'staging', + version: '4.2.1', + }, + }) + ).toMatch('"environment": "staging"') + + expect( + logFormatter({ + level: 10, + deploy: { + environment: 'staging', + version: '4.2.1', + }, + }) + ).toMatch('"version": "4.2.1"') + }) + }) }) diff --git a/packages/api-server/src/logFormatter/index.ts b/packages/api-server/src/logFormatter/index.ts index 9c8b2c704be5..ecfaea3799bd 100644 --- a/packages/api-server/src/logFormatter/index.ts +++ b/packages/api-server/src/logFormatter/index.ts @@ -84,18 +84,6 @@ export const LogFormatter = () => { const output = (logData: any) => { const output = [] - if (!logData.level) { - logData.level = 'customlevel' - } - - if (!logData.name) { - logData.name = '' - } - - if (!logData.ns) { - logData.ns = '' - } - output.push(formatDate(logData.time || Date.now())) output.push(formatLevel(logData.level)) output.push(formatNs(logData.ns)) @@ -106,31 +94,66 @@ export const LogFormatter = () => { const req = logData.req const res = logData.res - const statusCode = res ? res.statusCode : logData.statusCode - const responseTime = logData.responseTime || logData.elapsed - const method = req ? req.method : logData.method - const custom = logData.custom - const contentLength = logData.contentLength - const operationName = logData.operationName - const query = logData.query - const graphQLData = logData.data - const responseCache = logData.responseCache - const tracing = logData.tracing - const url = req ? req.url : logData.url - const userAgent = logData.userAgent + const { statusCode: responseStatusCode } = res || {} + const { method: requestMethod, url: requestUrl } = req || {} + + const { + level, + message, + name, + ns, + err: logDataErr, + stack: logDataStack, + statusCode: logDataStatusCode, + elapsed, + responseTime: logDataResponseTime, + method: logDataMethod, + custom, + contentLength, + operationName, + query, + data: graphQLData, + responseCache, + tracing, + url: logDataUrl, + userAgent, + ...rest + } = logData + + const statusCode = res ? responseStatusCode : logDataStatusCode + const responseTime = logDataResponseTime || elapsed + const method = requestMethod || logDataMethod + const url = requestUrl || logDataUrl + const stack = - logData.level === 'fatal' || logData.level === 'error' - ? logData.stack || (logData.err && logData.err.stack) + level === 'fatal' || level === 'error' + ? logDataStack || (logDataErr && logDataErr.stack) : null // Output err if it has more keys than 'stack' const err = - (logData.level === 'fatal' || logData.level === 'error') && - logData.err && - Object.keys(logData.err).find((key) => key !== 'stack') - ? logData.err + (level === 'fatal' || level === 'error') && + logDataErr && + Object.keys(logDataErr).find((key) => key !== 'stack') + ? logDataErr : null + if (!message) { + logData.message = '' + } + + if (!level) { + logData.level = 'customlevel' + } + + if (!name) { + logData.name = '' + } + + if (!ns) { + logData.ns = '' + } + if (method != null) { output.push(formatMethod(method)) output.push(formatStatusCode(statusCode)) @@ -184,6 +207,12 @@ export const LogFormatter = () => { output.push(formatStack(stack)) } + console.debug('rest', JSON.stringify(rest)) + + if (rest) { + output.push(formatCustom(rest)) + } + return output.filter(noEmpty).join(' ') } @@ -194,6 +223,8 @@ export const LogFormatter = () => { } const formatCustom = (query: any) => { + console.debug('query', query) + console.debug('js query', JSON.stringify(query, null, 2)) if (!isEmptyObject(query)) { return chalk.white( newline + '๐Ÿ—’ Custom' + newline + JSON.stringify(query, null, 2) @@ -224,6 +255,7 @@ export const LogFormatter = () => { const formatErrorProp = (errorPropValue: any) => { const errorType = errorPropValue['type'] || 'Error' + delete errorPropValue['message'] delete errorPropValue['stack'] delete errorPropValue['type'] @@ -252,24 +284,26 @@ export const LogFormatter = () => { } const formatMessage = (logData: any) => { - const msg = formatMessageName(logData.message) + const { level, message } = logData + + const msg = formatMessageName(message) let pretty - if (logData.level === 'error') { + if (level === 'error') { pretty = chalk.red(msg) } - if (logData.level === 'trace') { + if (level === 'trace') { pretty = chalk.white(msg) } - if (logData.level === 'warn') { + if (level === 'warn') { pretty = chalk.magenta(msg) } - if (logData.level === 'debug') { + if (level === 'debug') { pretty = chalk.yellow(msg) } - if (logData.level === 'info' || logData.level === 'customlevel') { + if (level === 'info' || level === 'customlevel') { pretty = chalk.green(msg) } - if (logData.level === 'fatal') { + if (level === 'fatal') { pretty = chalk.white.bgRed(msg) } return pretty @@ -283,8 +317,8 @@ export const LogFormatter = () => { return requestId && chalk.cyan(requestId) } - const formatNs = (name: any) => { - return chalk.cyan(name) + const formatNs = (ns: any) => { + return chalk.cyan(ns) } const formatName = (name: any) => { From 6b09aa723ce3a9a8c9737fe18c9055a7862555a3 Mon Sep 17 00:00:00 2001 From: David Thyresson Date: Tue, 14 Mar 2023 11:57:11 -0400 Subject: [PATCH 2/3] Refactor types and formatters --- .../api-server/src/logFormatter/formatters.ts | 211 ++++++++++++ packages/api-server/src/logFormatter/index.ts | 305 ++++-------------- 2 files changed, 272 insertions(+), 244 deletions(-) create mode 100644 packages/api-server/src/logFormatter/formatters.ts diff --git a/packages/api-server/src/logFormatter/formatters.ts b/packages/api-server/src/logFormatter/formatters.ts new file mode 100644 index 000000000000..dc5e99cd1c7d --- /dev/null +++ b/packages/api-server/src/logFormatter/formatters.ts @@ -0,0 +1,211 @@ +import chalk from 'chalk' +import prettyBytes from 'pretty-bytes' +import prettyMs from 'pretty-ms' + +export const NEWLINE = '\n' + +export const emojiLog: Record = { + warn: '๐Ÿšฆ', + info: '๐ŸŒฒ', + error: '๐Ÿšจ', + debug: '๐Ÿ›', + fatal: '๐Ÿ’€', + trace: '๐Ÿงต', +} + +export const isObject = (object?: Record) => { + return object && Object.prototype.toString.apply(object) === '[object Object]' +} + +export const isEmptyObject = (object?: Record) => { + return object && !Object.keys(object).length +} + +export const isPinoLog = (log?: Record) => { + return log && Object.prototype.hasOwnProperty.call(log, 'level') +} + +export const isWideEmoji = (character: string) => { + return character !== '๐Ÿšฆ' +} + +export const formatBundleSize = (bundle: string) => { + const bytes = parseInt(bundle, 10) + const size = prettyBytes(bytes).replace(/ /, '') + return chalk.gray(size) +} + +export const formatCustom = (query?: Record) => { + if (!isEmptyObject(query)) { + return chalk.white( + NEWLINE + '๐Ÿ—’ Custom' + NEWLINE + JSON.stringify(query, null, 2) + ) + } + + return +} + +export const formatData = (data?: Record) => { + if (!isEmptyObject(data)) { + return chalk.white( + NEWLINE + '๐Ÿ“ฆ Result Data' + NEWLINE + JSON.stringify(data, null, 2) + ) + } + + return +} + +export const formatDate = (instant: Date) => { + const date = new Date(instant) + const hours = date.getHours().toString().padStart(2, '0') + const minutes = date.getMinutes().toString().padStart(2, '0') + const seconds = date.getSeconds().toString().padStart(2, '0') + const prettyDate = hours + ':' + minutes + ':' + seconds + return chalk.gray(prettyDate) +} + +export const formatErrorProp = (errorPropValue: Record) => { + const errorType = errorPropValue['type'] || 'Error' + + delete errorPropValue['message'] + delete errorPropValue['stack'] + delete errorPropValue['type'] + + return chalk.redBright( + NEWLINE + + NEWLINE + + `๐Ÿšจ ${errorType} Info` + + NEWLINE + + NEWLINE + + JSON.stringify(errorPropValue, null, 2) + + NEWLINE + ) +} + +export const formatLevel = (level: any) => { + const emoji = emojiLog[level] + const padding = isWideEmoji(emoji) ? '' : ' ' + return emoji + padding +} + +export const formatLoadTime = (elapsedTime: any) => { + const elapsed = parseInt(elapsedTime, 10) + const time = prettyMs(elapsed) + return chalk.gray(time) +} + +export const formatMessage = (logData: any) => { + const { level, message } = logData + + const msg = formatMessageName(message) + let pretty + if (level === 'error') { + pretty = chalk.red(msg) + } + if (level === 'trace') { + pretty = chalk.white(msg) + } + if (level === 'warn') { + pretty = chalk.magenta(msg) + } + if (level === 'debug') { + pretty = chalk.yellow(msg) + } + if (level === 'info' || level === 'customlevel') { + pretty = chalk.green(msg) + } + if (level === 'fatal') { + pretty = chalk.white.bgRed(msg) + } + return pretty +} + +export const formatMethod = (method: string) => { + return chalk.white(method) +} + +export const formatRequestId = (requestId: string) => { + return requestId && chalk.cyan(requestId) +} + +export const formatNs = (ns: string) => { + return chalk.cyan(ns) +} + +export const formatName = (name: string) => { + return chalk.blue(name) +} + +export const formatMessageName = (message: string) => { + if (message === 'request') { + return '<--' + } + if (message === 'response') { + return '-->' + } + return message +} + +export const formatOperationName = (operationName: string) => { + return chalk.white(NEWLINE + '๐Ÿท ' + operationName) +} + +export const formatQuery = (query?: Record) => { + if (!isEmptyObject(query)) { + return chalk.white( + NEWLINE + '๐Ÿ”ญ Query' + NEWLINE + JSON.stringify(query, null, 2) + ) + } + + return +} + +export const formatResponseCache = ( + responseCache?: Record +) => { + if (!isEmptyObject(responseCache)) { + return chalk.white( + NEWLINE + + '๐Ÿ’พ Response Cache' + + NEWLINE + + JSON.stringify(responseCache, null, 2) + ) + } + + return +} + +export const formatStatusCode = (statusCode: string) => { + statusCode = statusCode || 'xxx' + return chalk.white(statusCode) +} + +export const formatStack = (stack?: string | Record) => { + return chalk.redBright( + stack + ? NEWLINE + '๐Ÿฅž Error Stack' + NEWLINE + NEWLINE + stack + NEWLINE + : '' + ) +} + +export const formatTracing = (data?: Record) => { + if (!isEmptyObject(data)) { + return chalk.white( + NEWLINE + 'โฐ Timing' + NEWLINE + JSON.stringify(data, null, 2) + ) + } + + return +} + +export const formatUrl = (url: string) => { + return chalk.white(url) +} + +export const formatUserAgent = (userAgent: string) => { + return chalk.grey(NEWLINE + '๐Ÿ•ต๏ธโ€โ™€๏ธ ' + userAgent) +} + +export const noEmpty = (value: any) => { + return !!value +} diff --git a/packages/api-server/src/logFormatter/index.ts b/packages/api-server/src/logFormatter/index.ts index ecfaea3799bd..0064606c9e0a 100644 --- a/packages/api-server/src/logFormatter/index.ts +++ b/packages/api-server/src/logFormatter/index.ts @@ -1,52 +1,50 @@ -import chalk from 'chalk' import jsonParse from 'fast-json-parse' -import prettyBytes from 'pretty-bytes' -import prettyMs from 'pretty-ms' - -const newline = '\n' - -const emojiLog: any = { - warn: '๐Ÿšฆ', - info: '๐ŸŒฒ', - error: '๐Ÿšจ', - debug: '๐Ÿ›', - fatal: '๐Ÿ’€', - trace: '๐Ÿงต', -} - -const isObject = (input: any) => { - return Object.prototype.toString.apply(input) === '[object Object]' -} - -const isEmptyObject = (object: any) => { - return object && !Object.keys(object).length -} - -const isPinoLog = (log: any) => { - return log && Object.prototype.hasOwnProperty.call(log, 'level') -} - -const isWideEmoji = (character: any) => { - return character !== '๐Ÿšฆ' -} +import type { FastifyRequest, FastifyReply } from 'fastify' + +import { + NEWLINE, + isObject, + isPinoLog, + noEmpty, + formatDate, + formatLevel, + formatBundleSize, + formatCustom, + formatData, + formatErrorProp, + formatLoadTime, + formatMessage, + formatMethod, + formatName, + formatNs, + formatOperationName, + formatQuery, + formatRequestId, + formatResponseCache, + formatStack, + formatStatusCode, + formatTracing, + formatUserAgent, + formatUrl, +} from './formatters' export const LogFormatter = () => { - const parse = (inputData: any) => { + const parse = (inputData: string | Record) => { let logData if (typeof inputData === 'string') { const parsedData = jsonParse(inputData) if (!parsedData.value || parsedData.err || !isPinoLog(parsedData.value)) { - return inputData + newline + return inputData + NEWLINE } logData = parsedData.value } else if (isObject(inputData) && isPinoLog(inputData)) { logData = inputData } else { - return inputData + newline + return inputData + NEWLINE } if (!logData.level) { - return inputData + newline + return inputData + NEWLINE } if (!logData.message) { @@ -57,10 +55,10 @@ export const LogFormatter = () => { convertLogNumber(logData) } - return output(logData) + newline + return output(logData) + NEWLINE } - const convertLogNumber = (logData: any) => { + const convertLogNumber = (logData: Record) => { if (logData.level === 10) { logData.level = 'trace' } @@ -81,18 +79,18 @@ export const LogFormatter = () => { } } - const output = (logData: any) => { + const output = (logData: Record) => { const output = [] - output.push(formatDate(logData.time || Date.now())) + output.push(formatDate((logData.time as Date) || Date.now())) output.push(formatLevel(logData.level)) - output.push(formatNs(logData.ns)) - output.push(formatName(logData.name)) - output.push(formatRequestId(logData.requestId)) + output.push(formatNs(logData.ns as string)) + output.push(formatName(logData.name as string)) + output.push(formatRequestId(logData.requestId as string)) output.push(formatMessage(logData)) - const req = logData.req - const res = logData.res + const req = logData.req as FastifyRequest + const res = logData.res as FastifyReply const { statusCode: responseStatusCode } = res || {} const { method: requestMethod, url: requestUrl } = req || {} @@ -118,16 +116,18 @@ export const LogFormatter = () => { url: logDataUrl, userAgent, ...rest - } = logData + }: Record = logData - const statusCode = res ? responseStatusCode : logDataStatusCode + const statusCode = responseStatusCode || logDataStatusCode const responseTime = logDataResponseTime || elapsed const method = requestMethod || logDataMethod const url = requestUrl || logDataUrl + const logDataErrStack = logDataErr && (logDataErr as Error).stack + const stack = level === 'fatal' || level === 'error' - ? logDataStack || (logDataErr && logDataErr.stack) + ? logDataStack || (logDataErr && logDataErrStack) : null // Output err if it has more keys than 'stack' @@ -155,247 +155,64 @@ export const LogFormatter = () => { } if (method != null) { - output.push(formatMethod(method)) - output.push(formatStatusCode(statusCode)) + output.push(formatMethod(method as string)) + output.push(formatStatusCode(statusCode as string)) } if (url != null) { - output.push(formatUrl(url)) + output.push(formatUrl(url as string)) } if (contentLength != null) { - output.push(formatBundleSize(contentLength)) + output.push(formatBundleSize(contentLength as string)) } if (custom) { - output.push(formatCustom(custom)) + output.push(formatCustom(custom as Record)) } if (responseTime != null) { - output.push(formatLoadTime(responseTime)) + output.push(formatLoadTime(responseTime as string)) } if (userAgent != null) { - output.push(formatUserAgent(userAgent)) + output.push(formatUserAgent(userAgent as string)) } if (operationName != null) { - output.push(formatOperationName(operationName)) + output.push(formatOperationName(operationName as string)) } if (query != null) { - output.push(formatQuery(query)) + output.push(formatQuery(query as Record)) } if (graphQLData != null) { - output.push(formatData(graphQLData)) + output.push(formatData(graphQLData as Record)) } if (responseCache != null) { - output.push(formatResponseCache(responseCache)) + output.push(formatResponseCache(responseCache as Record)) } if (tracing != null) { - output.push(formatTracing(tracing)) + output.push(formatTracing(tracing as Record)) } if (err != null) { - output.push(formatErrorProp(err)) + output.push(formatErrorProp(err as Record)) } if (stack != null) { - output.push(formatStack(stack)) + output.push(formatStack(stack as Record)) } - console.debug('rest', JSON.stringify(rest)) - if (rest) { - output.push(formatCustom(rest)) + output.push(formatCustom(rest as Record)) } return output.filter(noEmpty).join(' ') } - const formatBundleSize = (bundle: any) => { - const bytes = parseInt(bundle, 10) - const size = prettyBytes(bytes).replace(/ /, '') - return chalk.gray(size) - } - - const formatCustom = (query: any) => { - console.debug('query', query) - console.debug('js query', JSON.stringify(query, null, 2)) - if (!isEmptyObject(query)) { - return chalk.white( - newline + '๐Ÿ—’ Custom' + newline + JSON.stringify(query, null, 2) - ) - } - - return - } - - const formatData = (data: any) => { - if (!isEmptyObject(data)) { - return chalk.white( - newline + '๐Ÿ“ฆ Result Data' + newline + JSON.stringify(data, null, 2) - ) - } - - return - } - - const formatDate = (instant: Date) => { - const date = new Date(instant) - const hours = date.getHours().toString().padStart(2, '0') - const minutes = date.getMinutes().toString().padStart(2, '0') - const seconds = date.getSeconds().toString().padStart(2, '0') - const prettyDate = hours + ':' + minutes + ':' + seconds - return chalk.gray(prettyDate) - } - - const formatErrorProp = (errorPropValue: any) => { - const errorType = errorPropValue['type'] || 'Error' - - delete errorPropValue['message'] - delete errorPropValue['stack'] - delete errorPropValue['type'] - - return chalk.redBright( - newline + - newline + - `๐Ÿšจ ${errorType} Info` + - newline + - newline + - JSON.stringify(errorPropValue, null, 2) + - newline - ) - } - - const formatLevel = (level: any) => { - const emoji = emojiLog[level] - const padding = isWideEmoji(emoji) ? '' : ' ' - return emoji + padding - } - - const formatLoadTime = (elapsedTime: any) => { - const elapsed = parseInt(elapsedTime, 10) - const time = prettyMs(elapsed) - return chalk.gray(time) - } - - const formatMessage = (logData: any) => { - const { level, message } = logData - - const msg = formatMessageName(message) - let pretty - if (level === 'error') { - pretty = chalk.red(msg) - } - if (level === 'trace') { - pretty = chalk.white(msg) - } - if (level === 'warn') { - pretty = chalk.magenta(msg) - } - if (level === 'debug') { - pretty = chalk.yellow(msg) - } - if (level === 'info' || level === 'customlevel') { - pretty = chalk.green(msg) - } - if (level === 'fatal') { - pretty = chalk.white.bgRed(msg) - } - return pretty - } - - const formatMethod = (method: any) => { - return chalk.white(method) - } - - const formatRequestId = (requestId: any) => { - return requestId && chalk.cyan(requestId) - } - - const formatNs = (ns: any) => { - return chalk.cyan(ns) - } - - const formatName = (name: any) => { - return chalk.blue(name) - } - - const formatMessageName = (message: any) => { - if (message === 'request') { - return '<--' - } - if (message === 'response') { - return '-->' - } - return message - } - - const formatOperationName = (operationName: any) => { - return chalk.white(newline + '๐Ÿท ' + operationName) - } - - const formatQuery = (query: any) => { - if (!isEmptyObject(query)) { - return chalk.white( - newline + '๐Ÿ”ญ Query' + newline + JSON.stringify(query, null, 2) - ) - } - - return - } - - const formatResponseCache = (responseCache: any) => { - if (!isEmptyObject(responseCache)) { - return chalk.white( - newline + - '๐Ÿ’พ Response Cache' + - newline + - JSON.stringify(responseCache, null, 2) - ) - } - - return - } - - const formatStatusCode = (statusCode: any) => { - statusCode = statusCode || 'xxx' - return chalk.white(statusCode) - } - - const formatStack = (stack: any) => { - return chalk.redBright( - stack - ? newline + '๐Ÿฅž Error Stack' + newline + newline + stack + newline - : '' - ) - } - - const formatTracing = (data: any) => { - if (!isEmptyObject(data)) { - return chalk.white( - newline + 'โฐ Timing' + newline + JSON.stringify(data, null, 2) - ) - } - - return - } - - const formatUrl = (url: any) => { - return chalk.white(url) - } - - const formatUserAgent = (userAgent: any) => { - return chalk.grey(newline + '๐Ÿ•ต๏ธโ€โ™€๏ธ ' + userAgent) - } - - const noEmpty = (value: any) => { - return !!value - } - return parse } From d338f01b854ac21c59cac815d08872d67fd08595 Mon Sep 17 00:00:00 2001 From: David Thyresson Date: Tue, 11 Apr 2023 11:44:58 -0400 Subject: [PATCH 3/3] Update packages/api-server/src/__tests__/logFormatter.test.ts Co-authored-by: Tobbe Lundberg --- packages/api-server/src/__tests__/logFormatter.test.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/api-server/src/__tests__/logFormatter.test.ts b/packages/api-server/src/__tests__/logFormatter.test.ts index b3ef1bdb43e5..7dea1a00730e 100644 --- a/packages/api-server/src/__tests__/logFormatter.test.ts +++ b/packages/api-server/src/__tests__/logFormatter.test.ts @@ -98,16 +98,6 @@ describe('LogFormatter', () => { }) }) - // describe('Unknown log data', () => { - // it('Should not include an unknown log data attribute', () => { - // expect( - // logFormatter({ - // level: 10, - // unknown: 'I should not see this', - // }) - // ).not.toMatch('I should not see this') - // }) - // }) describe('Custom log data', () => { it('Should include the custom log attribute text', () => {