diff --git a/.github/workflows/autour-handler.yml b/.github/workflows/autour-handler.yml index d23e31c06..c4d241e5d 100644 --- a/.github/workflows/autour-handler.yml +++ b/.github/workflows/autour-handler.yml @@ -29,6 +29,9 @@ jobs: - name: Copy schemas working-directory: ./handlers/autour-handler run: cp -R ../../schemas src/ + - name: Copy config + working-directory: ./handlers/autour-handler + run: cp -R ../../config src/ - name: Install dependencies working-directory: ./handlers/autour-handler run: npm ci diff --git a/.github/workflows/high-charts-handler.yml b/.github/workflows/high-charts-handler.yml index 3ff3c8f4f..d9cbff548 100644 --- a/.github/workflows/high-charts-handler.yml +++ b/.github/workflows/high-charts-handler.yml @@ -29,6 +29,9 @@ jobs: - name: Copy schemas working-directory: ./handlers/high-charts run: cp -R ../../schemas src/ + - name: Copy config + working-directory: ./handlers/high-charts + run: cp -R ../../config src/ - name: Install dependencies working-directory: ./handlers/high-charts run: npm ci diff --git a/.github/workflows/motd.yml b/.github/workflows/motd.yml index f5914b10d..9a6a7f3fa 100644 --- a/.github/workflows/motd.yml +++ b/.github/workflows/motd.yml @@ -29,6 +29,9 @@ jobs: - name: Copy schemas working-directory: ./handlers/motd run: cp -R ../../schemas src/ + - name: Copy config + working-directory: ./handlers/motd + run: cp -R ../../config src/ - name: Install dependencies working-directory: ./handlers/motd run: npm ci diff --git a/.github/workflows/nominatim-preprocessor.yml b/.github/workflows/nominatim-preprocessor.yml index a7ffaa23b..f071c334d 100644 --- a/.github/workflows/nominatim-preprocessor.yml +++ b/.github/workflows/nominatim-preprocessor.yml @@ -29,6 +29,9 @@ jobs: - name: Copy schemas working-directory: ./preprocessors/nominatim run: cp -R ../../schemas src/ + - name: Copy config + working-directory: ./preprocessors/nominatim + run: cp -R ../../config src/ - name: Install dependencies working-directory: ./preprocessors/nominatim run: npm ci diff --git a/.github/workflows/osm-streets-handler.yml b/.github/workflows/osm-streets-handler.yml index efa97f6e0..fce70bc3d 100644 --- a/.github/workflows/osm-streets-handler.yml +++ b/.github/workflows/osm-streets-handler.yml @@ -29,6 +29,9 @@ jobs: - name: Copy schemas working-directory: ./handlers/osm-streets-handler run: cp -R ../../schemas src/ + - name: Copy config + working-directory: ./handlers/osm-streets-handler + run: cp -R ../../config src/ - name: Install dependencies working-directory: ./handlers/osm-streets-handler run: npm ci diff --git a/.github/workflows/photo-audio-handler.yml b/.github/workflows/photo-audio-handler.yml index 610b6284b..46c3cfb86 100644 --- a/.github/workflows/photo-audio-handler.yml +++ b/.github/workflows/photo-audio-handler.yml @@ -29,6 +29,9 @@ jobs: - name: Copy schemas working-directory: ./handlers/photo-audio-handler run: cp -R ../../schemas src/ + - name: Copy config + working-directory: ./handlers/photo-audio-handler + run: cp -R ../../config src/ - name: Install dependencies working-directory: ./handlers/photo-audio-handler run: npm ci diff --git a/.github/workflows/photo-audio-haptics-handler.yml b/.github/workflows/photo-audio-haptics-handler.yml index 193eed121..be51691ea 100644 --- a/.github/workflows/photo-audio-haptics-handler.yml +++ b/.github/workflows/photo-audio-haptics-handler.yml @@ -29,6 +29,9 @@ jobs: - name: Copy schemas working-directory: ./handlers/photo-audio-haptics-handler run: cp -R ../../schemas src/ + - name: Copy config + working-directory: ./handlers/photo-audio-haptics-handler + run: cp -R ../../config src/ - name: Install dependencies working-directory: ./handlers/photo-audio-haptics-handler run: npm ci diff --git a/build.yml b/build.yml index 0cefe8c96..7e42697ee 100644 --- a/build.yml +++ b/build.yml @@ -96,11 +96,6 @@ services: context: . dockerfile: ./preprocessors/graphic-caption/Dockerfile image: "graphic-caption:latest" - text-followup: - build: - context: . - dockerfile: ./preprocessors/text-followup/Dockerfile - image: "text-followup:latest" emotion-recognition: build: context: . @@ -268,11 +263,6 @@ services: context: . dockerfile: ./handlers/svg-action-recognition/Dockerfile image: "svg-action-recognition:latest" - text-followup-handler: - build: - context: . - dockerfile: ./handlers/text-followup-handler/Dockerfile - image: "text-followup-handler:latest" # Supercollider on Fedora 34 supercollider-base: build: diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 000000000..b34fa9b44 --- /dev/null +++ b/config/__init__.py @@ -0,0 +1,2 @@ +# /app/config/__init__.py +# This file marks the config directory as a Python package. diff --git a/config/logging_utils.py b/config/logging_utils.py new file mode 100644 index 000000000..7db1ee119 --- /dev/null +++ b/config/logging_utils.py @@ -0,0 +1,34 @@ +import logging +import os + +# Define a PII log level +PII_LOG_LEVEL = 5 +logging.addLevelName(PII_LOG_LEVEL, "PII") + + +def pii(self, message, *args, **kwargs): + if self.isEnabledFor(PII_LOG_LEVEL): + self._log(PII_LOG_LEVEL, message, args, **kwargs) + + +logging.Logger.pii = pii +logging.pii = lambda msg, *args, **kwargs: logging.log( + PII_LOG_LEVEL, msg, *args, **kwargs) + + +def configure_logging(): + """ + Configures logging based on environment variables. + """ + log_level = os.getenv("LOG_LEVEL", "INFO").upper() + pii_logging_enabled = os.getenv("PII_LOGGING_ENABLED", + "false").lower() == "true" + + level = getattr(logging, log_level, logging.INFO) + logging.basicConfig(level=level) + + if pii_logging_enabled: + logging.warning("Environment Unicorn: PII logging enabled!") + logging.getLogger().setLevel(PII_LOG_LEVEL) # Lower log level to PII + else: + logging.info("Environment Pegasus: PII logging is disabled.") diff --git a/config/logging_utils.ts b/config/logging_utils.ts new file mode 100644 index 000000000..a2df645e0 --- /dev/null +++ b/config/logging_utils.ts @@ -0,0 +1,47 @@ +// https://medium.com/@jaiprajapati3/masking-of-sensitive-data-in-logs-700850e233f5 +// https://github.com/winstonjs/winston/blob/c69cdb0cec15a138e0b6e374501e027d1c39606c/index.d.ts + +import winston, { LogMethod, LogEntry } from 'winston'; +const logger = winston.createLogger({ + level: 'info', + format: winston.format.json(), + transports: [ + new winston.transports.Console({ + format: winston.format.simple(), + }), + ], +}); + +interface PIILogger extends LogMethod { + pii: (message: string) => void; +} + +const piiLoggingEnabled = process.env.PII_LOGGING_ENABLED === 'true'; + +if (piiLoggingEnabled) { + logger.warn("Environment Unicorn: PII logging enabled!"); +} else { + logger.info("Environment Pegasus: PII logging is disabled."); +} + +// PII Logger Function +const piiLogger: PIILogger = ((arg1: string | LogEntry, arg2?: any) => { + if (typeof arg1 === 'string' && arg2 !== undefined) { // log when both level and message are provided + logger.log(arg1, arg2); + } else if (typeof arg1 === 'object') { // log when an object is provided + logger.log(arg1); + } else { + throw new Error('Invalid log format'); + } +}) as PIILogger; + +// Function for logging PII-related errors +piiLogger.pii = (message: string) => { + if (piiLoggingEnabled) { + logger.error(`[PII] ${message}`); + } else { + logger.warn("PII logging attempted but is DISABLED."); + } +}; + +export { piiLogger }; diff --git a/docker-compose.yml b/docker-compose.yml index 755251133..2dd461dc5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -104,17 +104,6 @@ services: env_file: ./config/ollama.env - text-followup: - profiles: [test, default] - image: ghcr.io/shared-reality-lab/image-preprocessor-text-followup:${REGISTRY_TAG} - restart: unless-stopped - labels: - ca.mcgill.a11y.image.preprocessor: 1 - ca.mcgill.a11y.image.port: 5000 - ca.mcgill.a11y.image.cacheTimeout: 0 - ca.mcgill.a11y.image.route: "followup" - env_file: - ./config/ollama.env graphic-tagger: profiles: [production, test, default] @@ -302,14 +291,6 @@ services: labels: ca.mcgill.a11y.image.handler: enable - text-followup-handler: - profiles: [test, default] - image: ghcr.io/shared-reality-lab/image-handler-text-followup:${REGISTRY_TAG} - restart: unless-stopped - labels: - ca.mcgill.a11y.image.handler: enable - ca.mcgill.a11y.image.route: "followup" - # end - common services # start - unicorn exclusive services diff --git a/handlers/autour-handler/Dockerfile b/handlers/autour-handler/Dockerfile index b266f47bc..2bbe1ec10 100644 --- a/handlers/autour-handler/Dockerfile +++ b/handlers/autour-handler/Dockerfile @@ -1,4 +1,4 @@ -FROM node:alpine as builder +FROM node:alpine AS builder RUN addgroup -g 4322 storage && addgroup node storage @@ -9,9 +9,10 @@ RUN npm ci COPY /handlers/autour-handler/src ./src COPY /handlers/autour-handler/types ./types COPY /schemas src/schemas +COPY /config ./src/config RUN npm run build && npm prune --production -FROM node:alpine as final +FROM node:alpine AS final RUN apk add --no-cache curl diff --git a/handlers/autour-handler/package-lock.json b/handlers/autour-handler/package-lock.json index d99989ac5..ee727e095 100644 --- a/handlers/autour-handler/package-lock.json +++ b/handlers/autour-handler/package-lock.json @@ -14,7 +14,8 @@ "geodesy": "^1.1.3", "osc": "^2.4.1", "pluralize": "^8.0.0", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.12", @@ -170,6 +171,24 @@ "node": ">=4" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -582,6 +601,11 @@ "@types/node": "*" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -887,6 +911,11 @@ "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1024,6 +1053,15 @@ "node": ">=0.10" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1039,8 +1077,38 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -1195,6 +1263,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1680,6 +1753,11 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1753,6 +1831,11 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2053,6 +2136,11 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2089,6 +2177,17 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2172,6 +2271,11 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2203,6 +2307,22 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -2351,8 +2471,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "devOptional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/mz": { "version": "2.7.0", @@ -2439,6 +2558,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -2648,6 +2775,19 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -2744,6 +2884,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2906,6 +3054,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -2952,6 +3108,14 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2960,6 +3124,14 @@ "node": ">= 0.8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3035,6 +3207,11 @@ "node": ">=8" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -3092,6 +3269,14 @@ "node": ">=0.6" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -3184,6 +3369,11 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -3229,6 +3419,40 @@ "node": ">= 8" } }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/wolfy87-eventemitter": { "version": "5.2.9", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz", @@ -3387,6 +3611,21 @@ } } }, + "@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==" + }, + "@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -3703,6 +3942,11 @@ "@types/node": "*" } }, + "@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -3894,6 +4138,11 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, + "async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4005,6 +4254,30 @@ "timers-ext": "^0.1.7" } }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4017,8 +4290,25 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "concat-map": { "version": "0.0.1", @@ -4134,6 +4424,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -4539,6 +4834,11 @@ "reusify": "^1.0.4" } }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4602,6 +4902,11 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -4809,6 +5114,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4836,6 +5146,11 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4907,6 +5222,11 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4935,6 +5255,19 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "requires": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -5047,8 +5380,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "devOptional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "mz": { "version": "2.7.0", @@ -5118,6 +5450,14 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -5254,6 +5594,16 @@ "unpipe": "1.0.0" } }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -5300,6 +5650,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5433,6 +5788,14 @@ "object-inspect": "^1.13.1" } }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -5469,11 +5832,24 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -5530,6 +5906,11 @@ } } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5578,6 +5959,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==" + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -5642,6 +6028,11 @@ "punycode": "^2.1.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -5672,6 +6063,34 @@ "isexe": "^2.0.0" } }, + "winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "requires": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + } + }, + "winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "requires": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + } + }, "wolfy87-eventemitter": { "version": "5.2.9", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz", diff --git a/handlers/autour-handler/package.json b/handlers/autour-handler/package.json index 8ba91685f..16e55677f 100644 --- a/handlers/autour-handler/package.json +++ b/handlers/autour-handler/package.json @@ -16,7 +16,8 @@ "geodesy": "^1.1.3", "osc": "^2.4.1", "pluralize": "^8.0.0", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.12", diff --git a/handlers/autour-handler/src/server.ts b/handlers/autour-handler/src/server.ts index ae3b86dc0..0996a3701 100644 --- a/handlers/autour-handler/src/server.ts +++ b/handlers/autour-handler/src/server.ts @@ -4,6 +4,7 @@ import fs from "fs/promises"; import osc from "osc"; import { v4 as uuidv4 } from "uuid"; import { LatLonVectors as LatLon } from "geodesy"; +import { piiLogger } from "./config/logging_utils"; // JSON imports import querySchemaJSON from "./schemas/request.schema.json"; @@ -32,6 +33,7 @@ app.post("/handler", async (req, res) => { // Check for good data if (!ajv.validate("https://image.a11y.mcgill.ca/request.schema.json", req.body)) { console.warn("Request did not pass the schema!"); + piiLogger.pii(`Validation error: ${JSON.stringify(ajv.errors)}`); res.status(400).json(ajv.errors); return; } @@ -48,7 +50,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid empty response!"); - console.error(ajv.errors); + piiLogger.pii(`Validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } return; @@ -66,7 +68,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid empty response!"); - console.error(ajv.errors); + piiLogger.pii(`Validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } return; @@ -83,7 +85,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid empty response!"); - console.error(ajv.errors); + piiLogger.pii(`Validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } return; @@ -161,8 +163,8 @@ app.post("/handler", async (req, res) => { } } catch (e) { - console.error(e); console.debug(`Cannot translate to ${targetLanguage}`); + piiLogger.pii(`Translation error: ${e}`); res.status(500).json({ "Error": "Cannot translate to target language", "Attempted target": targetLanguage @@ -187,7 +189,8 @@ app.post("/handler", async (req, res) => { }); ttsResponse = ttsResponse as Record; } catch (e) { - console.error(e); + console.error("TTS request failed."); + piiLogger.pii(`TTS error: ${(e as Error).message}`); res.status(500).json({"error": (e as Error).message}); return; } @@ -247,6 +250,7 @@ app.post("/handler", async (req, res) => { resolve(outFile); } else if (arg[0] === "fail") { + piiLogger.pii(`OSC failure: ${JSON.stringify(oscMsg)}`); oscPort.close(); reject(oscMsg); } @@ -263,7 +267,8 @@ app.post("/handler", async (req, res) => { }); oscPort.open(); } catch (e) { - console.error(e); + console.error("OSC communication error"); + piiLogger.pii(`${(e as Error).message}`) oscPort.close(); reject(e); } @@ -296,12 +301,12 @@ app.post("/handler", async (req, res) => { }); // Verify match of simple audio if (!ajv.validate("https://image.a11y.mcgill.ca/renderers/simpleaudio.schema.json", renderings[renderings.length - 1]["data"])) { - console.error("Failed to validate data of simple renderer."); + piiLogger.pii(`Simple audio validation error: ${JSON.stringify(ajv.errors)}`); renderings.pop(); - throw ajv.errors; + throw new Error("Failed to validate data of simple renderer"); } }).catch(err => { - console.error(err); + piiLogger.pii(`Processing error: ${(err as Error).message}`); }).finally(() => { // Delete our files if they exist on the disk if (inFile !== undefined) { @@ -326,7 +331,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid response."); - console.error(ajv.errors); + piiLogger.pii(`Final response validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } }); diff --git a/handlers/hello-handler/Dockerfile b/handlers/hello-handler/Dockerfile index 681c718d2..fd359d319 100644 --- a/handlers/hello-handler/Dockerfile +++ b/handlers/hello-handler/Dockerfile @@ -11,6 +11,7 @@ RUN npm ci COPY /handlers/hello-handler/*.json ./ COPY /handlers/hello-handler/.eslintrc.js ./ COPY /schemas src/schemas +COPY /config ./src/config COPY /handlers/hello-handler/src ./src RUN npm run build diff --git a/handlers/hello-handler/src/server.ts b/handlers/hello-handler/src/server.ts index a1fdf630b..7b5c8a16f 100644 --- a/handlers/hello-handler/src/server.ts +++ b/handlers/hello-handler/src/server.ts @@ -17,6 +17,7 @@ import express from "express"; import sharp from "sharp"; import Ajv from "ajv"; +import { piiLogger } from "./config/logging_utils"; import querySchemaJSON from "./schemas/request.schema.json"; import handlerResponseSchemaJSON from "./schemas/handler-response.schema.json"; @@ -30,9 +31,15 @@ const ajv = new Ajv({ }); async function extractDimensions(dataUrl: string) { - const imageBuffer = Buffer.from(dataUrl.split(",")[1], "base64"); - const metadata = await sharp(imageBuffer).metadata(); - return [metadata.width as number, metadata.height as number]; + try { + const imageBuffer = Buffer.from(dataUrl.split(",")[1], "base64"); + const metadata = await sharp(imageBuffer).metadata(); + return [metadata.width as number, metadata.height as number]; + } + catch (error) { + piiLogger.pii(`Image processing error: ${(error as Error).message}`); + throw new Error("Failed to process image dimensions."); + } } function generateRendering(width: number, height: number) { @@ -53,6 +60,7 @@ app.use(express.json({ limit: process.env.MAX_BODY })); app.post("/handler", async (req, res) => { console.debug("Received request"); + if (ajv.validate("https://image.a11y.mcgill.ca/request.schema.json", req.body)) { console.log("Request validated"); if (!req.body.graphic) { @@ -70,6 +78,7 @@ app.post("/handler", async (req, res) => { rendering.push(r); } else { console.error("Failed to generate a valid text rendering!"); + piiLogger.pii(`Text rendering validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); return; } @@ -86,10 +95,12 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.log("Failed to generate a valid response (did the schema change?)"); + piiLogger.pii(`Response validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } } else { console.log("Request did not pass the schema."); + piiLogger.pii(`Schema validation error: ${JSON.stringify(ajv.errors)}`); res.status(400).send(ajv.errors); } }); diff --git a/handlers/hello-svg-handler/Dockerfile b/handlers/hello-svg-handler/Dockerfile index e73e6e56b..413e9f6ec 100644 --- a/handlers/hello-svg-handler/Dockerfile +++ b/handlers/hello-svg-handler/Dockerfile @@ -11,6 +11,7 @@ COPY /handlers/hello-svg-handler/requirements.txt /usr/src/app/requirements.txt RUN pip install -r requirements.txt COPY /schemas /usr/src/app/schemas +COPY /config /usr/src/app/config COPY /handlers/hello-svg-handler/ /usr/src/app EXPOSE 80 diff --git a/handlers/hello-svg-handler/hello_svg.py b/handlers/hello-svg-handler/hello_svg.py index 45c6d4bfe..50bede76f 100644 --- a/handlers/hello-svg-handler/hello_svg.py +++ b/handlers/hello-svg-handler/hello_svg.py @@ -22,6 +22,10 @@ import time import drawSvg as draw from datetime import datetime +from config.logging_utils import configure_logging + + +configure_logging() app = Flask(__name__) @@ -29,16 +33,21 @@ @app.route("/handler", methods=["POST"]) def handle(): - logging.debug("Received request") - # Load necessary schema files - with open("./schemas/definitions.json") as f: - definitions_schema = json.load(f) - with open("./schemas/request.schema.json") as f: - request_schema = json.load(f) - with open("./schemas/handler-response.schema.json") as f: - response_schema = json.load(f) - with open("./schemas/renderers/svglayers.schema.json") as f: - renderer_schema = json.load(f) + try: + logging.debug("Received request") + # Load necessary schema files + with open("./schemas/definitions.json") as f: + definitions_schema = json.load(f) + with open("./schemas/request.schema.json") as f: + request_schema = json.load(f) + with open("./schemas/handler-response.schema.json") as f: + response_schema = json.load(f) + with open("./schemas/renderers/svglayers.schema.json") as f: + renderer_schema = json.load(f) + except Exception as e: + logging.error("Error loading schema files") + logging.pii(f"Schema loading error: {e}") + return jsonify("Schema files could not be loaded"), 500 store = { definitions_schema["$id"]: definitions_schema, request_schema["$id"]: request_schema, @@ -56,7 +65,8 @@ def handle(): ) validator.validate(contents) except ValidationError as e: - logging.error(e) + logging.error("Validation error occurred") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid request received!"), 400 # Check for dimensions @@ -95,8 +105,8 @@ def handle(): ) validator.validate(data) except ValidationError as e: - logging.error(e) logging.error("Failed to validate the response renderer!") + logging.pii(f"Renderer validation error: {e.message}") return jsonify("Failed to validate the response renderer"), 500 response = { "request_uuid": contents["request_uuid"], @@ -110,8 +120,9 @@ def handle(): validator.validate(response) except ValidationError as e: logging.error("Failed to generate a valid response") - logging.error(e) + logging.pii(f"Response validation error: {e.message}") return jsonify("Failed to generate a valid response"), 500 + logging.debug("Sending response") return response diff --git a/handlers/high-charts/Dockerfile b/handlers/high-charts/Dockerfile index b93815754..e75d910e6 100644 --- a/handlers/high-charts/Dockerfile +++ b/handlers/high-charts/Dockerfile @@ -1,13 +1,20 @@ -FROM node:alpine as builder +FROM node:alpine AS builder RUN addgroup -g 4322 storage && addgroup node storage WORKDIR /usr/src/app -COPY /handlers/high-charts/ /usr/src/app -RUN npm ci + +COPY /handlers/high-charts/package*.json ./ + +COPY /config src/config/ + +RUN npm install + COPY /schemas src/schemas +COPY /handlers/high-charts/ /usr/src/app + RUN npm run build && npm prune --production -FROM node:alpine as final +FROM node:alpine AS final RUN apk add --no-cache curl diff --git a/handlers/high-charts/package-lock.json b/handlers/high-charts/package-lock.json index 5e30e9b0f..0dea46d5c 100644 --- a/handlers/high-charts/package-lock.json +++ b/handlers/high-charts/package-lock.json @@ -13,7 +13,8 @@ "articles": "^0.2.2", "express": "^4.19.2", "osc": "^2.4.2", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", @@ -33,6 +34,24 @@ "node": ">=0.10.0" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.0.tgz", @@ -399,6 +418,11 @@ "@types/node": "*" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -686,6 +710,11 @@ "resolved": "https://registry.npmjs.org/articles/-/articles-0.2.2.tgz", "integrity": "sha512-S3Y4MPp+LD/l0HHm/4yrr6MoXhUkKT98ZdsV2tkTuBNywqUXEtvJT+NBO3KTSQEttc5EOwEJe2Xw8cZ9TI5Hrw==" }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -801,6 +830,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -816,8 +854,38 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -956,6 +1024,11 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1335,6 +1408,11 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1408,6 +1486,11 @@ "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1676,6 +1759,11 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1706,6 +1794,17 @@ "node": ">=0.12.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1735,6 +1834,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1754,6 +1858,22 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -1859,8 +1979,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "devOptional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -1921,6 +2040,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -2101,6 +2228,19 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -2197,6 +2337,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2359,6 +2507,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -2373,6 +2529,14 @@ "resolved": "https://registry.npmjs.org/slip/-/slip-1.0.2.tgz", "integrity": "sha1-ukWpIwNNbPQbGieuvnEoKCyNVR8=" }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2381,6 +2545,14 @@ "node": ">= 0.8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -2417,6 +2589,11 @@ "node": ">=8" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2443,6 +2620,14 @@ "node": ">=0.6" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -2529,6 +2714,11 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2574,6 +2764,40 @@ "node": ">= 8" } }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/wolfy87-eventemitter": { "version": "5.2.9", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz", @@ -2619,6 +2843,21 @@ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true }, + "@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==" + }, + "@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@eslint/eslintrc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.0.tgz", @@ -2889,6 +3128,11 @@ "@types/node": "*" } }, + "@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -3060,6 +3304,11 @@ "resolved": "https://registry.npmjs.org/articles/-/articles-0.2.2.tgz", "integrity": "sha512-S3Y4MPp+LD/l0HHm/4yrr6MoXhUkKT98ZdsV2tkTuBNywqUXEtvJT+NBO3KTSQEttc5EOwEJe2Xw8cZ9TI5Hrw==" }, + "async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3152,6 +3401,30 @@ "supports-color": "^7.1.0" } }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3164,8 +3437,25 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "concat-map": { "version": "0.0.1", @@ -3265,6 +3555,11 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -3571,6 +3866,11 @@ "reusify": "^1.0.4" } }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3634,6 +3934,11 @@ "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3821,6 +4126,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3842,6 +4152,11 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3868,6 +4183,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3884,6 +4204,19 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "requires": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -3959,8 +4292,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "devOptional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "natural-compare": { "version": "1.4.0", @@ -4007,6 +4339,14 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -4126,6 +4466,16 @@ "unpipe": "1.0.0" } }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -4172,6 +4522,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4305,6 +4660,14 @@ "object-inspect": "^1.13.1" } }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4316,11 +4679,24 @@ "resolved": "https://registry.npmjs.org/slip/-/slip-1.0.2.tgz", "integrity": "sha1-ukWpIwNNbPQbGieuvnEoKCyNVR8=" }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4345,6 +4721,11 @@ "has-flag": "^4.0.0" } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4365,6 +4746,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==" + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -4423,6 +4809,11 @@ "punycode": "^2.1.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -4453,6 +4844,34 @@ "isexe": "^2.0.0" } }, + "winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "requires": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + } + }, + "winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "requires": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + } + }, "wolfy87-eventemitter": { "version": "5.2.9", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz", diff --git a/handlers/high-charts/package.json b/handlers/high-charts/package.json index 9401748e4..202aa27e9 100644 --- a/handlers/high-charts/package.json +++ b/handlers/high-charts/package.json @@ -15,7 +15,8 @@ "articles": "^0.2.2", "express": "^4.19.2", "osc": "^2.4.2", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", diff --git a/handlers/high-charts/src/server.ts b/handlers/high-charts/src/server.ts index 33511c663..4a11ff5b1 100644 --- a/handlers/high-charts/src/server.ts +++ b/handlers/high-charts/src/server.ts @@ -18,6 +18,7 @@ import Ajv from "ajv"; import express from "express"; import fs from "fs/promises"; import { v4 as uuidv4 } from "uuid"; +import { piiLogger } from "./config/logging_utils"; import * as utils from "./utils"; @@ -45,6 +46,7 @@ app.post("/handler", async (req, res) => { // Validate the request data if (!ajv.validate("https://image.a11y.mcgill.ca/request.schema.json", req.body)) { console.warn("Request did not pass the schema!"); + piiLogger.pii(`Schema validation error: ${JSON.stringify(ajv.errors)}`); res.status(400).json(ajv.errors); return; } @@ -224,7 +226,8 @@ app.post("/handler", async (req, res) => { if (ajv.validate("https://image.a11y.mcgill.ca/renderers/simpleaudio.schema.json", rendering["data"])) { renderings.push(rendering); } else { - console.error(ajv.errors); + console.error("Validation error."); + piiLogger.pii(`Audio renderer validation error: ${JSON.stringify(ajv.errors)}`); } }).finally(() => { // Delete our files if they exist on the disk @@ -240,7 +243,7 @@ app.post("/handler", async (req, res) => { }); } catch(e) { console.error("Failed to generate audio!"); - console.error(e); + piiLogger.pii(`Audio generation error: ${(e as Error).message}`); } } } @@ -252,7 +255,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid response."); - console.error(ajv.errors); + piiLogger.pii(`Final response validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } }); diff --git a/handlers/high-charts/tsconfig.json b/handlers/high-charts/tsconfig.json index e5d8bce10..f4fbe36f0 100644 --- a/handlers/high-charts/tsconfig.json +++ b/handlers/high-charts/tsconfig.json @@ -72,6 +72,6 @@ }, "include": [ "src/**/*", - "types/**/*" + "types/**/*", ] } diff --git a/handlers/map-tactile-svg/Dockerfile b/handlers/map-tactile-svg/Dockerfile index 91f2e6f45..855486187 100644 --- a/handlers/map-tactile-svg/Dockerfile +++ b/handlers/map-tactile-svg/Dockerfile @@ -11,6 +11,7 @@ COPY /handlers/map-tactile-svg/requirements.txt /usr/src/app/requirements.txt RUN pip install -r requirements.txt COPY /schemas /usr/src/app/schemas +COPY /config /app/config COPY /handlers/map-tactile-svg/ /usr/src/app EXPOSE 80 diff --git a/handlers/map-tactile-svg/map-svg.py b/handlers/map-tactile-svg/map-svg.py index 2282d1c87..2b81b5ba4 100644 --- a/handlers/map-tactile-svg/map-svg.py +++ b/handlers/map-tactile-svg/map-svg.py @@ -22,6 +22,9 @@ import time import drawSvg as draw from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -29,16 +32,22 @@ @app.route("/handler", methods=["POST"]) def handle(): - logging.debug("Received request") - # Load necessary schema files - with open("./schemas/definitions.json") as f: - definitions_schema = json.load(f) - with open("./schemas/request.schema.json") as f: - request_schema = json.load(f) - with open("./schemas/handler-response.schema.json") as f: - response_schema = json.load(f) - with open("./schemas/renderers/tactilesvg.schema.json") as f: - renderer_schema = json.load(f) + try: + logging.debug("Received request") + # Load necessary schema files + with open("./schemas/definitions.json") as f: + definitions_schema = json.load(f) + with open("./schemas/request.schema.json") as f: + request_schema = json.load(f) + with open("./schemas/handler-response.schema.json") as f: + response_schema = json.load(f) + with open("./schemas/renderers/tactilesvg.schema.json") as f: + renderer_schema = json.load(f) + except Exception as e: + logging.error("Error loading schema files") + logging.pii(f"Schema loading error: {e}") + return jsonify("Schema files could not be loaded"), 500 + store = { definitions_schema["$id"]: definitions_schema, request_schema["$id"]: request_schema, @@ -56,7 +65,8 @@ def handle(): ) validator.validate(contents) except ValidationError as e: - logging.error(e) + logging.error("Validation error occurred") + logging.pii(f"Validation error: {e.message}") return jsonify("None"), 204 preprocessor = contents["preprocessors"] @@ -74,7 +84,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Missing " + "'ca.mcgill.a11y.image.renderer.TactileSVG'." + @@ -95,7 +106,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Missing " + "'ca.mcgill.a11y.image.preprocessor.openstreetmap'." + @@ -268,13 +280,13 @@ def handle(): + targetTag caption = "Map centered at " + targetTag except KeyError as e: - logging.debug("Missing key " + str(e) - + " in nominatim preprocessor") + logging.debug("Missing required key in nominatim preprocessor") + logging.pii(f"KeyError: {e}") logging.debug("Reverse geocode data not added to response") except (TypeError, ValueError) as e: - logging.debug("Did not obtain expected value as " - "POI name in nominatim") - logging.debug(str(e)) + logging.debug( + "Invalid value encountered in nominatim preprocessor") + logging.pii(f"Validation error: {e}") logging.debug("Reverse geocode data not added to response") # Drawing in the nodes of category @@ -313,8 +325,8 @@ def handle(): ) validator.validate(data) except ValidationError as e: - logging.error(e) logging.error("Failed to validate the response renderer!") + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to validate the response renderer"), 500 response = { "request_uuid": contents["request_uuid"], @@ -328,7 +340,7 @@ def handle(): validator.validate(response) except ValidationError as e: logging.error("Failed to generate a valid response") - logging.error(e) + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to generate a valid response"), 500 logging.debug("Sending response") return response diff --git a/handlers/motd/Dockerfile b/handlers/motd/Dockerfile index b39376e0e..926be029e 100644 --- a/handlers/motd/Dockerfile +++ b/handlers/motd/Dockerfile @@ -2,8 +2,10 @@ FROM node:alpine as builder WORKDIR /usr/src/app COPY /handlers/motd/ /usr/src/app +COPY /config src/config/ RUN npm ci COPY /schemas src/schemas + RUN npm run build && npm prune --production FROM node:alpine as final diff --git a/handlers/motd/package-lock.json b/handlers/motd/package-lock.json index dae698028..c2c5759e5 100644 --- a/handlers/motd/package-lock.json +++ b/handlers/motd/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "ajv": "^8.6.0", "express": "^4.19.2", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.12", @@ -133,6 +134,24 @@ "node": ">=4" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -321,6 +340,11 @@ "@types/node": "*" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -597,6 +621,11 @@ "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -712,6 +741,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -727,8 +765,38 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -873,6 +941,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1281,6 +1354,11 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1354,6 +1432,11 @@ "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1622,6 +1705,11 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1661,6 +1749,17 @@ "node": ">=0.12.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1697,6 +1796,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1722,6 +1826,22 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1822,8 +1942,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -1867,6 +1986,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -2042,6 +2169,19 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -2138,6 +2278,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2272,6 +2420,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -2304,6 +2460,14 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2312,6 +2476,14 @@ "node": ">= 0.8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2378,6 +2550,11 @@ "node": ">=10.0.0" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2404,6 +2581,14 @@ "node": ">=0.6" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -2490,6 +2675,11 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2535,6 +2725,40 @@ "node": ">= 8" } }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2639,6 +2863,21 @@ } } }, + "@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==" + }, + "@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -2807,6 +3046,11 @@ "@types/node": "*" } }, + "@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -2976,6 +3220,11 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, + "async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3068,6 +3317,30 @@ "supports-color": "^7.1.0" } }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3080,8 +3353,25 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "concat-map": { "version": "0.0.1", @@ -3187,6 +3477,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -3509,6 +3804,11 @@ "reusify": "^1.0.4" } }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3572,6 +3872,11 @@ "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3759,6 +4064,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3786,6 +4096,11 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3819,6 +4134,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3841,6 +4161,19 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "requires": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3911,8 +4244,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "natural-compare": { "version": "1.4.0", @@ -3947,6 +4279,14 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -4060,6 +4400,16 @@ "unpipe": "1.0.0" } }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -4106,6 +4456,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4217,6 +4572,14 @@ "object-inspect": "^1.13.1" } }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4240,11 +4603,24 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -4293,6 +4669,11 @@ "strip-ansi": "^6.0.1" } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4313,6 +4694,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==" + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -4371,6 +4757,11 @@ "punycode": "^2.1.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -4401,6 +4792,34 @@ "isexe": "^2.0.0" } }, + "winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "requires": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + } + }, + "winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "requires": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/handlers/motd/package.json b/handlers/motd/package.json index 25494d106..eb47f1246 100644 --- a/handlers/motd/package.json +++ b/handlers/motd/package.json @@ -12,7 +12,8 @@ "dependencies": { "ajv": "^8.6.0", "express": "^4.19.2", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.12", diff --git a/handlers/motd/src/server.ts b/handlers/motd/src/server.ts index 2489271cb..8e95c3f98 100644 --- a/handlers/motd/src/server.ts +++ b/handlers/motd/src/server.ts @@ -16,6 +16,7 @@ */ import express from "express"; import Ajv from "ajv"; +import { piiLogger } from "./config/logging_utils"; // JSON imports import querySchemaJSON from "./schemas/request.schema.json"; @@ -36,6 +37,7 @@ app.post("/handler", async (req, res) => { // Check for good data if (!ajv.validate("https://image.a11y.mcgill.ca/request.schema.json", req.body)) { console.warn("Request did not pass the schema!"); + piiLogger.pii(`Schema validation failed: ${JSON.stringify(ajv.errors)}`); res.status(400).json(ajv.errors); return; } @@ -51,7 +53,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid empty response!"); - console.error(ajv.errors); + piiLogger.pii(`Validation error in empty response: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } return; @@ -67,7 +69,7 @@ app.post("/handler", async (req, res) => { if (!ajv.validate("https://image.a11y.mcgill.ca/renderers/text.schema.json", rendering["data"])) { console.error("Failed to generate a valid text rendering!"); - console.error(ajv.errors); + piiLogger.pii(`Validation error in text rendering: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); return; } @@ -81,7 +83,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid response."); - console.error(ajv.errors); + piiLogger.pii(`Validation error in final response: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } }); diff --git a/handlers/ocr-handler/Dockerfile b/handlers/ocr-handler/Dockerfile index 7bc845ee4..dc7273983 100644 --- a/handlers/ocr-handler/Dockerfile +++ b/handlers/ocr-handler/Dockerfile @@ -12,7 +12,7 @@ COPY /handlers/ocr-handler/requirements.txt /app/requirements.txt RUN pip3 install -r requirements.txt COPY /schemas /app/schemas - +COPY /config /app/config COPY /handlers/ocr-handler/ /app EXPOSE 80 diff --git a/handlers/ocr-handler/server.py b/handlers/ocr-handler/server.py index 075f9b91a..2586498f8 100644 --- a/handlers/ocr-handler/server.py +++ b/handlers/ocr-handler/server.py @@ -21,6 +21,9 @@ import jsonschema from flask import Flask, request, jsonify from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) diff --git a/handlers/osm-streets-handler/Dockerfile b/handlers/osm-streets-handler/Dockerfile index 8e32fb99f..5b784e2e8 100644 --- a/handlers/osm-streets-handler/Dockerfile +++ b/handlers/osm-streets-handler/Dockerfile @@ -1,13 +1,14 @@ -FROM node:alpine as builder +FROM node:alpine AS builder RUN addgroup -g 4322 storage && addgroup node storage WORKDIR /usr/src/app COPY /handlers/osm-streets-handler/ /usr/src/app RUN npm ci COPY /schemas src/schemas +COPY /config ./src/config RUN npm run build && npm prune --production -FROM node:alpine as final +FROM node:alpine AS final RUN apk add --no-cache curl diff --git a/handlers/osm-streets-handler/package-lock.json b/handlers/osm-streets-handler/package-lock.json index a0a984960..b52e5bc74 100644 --- a/handlers/osm-streets-handler/package-lock.json +++ b/handlers/osm-streets-handler/package-lock.json @@ -14,7 +14,8 @@ "express": "^4.19.2", "osc": "^2.4.2", "pluralize": "^8.0.0", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", @@ -34,6 +35,24 @@ "node": ">=0.10.0" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -419,6 +438,11 @@ "@types/node": "*" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -706,6 +730,11 @@ "resolved": "https://registry.npmjs.org/articles/-/articles-0.2.2.tgz", "integrity": "sha512-S3Y4MPp+LD/l0HHm/4yrr6MoXhUkKT98ZdsV2tkTuBNywqUXEtvJT+NBO3KTSQEttc5EOwEJe2Xw8cZ9TI5Hrw==" }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -821,6 +850,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -836,8 +874,38 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -976,6 +1044,11 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1362,6 +1435,11 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1451,6 +1529,11 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1725,6 +1808,11 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1755,6 +1843,17 @@ "node": ">=0.12.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1784,6 +1883,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1818,6 +1922,22 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -1923,8 +2043,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "devOptional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -1985,6 +2104,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -2212,6 +2339,19 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -2308,6 +2448,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2470,6 +2618,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -2484,6 +2640,14 @@ "resolved": "https://registry.npmjs.org/slip/-/slip-1.0.2.tgz", "integrity": "sha512-XrcHe3NAcyD3wO+O4I13RcS4/3AF+S9RvGNj9JhJeS02HyImwD2E3QWLrmn9hBfL+fB6yapagwxRkeyYzhk98g==" }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2492,6 +2656,14 @@ "node": ">= 0.8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -2528,6 +2700,11 @@ "node": ">=8" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2554,6 +2731,14 @@ "node": ">=0.6" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -2640,6 +2825,11 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2685,6 +2875,40 @@ "node": ">= 8" } }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/wolfy87-eventemitter": { "version": "5.2.9", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz", @@ -2742,6 +2966,21 @@ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true }, + "@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==" + }, + "@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -3028,6 +3267,11 @@ "@types/node": "*" } }, + "@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -3199,6 +3443,11 @@ "resolved": "https://registry.npmjs.org/articles/-/articles-0.2.2.tgz", "integrity": "sha512-S3Y4MPp+LD/l0HHm/4yrr6MoXhUkKT98ZdsV2tkTuBNywqUXEtvJT+NBO3KTSQEttc5EOwEJe2Xw8cZ9TI5Hrw==" }, + "async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3291,6 +3540,30 @@ "supports-color": "^7.1.0" } }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3303,8 +3576,25 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "concat-map": { "version": "0.0.1", @@ -3404,6 +3694,11 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -3714,6 +4009,11 @@ "reusify": "^1.0.4" } }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3787,6 +4087,11 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3980,6 +4285,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4001,6 +4311,11 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4027,6 +4342,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4052,6 +4372,19 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "requires": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -4127,8 +4460,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "devOptional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "natural-compare": { "version": "1.4.0", @@ -4175,6 +4507,14 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -4323,6 +4663,16 @@ "unpipe": "1.0.0" } }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -4369,6 +4719,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4502,6 +4857,14 @@ "object-inspect": "^1.13.1" } }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4513,11 +4876,24 @@ "resolved": "https://registry.npmjs.org/slip/-/slip-1.0.2.tgz", "integrity": "sha512-XrcHe3NAcyD3wO+O4I13RcS4/3AF+S9RvGNj9JhJeS02HyImwD2E3QWLrmn9hBfL+fB6yapagwxRkeyYzhk98g==" }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4542,6 +4918,11 @@ "has-flag": "^4.0.0" } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4562,6 +4943,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==" + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -4620,6 +5006,11 @@ "punycode": "^2.1.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -4650,6 +5041,34 @@ "isexe": "^2.0.0" } }, + "winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "requires": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + } + }, + "winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "requires": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + } + }, "wolfy87-eventemitter": { "version": "5.2.9", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz", diff --git a/handlers/osm-streets-handler/package.json b/handlers/osm-streets-handler/package.json index 041eaa8c9..6a844b486 100644 --- a/handlers/osm-streets-handler/package.json +++ b/handlers/osm-streets-handler/package.json @@ -16,7 +16,8 @@ "express": "^4.19.2", "osc": "^2.4.2", "pluralize": "^8.0.0", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", diff --git a/handlers/osm-streets-handler/src/server.ts b/handlers/osm-streets-handler/src/server.ts index c0f906d59..050d34b7e 100644 --- a/handlers/osm-streets-handler/src/server.ts +++ b/handlers/osm-streets-handler/src/server.ts @@ -18,6 +18,7 @@ import Ajv from "ajv"; import express from "express"; import fs from "fs/promises"; import { v4 as uuidv4 } from "uuid"; +import { piiLogger } from "./config/logging_utils"; import * as utils from "./utils"; @@ -48,6 +49,7 @@ app.post("/handler", async (req, res) => { // Validate the request data if (!ajv.validate("https://image.a11y.mcgill.ca/request.schema.json", req.body)) { console.warn("Request did not pass the schema!"); + piiLogger.pii(`Schema validation failed: ${JSON.stringify(ajv.errors)}`); res.status(400).json(ajv.errors); return; } @@ -164,7 +166,8 @@ app.post("/handler", async (req, res) => { if (ajv.validate("https://image.a11y.mcgill.ca/renderers/segmentaudio.schema.json", rendering["data"])) { renderings.push(rendering); } else { - console.error(ajv.errors); + console.error("SegmentAudio validation failed"); + piiLogger.pii(`Validation error: ${JSON.stringify(ajv.errors)}`); } } else if (hasSimple) { @@ -181,7 +184,8 @@ app.post("/handler", async (req, res) => { if (ajv.validate("https://image.a11y.mcgill.ca/renderers/simpleaudio.schema.json", rendering["data"])) { renderings.push(rendering); } else { - console.error(ajv.errors); + console.error("SimpleAudio validation failed"); + piiLogger.pii(`Validation error: ${JSON.stringify(ajv.errors)}`); } } }).finally(() => { @@ -198,7 +202,7 @@ app.post("/handler", async (req, res) => { }); } catch(e) { console.error("Failed to generate audio!"); - console.error(e); + piiLogger.pii(`Audio generation error: ${(e as Error).message}`); } // Send response @@ -210,7 +214,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid response."); - console.error(ajv.errors); + piiLogger.pii(`Response validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } }); diff --git a/handlers/package-lock.json b/handlers/package-lock.json new file mode 100644 index 000000000..35288e198 --- /dev/null +++ b/handlers/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "handlers", + "lockfileVersion": 2, + "requires": true, + "packages": {} +} diff --git a/handlers/photo-audio-handler/Dockerfile b/handlers/photo-audio-handler/Dockerfile index 73d864e2a..715f19beb 100644 --- a/handlers/photo-audio-handler/Dockerfile +++ b/handlers/photo-audio-handler/Dockerfile @@ -5,6 +5,7 @@ WORKDIR /usr/src/app COPY /handlers/photo-audio-handler/ /usr/src/app RUN npm ci COPY /schemas src/schemas +COPY /config ./src/config RUN npm run build && npm prune --production FROM node:alpine as final diff --git a/handlers/photo-audio-handler/package-lock.json b/handlers/photo-audio-handler/package-lock.json index 4a124978e..47314da79 100644 --- a/handlers/photo-audio-handler/package-lock.json +++ b/handlers/photo-audio-handler/package-lock.json @@ -14,7 +14,8 @@ "express": "^4.19.2", "osc": "^2.4.2", "pluralize": "^8.0.0", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", @@ -35,6 +36,24 @@ "node": ">=0.10.0" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -491,6 +510,11 @@ "@types/node": "*" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -782,6 +806,11 @@ "resolved": "https://registry.npmjs.org/articles/-/articles-0.2.2.tgz", "integrity": "sha512-S3Y4MPp+LD/l0HHm/4yrr6MoXhUkKT98ZdsV2tkTuBNywqUXEtvJT+NBO3KTSQEttc5EOwEJe2Xw8cZ9TI5Hrw==" }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -906,6 +935,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -921,8 +959,38 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -1058,6 +1126,11 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -1436,6 +1509,11 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1525,6 +1603,11 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1788,6 +1871,11 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1827,6 +1915,17 @@ "node": ">=8" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1866,6 +1965,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1900,6 +2004,22 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -2016,8 +2136,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "devOptional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -2087,6 +2206,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -2314,6 +2441,19 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -2398,6 +2538,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2603,6 +2751,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -2617,6 +2773,14 @@ "resolved": "https://registry.npmjs.org/slip/-/slip-1.0.2.tgz", "integrity": "sha512-XrcHe3NAcyD3wO+O4I13RcS4/3AF+S9RvGNj9JhJeS02HyImwD2E3QWLrmn9hBfL+fB6yapagwxRkeyYzhk98g==" }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2625,6 +2789,14 @@ "node": ">= 0.8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -2661,6 +2833,11 @@ "node": ">=8" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2687,6 +2864,14 @@ "node": ">=0.6" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -2773,6 +2958,11 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2812,6 +3002,40 @@ "node": ">= 8" } }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/wolfy87-eventemitter": { "version": "5.2.9", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz", diff --git a/handlers/photo-audio-handler/package.json b/handlers/photo-audio-handler/package.json index b723502f2..9f71a0ca7 100644 --- a/handlers/photo-audio-handler/package.json +++ b/handlers/photo-audio-handler/package.json @@ -16,7 +16,8 @@ "express": "^4.19.2", "osc": "^2.4.2", "pluralize": "^8.0.0", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", diff --git a/handlers/photo-audio-handler/src/server.ts b/handlers/photo-audio-handler/src/server.ts index 2ca7544cf..9db617058 100644 --- a/handlers/photo-audio-handler/src/server.ts +++ b/handlers/photo-audio-handler/src/server.ts @@ -18,6 +18,7 @@ import Ajv from "ajv"; import express from "express"; import fs from "fs/promises"; import { v4 as uuidv4 } from "uuid"; +import { piiLogger } from "./config/logging_utils"; import * as utils from "./utils"; @@ -49,6 +50,7 @@ app.post("/handler", async (req, res) => { // Validate the request data if (!ajv.validate("https://image.a11y.mcgill.ca/request.schema.json", req.body)) { console.warn("Request did not pass the schema!"); + piiLogger.pii(`Schema validation failed: ${JSON.stringify(ajv.errors)}`); res.status(400).json(ajv.errors); return; } @@ -151,6 +153,7 @@ app.post("/handler", async (req, res) => { } } catch (err) { console.error(`Failed to translate ttsData to ${targetLanguage}!`); + piiLogger.pii(`Translation error: ${(err as Error).message}`); } } @@ -167,7 +170,7 @@ app.post("/handler", async (req, res) => { renderings.push(rendering); } else { console.error("Failed to generate a valid text rendering!"); - console.error(ajv.errors); + piiLogger.pii(`Text rendering validation error: ${JSON.stringify(ajv.errors)}`); console.warn("Trying to continue..."); } } else { @@ -246,7 +249,7 @@ app.post("/handler", async (req, res) => { if (ajv.validate("https://image.a11y.mcgill.ca/renderers/segmentaudio.schema.json", rendering["data"])) { renderings.push(rendering); } else { - console.error(ajv.errors); + piiLogger.pii(`SegmentAudio validation error: ${JSON.stringify(ajv.errors)}`); } } else if (hasSimple) { @@ -264,7 +267,9 @@ app.post("/handler", async (req, res) => { if (ajv.validate("https://image.a11y.mcgill.ca/renderers/simpleaudio.schema.json", rendering["data"])) { renderings.push(rendering); } else { - console.error(ajv.errors); + console.error("Simple Audio validation failed."); + piiLogger.pii(`Simple Audio validation error: ${JSON.stringify(ajv.errors)}`); + } } }).finally(() => { @@ -281,7 +286,7 @@ app.post("/handler", async (req, res) => { }); } catch(e) { console.error("Failed to generate audio!"); - console.error(e); + piiLogger.pii(`TTS generation error: ${(e as Error).message}`); } } @@ -298,8 +303,8 @@ app.post("/handler", async (req, res) => { renderings[i]["description"] = translatedDesc[i]; } } catch(e) { - console.error("Failed to translate rendering descriptions to " + targetLanguage); - console.error(e); + console.error("Failed to generate audio!"); + piiLogger.pii(`Error: ${(e as Error).message}`); } } // Send response @@ -311,7 +316,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid response."); - console.error(ajv.errors); + piiLogger.pii(`Response validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } }); diff --git a/handlers/photo-audio-haptics-handler/Dockerfile b/handlers/photo-audio-haptics-handler/Dockerfile index 2eb80cf1a..4e2b5c711 100644 --- a/handlers/photo-audio-haptics-handler/Dockerfile +++ b/handlers/photo-audio-haptics-handler/Dockerfile @@ -5,6 +5,7 @@ WORKDIR /usr/src/app COPY /handlers/photo-audio-haptics-handler/ /usr/src/app RUN npm ci COPY /schemas src/schemas +COPY /config ./src/config RUN npm run build && npm prune --production FROM node:alpine as final diff --git a/handlers/photo-audio-haptics-handler/package-lock.json b/handlers/photo-audio-haptics-handler/package-lock.json index f8adefc1d..265b85b37 100644 --- a/handlers/photo-audio-haptics-handler/package-lock.json +++ b/handlers/photo-audio-haptics-handler/package-lock.json @@ -14,7 +14,8 @@ "express": "^4.17.2", "osc": "^2.4.2", "pluralize": "^8.0.0", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", @@ -35,6 +36,24 @@ "node": ">=0.10.0" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", @@ -534,6 +553,11 @@ "@types/node": "*" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -904,6 +928,11 @@ "resolved": "https://registry.npmjs.org/articles/-/articles-0.2.2.tgz", "integrity": "sha512-S3Y4MPp+LD/l0HHm/4yrr6MoXhUkKT98ZdsV2tkTuBNywqUXEtvJT+NBO3KTSQEttc5EOwEJe2Xw8cZ9TI5Hrw==" }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1006,6 +1035,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1021,8 +1059,38 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -1152,6 +1220,11 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1574,6 +1647,11 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1634,6 +1712,11 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1902,6 +1985,11 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1932,6 +2020,17 @@ "node": ">=0.12.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1961,6 +2060,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1980,6 +2084,27 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -2149,6 +2274,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -2337,6 +2470,19 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -2433,6 +2579,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2605,6 +2759,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -2619,6 +2781,14 @@ "resolved": "https://registry.npmjs.org/slip/-/slip-1.0.2.tgz", "integrity": "sha1-ukWpIwNNbPQbGieuvnEoKCyNVR8=" }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2627,6 +2797,14 @@ "node": ">= 0.8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2639,6 +2817,11 @@ "node": ">=8" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2665,6 +2848,14 @@ "node": ">=0.6" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -2751,6 +2942,11 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2796,6 +2992,40 @@ "node": ">= 8" } }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/wolfy87-eventemitter": { "version": "5.2.9", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz", @@ -2841,6 +3071,21 @@ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true }, + "@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==" + }, + "@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@eslint/eslintrc": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", @@ -3206,6 +3451,11 @@ "@types/node": "*" } }, + "@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -3439,6 +3689,11 @@ "resolved": "https://registry.npmjs.org/articles/-/articles-0.2.2.tgz", "integrity": "sha512-S3Y4MPp+LD/l0HHm/4yrr6MoXhUkKT98ZdsV2tkTuBNywqUXEtvJT+NBO3KTSQEttc5EOwEJe2Xw8cZ9TI5Hrw==" }, + "async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3516,6 +3771,30 @@ "supports-color": "^7.1.0" } }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3528,8 +3807,25 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "concat-map": { "version": "0.0.1", @@ -3628,6 +3924,11 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -3955,6 +4256,11 @@ "reusify": "^1.0.4" } }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4003,6 +4309,11 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -4190,6 +4501,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4211,6 +4527,11 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4237,6 +4558,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4253,6 +4579,26 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "requires": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -4375,6 +4721,14 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -4499,6 +4853,16 @@ "unpipe": "1.0.0" } }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -4545,6 +4909,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4680,6 +5049,14 @@ "object-inspect": "^1.13.1" } }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4691,11 +5068,24 @@ "resolved": "https://registry.npmjs.org/slip/-/slip-1.0.2.tgz", "integrity": "sha1-ukWpIwNNbPQbGieuvnEoKCyNVR8=" }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -4705,6 +5095,11 @@ "has-flag": "^4.0.0" } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4725,6 +5120,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==" + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -4783,6 +5183,11 @@ "punycode": "^2.1.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -4813,6 +5218,34 @@ "isexe": "^2.0.0" } }, + "winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "requires": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + } + }, + "winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "requires": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + } + }, "wolfy87-eventemitter": { "version": "5.2.9", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz", diff --git a/handlers/photo-audio-haptics-handler/package.json b/handlers/photo-audio-haptics-handler/package.json index aa24ad7d4..f01a1ea62 100644 --- a/handlers/photo-audio-haptics-handler/package.json +++ b/handlers/photo-audio-haptics-handler/package.json @@ -16,7 +16,8 @@ "express": "^4.17.2", "osc": "^2.4.2", "pluralize": "^8.0.0", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", diff --git a/handlers/photo-audio-haptics-handler/src/server.ts b/handlers/photo-audio-haptics-handler/src/server.ts index 64a0130e7..9868679c4 100644 --- a/handlers/photo-audio-haptics-handler/src/server.ts +++ b/handlers/photo-audio-haptics-handler/src/server.ts @@ -27,6 +27,7 @@ import descriptionJSON from "./schemas/services/supercollider/tts-description.sc import segmentJSON from "./schemas/services/supercollider/tts-segment.schema.json"; import rendererDefJSON from "./schemas/renderers/definitions.json"; import photoAudioHapticsJSON from "./schemas/renderers/photoaudiohaptics.schema.json"; +import { piiLogger } from "./config/logging_utils"; import * as utils from "./utils"; @@ -54,6 +55,7 @@ app.post("/handler", async (req, res) => { // Validate the request data (just in case) if (!ajv.validate("https://image.a11y.mcgill.ca/request.schema.json", req.body)) { console.warn("Request did not pass the schema!"); + piiLogger.pii(`Schema validation failed: ${JSON.stringify(ajv.errors)}`); res.status(400).json(ajv.errors); return; } @@ -77,7 +79,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid empty response!"); - console.error(ajv.errors); + piiLogger.pii(`Empty response validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } return; @@ -94,7 +96,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid empty response!"); - console.error(ajv.errors); + piiLogger.pii(`Renderer availability check failed: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } return; @@ -232,7 +234,7 @@ app.post("/handler", async (req, res) => { renderings.push(rendering); console.log("finished forming audio-haptics rendering"); } else { - console.error(ajv.errors); + piiLogger.pii(`PhotoAudioHaptics validation error: ${JSON.stringify(ajv.errors)}`); } } }).finally(() => { @@ -249,7 +251,7 @@ app.post("/handler", async (req, res) => { }); } catch (e) { console.error("Failed to generate audio!"); - console.error(e); + piiLogger.pii(`Audio generation error: ${(e as Error).message}`); } } @@ -260,7 +262,7 @@ app.post("/handler", async (req, res) => { res.json(response); } else { console.error("Failed to generate a valid response."); - console.error(ajv.errors); + piiLogger.pii(`Final response validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } }); diff --git a/handlers/photo-tactile-svg/Dockerfile b/handlers/photo-tactile-svg/Dockerfile index e2d09a15a..9dffea46f 100644 --- a/handlers/photo-tactile-svg/Dockerfile +++ b/handlers/photo-tactile-svg/Dockerfile @@ -8,9 +8,11 @@ ENV PATH="/home/python/.local/bin:${PATH}" RUN pip install --upgrade pip COPY /handlers/photo-tactile-svg/requirements.txt /usr/src/app/requirements.txt + RUN pip install -r requirements.txt COPY /schemas /usr/src/app/schemas +COPY /config /usr/src/app/config COPY /handlers/photo-tactile-svg/ /usr/src/app EXPOSE 80 diff --git a/handlers/photo-tactile-svg/tactile_svg.py b/handlers/photo-tactile-svg/tactile_svg.py index f859e9733..c5cb30cf3 100644 --- a/handlers/photo-tactile-svg/tactile_svg.py +++ b/handlers/photo-tactile-svg/tactile_svg.py @@ -22,8 +22,10 @@ import time import drawSvg as draw import inflect +from config.logging_utils import configure_logging from datetime import datetime +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -31,15 +33,20 @@ @app.route("/handler", methods=["POST"]) def handle(): logging.debug("Received request") - # Load necessary schema files - with open("./schemas/definitions.json") as f: - definitions_schema = json.load(f) - with open("./schemas/request.schema.json") as f: - request_schema = json.load(f) - with open("./schemas/handler-response.schema.json") as f: - response_schema = json.load(f) - with open("./schemas/renderers/tactilesvg.schema.json") as f: - renderer_schema = json.load(f) + try: + # Load necessary schema files + with open("./schemas/definitions.json") as f: + definitions_schema = json.load(f) + with open("./schemas/request.schema.json") as f: + request_schema = json.load(f) + with open("./schemas/handler-response.schema.json") as f: + response_schema = json.load(f) + with open("./schemas/renderers/tactilesvg.schema.json") as f: + renderer_schema = json.load(f) + except Exception as e: + logging.error("Error loading schema files") + logging.pii(f"Schema loading error: {e}") + return jsonify("Schema files could not be loaded"), 500 store = { definitions_schema["$id"]: definitions_schema, @@ -59,7 +66,8 @@ def handle(): ) validator.validate(contents) except ValidationError as e: - logging.error(e) + logging.error("Validation error in request schema") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid request received!"), 400 preprocessors = contents['preprocessors'] @@ -78,7 +86,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Renderer validation error") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -104,7 +113,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Preprocessor validation error") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -129,7 +139,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Graphic validation error") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -293,8 +304,8 @@ def handle(): ) validator.validate(data) except ValidationError as e: - logging.error(e) - logging.debug("Failed to validate the response renderer!") + logging.error("Failed to validate the response renderer") + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to validate the response renderer"), 500 response = { "request_uuid": contents["request_uuid"], @@ -308,7 +319,7 @@ def handle(): validator.validate(response) except ValidationError as e: logging.debug("Failed to generate a valid response") - logging.error(e) + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to generate a valid response"), 500 logging.debug("Sending response") return response diff --git a/handlers/svg-action-recognition/Dockerfile b/handlers/svg-action-recognition/Dockerfile index 151e8100e..9dafc48f9 100644 --- a/handlers/svg-action-recognition/Dockerfile +++ b/handlers/svg-action-recognition/Dockerfile @@ -11,6 +11,7 @@ COPY /handlers/svg-action-recognition/requirements.txt /usr/src/app/requirements RUN pip install -r requirements.txt COPY /schemas /usr/src/app/schemas +COPY /config /usr/src/app/config COPY /handlers/svg-action-recognition/ /usr/src/app EXPOSE 80 diff --git a/handlers/svg-action-recognition/ar_svg.py b/handlers/svg-action-recognition/ar_svg.py index 4769d68be..61bcc6793 100644 --- a/handlers/svg-action-recognition/ar_svg.py +++ b/handlers/svg-action-recognition/ar_svg.py @@ -21,23 +21,32 @@ import logging import time import drawSvg as draw +from config.logging_utils import configure_logging from datetime import datetime + +configure_logging() + app = Flask(__name__) @app.route("/handler", methods=["POST"]) def handle(): logging.debug("Received request") - # Load necessary schema files - with open("./schemas/definitions.json") as f: - definitions_schema = json.load(f) - with open("./schemas/request.schema.json") as f: - request_schema = json.load(f) - with open("./schemas/handler-response.schema.json") as f: - response_schema = json.load(f) - with open("./schemas/renderers/svglayers.schema.json") as f: - renderer_schema = json.load(f) + try: + # Load necessary schema files + with open("./schemas/definitions.json") as f: + definitions_schema = json.load(f) + with open("./schemas/request.schema.json") as f: + request_schema = json.load(f) + with open("./schemas/handler-response.schema.json") as f: + response_schema = json.load(f) + with open("./schemas/renderers/svglayers.schema.json") as f: + renderer_schema = json.load(f) + except Exception as e: + logging.error("Error loading schema files") + logging.pii(f"Schema loading error: {e}") + return jsonify("Schema files could not be loaded"), 500 store = { definitions_schema["$id"]: definitions_schema, request_schema["$id"]: request_schema, @@ -55,7 +64,8 @@ def handle(): ) validator.validate(contents) except ValidationError as e: - logging.error(e) + logging.error("Validation error in request schema") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid request received!"), 400 # Check preprocessor data @@ -76,8 +86,10 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 + logging.debug("Sending response") return response @@ -95,10 +107,12 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response + # No Action recognition output found if "ca.mcgill.a11y.image.preprocessor.actionRecognition"\ not in preprocessors: @@ -113,7 +127,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -136,7 +151,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -161,7 +177,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -217,8 +234,8 @@ def handle(): ) validator.validate(data) except ValidationError as e: - logging.error(e) - logging.error("Failed to validate the response renderer!") + logging.error("Failed to validate the response renderer") + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to validate the response renderer"), 500 response = { "request_uuid": contents["request_uuid"], @@ -232,7 +249,7 @@ def handle(): validator.validate(response) except ValidationError as e: logging.error("Failed to generate a valid response") - logging.error(e) + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to generate a valid response"), 500 logging.debug("Sending response") return response diff --git a/handlers/svg-depth-map/Dockerfile b/handlers/svg-depth-map/Dockerfile index 1eab0bb9f..a803ad000 100644 --- a/handlers/svg-depth-map/Dockerfile +++ b/handlers/svg-depth-map/Dockerfile @@ -11,6 +11,7 @@ COPY /handlers/svg-depth-map/requirements.txt /usr/src/app/requirements.txt RUN pip install -r requirements.txt COPY /schemas /usr/src/app/schemas +COPY /config /usr/src/app/config COPY /handlers/svg-depth-map/ /usr/src/app EXPOSE 80 diff --git a/handlers/svg-depth-map/svg-depth-map.py b/handlers/svg-depth-map/svg-depth-map.py index 3ffb23b27..ef69d76a2 100644 --- a/handlers/svg-depth-map/svg-depth-map.py +++ b/handlers/svg-depth-map/svg-depth-map.py @@ -23,22 +23,31 @@ import svgwrite import base64 from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) @app.route("/handler", methods=["POST"]) def handle(): - logging.debug("Received request") - # Load necessary schema files - with open("./schemas/definitions.json") as f: - definitions_schema = json.load(f) - with open("./schemas/request.schema.json") as f: - request_schema = json.load(f) - with open("./schemas/handler-response.schema.json") as f: - response_schema = json.load(f) - with open("./schemas/renderers/svglayers.schema.json") as f: - renderer_schema = json.load(f) + try: + logging.debug("Received request") + # Load necessary schema files + with open("./schemas/definitions.json") as f: + definitions_schema = json.load(f) + with open("./schemas/request.schema.json") as f: + request_schema = json.load(f) + with open("./schemas/handler-response.schema.json") as f: + response_schema = json.load(f) + with open("./schemas/renderers/svglayers.schema.json") as f: + renderer_schema = json.load(f) + except Exception as e: + logging.error("Error loading schema files") + logging.pii(f"Schema loading error: {e}") + return jsonify("Schema files could not be loaded"), 500 + store = { definitions_schema["$id"]: definitions_schema, request_schema["$id"]: request_schema, @@ -56,7 +65,8 @@ def handle(): ) validator.validate(contents) except ValidationError as e: - logging.error(e) + logging.error("Validation error in request schema") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid request received!"), 400 # Check preprocessor data @@ -77,7 +87,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -96,7 +107,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -115,10 +127,12 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response + if "dimensions" in contents: # If an existing graphic exists, often it is # best to use that for convenience. @@ -137,7 +151,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -169,9 +184,10 @@ def handle(): ) validator.validate(data) except ValidationError as e: - logging.error(e) - logging.error("Failed to validate the response renderer!") + logging.error("Failed to validate the response renderer") + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to validate the response renderer"), 500 + response = { "request_uuid": contents["request_uuid"], "timestamp": int(time.time()), @@ -184,7 +200,7 @@ def handle(): validator.validate(response) except ValidationError as e: logging.error("Failed to generate a valid response") - logging.error(e) + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to generate a valid response"), 500 logging.debug("Sending response") return response diff --git a/handlers/svg-object-detection/Dockerfile b/handlers/svg-object-detection/Dockerfile index d82f2b7ef..85bff5344 100644 --- a/handlers/svg-object-detection/Dockerfile +++ b/handlers/svg-object-detection/Dockerfile @@ -11,6 +11,7 @@ COPY /handlers/svg-object-detection/requirements.txt /usr/src/app/requirements.t RUN pip install -r requirements.txt COPY /schemas /usr/src/app/schemas +COPY /config /app/config COPY /handlers/svg-object-detection/ /usr/src/app EXPOSE 80 diff --git a/handlers/svg-object-detection/od_svg.py b/handlers/svg-object-detection/od_svg.py index bc0a686cc..f9f5cfb01 100644 --- a/handlers/svg-object-detection/od_svg.py +++ b/handlers/svg-object-detection/od_svg.py @@ -22,6 +22,9 @@ import time import drawSvg as draw from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) @@ -29,15 +32,21 @@ @app.route("/handler", methods=["POST"]) def handle(): logging.debug("Received request") - # Load necessary schema files - with open("./schemas/definitions.json") as f: - definitions_schema = json.load(f) - with open("./schemas/request.schema.json") as f: - request_schema = json.load(f) - with open("./schemas/handler-response.schema.json") as f: - response_schema = json.load(f) - with open("./schemas/renderers/svglayers.schema.json") as f: - renderer_schema = json.load(f) + try: + # Load necessary schema files + with open("./schemas/definitions.json") as f: + definitions_schema = json.load(f) + with open("./schemas/request.schema.json") as f: + request_schema = json.load(f) + with open("./schemas/handler-response.schema.json") as f: + response_schema = json.load(f) + with open("./schemas/renderers/svglayers.schema.json") as f: + renderer_schema = json.load(f) + except Exception as e: + logging.error("Error loading schema files") + logging.pii(f"Schema loading error: {e}") + return jsonify("Schema files could not be loaded"), 500 + store = { definitions_schema["$id"]: definitions_schema, request_schema["$id"]: request_schema, @@ -55,7 +64,8 @@ def handle(): ) validator.validate(contents) except ValidationError as e: - logging.error(e) + logging.error("Validation error in request schema") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid request received!"), 400 # Check preprocessor data @@ -76,7 +86,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -95,7 +106,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -117,7 +129,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -193,9 +206,10 @@ def handle(): ) validator.validate(data) except ValidationError as e: - logging.error(e) - logging.error("Failed to validate the response renderer!") + logging.error("Failed to validate the response renderer") + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to validate the response renderer"), 500 + response = { "request_uuid": contents["request_uuid"], "timestamp": int(time.time()), @@ -208,7 +222,7 @@ def handle(): validator.validate(response) except ValidationError as e: logging.error("Failed to generate a valid response") - logging.error(e) + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to generate a valid response"), 500 logging.debug("Sending response") return response diff --git a/handlers/svg-open-street-map/Dockerfile b/handlers/svg-open-street-map/Dockerfile index c3c23944d..794edac52 100644 --- a/handlers/svg-open-street-map/Dockerfile +++ b/handlers/svg-open-street-map/Dockerfile @@ -11,6 +11,7 @@ COPY /handlers/svg-open-street-map/requirements.txt /usr/src/app/requirements.tx RUN pip install -r requirements.txt COPY /schemas /usr/src/app/schemas +COPY /config /app/config COPY /handlers/svg-open-street-map/ /usr/src/app EXPOSE 5000 diff --git a/handlers/svg-open-street-map/osm-svg.py b/handlers/svg-open-street-map/osm-svg.py index e2ffce66c..01f48adaf 100644 --- a/handlers/svg-open-street-map/osm-svg.py +++ b/handlers/svg-open-street-map/osm-svg.py @@ -22,32 +22,31 @@ import time import drawSvg as draw from datetime import datetime +from config.logging_utils import configure_logging -app = Flask(__name__) - -# Configure the logging settings -logging.basicConfig( - level=logging.DEBUG, - format="%(asctime)s [%(levelname)s]: %(message)s", - datefmt="%y-%m-%d %H:%M %Z", -) +configure_logging() -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) +app = Flask(__name__) @app.route("/handler", methods=["POST"]) def handle(): - LOGGER.debug("Received request") - # Load necessary schema files - with open("./schemas/definitions.json") as f: - definitions_schema = json.load(f) - with open("./schemas/request.schema.json") as f: - request_schema = json.load(f) - with open("./schemas/handler-response.schema.json") as f: - response_schema = json.load(f) - with open("./schemas/renderers/svglayers.schema.json") as f: - renderer_schema = json.load(f) + logging.debug("Received request") + try: + # Load necessary schema files + with open("./schemas/definitions.json") as f: + definitions_schema = json.load(f) + with open("./schemas/request.schema.json") as f: + request_schema = json.load(f) + with open("./schemas/handler-response.schema.json") as f: + response_schema = json.load(f) + with open("./schemas/renderers/svglayers.schema.json") as f: + renderer_schema = json.load(f) + except Exception as e: + logging.error("Error loading schema files") + logging.pii(f"Schema loading error: {e}") + return jsonify("Schema files could not be loaded"), 500 + store = { definitions_schema["$id"]: definitions_schema, request_schema["$id"]: request_schema, @@ -60,18 +59,19 @@ def handle(): # Get and validate the request contents contents = request.get_json() try: - LOGGER.debug("Validating request") + logging.debug("Validating request") validator = jsonschema.Draft7Validator( request_schema, resolver=resolver ) validator.validate(contents) except ValidationError as e: - LOGGER.error(e) + logging.error("Validation error in request schema") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid request received!"), 400 # Check preprocessor data if "preprocessors" not in contents: - LOGGER.debug(" Missing preprocessor key. OSM SVG can't handle this") + logging.debug(" Missing preprocessor key. OSM SVG can't handle this") response = { "request_uuid": contents["request_uuid"], "timestamp": int(time.time()), @@ -82,19 +82,19 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - LOGGER.error(error) + logging.pii(f"Renderer validation error: {error}") return jsonify("Invalid Preprocessor JSON format"), 500 - LOGGER.debug("Sending response") + logging.debug("Sending response") return response else: preprocessor = contents['preprocessors'] # Check if renderer is supported - LOGGER.debug("Checking whether renderer is supported") + logging.debug("Checking whether renderer is supported") if ("ca.mcgill.a11y.image.renderer.SVGLayers" not in contents["renderers"]): - LOGGER.debug("OpenStreetMap SVG renderer not supported!") + logging.debug("OpenStreetMap SVG renderer not supported!") response = { "request_uuid": contents["request_uuid"], "timestamp": int(time.time()), @@ -105,16 +105,16 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - LOGGER.error(error) + logging.pii(f"Renderer validation error: {error}") return jsonify("Invalid Preprocessor JSON format"), 500 - LOGGER.debug("Sending response") + logging.debug("Sending response") return response # Check if DebugMode is enabled if ("ca.mcgill.a11y.image.capability.DebugMode" not in contents['capabilities']): - LOGGER.debug("DebugMode not enabled. Can't process further!") + logging.debug("DebugMode not enabled. Can't process further!") response = { "request_uuid": contents["request_uuid"], "timestamp": int(time.time()), @@ -125,15 +125,15 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - LOGGER.error(error) + logging.pii(f"Renderer validation error: {error}") return jsonify("Invalid Preprocessor JSON format"), 500 - LOGGER.debug("Sending response") + logging.debug("Sending response") return response - LOGGER.debug("Checking for OpenStreetMap map data ") + logging.debug("Checking for OpenStreetMap map data ") if "ca.mcgill.a11y.image.preprocessor.openstreetmap"\ not in preprocessor: - LOGGER.info("OSM map data not present. Skipping ...") + logging.info("OSM map data not present. Skipping ...") response = { "request_uuid": contents["request_uuid"], "timestamp": int(time.time()), @@ -144,13 +144,13 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - LOGGER.error(error) + logging.pii(f"Renderer validation error: {error}") return jsonify("Invalid Preprocessor JSON format"), 500 - LOGGER.debug("Sending response") + logging.debug("Sending response") return response else: - LOGGER.debug("Map data found! Processing data!") + logging.debug("Map data found! Processing data!") svg_layers = [] dimensions = 700, 700 @@ -286,7 +286,7 @@ def handle(): svg_layers.append( {"label": "AllLayers", "svg": all_svg.asDataUri()}) - LOGGER.debug("Providing final result!") + logging.debug("Providing final result!") data = { "layers": svg_layers @@ -302,13 +302,13 @@ def handle(): ) validator.validate(data) except ValidationError as e: - LOGGER.debug( + logging.debug( "Failed to produce a valid renderer response!") - LOGGER.error(e) + logging.pii(f"Renderer validation error: {e}") return jsonify( "Failed to produce a valid renderer response!"), 500 else: - LOGGER.info("No data for streets rendering. Skipping ...") + logging.info("No data for streets rendering. Skipping ...") response = { "request_uuid": contents["request_uuid"], "timestamp": int(time.time()), @@ -326,10 +326,10 @@ def handle(): ) validator.validate(response) except ValidationError as e: - LOGGER.debug("Failed to generate a valid response") - LOGGER.error(e) + logging.debug("Failed to generate a valid response") + logging.pii(f"Response validation error: {e}") return jsonify("Failed to generate a valid response"), 500 - LOGGER.debug("Sending final response") + logging.debug("Sending final response") return response diff --git a/handlers/svg-semantic-seg/Dockerfile b/handlers/svg-semantic-seg/Dockerfile index 81b0f3b08..34431d794 100644 --- a/handlers/svg-semantic-seg/Dockerfile +++ b/handlers/svg-semantic-seg/Dockerfile @@ -11,6 +11,7 @@ COPY /handlers/svg-semantic-seg/requirements.txt /usr/src/app/requirements.txt RUN pip install -r requirements.txt COPY /schemas /usr/src/app/schemas +COPY /config /app/config COPY /handlers/svg-semantic-seg/ /usr/src/app EXPOSE 80 diff --git a/handlers/svg-semantic-seg/sem_seg_svg.py b/handlers/svg-semantic-seg/sem_seg_svg.py index 5764acf13..8c53520b2 100644 --- a/handlers/svg-semantic-seg/sem_seg_svg.py +++ b/handlers/svg-semantic-seg/sem_seg_svg.py @@ -22,23 +22,32 @@ import time import drawSvg as draw import random +from config.logging_utils import configure_logging from datetime import datetime +configure_logging() + app = Flask(__name__) @app.route("/handler", methods=["POST"]) def handle(): - logging.debug("Received request") - # Load necessary schema files - with open("./schemas/definitions.json") as f: - definitions_schema = json.load(f) - with open("./schemas/request.schema.json") as f: - request_schema = json.load(f) - with open("./schemas/handler-response.schema.json") as f: - response_schema = json.load(f) - with open("./schemas/renderers/svglayers.schema.json") as f: - renderer_schema = json.load(f) + try: + logging.debug("Received request") + # Load necessary schema files + with open("./schemas/definitions.json") as f: + definitions_schema = json.load(f) + with open("./schemas/request.schema.json") as f: + request_schema = json.load(f) + with open("./schemas/handler-response.schema.json") as f: + response_schema = json.load(f) + with open("./schemas/renderers/svglayers.schema.json") as f: + renderer_schema = json.load(f) + except Exception as e: + logging.error("Error loading schema files") + logging.pii(f"Schema loading error: {e}") + return jsonify("Schema files could not be loaded"), 500 + store = { definitions_schema["$id"]: definitions_schema, request_schema["$id"]: request_schema, @@ -56,7 +65,8 @@ def handle(): ) validator.validate(contents) except ValidationError as e: - logging.error(e) + logging.error("Validation error in request schema") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid request received!"), 400 # Check preprocessor data @@ -77,7 +87,7 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.pii(f"Renderer validation error: {error}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -96,7 +106,7 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.pii(f"Preprocessor validation error: {error}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -118,7 +128,7 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.pii(f"Preprocessor validation error: {error}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -177,9 +187,10 @@ def handle(): ) validator.validate(data) except ValidationError as e: - logging.error(e) logging.error("Failed to validate the response renderer!") + logging.pii(f"Renderer validation error: {e}") return jsonify("Failed to validate the response renderer"), 500 + response = { "request_uuid": contents["request_uuid"], "timestamp": int(time.time()), @@ -191,9 +202,10 @@ def handle(): ) validator.validate(response) except ValidationError as e: - logging.error("Failed to generate a valid response") - logging.error(e) - return jsonify("Failed to generate a valid response"), 500 + logging.debug("Failed to generate a valid response") + logging.pii(f"Response validation error: {e}") + return jsonify("Failed to generate a valid response"), 500\ + logging.debug("Sending response") return response diff --git a/handlers/text-followup-handler/Dockerfile b/handlers/text-followup-handler/Dockerfile index ac89d1300..a020b9cd5 100644 --- a/handlers/text-followup-handler/Dockerfile +++ b/handlers/text-followup-handler/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.13 -RUN apt-get install libcairo2 +RUN apt-get update && apt-get install -y libcairo2 curl && rm -rf /var/lib/apt/lists/* RUN adduser --disabled-password python WORKDIR /usr/src/app @@ -11,8 +11,13 @@ COPY /handlers/text-followup-handler/requirements.txt /usr/src/app/requirements. RUN pip install -r requirements.txt COPY /schemas /usr/src/app/schemas +COPY /config /usr/src/app/config COPY /handlers/text-followup-handler/ /usr/src/app EXPOSE 80 USER python + +HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ + CMD curl -f http://localhost:80/health || exit 1 + CMD ["gunicorn", "followup:app", "-b", "0.0.0.0:80", "--capture-output", "--log-level=debug" ] diff --git a/handlers/text-followup-handler/followup.py b/handlers/text-followup-handler/followup.py index 0ed181b62..9eb535de9 100644 --- a/handlers/text-followup-handler/followup.py +++ b/handlers/text-followup-handler/followup.py @@ -20,6 +20,10 @@ from jsonschema.exceptions import ValidationError import logging import time +from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -27,16 +31,20 @@ @app.route("/handler", methods=["POST"]) def handle(): - logging.debug("Received request") - # Load necessary schema files - with open("./schemas/definitions.json") as f: - definitions_schema = json.load(f) - with open("./schemas/request.schema.json") as f: - request_schema = json.load(f) - with open("./schemas/handler-response.schema.json") as f: - response_schema = json.load(f) - with open("./schemas/renderers/text.schema.json") as f: - renderer_schema = json.load(f) + try: + # Load necessary schema files + with open("./schemas/definitions.json") as f: + definitions_schema = json.load(f) + with open("./schemas/request.schema.json") as f: + request_schema = json.load(f) + with open("./schemas/handler-response.schema.json") as f: + response_schema = json.load(f) + with open("./schemas/renderers/text.schema.json") as f: + renderer_schema = json.load(f) + except Exception as e: + logging.error("Error loading schema files") + logging.pii(f"Schema loading error: {e}") + return jsonify("Schema files could not be loaded"), 500 store = { definitions_schema["$id"]: definitions_schema, @@ -56,7 +64,8 @@ def handle(): ) validator.validate(contents) except ValidationError as e: - logging.error(e) + logging.error("Request validation failed") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid request received!"), 400 preprocessors = contents['preprocessors'] @@ -74,7 +83,8 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response schema validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -95,7 +105,9 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed for \ + missing text-followup") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -121,7 +133,9 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed for \ + missing graphic/dimensions") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -140,7 +154,9 @@ def handle(): response_schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Response validation failed for \ + missing follow-up query") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -160,8 +176,8 @@ def handle(): ) validator.validate(data) except ValidationError as e: - logging.error(e) - logging.debug("Failed to validate the response renderer!") + logging.error("Renderer validation failed") + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to validate the response renderer"), 500 response = { "request_uuid": contents["request_uuid"], @@ -175,11 +191,22 @@ def handle(): validator.validate(response) except ValidationError as e: logging.debug("Failed to generate a valid response") - logging.error(e) + logging.pii(f"Validation error: {e.message}") return jsonify("Failed to generate a valid response"), 500 logging.debug("Sending response") return response +@app.route("/health", methods=["GET"]) +def health(): + """ + Health check endpoint to verify if the service is running + """ + return jsonify({ + "status": "healthy", + "timestamp": datetime.now().isoformat() + }), 200 + + if __name__ == "__main__": app.run(host="0.0.0.0", port=80, debug=True) diff --git a/orchestrator/Dockerfile b/orchestrator/Dockerfile index fad1888c8..21c0f1cd1 100644 --- a/orchestrator/Dockerfile +++ b/orchestrator/Dockerfile @@ -10,7 +10,7 @@ RUN npm run build && npm prune --production FROM node:alpine AS final -RUN apk add memcached supercronic curl +RUN apk add memcached supercronic # Set up for logging WORKDIR /var/log/IMAGE @@ -29,7 +29,4 @@ ENV NODE_ENV=production EXPOSE 8080 USER node - -HEALTHCHECK --interval=60s --timeout=10s --start-period=120s --retries=5 CMD curl -f http://localhost:8080/health || exit 1 - CMD supercronic -quiet clean-cron & node dist/server.js diff --git a/orchestrator/src/server.ts b/orchestrator/src/server.ts index 7f6f067c6..5efe98c5a 100644 --- a/orchestrator/src/server.ts +++ b/orchestrator/src/server.ts @@ -167,38 +167,23 @@ async function runPreprocessorsParallel(data: Record, preproces data["preprocessors"] = {}; } let currentPriorityGroup: number | undefined = undefined; - const queue: (string | number)[][] = []; //Microservice queue for preprocessors and handlers - - - //function that dequeues everything in the queue at once, executes them and waits for them to finish processing - const processQueue = async (): Promise => { - try { - await Promise.all(queue.map(preprocessor => executePreprocessor(preprocessor, data))); - } catch (error) { - console.error(`One or more of the promises failed at priority group ${currentPriorityGroup}.`, error); - } - finally { //empty the queue - queue.length = 0; - } - }; + let promises: Promise[] = []; // array to hold promises for preprocessor executions within the current priority group for (const preprocessor of preprocessors) { - //If the priority group changes, process the queue and move to the next group + // check if priority group changes - if so, wait for the current promises to finish if (preprocessor[2] !== currentPriorityGroup) { - if (queue.length > 0) { - await processQueue(); //Process everything in the queue + if (promises.length > 0) { + await Promise.all(promises); // wait for all preprocessors in the current group + promises = []; // reset promises for the new priority group } currentPriorityGroup = Number(preprocessor[2]); console.debug(`Now on priority group ${currentPriorityGroup}`); } - - //Add the preprocessor to the queue - queue.push(preprocessor); + // add the execution of the current preprocessor to the promises array + promises.push(executePreprocessor(preprocessor, data)); } - - //Process any remaining items in the queue - if (queue.length > 0) { - await processQueue(); + if (promises.length > 0) { + await Promise.all(promises); // wait for remaining promises } return data; @@ -477,11 +462,6 @@ app.get("/authenticate/:uuid/:check", async (req, res) => { } }); -// Healthcheck endpoint -app.get('/health', (req, res) => { - res.status(200).json({ status: 'healthy', timestamp: new Date().toISOString() }); -}); - app.listen(port, () => { console.log(`Started server on port ${port}`); }); diff --git a/preprocessors/action-recognition/Dockerfile b/preprocessors/action-recognition/Dockerfile index 65f541f2b..b9c137ad9 100644 --- a/preprocessors/action-recognition/Dockerfile +++ b/preprocessors/action-recognition/Dockerfile @@ -22,6 +22,7 @@ RUN pip3 install --no-cache-dir --upgrade pip && \ pip3 install --no-cache-dir -r /app/requirements.txt COPY --chown=python:python /schemas /app/schemas +COPY --chown=python:python /config /app/config COPY --chown=python:python /preprocessors/action-recognition /app EXPOSE 5000 diff --git a/preprocessors/action-recognition/action-recognition.py b/preprocessors/action-recognition/action-recognition.py index 29c27bab8..ac5bed1d8 100644 --- a/preprocessors/action-recognition/action-recognition.py +++ b/preprocessors/action-recognition/action-recognition.py @@ -30,6 +30,9 @@ from datetime import datetime from utils import detect, Classifier +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) @@ -86,7 +89,8 @@ def run(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for input request") + logging.pii(f"Validation error: {e.message} | Data: {content}") return jsonify("Invalid Preprocessor JSON format"), 400 logging.info("Schemas validated") @@ -116,8 +120,9 @@ def run(): try: MODEL = MODEL.to("cuda") except Exception as e: - logging.error("Error while loading model on GPU: {}".format(e)) - return jsonify("Error while loading model on GPU"), 500 + logging.error("Failed to load model on GPU") + logging.pii(f"GPU loading error: {e}") + return jsonify("Error loading model on GPU"), 500 if len(people) == 1: # don't crop if only one person detected @@ -159,8 +164,9 @@ def run(): MODEL.to("cpu") except Exception as e: - logging.error(f"Error while predicting actions: {e}") - return jsonify("Error while predicting actions"), 500 + logging.error("Error during action prediction") + logging.pii(f"Prediction error: {e}") + return jsonify("Error during action prediction"), 500 final = {"actions": data} logging.info("Validating results schema") @@ -168,7 +174,8 @@ def run(): validator = jsonschema.Draft7Validator(data_schema) validator.validate(final) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for action results") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 response = { "request_uuid": request_uuid, @@ -182,7 +189,8 @@ def run(): resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for preprocessor response") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.info("Schema validated") logging.info("Returning response") diff --git a/preprocessors/autour/Dockerfile b/preprocessors/autour/Dockerfile index 5c55891e9..a79f1c6bb 100644 --- a/preprocessors/autour/Dockerfile +++ b/preprocessors/autour/Dockerfile @@ -10,6 +10,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/autour/ /app EXPOSE 5000 diff --git a/preprocessors/autour/autour.py b/preprocessors/autour/autour.py index ac5518f52..33b8a8656 100644 --- a/preprocessors/autour/autour.py +++ b/preprocessors/autour/autour.py @@ -22,6 +22,9 @@ import requests from flask import Flask, request, jsonify from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -91,7 +94,13 @@ def get_map_data(): api_request = ''.join(api_request.split()) - response = requests.get(api_request).json() + try: + response = requests.get(api_request).json() + except Exception as e: + logging.error("Failed to fetch data from Autour API") + logging.pii(f"Error: {e}") + return jsonify("Failed to fetch data from Autour API"), 500 + results = response['results'] name = 'ca.mcgill.a11y.image.preprocessor.autour' @@ -157,7 +166,8 @@ def validate(schema, data, resolver, json_message, error_code): validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(data) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Validation error occurred") + logging.pii(f"Validation error: {error.message}") return jsonify(json_message), error_code return None @@ -189,6 +199,8 @@ def get_coordinates(content): place_response = requests.get(request).json() if not check_google_response(place_response): + logging.error("Failed to retrieve valid response from Google API") + logging.pii(f"Google API response: {place_response}") return None location = place_response['results'][0]['geometry']['location'] @@ -213,7 +225,7 @@ def check_google_response(place_response): """ if 'results' not in place_response or len(place_response['results']) == 0: logging.error("No results found for placeID") - logging.error(place_response) + logging.pii(f"Google API response: {place_response}") return False results = place_response['results'][0] diff --git a/preprocessors/celebrity-detector/Dockerfile b/preprocessors/celebrity-detector/Dockerfile index ea467b85b..2aed4ef6c 100644 --- a/preprocessors/celebrity-detector/Dockerfile +++ b/preprocessors/celebrity-detector/Dockerfile @@ -12,6 +12,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/celebrity-detector /app EXPOSE 5000 diff --git a/preprocessors/clothes-detector/Dockerfile b/preprocessors/clothes-detector/Dockerfile index ae8c19633..84baf0750 100644 --- a/preprocessors/clothes-detector/Dockerfile +++ b/preprocessors/clothes-detector/Dockerfile @@ -5,10 +5,6 @@ FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-runtime ENV DEBIAN_FRONTEND=noninteractive -ENV DEBIAN_FRONTEND=noninteractive - -ENV DEBIAN_FRONTEND=noninteractive - RUN adduser --disabled-password python WORKDIR /app ENV PATH="/home/python/.local/bin:${PATH}" @@ -29,7 +25,7 @@ RUN pip3 install --upgrade pip && \ # COPY ./requirements.txt /app/requirements.txt COPY /schemas /app/schemas -# COPY ./schemas /app/schemas +COPY /config /app/config # good practice to remove the archive RUN wget https://image.a11y.mcgill.ca/models/clothesDetector/yolo.zip && \ @@ -37,7 +33,6 @@ RUN wget https://image.a11y.mcgill.ca/models/clothesDetector/yolo.zip && \ rm yolo.zip COPY /preprocessors/clothes-detector /app -# COPY ./ /app EXPOSE 5000 ENV FLASK_APP=clothes.py diff --git a/preprocessors/collage-detector/Dockerfile b/preprocessors/collage-detector/Dockerfile index 36a66603d..6dccf794c 100644 --- a/preprocessors/collage-detector/Dockerfile +++ b/preprocessors/collage-detector/Dockerfile @@ -11,6 +11,7 @@ RUN pip3 install --upgrade pip && \ pip install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/collage-detector/ /app EXPOSE 5000 diff --git a/preprocessors/collage-detector/detect.py b/preprocessors/collage-detector/detect.py index 01e1d650f..0200a5fba 100644 --- a/preprocessors/collage-detector/detect.py +++ b/preprocessors/collage-detector/detect.py @@ -24,6 +24,9 @@ import logging import time from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -54,9 +57,11 @@ def detect_collage(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 400 - # check for image + + # check for image if "graphic" not in content: logging.info("Request is not a graphic. Skipping...") return "", 204 # No content @@ -79,8 +84,10 @@ def detect_collage(): validator = jsonschema.Draft7Validator(data_schema) validator.validate(type) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for model output") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 + response = { "request_uuid": request_uuid, "timestamp": int(timestamp), @@ -91,8 +98,10 @@ def detect_collage(): validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for response") + logging.pii(f"Validation error: {e.message} | Response: {response}") return jsonify("Invalid Preprocessor JSON format"), 500 + logging.debug(type) return response diff --git a/preprocessors/content-categoriser/Dockerfile b/preprocessors/content-categoriser/Dockerfile index 25038fc60..50b242f71 100644 --- a/preprocessors/content-categoriser/Dockerfile +++ b/preprocessors/content-categoriser/Dockerfile @@ -11,6 +11,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/content-categoriser/ /app EXPOSE 5000 diff --git a/preprocessors/content-categoriser/categoriser.py b/preprocessors/content-categoriser/categoriser.py index 5e2590480..0796873d7 100644 --- a/preprocessors/content-categoriser/categoriser.py +++ b/preprocessors/content-categoriser/categoriser.py @@ -55,7 +55,8 @@ def categorise(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 400 # check we received a graphic (e.g., not a map or chart request) @@ -153,7 +154,8 @@ def categorise(): validator = jsonschema.Draft7Validator(data_schema) validator.validate(graphic_category_json) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for categorizer response") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 # create full response & check meets overall preprocessor response schema @@ -167,7 +169,8 @@ def categorise(): validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for final response") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 # all done. give final category information and return to orchestrator diff --git a/preprocessors/depth-map-gen/Dockerfile b/preprocessors/depth-map-gen/Dockerfile index 1c9cb300f..cc6314a05 100644 --- a/preprocessors/depth-map-gen/Dockerfile +++ b/preprocessors/depth-map-gen/Dockerfile @@ -21,6 +21,7 @@ RUN pip3 install --upgrade pip && \ #schema COPY /schemas /app/schemas +COPY /config /app/config #model download, app code RUN git clone https://github.com/aim-uofa/AdelaiDepth && \ diff --git a/preprocessors/depth-map-gen/depth-map-generator.py b/preprocessors/depth-map-gen/depth-map-generator.py index df709af1d..eff12c28d 100644 --- a/preprocessors/depth-map-gen/depth-map-generator.py +++ b/preprocessors/depth-map-gen/depth-map-generator.py @@ -31,6 +31,9 @@ import base64 from lib.multi_depth_model_woauxi import RelDepthModel from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -108,8 +111,10 @@ def depthgenerator(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 400 + # check content category from contentCategoriser preprocess_output = content.get("preprocessors", {}) classifier_1 = "ca.mcgill.a11y.image.preprocessor.contentCategoriser" @@ -146,12 +151,18 @@ def depthgenerator(): depth_model.eval() # load checkpoint - checkpoint = torch.load("/app/res101.pth") - depth_model.load_state_dict(strip_prefix_if_present( - checkpoint['depth_model'], "module."), - strict=True) - del checkpoint - torch.cuda.empty_cache() + try: + checkpoint = torch.load("/app/res101.pth") + depth_model.load_state_dict(strip_prefix_if_present( + checkpoint['depth_model'], "module."), + strict=True) + except Exception as e: + logging.error("Error loading model checkpoint") + logging.pii(f"Checkpoint load error: {e}") + return jsonify("Depth Model cannot complete"), 500 + finally: + del checkpoint + torch.cuda.empty_cache() depth_model.cuda() @@ -170,15 +181,18 @@ def depthgenerator(): jsondepth = "data:image/jpeg;base64," + depthgraphic depth = {"depth-map": jsondepth, "scaling": 0} except Exception as e: - logging.error(e) + logging.error("Depth model inference error") + logging.pii(f"Inference error: {e}") return jsonify("Depth Model cannot complete"), 500 try: validator = jsonschema.Draft7Validator(data_schema) validator.validate(depth) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for depth data") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 + response = { "request_uuid": request_uuid, "timestamp": int(timestamp), @@ -189,8 +203,10 @@ def depthgenerator(): validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for final response") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 + torch.cuda.empty_cache() logging.debug("Sending response") return response diff --git a/preprocessors/graphic-caption/Dockerfile b/preprocessors/graphic-caption/Dockerfile index bfab05fc6..a55fc9f20 100644 --- a/preprocessors/graphic-caption/Dockerfile +++ b/preprocessors/graphic-caption/Dockerfile @@ -10,6 +10,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/graphic-caption/ /app EXPOSE 5000 diff --git a/preprocessors/graphic-caption/caption.py b/preprocessors/graphic-caption/caption.py index 616a42070..46c4c3b1d 100644 --- a/preprocessors/graphic-caption/caption.py +++ b/preprocessors/graphic-caption/caption.py @@ -22,6 +22,9 @@ import logging import os from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -55,7 +58,8 @@ def categorise(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 400 # check we received a graphic (e.g., not a map or chart request) @@ -125,9 +129,8 @@ def categorise(): validator = jsonschema.Draft7Validator(data_schema) validator.validate(graphic_caption_json) except jsonschema.exceptions.ValidationError as e: - logging.error(f"JSON schema validation fail: {e.validator} {e.schema}") - # TODO: add back next line once IMAGE-server #941 is complete - # logging.debug(e) # print full error only in debug, due to PII + logging.error("Validation failed for graphic caption data") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 # create full response & check meets overall preprocessor response schema @@ -141,9 +144,8 @@ def categorise(): validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(f"JSON schema validation fail: {e.validator} {e.schema}") - # TODO: add back next line once IMAGE-server #912 is complete - # logging.debug(e) # print full error only in debug, due to PII + logging.error("Validation failed for final response") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 # all done; return to orchestrator diff --git a/preprocessors/graphic-tagger/Dockerfile b/preprocessors/graphic-tagger/Dockerfile index c4ba0500f..7ed71a056 100644 --- a/preprocessors/graphic-tagger/Dockerfile +++ b/preprocessors/graphic-tagger/Dockerfile @@ -11,6 +11,7 @@ RUN pip3 install --upgrade pip && \ pip install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/graphic-tagger /app EXPOSE 5000 diff --git a/preprocessors/graphic-tagger/azure_api.py b/preprocessors/graphic-tagger/azure_api.py index 7fdb86219..1165d2bfd 100644 --- a/preprocessors/graphic-tagger/azure_api.py +++ b/preprocessors/graphic-tagger/azure_api.py @@ -27,6 +27,9 @@ import os from flask import Flask, request, jsonify from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -58,7 +61,8 @@ def process_image(image, labels): try: api_key = os.environ["AZURE_API_KEY"] except Exception as e: - logging.error(e) + logging.error("Azure API key not found") + logging.pii(f"Environment error: {e}") return "", 500 # Set request headers @@ -99,6 +103,9 @@ def process_image(image, labels): return "Azure response not in json format", 500 else: + logging.error(f"Azure API error with status code" + f"{response.status_code}") + logging.pii(f"Azure API error response: {response.text}") return response.status_code return label @@ -131,8 +138,10 @@ def categorise(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 400 + request_uuid = content["request_uuid"] timestamp = time.time() name = "ca.mcgill.a11y.image.preprocessor.graphicTagger" @@ -172,7 +181,8 @@ def categorise(): validator = jsonschema.Draft7Validator(data_schema) validator.validate(type) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for graphic tagger result") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 response = { "request_uuid": request_uuid, @@ -186,8 +196,10 @@ def categorise(): resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for final response") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 + logging.debug(type) return response diff --git a/preprocessors/grouping/Dockerfile b/preprocessors/grouping/Dockerfile index c27846376..a43720de3 100644 --- a/preprocessors/grouping/Dockerfile +++ b/preprocessors/grouping/Dockerfile @@ -10,6 +10,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/grouping/ /app EXPOSE 5000 diff --git a/preprocessors/grouping/grouping.py b/preprocessors/grouping/grouping.py index a1f2c9c91..7d04b807c 100644 --- a/preprocessors/grouping/grouping.py +++ b/preprocessors/grouping/grouping.py @@ -22,11 +22,12 @@ import collections from math import sqrt from operator import itemgetter +from config.logging_utils import configure_logging from datetime import datetime +configure_logging() app = Flask(__name__) -logging.basicConfig(level=logging.DEBUG) def calculate_diagonal(x1, y1, x2, y2): @@ -38,7 +39,7 @@ def calculate_diagonal(x1, y1, x2, y2): @app.route("/preprocessor", methods=['POST', 'GET']) def readImage(): - logging.debug("Received request") + logging.pii("Received request") object_type = [] dimensions = [] ungrouped = [] @@ -60,12 +61,15 @@ def readImage(): resolver = jsonschema.RefResolver.from_schema( schema, store=schema_store) content = request.get_json() + try: validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message} | Data: {content}") return jsonify("Invalid Preprocessor JSON format"), 400 + preprocessor = content["preprocessors"] if "ca.mcgill.a11y.image.preprocessor.objectDetection" \ not in preprocessor: @@ -75,6 +79,7 @@ def readImage(): oDpreprocessor = \ preprocessor["ca.mcgill.a11y.image.preprocessor.objectDetection"] objects = oDpreprocessor["objects"] + for i in range(len(objects)): object_type.append(objects[i]["type"]) dimensions.append(objects[i]["dimensions"]) @@ -113,12 +118,15 @@ def readImage(): logging.debug("Number of groups " + str(len(final_group))) logging.debug("Number of ungrouped objects " + str(len(ungrouped))) data = {"grouped": final_group, "ungrouped": ungrouped} + try: validator = jsonschema.Draft7Validator(data_schema) validator.validate(data) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for grouped data") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 + response = { "title": "Grouping Data", "description": "Grouped data for objects", @@ -127,13 +135,15 @@ def readImage(): "name": name, "data": data } + try: validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for response schema") + logging.pii(f"Validation error: {e.message} | Response: {response}") return jsonify("Invalid Preprocessor JSON format"), 500 - logging.debug("Sending response") + return response diff --git a/preprocessors/hello-preprocessor/Dockerfile b/preprocessors/hello-preprocessor/Dockerfile index a07f8edd1..c1bebd928 100644 --- a/preprocessors/hello-preprocessor/Dockerfile +++ b/preprocessors/hello-preprocessor/Dockerfile @@ -9,6 +9,7 @@ WORKDIR /usr/src/app COPY /preprocessors/hello-preprocessor/package*.json ./ RUN npm ci COPY /schemas src/schemas +COPY /config /app/config COPY /preprocessors/hello-preprocessor/ . RUN npm run build diff --git a/preprocessors/line-charts/Dockerfile b/preprocessors/line-charts/Dockerfile index 33502e65a..6d916110c 100644 --- a/preprocessors/line-charts/Dockerfile +++ b/preprocessors/line-charts/Dockerfile @@ -13,6 +13,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/line-charts/ /app EXPOSE 5000 diff --git a/preprocessors/line-charts/charts.py b/preprocessors/line-charts/charts.py index e0d26c561..ba26a4e3b 100644 --- a/preprocessors/line-charts/charts.py +++ b/preprocessors/line-charts/charts.py @@ -20,11 +20,14 @@ import logging import jsonschema from flask import Flask, request, jsonify +from config.logging_utils import configure_logging from charts_utils import getLowerPointsOnLeft, getHigherPointsOnLeft from charts_utils import getLowerPointsOnRight, getHigherPointsOnRight from datetime import datetime +configure_logging() + app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -67,7 +70,8 @@ def get_chart_info(): ) validator.validate(content) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Request JSON format"), 400 # Use response schema to validate response resolver = jsonschema.RefResolver.from_schema( @@ -108,7 +112,8 @@ def get_chart_info(): validator = jsonschema.Draft7Validator(data_schema, resolver=resolver) validator.validate(data) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Validation failed for proccessed data") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 response = { @@ -122,7 +127,8 @@ def get_chart_info(): validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Validation failed for response") + logging.pii(f"Validation error: {error.message} | {response}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") diff --git a/preprocessors/mmsemseg/Dockerfile b/preprocessors/mmsemseg/Dockerfile index 7c17ecb0e..3908b3e4f 100644 --- a/preprocessors/mmsemseg/Dockerfile +++ b/preprocessors/mmsemseg/Dockerfile @@ -42,6 +42,7 @@ RUN pip install --upgrade pip && \ pip install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/mmsemseg/ /app # Download the model checkpoint diff --git a/preprocessors/mmsemseg/segment.py b/preprocessors/mmsemseg/segment.py index 8290193c0..034f5ba44 100644 --- a/preprocessors/mmsemseg/segment.py +++ b/preprocessors/mmsemseg/segment.py @@ -34,8 +34,10 @@ from time import time import logging +from config.logging_utils import configure_logging from datetime import datetime +configure_logging() # configuration and checkpoint files BEIT_CONFIG = "/app/config/upernet_beit-base_8x2_640x640_160k_ade20k.py" BEIT_CHECKPOINT = "/app/upernet_beit-base_8x2_640x640_160k_ade20k-eead221d.pth" @@ -54,22 +56,24 @@ def run_segmentation(url, model, dictionary): # https://gist.github.com/daino3/b671b2d171b3948692887e4c484caf47 logging.info("converting base64 to numpy array") - image_b64 = url.split(",")[1] - binary = base64.b64decode(image_b64) - image = np.asarray(bytearray(binary), dtype="uint8") - image_np = cv2.imdecode(image, cv2.IMREAD_COLOR) + try: + image_b64 = url.split(",")[1] + binary = base64.b64decode(image_b64) + image = np.asarray(bytearray(binary), dtype="uint8") + image_np = cv2.imdecode(image, cv2.IMREAD_COLOR) + except Exception as e: + logging.error("Error decoding base64 image: {}".format(e)) + raise e # rescale the image height, width, channels = image_np.shape scale_factor = float(1500.0 / float(max(height, width))) - logging.info("graphic oiginal dimension {}".format(image_np.shape)) + logging.info("graphic original dimension {}".format(image_np.shape)) if scale_factor <= 1.0: logging.info("scaling down an image") - image_np = mmcv.imrescale(image_np, scale_factor) - logging.info("graphic scaled dimension: {}".format(image_np.shape)) height, width, channels = image_np.shape @@ -153,7 +157,8 @@ def segment(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(request_json) except jsonschema.exceptions.ValidationError as e: - logging.error(f"Request validation error: {e.message}") + logging.error("Request validation failed") + logging.pii(f"Validation error: {e.message} | Data: {request_json}") return jsonify("Invalid Preprocessor JSON format"), 400 if "graphic" not in request_json: @@ -189,7 +194,8 @@ def segment(): try: segment = run_segmentation( request_json["graphic"], model, dictionary) - except Exception: + except Exception as e: + logging.pii(f"Segmentation error: {e}") return jsonify("Error while running segmentation"), 500 else: """We are providing the user the ability to process an image @@ -199,7 +205,8 @@ def segment(): try: segment = run_segmentation( request_json["graphic"], model, dictionary) - except Exception: + except Exception as e: + logging.pii(f"Segmentation error: {e}") return jsonify("Error while running the segmentation"), 500 else: """We are providing the user the ability to process an image @@ -209,7 +216,8 @@ def segment(): try: segment = run_segmentation( request_json["graphic"], model, dictionary) - except Exception: + except Exception as e: + logging.pii(f"Segmentation error: {e}") return jsonify("Error while running the segmentation"), 500 torch.cuda.empty_cache() @@ -219,7 +227,8 @@ def segment(): validator = jsonschema.Draft7Validator(data_schema) validator.validate(segment) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Data validation failed") + logging.pii(f"Validation error: {e.message} | Data: {segment}") return jsonify("Invalid Preprocessor JSON format"), 500 response = { @@ -234,7 +243,8 @@ def segment(): validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Response validation failed") + logging.pii(f"Validation error: {e.message} | Response: {response}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.info("Valid response generated") diff --git a/preprocessors/ner/Dockerfile b/preprocessors/ner/Dockerfile index 7413b4b54..6e458acfd 100644 --- a/preprocessors/ner/Dockerfile +++ b/preprocessors/ner/Dockerfile @@ -21,6 +21,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/ner/ /app EXPOSE 5000 diff --git a/preprocessors/ner/ner.py b/preprocessors/ner/ner.py index b04cc2bef..768381010 100644 --- a/preprocessors/ner/ner.py +++ b/preprocessors/ner/ner.py @@ -24,12 +24,14 @@ import jsonschema from bs4 import BeautifulSoup from flask import Flask, request, jsonify +from config.logging_utils import configure_logging from datetime import datetime import nltk import clipscore from nltk.tag.stanford import StanfordNERTagger +configure_logging() nltk.download('punkt') app = Flask(__name__) @@ -167,7 +169,8 @@ def main(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 400 # ------ START COMPUTATION ------ # @@ -241,14 +244,16 @@ def main(): validator = jsonschema.Draft7Validator(data_schema, resolver=resolver) validator.validate(response['data']) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for response data") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 try: validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for response") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") diff --git a/preprocessors/nominatim/Dockerfile b/preprocessors/nominatim/Dockerfile index e8ac519df..8914a356b 100644 --- a/preprocessors/nominatim/Dockerfile +++ b/preprocessors/nominatim/Dockerfile @@ -1,13 +1,17 @@ -FROM node:alpine as builder +FROM node:alpine AS builder WORKDIR /usr/src/app + COPY /preprocessors/nominatim/package*.json ./ -RUN npm ci COPY /schemas src/schemas +COPY /config /usr/src/app/src/config + +RUN npm ci + COPY /preprocessors/nominatim/ /usr/src/app RUN npm run build && npm prune --production -FROM node:alpine as final +FROM node:alpine AS final RUN apk add --no-cache curl diff --git a/preprocessors/nominatim/package-lock.json b/preprocessors/nominatim/package-lock.json index 7e9185c65..2f68e7a2c 100644 --- a/preprocessors/nominatim/package-lock.json +++ b/preprocessors/nominatim/package-lock.json @@ -11,10 +11,14 @@ "dependencies": { "ajv": "^8.9.0", "express": "^4.19.2", - "uuid": "^8.3.2" + "node-fetch": "^2.7.0", + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", + "@types/node": "^22.13.1", + "@types/node-fetch": "^2.6.12", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.10.0", "@typescript-eslint/parser": "^5.10.0", @@ -31,6 +35,24 @@ "node": ">=0.10.0" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -233,10 +255,23 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.1.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.3.tgz", - "integrity": "sha512-NP2yfZpgmf2eDRPmgGq+fjGjSwFgYbihA8/gK+ey23qT9RkxsgNTZvGOEpXgzIGqesTYkElELLgtKoMQTys5vA==", - "dev": true + "version": "22.13.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz", + "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==", + "dev": true, + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } }, "node_modules/@types/qs": { "version": "6.9.7", @@ -276,6 +311,11 @@ "@types/node": "*" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", @@ -562,6 +602,17 @@ "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -569,9 +620,9 @@ "dev": true }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -581,7 +632,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -634,16 +685,25 @@ "node": ">= 0.8" } }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", "dependencies": { - "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -677,6 +737,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -692,8 +761,50 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -721,9 +832,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -734,9 +845,9 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -770,20 +881,13 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.4.0" } }, "node_modules/depd": { @@ -827,26 +931,41 @@ "node": ">=6.0.0" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "engines": { "node": ">= 0.4" } @@ -859,6 +978,17 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1091,36 +1221,36 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1129,6 +1259,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/debug": { @@ -1198,6 +1332,11 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1223,12 +1362,12 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1287,6 +1426,25 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1318,15 +1476,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -1335,6 +1498,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -1403,11 +1578,11 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1428,32 +1603,10 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "engines": { "node": ">= 0.4" }, @@ -1555,6 +1708,11 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1594,6 +1752,17 @@ "node": ">=8" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1633,6 +1802,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1667,6 +1841,22 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1679,6 +1869,14 @@ "node": ">=10" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1688,9 +1886,12 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge2": { "version": "1.4.1", @@ -1710,12 +1911,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -1767,8 +1968,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -1790,10 +1990,32 @@ "node": ">= 0.6" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1818,6 +2040,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -1913,9 +2143,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/path-type": { "version": "4.0.0", @@ -1968,11 +2198,11 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -2023,6 +2253,19 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -2107,6 +2350,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2128,9 +2379,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -2163,41 +2414,33 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -2225,14 +2468,15 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2241,6 +2485,64 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -2250,6 +2552,14 @@ "node": ">=8" } }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2258,6 +2568,14 @@ "node": ">= 0.8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -2294,6 +2612,11 @@ "node": ">=8" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2320,6 +2643,19 @@ "node": ">=0.6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -2390,6 +2726,12 @@ "node": ">=4.2.0" } }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -2406,6 +2748,11 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2430,6 +2777,20 @@ "node": ">= 0.8" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2445,6 +2806,40 @@ "node": ">= 8" } }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/preprocessors/nominatim/package.json b/preprocessors/nominatim/package.json index a1efe1f85..816c742b9 100644 --- a/preprocessors/nominatim/package.json +++ b/preprocessors/nominatim/package.json @@ -13,10 +13,14 @@ "dependencies": { "ajv": "^8.9.0", "express": "^4.19.2", - "uuid": "^8.3.2" + "node-fetch": "^2.7.0", + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", + "@types/node": "^22.13.1", + "@types/node-fetch": "^2.6.12", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.10.0", "@typescript-eslint/parser": "^5.10.0", diff --git a/preprocessors/nominatim/src/server.ts b/preprocessors/nominatim/src/server.ts index 435ca5f1e..cec1ca12d 100644 --- a/preprocessors/nominatim/src/server.ts +++ b/preprocessors/nominatim/src/server.ts @@ -16,7 +16,9 @@ */ import Ajv from "ajv"; -import express, { Request, Response } from "express"; +import express from "express"; +import { piiLogger } from "./config/logging_utils"; + import querySchemaJSON from "./schemas/request.schema.json"; import preprocessorResponseJSON from "./schemas/preprocessor-response.schema.json"; import definitionsJSON from "./schemas/definitions.json"; @@ -36,6 +38,7 @@ app.post("/preprocessor", async (req, res) => { // Validate the request data if (!ajv.validate("https://image.a11y.mcgill.ca/request.schema.json", req.body)) { console.warn("Request did not pass the schema!"); + piiLogger.pii(`Validation error: ${JSON.stringify(ajv.errors)}`); res.status(400).json(ajv.errors); return; } @@ -75,15 +78,17 @@ app.post("/preprocessor", async (req, res) => { res.json(response); } else { console.error("Nominatim preprocessor data failed validation (possibly not an object?)"); - console.error(ajv.errors); + piiLogger.pii(`Validation error: ${JSON.stringify(ajv.errors)}`); res.status(500).json(ajv.errors); } } else { console.error("Failed to generate a valid response"); + piiLogger.pii(`Validation error: ${JSON.stringify(ajv.errors)} | Response: ${JSON.stringify(response)}`); res.status(500).json(ajv.errors); } } catch (e) { - console.error(e); + console.error("Unexpected error occured."); + piiLogger.pii(`${(e as Error).message}`); res.status(500).json({"message": (e as Error).message}); } }); diff --git a/preprocessors/nominatim/tsconfig.json b/preprocessors/nominatim/tsconfig.json index e5d8bce10..2a1fd7aed 100644 --- a/preprocessors/nominatim/tsconfig.json +++ b/preprocessors/nominatim/tsconfig.json @@ -72,6 +72,7 @@ }, "include": [ "src/**/*", - "types/**/*" + "types/**/*", + "src/config/**/*" ] } diff --git a/preprocessors/object-depth-calculator/Dockerfile b/preprocessors/object-depth-calculator/Dockerfile index 78e6ee600..7ce833bbf 100644 --- a/preprocessors/object-depth-calculator/Dockerfile +++ b/preprocessors/object-depth-calculator/Dockerfile @@ -10,6 +10,7 @@ RUN pip3 install --upgrade pip && \ pip install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/object-depth-calculator/ /app EXPOSE 5000 diff --git a/preprocessors/object-depth-calculator/object-depth-calculator.py b/preprocessors/object-depth-calculator/object-depth-calculator.py index dd75486d1..f91777f2e 100644 --- a/preprocessors/object-depth-calculator/object-depth-calculator.py +++ b/preprocessors/object-depth-calculator/object-depth-calculator.py @@ -23,6 +23,9 @@ import base64 import logging from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -56,8 +59,10 @@ def objectdepth(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 400 + # check for depth-map if ("ca.mcgill.a11y.image.preprocessor.depth-map-gen" not in content["preprocessors"]): @@ -88,7 +93,8 @@ def objectdepth(): schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Validation failed for response without dimensions") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response @@ -144,7 +150,8 @@ def objectdepth(): validator = jsonschema.Draft7Validator(data_schema) validator.validate(obj_depth_output) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for object depth output") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 response = { "request_uuid": request_uuid, @@ -156,9 +163,9 @@ def objectdepth(): validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for final response") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 - logging.debug("Sending response") return response diff --git a/preprocessors/object-detection-azure/Dockerfile b/preprocessors/object-detection-azure/Dockerfile index fdfe3e537..badfdaa5c 100644 --- a/preprocessors/object-detection-azure/Dockerfile +++ b/preprocessors/object-detection-azure/Dockerfile @@ -13,6 +13,7 @@ RUN pip3 install --upgrade pip && \ pip install -r /app/requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/object-detection-azure /app EXPOSE 5000 diff --git a/preprocessors/object-detection-azure/objdetect.py b/preprocessors/object-detection-azure/objdetect.py index 9f864a6f0..463762aa9 100644 --- a/preprocessors/object-detection-azure/objdetect.py +++ b/preprocessors/object-detection-azure/objdetect.py @@ -24,6 +24,9 @@ import os from flask import Flask, request, jsonify from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -78,7 +81,8 @@ def process_image(image): try: api_key = os.environ["AZURE_API_KEY"] except Exception as e: - logging.error(e) + logging.error("Azure API key is missing") + logging.pii(f"Error: {e}") return "", 500 # Set request headers @@ -136,7 +140,8 @@ def categorise(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 400 request_uuid = content["request_uuid"] timestamp = time.time() @@ -177,7 +182,8 @@ def categorise(): validator = jsonschema.Draft7Validator(data_schema) validator.validate(type) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for processed image data") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 response = { "request_uuid": request_uuid, @@ -191,7 +197,8 @@ def categorise(): resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for final response") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") return response diff --git a/preprocessors/ocr/Dockerfile b/preprocessors/ocr/Dockerfile index 43e7622ee..3743ce402 100644 --- a/preprocessors/ocr/Dockerfile +++ b/preprocessors/ocr/Dockerfile @@ -10,6 +10,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/ocr/ /app EXPOSE 5000 diff --git a/preprocessors/ocr/ocr.py b/preprocessors/ocr/ocr.py index 4e48ff3b9..661db644b 100644 --- a/preprocessors/ocr/ocr.py +++ b/preprocessors/ocr/ocr.py @@ -32,6 +32,9 @@ find_obj_enclosing, process_azure_read_v4_preview ) +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -75,7 +78,8 @@ def get_ocr_text(): ) validator.validate(content) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Request JSON format"), 400 # Use response schema to validate response resolver = jsonschema.RefResolver.from_schema( @@ -105,7 +109,8 @@ def get_ocr_text(): validator = jsonschema.Draft7Validator(data_schema, resolver=resolver) validator.validate(data) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Validation failed for processed OCR data") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 response = { @@ -119,7 +124,8 @@ def get_ocr_text(): validator = jsonschema.Draft7Validator(schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Validation failed for final response") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Sending response") @@ -136,20 +142,25 @@ def analyze_image(source, width, height, cld_srv_optn): binary = base64.b64decode(image_b64) stream = io.BytesIO(binary) - if cld_srv_optn == "AZURE_READ": - return process_azure_read(stream, width, height) + try: + if cld_srv_optn == "AZURE_READ": + return process_azure_read(stream, width, height) - elif cld_srv_optn == "AZURE_READ_v4_PREVIEW": - return process_azure_read_v4_preview(stream, width, height) + elif cld_srv_optn == "AZURE_READ_v4_PREVIEW": + return process_azure_read_v4_preview(stream, width, height) - elif cld_srv_optn == "AZURE_OCR": - return process_azure_ocr(stream, width, height) + elif cld_srv_optn == "AZURE_OCR": + return process_azure_ocr(stream, width, height) - elif cld_srv_optn == "FREE_OCR": - return process_free_ocr(source, width, height) + elif cld_srv_optn == "FREE_OCR": + return process_free_ocr(source, width, height) - elif cld_srv_optn == "GOOGLE_VISION": - return process_google_vision(image_b64, width, height) + elif cld_srv_optn == "GOOGLE_VISION": + return process_google_vision(image_b64, width, height) + except Exception as e: + logging.error("Error during OCR analysis") + logging.pii(f"OCR analysis error: {e}") + return None @app.route("/health", methods=["GET"]) diff --git a/preprocessors/ocr/ocr_utils.py b/preprocessors/ocr/ocr_utils.py index ec41694e5..1891fa420 100644 --- a/preprocessors/ocr/ocr_utils.py +++ b/preprocessors/ocr/ocr_utils.py @@ -22,6 +22,9 @@ from azure.cognitiveservices.vision.computervision.models import OperationStatusCodes # noqa from msrest.authentication import CognitiveServicesCredentials from google.cloud import vision +from config.logging_utils import configure_logging + +configure_logging() # Pull key value and declare endpoint for Azure OCR API azure_subscr_key = os.environ["AZURE_API_KEY"] @@ -72,132 +75,156 @@ def process_azure_read(stream, width, height): return ocr_results else: logging.error("OCR text: {}".format(read_result.status)) + logging.pii(f"Azure Read OCR failure details: {read_result.status}") return None def process_azure_read_v4_preview(stream, width, height): - headers = { - 'Content-Type': 'application/octet-stream', - 'Ocp-Apim-Subscription-Key': azure_subscr_key, - } + try: + headers = { + 'Content-Type': 'application/octet-stream', + 'Ocp-Apim-Subscription-Key': azure_subscr_key, + } - param = "features=Read&model-version=latest&api-version=2022-10-12-preview" - ocr_url = azure_endpoint + "computervision/imageanalysis:analyze?" + param + param = \ + "features=Read&model-version=latest&api-version=2022-10-12-preview" + ocr_url = azure_endpoint + "computervision/imageanalysis:analyze?" \ + + param - response = requests.post(ocr_url, headers=headers, data=stream) - response.raise_for_status() + response = requests.post(ocr_url, headers=headers, data=stream) + response.raise_for_status() - read_result = response.json() + read_result = response.json() - # Check for success - if (len(read_result['readResult']) == 0): - logging.error("No READ response") + # Check for success + if (len(read_result['readResult']) == 0): + logging.error("No READ response") + return None + else: + ocr_results = [] + for page in read_result['readResult']['pages']: + for line in page['lines']: + line_text = line['content'] + # Get normalized bounding box for each line + bbx = line['boundingBox'] + bg_bx = [bbx[0], bbx[1], bbx[4], bbx[5]] + bounding_box = normalize_bdg_box(bg_bx, width, height) + ocr_results.append({ + 'text': line_text, + 'bounding_box': bounding_box + }) + return ocr_results + + except requests.exceptions.RequestException as e: + logging.error("Request failed for Azure Read V4") + logging.pii(f"Azure Read V4 error details: {e}") return None - else: - ocr_results = [] - for page in read_result['readResult']['pages']: - for line in page['lines']: - line_text = line['content'] - # Get normalized bounding box for each line - bbx = line['boundingBox'] - bg_bx = [bbx[0], bbx[1], bbx[4], bbx[5]] - bounding_box = normalize_bdg_box(bg_bx, width, height) - ocr_results.append({ - 'text': line_text, - 'bounding_box': bounding_box - }) - return ocr_results def process_azure_ocr(stream, width, height): - headers = { - 'Content-Type': 'application/octet-stream', - 'Ocp-Apim-Subscription-Key': azure_subscr_key, - } + try: + headers = { + 'Content-Type': 'application/octet-stream', + 'Ocp-Apim-Subscription-Key': azure_subscr_key, + } + + ocr_url = azure_endpoint + "vision/v3.2/ocr" + + response = requests.post(ocr_url, headers=headers, data=stream) + response.raise_for_status() + + read_result = response.json() - ocr_url = azure_endpoint + "vision/v3.2/ocr" - - response = requests.post(ocr_url, headers=headers, data=stream) - response.raise_for_status() - - read_result = response.json() - - ocr_results = [] - for region in read_result['regions']: - region_text = "" - for line in region['lines']: - for word in line['words']: - region_text += word['text'] + " " - region_text = region_text[:-1] - # Get normalized bounding box for each region - bb = region['boundingBox'].split(",") - maxX = float(bb[0]) + float(bb[2]) - maxY = float(bb[1]) + float(bb[3]) - bndng_bx = [float(bb[0]), float(bb[1]), maxX, maxY] - bounding_box = normalize_bdg_box(bndng_bx, width, height) - ocr_results.append({ - 'text': region_text, - 'bounding_box': bounding_box - }) - if not ocr_results: + ocr_results = [] + for region in read_result['regions']: + region_text = "" + for line in region['lines']: + for word in line['words']: + region_text += word['text'] + " " + region_text = region_text[:-1] + # Get normalized bounding box for each region + bb = region['boundingBox'].split(",") + maxX = float(bb[0]) + float(bb[2]) + maxY = float(bb[1]) + float(bb[3]) + bndng_bx = [float(bb[0]), float(bb[1]), maxX, maxY] + bounding_box = normalize_bdg_box(bndng_bx, width, height) + ocr_results.append({ + 'text': region_text, + 'bounding_box': bounding_box + }) + if not ocr_results: + return None + return ocr_results + except Exception as e: + logging.error("Error in Azure OCR") + logging.pii(f"Azure OCR error details: {e}") return None - return ocr_results def process_free_ocr(source, width, height): - payload = { - 'base64Image': source, - 'apikey': freeocr_subscription_key, - 'isOverlayRequired': True - } - response = requests.post(freeocr_endpoint, data=payload) - read_result = response.json() + try: + payload = { + 'base64Image': source, + 'apikey': freeocr_subscription_key, + 'isOverlayRequired': True + } + response = requests.post(freeocr_endpoint, data=payload) + read_result = response.json() + + # Check for success + if not read_result['ParsedResults']: + return None - # Check for success - if not read_result['ParsedResults']: + ocr_results = [] + for line in read_result['ParsedResults'][0]['TextOverlay']['Lines']: + line_text = line['LineText'] + # Get normalized bounding box for each line + maxY = line['MinTop'] + line['MaxHeight'] + maxX = line['Words'][-1]['Left'] + line['Words'][-1]['Width'] + bndng_bx = [line['Words'][0]['Left'], line['MinTop'], + maxX, maxY] + bounding_box = normalize_bdg_box(bndng_bx, width, height) + ocr_results.append({ + 'text': line_text, + 'bounding_box': bounding_box + }) + return ocr_results + except Exception as e: + logging.error("Error in Free OCR processing") + logging.pii(f"Free OCR error details: {e}") return None - ocr_results = [] - for line in read_result['ParsedResults'][0]['TextOverlay']['Lines']: - line_text = line['LineText'] - # Get normalized bounding box for each line - maxY = line['MinTop'] + line['MaxHeight'] - maxX = line['Words'][-1]['Left'] + line['Words'][-1]['Width'] - bndng_bx = [line['Words'][0]['Left'], line['MinTop'], - maxX, maxY] - bounding_box = normalize_bdg_box(bndng_bx, width, height) - ocr_results.append({ - 'text': line_text, - 'bounding_box': bounding_box - }) - return ocr_results - def process_google_vision(image_b64, width, height): - client = vision.ImageAnnotatorClient() - image = vision.Image(content=image_b64) - response = client.text_detection(image=image) + try: + client = vision.ImageAnnotatorClient() + image = vision.Image(content=image_b64) + response = client.text_detection(image=image) + + # Check for success + if response.error.message: + logging.error(response.error.message) + return None - # Check for success - if response.error.message: - logging.error(response.error.message) - return None + ocr_results = [] - ocr_results = [] - - for word in response.text_annotations[1:]: - text = word.description - # Get normalized bounding box for each word - bndng_bx = [word.bounding_poly.vertices[0].x, - word.bounding_poly.vertices[0].y, - word.bounding_poly.vertices[2].x, - word.bounding_poly.vertices[2].y] - bounding_box = normalize_bdg_box(bndng_bx, width, height) - ocr_results.append({ - 'text': text, - 'bounding_box': bounding_box - }) - return ocr_results + for word in response.text_annotations[1:]: + text = word.description + # Get normalized bounding box for each word + bndng_bx = [word.bounding_poly.vertices[0].x, + word.bounding_poly.vertices[0].y, + word.bounding_poly.vertices[2].x, + word.bounding_poly.vertices[2].y] + bounding_box = normalize_bdg_box(bndng_bx, width, height) + ocr_results.append({ + 'text': text, + 'bounding_box': bounding_box + }) + return ocr_results + except Exception as e: + logging.error("Error in Google Vision processing") + logging.pii(f"Google Vision error details: {e}") + return None def normalize_bdg_box(bndng_bx, width, height): diff --git a/preprocessors/openstreetmap/Dockerfile b/preprocessors/openstreetmap/Dockerfile index 8acf04720..7eb18e659 100644 --- a/preprocessors/openstreetmap/Dockerfile +++ b/preprocessors/openstreetmap/Dockerfile @@ -10,6 +10,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r /app/requirements.txt COPY ./schemas /app/schemas +COPY /config /app/config COPY ./preprocessors/openstreetmap/ /app EXPOSE 5000 diff --git a/preprocessors/openstreetmap/main.py b/preprocessors/openstreetmap/main.py index aac6aa615..005a16713 100644 --- a/preprocessors/openstreetmap/main.py +++ b/preprocessors/openstreetmap/main.py @@ -16,19 +16,13 @@ validate, get_coordinates, ) +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) app.config['JSON_SORT_KEYS'] = False - -# Configure logging settings -logging.basicConfig( - level=logging.DEBUG, - format="%(asctime)s [%(levelname)s]: %(message)s", - datefmt="%y-%m-%d %H:%M %Z", -) - -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) +logging.basicConfig(level=logging.DEBUG) @app.route('/preprocessor', methods=['POST', ]) @@ -36,7 +30,7 @@ def get_map_data(): """ Gets map data from OpenStreetMap """ - LOGGER.debug("Received request") + logging.debug("Received request") # Load schemas with open('./schemas/preprocessors/openstreetmap.schema.json') as jsonfile: data_schema = json.load(jsonfile) @@ -49,29 +43,37 @@ def get_map_data(): schema['$id']: schema, definition_schema['$id']: definition_schema } - content = request.get_json() - LOGGER.debug("Validating request") - with open('./schemas/request.schema.json') as jsonfile: - request_schema = json.load(jsonfile) - # Validate incoming request - resolver = jsonschema.RefResolver.from_schema( - request_schema, store=schema_store) + try: + content = request.get_json() + logging.debug("Validating request") + with open('./schemas/request.schema.json') as jsonfile: + request_schema = json.load(jsonfile) - validated = validate( - schema=request_schema, - data=content, - resolver=resolver, - json_message="Invalid Request JSON format", - error_code=400) + # Validate incoming request + resolver = jsonschema.RefResolver.from_schema( + request_schema, store=schema_store) + + validated = validate( + schema=request_schema, + data=content, + resolver=resolver, + json_message="Invalid Request JSON format", + error_code=400 + ) + + if validated is not None: + return validated + except jsonschema.exceptions.ValidationError as e: + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") + return jsonify("Invalid Request JSON format"), 400 - if validated is not None: - return validated time_stamp = int(get_timestamp()) name = "ca.mcgill.a11y.image.preprocessor.openstreetmap" request_uuid = content["request_uuid"] # Check if this request is for an openstreetmap if 'coordinates' not in content and 'placeID' not in content: - LOGGER.info("Not map content. Skipping...") + logging.info("Not map content. Skipping...") return jsonify(""), 204 # Build OpenStreetMap request @@ -164,7 +166,7 @@ def get_map_data(): if validated is not None: return validated - LOGGER.debug("Sending final response") + logging.debug("Sending final response") return response diff --git a/preprocessors/sorting/Dockerfile b/preprocessors/sorting/Dockerfile index 66e49bdaa..465713bd9 100644 --- a/preprocessors/sorting/Dockerfile +++ b/preprocessors/sorting/Dockerfile @@ -11,6 +11,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r requirements.txt COPY /schemas /app/schemas +COPY /config /app/config COPY /preprocessors/sorting/ /app EXPOSE 5000 diff --git a/preprocessors/sorting/sorting.py b/preprocessors/sorting/sorting.py index fb63b41fb..c0a9cbca3 100644 --- a/preprocessors/sorting/sorting.py +++ b/preprocessors/sorting/sorting.py @@ -21,6 +21,9 @@ import logging from math import sqrt from datetime import datetime +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) @@ -70,8 +73,10 @@ def readImage(): validator = jsonschema.Draft7Validator(first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 400 + preprocessor = content["preprocessors"] if "ca.mcgill.a11y.image.preprocessor.objectDetection" \ not in preprocessor: @@ -111,8 +116,10 @@ def readImage(): validator = jsonschema.Draft7Validator(data_schema) validator.validate(data) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for processed data") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 + response = { "request_uuid": request_uuid, "timestamp": int(timestamp), @@ -124,8 +131,10 @@ def readImage(): schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for final response") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 + logging.debug("Sending response") return response diff --git a/preprocessors/yolov8/Dockerfile b/preprocessors/yolov8/Dockerfile index 921dc6574..ee278b05c 100644 --- a/preprocessors/yolov8/Dockerfile +++ b/preprocessors/yolov8/Dockerfile @@ -14,6 +14,7 @@ RUN pip3 install --upgrade pip && \ pip3 install -r /usr/src/app/requirements.txt COPY /schemas /usr/src/app/schemas +COPY /config /app/config RUN wget https://image.a11y.mcgill.ca/models/objectDetectionWeights/yolov8x.pt diff --git a/preprocessors/yolov8/detect.py b/preprocessors/yolov8/detect.py index ae2dff431..3068d5e6b 100644 --- a/preprocessors/yolov8/detect.py +++ b/preprocessors/yolov8/detect.py @@ -34,6 +34,9 @@ from ultralytics.yolo.utils.torch_utils import select_device from ultralytics.yolo.utils.checks import check_imgsz from ultralytics.yolo.utils.ops import scale_coords, non_max_suppression +from config.logging_utils import configure_logging + +configure_logging() os.environ['KMP_DUPLICATE_LIB_OK'] = 'True' app = Flask(__name__) @@ -255,8 +258,10 @@ def run(weights='yolov8x.pt', first_schema, resolver=resolver) validator.validate(content) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for incoming request") + logging.pii(f"Validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 400 + if "graphic" not in content: logging.info("No graphic content. Skipping...") return "", 204 @@ -354,7 +359,8 @@ def run(weights='yolov8x.pt', validator = jsonschema.Draft7Validator(data_schema) validator.validate(things) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for object detection results") + logging.pii(f"Object detection validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 response = { "request_uuid": request_uuid, @@ -367,7 +373,8 @@ def run(weights='yolov8x.pt', schema, resolver=resolver) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(e) + logging.error("Validation failed for response") + logging.pii(f"Response validation error: {e.message}") return jsonify("Invalid Preprocessor JSON format"), 500 logging.debug("Total number of Objects Detected - " + str(len(things["objects"]))) diff --git a/services/espnet-tts-fr/Dockerfile b/services/espnet-tts-fr/Dockerfile index 61e92fd72..aa9434150 100644 --- a/services/espnet-tts-fr/Dockerfile +++ b/services/espnet-tts-fr/Dockerfile @@ -1,6 +1,6 @@ FROM pytorch/pytorch:1.12.1-cuda11.3-cudnn8-runtime -RUN apt-get update && apt-get install -y libsndfile1 espeak-ng build-essential curl && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y libsndfile1 espeak-ng build-essential && rm -rf /var/lib/apt/lists/* ## phonemizedf @@ -47,7 +47,5 @@ COPY /services/espnet-tts-fr/conf/model-conf/feats_stats.npz ./ ENV TORCH_DEVICE="cpu" EXPOSE 80 -HEALTHCHECK --interval=60s --timeout=10s --start-period=120s --retries=5 CMD curl -f http://localhost:80/health || exit 1 - CMD ["gunicorn", "app:app", "-b", "0.0.0.0:80", "--capture-output", "--log-level=debug"] diff --git a/services/espnet-tts-fr/src/app.py b/services/espnet-tts-fr/src/app.py index e54ca902c..ce9efdb44 100644 --- a/services/espnet-tts-fr/src/app.py +++ b/services/espnet-tts-fr/src/app.py @@ -21,14 +21,13 @@ import numpy as np import soundfile as sf from espnet_util import tts, fs -from flask import Flask, Response, request, jsonify +from flask import Flask, Response, request from io import BytesIO from jsonschema import validate from torch.cuda import empty_cache from werkzeug.wsgi import FileWrapper from num2words import num2words import re # for regular expression processing -from datetime import datetime logging.basicConfig(format="%(asctime)s %(message)s") logger = logging.getLogger(__name__) @@ -170,14 +169,3 @@ def segment_tts(): }, 500 finally: empty_cache() - - -@app.route("/health", methods=["GET"]) -def health(): - """ - Health check endpoint to verify if the service is running - """ - return jsonify({ - "status": "healthy", - "timestamp": datetime.now().isoformat() - }), 200 diff --git a/services/espnet-tts/Dockerfile b/services/espnet-tts/Dockerfile index 6ae3f61ed..b052048e4 100644 --- a/services/espnet-tts/Dockerfile +++ b/services/espnet-tts/Dockerfile @@ -1,6 +1,6 @@ FROM pytorch/pytorch:1.10.0-cuda11.3-cudnn8-runtime -RUN apt-get update && apt-get install -y libsndfile1 build-essential wget curl && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y libsndfile1 build-essential wget && rm -rf /var/lib/apt/lists/* WORKDIR /run/tts RUN adduser --disabled-password python && chown python:python . @@ -12,8 +12,8 @@ COPY /services/espnet-tts/requirements.txt . RUN pip install -r requirements.txt COPY /services/espnet-tts/src/predownload.py . -RUN python predownload.py && \ - mkdir -p /home/python/.cache/parallel_wavegan/ljspeech_full_band_melgan.v2 && \ +RUN python predownload.py +RUN mkdir -p /home/python/.cache/parallel_wavegan/ljspeech_full_band_melgan.v2 && \ wget https://image.a11y.mcgill.ca/models/espnet/train_nodev_ljspeech_full_band_melgan.v2.tar.gz -O /home/python/.cache/parallel_wavegan/ljspeech_full_band_melgan.v2.tar.gz && \ tar xzvf /home/python/.cache/parallel_wavegan/ljspeech_full_band_melgan.v2.tar.gz -C /home/python/.cache/parallel_wavegan/ljspeech_full_band_melgan.v2/ @@ -22,6 +22,4 @@ COPY /schemas/services/tts/* ./ ENV TORCH_DEVICE="cpu" EXPOSE 80 -HEALTHCHECK --interval=60s --timeout=10s --start-period=120s --retries=5 CMD curl -f http://localhost:80/health || exit 1 - CMD ["gunicorn", "app:app", "-b", "0.0.0.0:80", "--capture-output", "--log-level=debug"] diff --git a/services/espnet-tts/src/app.py b/services/espnet-tts/src/app.py index a825776d5..bca2e36a4 100644 --- a/services/espnet-tts/src/app.py +++ b/services/espnet-tts/src/app.py @@ -21,12 +21,11 @@ import numpy as np import soundfile as sf from espnet_util import tts, fs -from flask import Flask, Response, request, jsonify +from flask import Flask, Response, request from io import BytesIO from jsonschema import validate from torch.cuda import empty_cache from werkzeug.wsgi import FileWrapper -from datetime import datetime logging.basicConfig(format="%(asctime)s %(message)s") logger = logging.getLogger(__name__) @@ -113,14 +112,3 @@ def segment_tts(): }, 500 finally: empty_cache() - - -@app.route("/health", methods=["GET"]) -def health(): - """ - Health check endpoint to verify if the service is running - """ - return jsonify({ - "status": "healthy", - "timestamp": datetime.now().isoformat() - }), 200 diff --git a/services/monarch-link-app/Dockerfile b/services/monarch-link-app/Dockerfile index 377932695..e0a131477 100644 --- a/services/monarch-link-app/Dockerfile +++ b/services/monarch-link-app/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.11-alpine3.20 -RUN apk add supercronic curl +RUN apk add supercronic RUN adduser --disabled-password python WORKDIR /usr/src/app @@ -16,8 +16,5 @@ RUN chown -R python:python /usr/src/app EXPOSE 80 USER python - -HEALTHCHECK --interval=60s --timeout=10s --start-period=120s --retries=5 CMD curl -f http://localhost:80/health || exit 1 - CMD supercronic -quiet /usr/src/app/cronjob \ & gunicorn app:app -b 0.0.0.0:80 --capture-output --log-level=debug \ No newline at end of file diff --git a/services/monarch-link-app/app.py b/services/monarch-link-app/app.py index 24c4e9f26..bacbfa687 100644 --- a/services/monarch-link-app/app.py +++ b/services/monarch-link-app/app.py @@ -14,7 +14,7 @@ # If not, see # . -from flask import Flask, request, abort, Response, jsonify +from flask import Flask, request, abort, Response from flask_bcrypt import Bcrypt from flask_cors import CORS, cross_origin from datetime import datetime @@ -200,16 +200,5 @@ def home(): return "Hi" -@app.route("/health", methods=["GET"]) -def health(): - """ - Health check endpoint to verify if the service is running - """ - return jsonify({ - "status": "healthy", - "timestamp": datetime.now().isoformat() - }), 200 - - if __name__ == "__main__": app.run(host="0.0.0.0", port=80, debug=True) diff --git a/services/multilang-support/Dockerfile b/services/multilang-support/Dockerfile index ea73b1495..81ce840fe 100644 --- a/services/multilang-support/Dockerfile +++ b/services/multilang-support/Dockerfile @@ -2,7 +2,7 @@ FROM pytorch/pytorch:latest # See README.md#docker-image for visualisation of the directory structure WORKDIR /app -RUN apt-get update && apt-get install python3 python3-pip git git-lfs curl -y +RUN apt-get update && apt-get install python3 python3-pip git git-lfs -y # Copy requirements COPY services/multilang-support/requirements.txt /app/ @@ -27,7 +27,4 @@ COPY services/multilang-support/src/*.py /app/src/ EXPOSE 80 ENV FLASK_APP=src/app.py - -HEALTHCHECK --interval=60s --timeout=10s --start-period=120s --retries=5 CMD curl -f http://localhost:80/health || exit 1 - CMD [ "gunicorn", "src.translate:app", "--bind", "0.0.0.0:80", "--log-level=info", "--timeout=120"] diff --git a/services/multilang-support/src/translate.py b/services/multilang-support/src/translate.py index 21fb207f2..bce14cf46 100644 --- a/services/multilang-support/src/translate.py +++ b/services/multilang-support/src/translate.py @@ -4,7 +4,6 @@ from .utils import LOGGER, Translator, SUPPORTED_LANGS import json import jsonschema -from datetime import datetime app = Flask(__name__) @@ -92,14 +91,3 @@ def translate_request(): LOGGER.debug(f"- Response SENT! Time taken: {elapsed_time} ms -") # Return response return jsonify(response), 200 - - -@app.route("/health", methods=["GET"]) -def health(): - """ - Health check endpoint to verify if the service is running - """ - return jsonify({ - "status": "healthy", - "timestamp": datetime.now().isoformat() - }), 200 diff --git a/services/supercollider-images/supercollider-alpine/Dockerfile b/services/supercollider-images/supercollider-alpine/Dockerfile index 5730b2c00..c05ee0cd1 100644 --- a/services/supercollider-images/supercollider-alpine/Dockerfile +++ b/services/supercollider-images/supercollider-alpine/Dockerfile @@ -2,7 +2,7 @@ FROM alpine:latest # Default to latest version of supercollider ARG VERSION=develop -RUN apk add --no-cache git g++ cmake make pipewire pipewire-jack libsndfile-dev fftw-dev jack-dev avahi-dev readline-dev linux-headers curl +RUN apk add --no-cache git g++ cmake make pipewire pipewire-jack libsndfile-dev fftw-dev jack-dev avahi-dev readline-dev linux-headers # Despite the files being present, the cmake script fails to find them without this RUN ln -sf /usr/lib/pipewire-0.3/jack/libjack.* /usr/lib diff --git a/services/supercollider-images/supercollider-alpine/entrypoint b/services/supercollider-images/supercollider-alpine/entrypoint index 200d546db..d235cd03b 100644 --- a/services/supercollider-images/supercollider-alpine/entrypoint +++ b/services/supercollider-images/supercollider-alpine/entrypoint @@ -2,9 +2,4 @@ /usr/bin/pipewire & -#healthcheck -while :; do - echo -e "HTTP/1.1 200 OK\nContent-Type: application/json\n\n{\"status\": \"healthy\"}" | nc -l -p 57110 || break -done & - exec "$@" diff --git a/services/supercollider-images/supercollider-extra/Dockerfile b/services/supercollider-images/supercollider-extra/Dockerfile index 7e606899e..0ea0e93ac 100644 --- a/services/supercollider-images/supercollider-extra/Dockerfile +++ b/services/supercollider-images/supercollider-extra/Dockerfile @@ -4,7 +4,7 @@ ARG VERSION=Version-3.13.0 USER root # Wanted by MP3 -RUN dnf install -q -y lame vorbis-tools unzip which curl && \ +RUN dnf install -q -y lame vorbis-tools unzip which && \ rm -rf /var/cache/dnf # Install sc3-plugins @@ -34,5 +34,4 @@ COPY atk_install.scd /tmp/sc/atk_install.scd RUN sclang atk_install.scd RUN rm atk_install.scd - ENTRYPOINT ["/run/entrypoint"] diff --git a/services/supercollider-images/supercollider/Dockerfile b/services/supercollider-images/supercollider/Dockerfile index c5d612d02..b66039e7b 100644 --- a/services/supercollider-images/supercollider/Dockerfile +++ b/services/supercollider-images/supercollider/Dockerfile @@ -1,7 +1,7 @@ FROM fedora:38 ARG VERSION=Version-3.13.0 -RUN dnf install -q -y pipewire git cmake gcc-c++ pipewire-jack-audio-connection-kit-devel fftw-devel libsndfile-devel avahi-devel readline-devel libatomic curl nc && \ +RUN dnf install -q -y pipewire git cmake gcc-c++ pipewire-jack-audio-connection-kit-devel fftw-devel libsndfile-devel avahi-devel readline-devel libatomic && \ rm -rf /var/cache/dnf # Despite the files being present, the cmake script fails to find them without this @@ -33,6 +33,4 @@ RUN chmod +x /run/entrypoint && \ USER sclang -HEALTHCHECK --interval=60s --timeout=10s --start-period=120s --retries=5 CMD curl -f http://localhost:57110/health || exit 1 - ENTRYPOINT ["/run/entrypoint"] diff --git a/services/supercollider-images/supercollider/entrypoint b/services/supercollider-images/supercollider/entrypoint index 200d546db..d235cd03b 100644 --- a/services/supercollider-images/supercollider/entrypoint +++ b/services/supercollider-images/supercollider/entrypoint @@ -2,9 +2,4 @@ /usr/bin/pipewire & -#healthcheck -while :; do - echo -e "HTTP/1.1 200 OK\nContent-Type: application/json\n\n{\"status\": \"healthy\"}" | nc -l -p 57110 || break -done & - exec "$@" diff --git a/services/tat/Dockerfile b/services/tat/Dockerfile index 1678aad39..a3b01e1d2 100644 --- a/services/tat/Dockerfile +++ b/services/tat/Dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build the application -FROM node:20-alpine AS build +FROM node:20-alpine as build # Set the working directory inside the container WORKDIR /app @@ -31,17 +31,11 @@ FROM nginx:alpine # Copy the build output from the previous stage to the Nginx HTML directory COPY --from=build /app/dist/editor/ /usr/share/nginx/html -# Add a static health check file -COPY services/tat/healthcheck.html /usr/share/nginx/html/ - # Copy a custom Nginx configuration file, if needed (optional) # COPY nginx.conf /etc/nginx/nginx.conf # Expose the default Nginx port EXPOSE 80 -# Healthcheck -HEALTHCHECK --interval=60s --timeout=10s --start-period=120s --retries=5 CMD curl -f http://localhost/healthcheck.html || exit 1 - # Start the Nginx server CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/services/tat/healthcheck.html b/services/tat/healthcheck.html deleted file mode 100644 index 7d1a9afde..000000000 --- a/services/tat/healthcheck.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - Health Check - - -

Healthy

-

The service 'tat' is running correctly!

- - - diff --git a/test-docker-compose.yml b/test-docker-compose.yml index 750eb9516..92006e014 100644 --- a/test-docker-compose.yml +++ b/test-docker-compose.yml @@ -114,8 +114,4 @@ services: - "traefik.http.routers.tat.tls.certresolver=myresolver" - traefik.docker.network=traefik environment: - - SERVER_NAME=unicorn.cim.mcgill.ca - - text-followup: - environment: - LOG_PII: "true" \ No newline at end of file + - SERVER_NAME=unicorn.cim.mcgill.ca \ No newline at end of file