From ba9f95bc9de3d693829de374c03af0996cc6b107 Mon Sep 17 00:00:00 2001 From: Thierry DEGREMONT Date: Tue, 23 Jul 2024 11:45:29 +0200 Subject: [PATCH] add prom client and logger fix --- package-lock.json | 10 +- package.json | 7 +- .../custom-plugins/monitor-envelop.ts | 4 +- .../custom-plugins/monitor-yoga.ts | 10 +- packages/graphql-mesh/package-lock.json | 7 +- packages/graphql-mesh/package.json | 1 + packages/graphql-mesh/utils/logger.ts | 107 +++++++++--------- 7 files changed, 75 insertions(+), 71 deletions(-) diff --git a/package-lock.json b/package-lock.json index cb2404d..aa2d0ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,9 @@ "": { "name": "graphql-mesh", "hasInstallScript": true, + "dependencies": { + "prom-client": "^15.1.3" + }, "devDependencies": { "concurrently": "^8.2.2", "patch-package": "^8.0.0" @@ -1066,7 +1069,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -1714,8 +1716,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -3299,7 +3300,6 @@ "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.3.tgz", "integrity": "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/api": "^1.4.0", "tdigest": "^0.1.1" @@ -3730,7 +3730,6 @@ "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", "license": "MIT", - "peer": true, "dependencies": { "bintrees": "1.0.2" } @@ -4323,6 +4322,7 @@ "monitor-fetch": "file:./custom-plugins/monitor-fetch.ts", "monitor-yoga": "file:./custom-plugins/monitor-yoga.ts", "patch-package": "^8.0.0", + "prom-client": "^15.1.3", "sucrase": "^3.35.0" }, "devDependencies": { diff --git a/package.json b/package.json index e336a64..1418a8b 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build:local:packages": "concurrently \"npm run pack -w directive-spl\" \"npm run pack -w inject-additional-transforms\"", "preinstall": "npm run build:local:packages", "start": "npm start -w graphql-mesh", - "startmesh": "npm run startmesh -w graphql-mesh" + "startmesh": "npm run startmesh -w graphql-mesh" }, "devDependencies": { "concurrently": "^8.2.2", @@ -21,5 +21,8 @@ "engines": { "node": "18" }, - "packageManager": "npm@9.5.1" + "packageManager": "npm@9.5.1", + "dependencies": { + "prom-client": "^15.1.3" + } } diff --git a/packages/graphql-mesh/custom-plugins/monitor-envelop.ts b/packages/graphql-mesh/custom-plugins/monitor-envelop.ts index fe74e9d..a113daf 100644 --- a/packages/graphql-mesh/custom-plugins/monitor-envelop.ts +++ b/packages/graphql-mesh/custom-plugins/monitor-envelop.ts @@ -21,9 +21,9 @@ const formatter = (error: GraphQLError, mask: string): GraphQLError => { export default ({ options }): Plugin => { // not allow by default // do not enabled enabledIntrospection in production - const enabledIntrospection = process.env['IS_PROUCTION_ENV'] != 'true' && ( options.enabledIntrospection || process.env['ENABLED_INTROSPECTION'] || false ) + const enabledIntrospection = process.env['IS_PROUCTION_ENV'] != 'true' && ( options?.enabledIntrospection || process.env['ENABLED_INTROSPECTION'] || false ) // low info in log by default - const resultLogInfoLevel= options.resultLogInfoLevel ? options.resultLogInfoLevel : "low" + const resultLogInfoLevel= options?.resultLogInfoLevel ? options.resultLogInfoLevel : "low" return { onParse({ params, context }) { diff --git a/packages/graphql-mesh/custom-plugins/monitor-yoga.ts b/packages/graphql-mesh/custom-plugins/monitor-yoga.ts index 2496f66..28fcc8e 100644 --- a/packages/graphql-mesh/custom-plugins/monitor-yoga.ts +++ b/packages/graphql-mesh/custom-plugins/monitor-yoga.ts @@ -13,13 +13,13 @@ import { GraphQLError } from 'graphql' * - remove a eventualy not allowed instropection data in result */ export function useYagaMonitoring({ options }): Plugin { - const isMaskErrors = options.maskError?.enabled || process.env['MASK_ERRORS'] || false + const isMaskErrors = options?.maskError?.enabled || process.env['MASK_ERRORS'] || false // filter in production anyway - const isFilterError = options.filterError?.enabled || process.env['FILTER_ERRORS'] == 'true' || process.env['IS_PROUCTION_ENV'] == 'true' || false + const isFilterError = options?.filterError?.enabled || process.env['FILTER_ERRORS'] == 'true' || process.env['IS_PROUCTION_ENV'] == 'true' || false - const errorMaskMessage = options.maskError?.message ? options.maskError.message : "something goes wrong" - const reponseLogInfoLevel = options.reponseLogInfoLevel ? options.reponseLogInfoLevel : "low" - const resultLogInfoLevel = options.resultLogInfoLevel ? options.resultLogInfoLevel : "low" + const errorMaskMessage = options?.maskError?.message ? options.maskError.message : "something goes wrong" + const reponseLogInfoLevel = options?.reponseLogInfoLevel ? options.reponseLogInfoLevel : "low" + const resultLogInfoLevel = options?.resultLogInfoLevel ? options.resultLogInfoLevel : "low" return { diff --git a/packages/graphql-mesh/package-lock.json b/packages/graphql-mesh/package-lock.json index 1a34eda..7d72698 100644 --- a/packages/graphql-mesh/package-lock.json +++ b/packages/graphql-mesh/package-lock.json @@ -27,6 +27,7 @@ "monitor-fetch": "file:./custom-plugins/monitor-fetch.ts", "monitor-yoga": "file:./custom-plugins/monitor-yoga.ts", "patch-package": "^8.0.0", + "prom-client": "^15.1.3", "sucrase": "^3.35.0" }, "devDependencies": { @@ -2753,7 +2754,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -3117,8 +3117,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/brace-expansion": { "version": "2.0.1", @@ -5829,7 +5828,6 @@ "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.3.tgz", "integrity": "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/api": "^1.4.0", "tdigest": "^0.1.1" @@ -6409,7 +6407,6 @@ "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", "license": "MIT", - "peer": true, "dependencies": { "bintrees": "1.0.2" } diff --git a/packages/graphql-mesh/package.json b/packages/graphql-mesh/package.json index f7579ef..fd8031a 100644 --- a/packages/graphql-mesh/package.json +++ b/packages/graphql-mesh/package.json @@ -22,6 +22,7 @@ "@graphql-mesh/transform-type-merging": "^0.96.2", "@graphql-tools/schema": "^10.0.2", "@graphql-tools/utils": "^10.0.12", + "prom-client": "^15.1.3", "directive-spl": "file:./local-pkg/directive-spl-1.0.0.tgz", "monitor-envelop": "file:./custom-plugins/monitor-envelop.ts", "monitor-fetch": "file:./custom-plugins/monitor-fetch.ts", diff --git a/packages/graphql-mesh/utils/logger.ts b/packages/graphql-mesh/utils/logger.ts index c0dc067..b14144c 100644 --- a/packages/graphql-mesh/utils/logger.ts +++ b/packages/graphql-mesh/utils/logger.ts @@ -13,16 +13,16 @@ export class Logger { private static maxSkackLogSize = process.env["LogStackTraceMaxSize"] ? parseInt(process.env["LogStackTraceMaxSize"]) : 100 private static trackerOnly: boolean = process.env["LogTrackerHeadersOnly"] ? process.env["LogTrackerHeadersOnly"] == 'true' : false private static envLog: string = process.env["LogEnvFieldToAdd"] // use to add env extra field in json log ex "app=graphql,env.name=production,env.site=Paris" - private static localDateCountry: string = process.env["LogLocalDateCountry"] - private static logHeaders = process.env["LogHeaders"] || "host,origin,user-agent,content-length" - private static logTrackerHeaders = process.env["LogTrackerHeaders"] + private static localDateCountry: string = process.env["LogLocalDateCountry"] || "fr-FR" + private static logHeaders = process.env["LogHeaders"] || "x-request-id,host,origin,user-agent,content-length,authorization" + private static logTrackerHeaders = process.env["LogTrackerHeaders"] || "x-request-id" constructor() { } /** * Core logger with Human format or machine one line json string format */ - private static log(level: string, typeEv: string, message: string, data: any = null) { + private static log(level: string, typeEv: string, message: string, data: any = null, err = null) { const date = new Date(); const timestamp = date.getTime(); @@ -39,35 +39,42 @@ export class Logger { if (data) { log['data'] = data } + if (err) { + log['exeception'] = {} + for (const key in Object.keys(err)) { + log['exeception'][key] = err[key] + + } + } // if define add extra env field if (this.envLog) { addEnvFieldLog(this.envLog, log) } console.log(JSON.stringify(log)) } else { - console.log(date.toLocaleString(this.localDateCountry), level, typeEv, message, data) + console.log(date.toLocaleString(this.localDateCountry), level, typeEv, message, data, err) } } - public static error(typeEv: string, source: string, message: string, data: any = null) { + public static error(typeEv: string, source: string, message: string, data: any = null, e = null) { if (Logger.level == 'ERROR' || Logger.level == 'WARN' || Logger.level == 'INFO' || Logger.level == 'DEBUG') { - Logger.log('ERROR', typeEv, source + ":" + message, data) + Logger.log('ERROR', typeEv, source + ":" + message, data, e) } } - public static warn(typeEv: string, source: string, message: string, data: any = null) { + public static warn(typeEv: string, source: string, message: string, data: any = null, e = null) { if (Logger.level == 'WARN' || Logger.level == 'INFO' || Logger.level == 'DEBUG') { - Logger.log('INFO', typeEv, source + ":" + message, data) + Logger.log('INFO', typeEv, source + ":" + message, data, e) } } - public static info(typeEv: string, source: string, message: string, data: any = null) { + public static info(typeEv: string, source: string, message: string, data: any = null, e = null) { if (Logger.level == 'INFO' || Logger.level == 'DEBUG') { - Logger.log('INFO', typeEv, source + ":" + message, data) + Logger.log('INFO', typeEv, source + ":" + message, data, e) } } - public static debug(typeEv: string, source: string, message: string, data: any = null) { + public static debug(typeEv: string, source: string, message: string, data: any = null, e = null) { if (Logger.level == 'DEBUG') { - Logger.log('DEBUG', typeEv, source + ":" + message, data) + Logger.log('DEBUG', typeEv, source + ":" + message, data, e) } } public static onParse(headers: any) { @@ -77,7 +84,7 @@ export class Logger { Logger.log('INFO', "ON-PARSE", "Request", headersToLog(headers, this.logTrackerHeaders, this.logHeaders, this.trackerOnly)) } catch (e) { - Logger.error('LOGGER_ERROR', 'endExec logger', 'error during log generation', e) + Logger.error('LOGGER_ERROR', 'endExec logger', 'error during log generation', null, e) } } @@ -95,7 +102,7 @@ export class Logger { } Logger.log('INFO', "endExecDone", "Request", toLog) } catch (e) { - Logger.error('LOGGER_ERROR', 'endExec logger', 'error during log generation', e) + Logger.error('LOGGER_ERROR', 'endExec logger', 'error during log generation', null, e) } } @@ -115,7 +122,7 @@ export class Logger { Logger.log('INFO', "onResultProcess", "Result", toLog) } catch (e) { - Logger.error('LOGGER_ERROR', 'onResponse logger', 'error during log generation', e) + Logger.error('LOGGER_ERROR', 'onResponse logger', 'error during log generation', null, e) } } @@ -162,7 +169,7 @@ export class Logger { Logger.log('INFO', "onResponse", "response", toLog) } catch (e) { - Logger.error('LOGGER_ERROR', 'onResponse logger', 'error during log generation', e) + Logger.error('LOGGER_ERROR', 'onResponse logger', 'error during log generation', null, e) } } @@ -182,8 +189,7 @@ export class Logger { } catch (e) { - console.log("erreur", e) - Logger.error('LOGGER_ERROR', 'onRequest logger', 'error during log generation', e) + Logger.error('LOGGER_ERROR', 'onRequest logger', 'error during log generation', null, e) } } @@ -199,7 +205,7 @@ export class Logger { } Logger.log('INFO', "onFetch", "fetch", toLog) } catch (e) { - Logger.error('LOGGER_ERROR', 'onFetch logger', 'error during log generation', e) + Logger.error('LOGGER_ERROR', 'onFetch logger', 'error during log generation', null, e) } } @@ -214,7 +220,7 @@ export class Logger { } Logger.log('INFO', "graphqlQuery", "GraphQL Query", queryTolog) } catch (e) { - Logger.error('LOGGER_ERROR', 'graphql query logger', 'error during log generation', e) + Logger.error('LOGGER_ERROR', 'graphql query logger', 'error during log generation', null, e) } } } @@ -289,49 +295,46 @@ function extractBody(body: String, bodyMaxLogSize: number) { } } function headersToLog(headers: any, trackerHeaders: string, customHeaders: string, trackerOnly: boolean) { + const headersToLog = {} try { const headerMap = headers["_map"] - - if (trackerOnly == false) { - const headersToLog = { - - } - if (customHeaders) { - const cHeaders = customHeaders.split(',') - - for (const headerKey in cHeaders) { - const header = cHeaders[headerKey].trim() - if (headerMap.get(header)) { - if (header.toLowerCase() == "authorization") { - mask(headerMap.get('authorization')) - } else { - headersToLog[header] = headerMap.get(header) + if (headerMap) { + if (trackerOnly == false) { + if (customHeaders) { + const cHeaders = customHeaders.split(',') + + for (const headerKey in cHeaders) { + const header = cHeaders[headerKey].trim() + if (headerMap.get(header)) { + if (header.toLowerCase() == "authorization") { + headersToLog[header] = mask(headerMap.get('authorization')) + } else { + headersToLog[header] = headerMap.get(header) + } } } } - } - return headersToLog - } else { - const headersToLog = {} - if (trackerHeaders) { - const tHeaders = trackerHeaders.split(',') - for (const headerKey in tHeaders) { - const header = tHeaders[headerKey] - if (headerMap.get(header)) { - if (header.toLowerCase() == "authorization") { - mask(headerMap.get('authorization')) - } else { - headersToLog[header] = headerMap.get(header) + return headersToLog + } else { + if (trackerHeaders) { + const tHeaders = trackerHeaders.split(',') + for (const headerKey in tHeaders) { + const header = tHeaders[headerKey] + if (headerMap.get(header)) { + if (header.toLowerCase() == "authorization") { + headersToLog[header] = mask(headerMap.get('authorization')) + } else { + headersToLog[header] = headerMap.get(header) + } } } } } - - return headersToLog } } catch (e) { - Logger.error('LOGGER_ERROR', 'oheadersToLog', 'error during headers log generation', e) + Logger.error('LOGGER_ERROR', 'onheadersToLog', 'error during headers log generation', null, e) } + return headersToLog } /** * Use to add some environment fields to log, like env.name, app.name ...