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/config/init.py b/config/init.py new file mode 100644 index 000000000..868896d22 --- /dev/null +++ b/config/init.py @@ -0,0 +1,2 @@ +# /app/config/__init__.py +# This file marks the config directory as a Python package. \ No newline at end of file diff --git a/config/logging_utils.py b/config/logging_utils.py new file mode 100644 index 000000000..e4dd0f18e --- /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.") \ No newline at end of file diff --git a/config/logging_utils.ts b/config/logging_utils.ts new file mode 100644 index 000000000..4e5dfab41 --- /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.debug("PII logging attempted but is DISABLED."); + } +}; + +export { piiLogger }; \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index a8b28a130..35b8d1f04 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -79,30 +79,34 @@ services: ca.mcgill.a11y.image.preprocessor: 1 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 - + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} content-categoriser: - profiles: [production, test, default] - image: ghcr.io/shared-reality-lab/image-preprocessor-content-categoriser:${REGISTRY_TAG} - restart: unless-stopped - labels: - ca.mcgill.a11y.image.preprocessor: 1 - ca.mcgill.a11y.image.port: 5000 - ca.mcgill.a11y.image.cacheTimeout: 3600 - env_file: - ./config/ollama.env - + profiles: [production, test, default] + image: ghcr.io/shared-reality-lab/image-preprocessor-content-categoriser:${REGISTRY_TAG} + restart: unless-stopped + labels: + ca.mcgill.a11y.image.preprocessor: 1 + ca.mcgill.a11y.image.port: 5000 + ca.mcgill.a11y.image.cacheTimeout: 3600 + env_file: + ./config/ollama.env + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} graphic-caption: - profiles: [production, test, default] - image: ghcr.io/shared-reality-lab/image-preprocessor-graphic-caption:${REGISTRY_TAG} - restart: unless-stopped - labels: - ca.mcgill.a11y.image.preprocessor: 1 - ca.mcgill.a11y.image.port: 5000 - ca.mcgill.a11y.image.cacheTimeout: 3600 - env_file: - ./config/ollama.env + profiles: [production, test, default] + image: ghcr.io/shared-reality-lab/image-preprocessor-graphic-caption:${REGISTRY_TAG} + restart: unless-stopped + labels: + ca.mcgill.a11y.image.preprocessor: 1 + ca.mcgill.a11y.image.port: 5000 + ca.mcgill.a11y.image.cacheTimeout: 3600 + env_file: + ./config/ollama.env + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} text-followup: profiles: [test, default] @@ -118,7 +122,9 @@ services: ca.mcgill.a11y.image.route: "followup" env_file: ./config/ollama.env - + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} + graphic-tagger: profiles: [production, test, default] image: ghcr.io/shared-reality-lab/image-preprocessor-graphic-tagger:${REGISTRY_TAG} @@ -129,7 +135,9 @@ services: ca.mcgill.a11y.image.preprocessor: 2 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 - + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} + object-detection: profiles: [production, default, test] image: ghcr.io/shared-reality-lab/image-preprocessor-object-detection-v8:${REGISTRY_TAG} @@ -144,6 +152,8 @@ services: devices: - driver: nvidia capabilities: ["gpu", "utility", "compute"] + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} object-grouping: profiles: [production, test, default] @@ -153,6 +163,8 @@ services: ca.mcgill.a11y.image.preprocessor: 4 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} openstreetmap: profiles: [production, test, default] @@ -164,7 +176,8 @@ services: ca.mcgill.a11y.image.preprocessor: 3 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 - + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} object-sorting: profiles: [production, test, default] @@ -174,7 +187,8 @@ services: ca.mcgill.a11y.image.preprocessor: 5 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 - + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} semantic-segmentation: profiles: [production, test, default] @@ -190,7 +204,9 @@ services: ca.mcgill.a11y.image.preprocessor: 3 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 - + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} + supercollider: profiles: [production, test, default] image: ghcr.io/shared-reality-lab/image-service-supercollider:${REGISTRY_TAG} @@ -200,6 +216,8 @@ services: - sc-store:/tmp/sc-store deploy: replicas: 2 + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} photo-audio-handler: profiles: [production, test, default] @@ -211,6 +229,8 @@ services: ca.mcgill.a11y.image.handler: enable volumes: - sc-store:/tmp/sc-store + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} autour-handler: profiles: [production, test, default] @@ -222,6 +242,8 @@ services: ca.mcgill.a11y.image.handler: enable volumes: - sc-store:/tmp/sc-store + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} photo-audio-haptics-handler: profiles: [production, test, default] @@ -233,6 +255,8 @@ services: ca.mcgill.a11y.image.handler: enable volumes: - sc-store:/tmp/sc-store + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} high-charts-handler: profiles: [production, test, default] @@ -244,6 +268,8 @@ services: ca.mcgill.a11y.image.handler: enable volumes: - sc-store:/tmp/sc-store + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} svg-od-handler: profiles: [production, test, default] @@ -251,6 +277,8 @@ services: restart: unless-stopped labels: ca.mcgill.a11y.image.handler: enable + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} svg-semantic-seg-handler: profiles: [production, test, default] @@ -258,6 +286,8 @@ services: restart: unless-stopped labels: ca.mcgill.a11y.image.handler: enable + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} depth-map-generator: profiles: [production, test, default] @@ -273,6 +303,8 @@ services: ca.mcgill.a11y.image.preprocessor: 3 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} svg-depth-map: profiles: [production, test, default] @@ -280,6 +312,8 @@ services: restart: unless-stopped labels: ca.mcgill.a11y.image.handler: enable + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} nominatim-preprocessor: profiles: [production, test, default] @@ -290,6 +324,8 @@ services: labels: ca.mcgill.a11y.image.preprocessor: 2 ca.mcgill.a11y.image.cacheTimeout: 3600 + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} photo-tactile-svg-handler: profiles: [production, test, default] @@ -297,6 +333,8 @@ services: restart: unless-stopped labels: ca.mcgill.a11y.image.handler: enable + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} map-tactile-svg-handler: profiles: [production, test, default] @@ -304,6 +342,8 @@ services: restart: unless-stopped labels: ca.mcgill.a11y.image.handler: enable + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} text-followup-handler: profiles: [test, default] @@ -312,6 +352,8 @@ services: labels: ca.mcgill.a11y.image.handler: enable ca.mcgill.a11y.image.route: "followup" + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} # end - common services @@ -325,6 +367,7 @@ services: - ./config/express-common.env environment: - MOTD=Hello, world! + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} labels: ca.mcgill.a11y.image.handler: enable @@ -336,7 +379,9 @@ services: - ./config/express-common.env labels: ca.mcgill.a11y.image.handler: enable - + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} + # For environment setup refer to https://github.com/Shared-Reality-Lab/IMAGE-server/tree/main/preprocessors/ocr ocr-clouds-preprocessor: profiles: [test, default] @@ -348,6 +393,8 @@ services: ca.mcgill.a11y.image.preprocessor: 4 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} object-depth-calculator: profiles: [test, default] @@ -357,6 +404,8 @@ services: ca.mcgill.a11y.image.preprocessor: 4 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} line-charts: profiles: [test, default] @@ -366,6 +415,8 @@ services: ca.mcgill.a11y.image.preprocessor: 1 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} action-recognition: profiles: [test, default] @@ -381,6 +432,8 @@ services: devices: - driver: nvidia capabilities: ["gpu", "utility", "compute"] + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} ocr-handler: profiles: [test, default] @@ -388,6 +441,8 @@ services: restart: unless-stopped labels: ca.mcgill.a11y.image.handler: enable + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} osm-streets-handler: profiles: [test, default] @@ -402,6 +457,8 @@ services: ca.mcgill.a11y.image.handler: enable volumes: - sc-store:/tmp/sc-store + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} svg-open-street-map-handler: profiles: [test, default] @@ -410,6 +467,8 @@ services: labels: ca.mcgill.a11y.image.handler: enable ca.mcgill.a11y.image.port: 5000 + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} collage-detector-preprocessor: profiles: [production, test, default] @@ -419,12 +478,16 @@ services: ca.mcgill.a11y.image.preprocessor: 1 ca.mcgill.a11y.image.port: 5000 ca.mcgill.a11y.image.cacheTimeout: 3600 + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} svg-action-recognition-handler: profiles: [test, default] image: ghcr.io/shared-reality-lab/image-handler-svg-action-recognition:${REGISTRY_TAG} labels: ca.mcgill.a11y.image.handler: enable + environment: + - PII_LOGGING_ENABLED=${PII_LOGGING_ENABLED} monarch-link-app: profiles: [test, default] 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 3d05acd54..35697925e 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,17 +50,14 @@ 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; } const autourData = preprocessors["ca.mcgill.a11y.image.preprocessor.autour"]; - - // Filter places we will not use before checking for non-zero length. - const places = autourData["places"].filter((p: { "cat": number }) => !filterCategories.includes(p["cat"])); - if (places.length === 0) { + if (autourData["places"].length === 0) { console.warn("No places detected despite running."); const response = { "request_uuid": req.body["request_uuid"], @@ -69,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; @@ -86,14 +85,15 @@ 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; } - // Sort and filter POIs by distance. - // Do this before TTS since it is time consuming + // Sort and filter POIs + // Do this before since TTS is time consuming + const places = autourData["places"].filter((p: { "cat": number }) => !filterCategories.includes(p["cat"])); const source = new LatLon(autourData["lat"], autourData["lon"]); for (const place of places) { const dest = new LatLon(place["ll"][0], place["ll"][1]); @@ -138,7 +138,7 @@ app.post("/handler", async (req, res) => { const translateSegments = []; // Combine map description with data to translate translateSegments.push(description); translateSegments.push(...segments); - + const translated:string[] = await fetch( "http://multilang-support/service/translate", { "method": "POST", "headers": { @@ -161,9 +161,10 @@ app.post("/handler", async (req, res) => { for(let i = 1; i < translated.length; i++) { segments[i - 1] = translated[i]; } + } 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 @@ -171,7 +172,7 @@ app.post("/handler", async (req, res) => { return; } } - + // Forming Response let ttsResponse; try { @@ -188,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; } @@ -248,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); } @@ -264,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); } @@ -297,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) { @@ -327,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); } }); @@ -338,4 +342,4 @@ app.get("/health", (req, res) => { app.listen(port, () => { console.log(`Started server on port ${port}`); -}); +}); \ No newline at end of file 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/package-lock.json b/handlers/hello-handler/package-lock.json index e95a9eee5..0123a9ebf 100644 --- a/handlers/hello-handler/package-lock.json +++ b/handlers/hello-handler/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "ajv": "^8.3.0", "express": "^4.19.2", - "sharp": "^0.33.4" + "sharp": "^0.33.4", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.11", @@ -31,6 +32,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/@emnapi/runtime": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", @@ -675,6 +694,11 @@ "sharp": "*" } }, + "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/@typescript-eslint/eslint-plugin": { "version": "5.9.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.1.tgz", @@ -960,6 +984,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", @@ -1112,6 +1141,37 @@ "simple-swizzle": "^0.2.2" } }, + "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/colorspace/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/colorspace/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/colorspace/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/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1257,6 +1317,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", @@ -1660,6 +1725,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", @@ -1733,6 +1803,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", @@ -2036,6 +2111,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", @@ -2065,6 +2151,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", @@ -2084,6 +2175,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/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2172,8 +2279,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", @@ -2217,6 +2323,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", @@ -2392,6 +2506,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", @@ -2488,6 +2615,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", @@ -2674,6 +2809,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", @@ -2682,6 +2825,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", @@ -2718,6 +2869,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", @@ -2744,6 +2900,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", @@ -2830,6 +2994,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", @@ -2867,6 +3036,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", @@ -2881,6 +3084,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" + } + }, "@emnapi/runtime": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", @@ -3216,6 +3434,11 @@ "sharp": "*" } }, + "@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==" + }, "@typescript-eslint/eslint-plugin": { "version": "5.9.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.1.tgz", @@ -3382,6 +3605,11 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "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", @@ -3505,6 +3733,39 @@ "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" + }, + "dependencies": { + "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" + } + }, + "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==" + } + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3608,6 +3869,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", @@ -3932,6 +4198,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", @@ -3995,6 +4266,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", @@ -4208,6 +4484,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", @@ -4234,6 +4515,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", @@ -4250,6 +4536,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" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -4311,8 +4610,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", @@ -4347,6 +4645,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", @@ -4460,6 +4766,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", @@ -4506,6 +4822,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", @@ -4656,11 +4977,24 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "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", @@ -4685,6 +5019,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", @@ -4705,6 +5044,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", @@ -4763,6 +5107,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", @@ -4788,6 +5137,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/hello-handler/package.json b/handlers/hello-handler/package.json index e1c0cd5a0..7b4597def 100644 --- a/handlers/hello-handler/package.json +++ b/handlers/hello-handler/package.json @@ -12,7 +12,8 @@ "dependencies": { "ajv": "^8.3.0", "express": "^4.19.2", - "sharp": "^0.33.4" + "sharp": "^0.33.4", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.11", diff --git a/handlers/hello-handler/src/server.ts b/handlers/hello-handler/src/server.ts index a1fdf630b..043dbc819 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); } }); @@ -100,4 +111,4 @@ app.get("/health", (req, res) => { app.listen(port, () => { console.log(`Started server on port ${port}`); -}); +}); \ No newline at end of file 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..3f96a507b 100644 --- a/handlers/high-charts/Dockerfile +++ b/handlers/high-charts/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/high-charts/ /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/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/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 3b479e904..aee736b67 100644 --- a/handlers/map-tactile-svg/map-svg.py +++ b/handlers/map-tactile-svg/map-svg.py @@ -23,6 +23,9 @@ import drawSvg as draw from datetime import datetime import math +from config.logging_utils import configure_logging + +configure_logging() app = Flask(__name__) logging.basicConfig(level=logging.DEBUG) @@ -30,16 +33,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, @@ -57,7 +66,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"] @@ -75,7 +85,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'." + @@ -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("Missing " + "'ca.mcgill.a11y.image.preprocessor.openstreetmap'." + @@ -272,13 +284,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 @@ -317,8 +329,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"], @@ -332,7 +344,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..40d0ca01b 100644 --- a/handlers/motd/Dockerfile +++ b/handlers/motd/Dockerfile @@ -1,12 +1,13 @@ -FROM node:alpine as builder +FROM node:alpine AS builder WORKDIR /usr/src/app COPY /handlers/motd/ /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/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..0c8444a19 100644 --- a/handlers/ocr-handler/Dockerfile +++ b/handlers/ocr-handler/Dockerfile @@ -13,6 +13,8 @@ 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..3492fa68a 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__) @@ -32,15 +35,20 @@ def render_ocr(): """ logging.debug("Received request") - # Load schemas - with open('./schemas/handler-response.schema.json') as jsonfile: - schema = json.load(jsonfile) - with open('./schemas/definitions.json') as jsonfile: - definition_schema = json.load(jsonfile) - schema_store = { - schema['$id']: schema, - definition_schema['$id']: definition_schema - } + try: + # Load schemas + with open('./schemas/handler-response.schema.json') as jsonfile: + schema = json.load(jsonfile) + with open('./schemas/definitions.json') as jsonfile: + definition_schema = json.load(jsonfile) + schema_store = { + schema['$id']: schema, + definition_schema['$id']: definition_schema + } + 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 # Get request data content = request.get_json() @@ -57,7 +65,8 @@ def render_ocr(): ) validator.validate(content) except jsonschema.exceptions.ValidationError as error: - logging.error(error) + logging.error("Request validation failed") + logging.pii(f"Validation error: {error.message}") return jsonify("Invalid Request JSON format"), 400 # Check preprocessor data @@ -75,7 +84,8 @@ def render_ocr(): validator = jsonschema.Draft7Validator(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 @@ -94,7 +104,8 @@ def render_ocr(): validator = jsonschema.Draft7Validator(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 @@ -111,7 +122,8 @@ def render_ocr(): validator = jsonschema.Draft7Validator(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 @@ -175,7 +187,8 @@ def render_ocr(): validator = jsonschema.Draft7Validator(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 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/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 86fb177f7..dd1aa5751 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; } @@ -148,6 +150,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}`); } } @@ -164,7 +167,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 { @@ -243,7 +246,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) { @@ -261,7 +264,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(() => { @@ -278,7 +283,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}`); } } @@ -296,7 +301,7 @@ app.post("/handler", async (req, res) => { } } catch(e) { console.error("Failed to translate rendering descriptions to " + targetLanguage); - console.error(e); + piiLogger.pii(`Error: ${(e as Error).message}`); } } // Send response @@ -308,7 +313,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..289f6f3a0 100644 --- a/handlers/photo-audio-haptics-handler/Dockerfile +++ b/handlers/photo-audio-haptics-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/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 +FROM node:alpine AS final RUN apk add --no-cache curl 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..827cfa932 100644 --- a/handlers/photo-tactile-svg/Dockerfile +++ b/handlers/photo-tactile-svg/Dockerfile @@ -11,6 +11,7 @@ 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..fb12118d1 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 RUN adduser --disabled-password python WORKDIR /usr/src/app @@ -11,8 +11,12 @@ 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=60s --timeout=10s --start-period=120s --retries=5 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/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/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..0b0fb2515 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) @@ -32,7 +35,6 @@ @app.route('/preprocessor', methods=['POST']) def detect_collage(): logging.debug("Received request") - with open('./schemas/preprocessors/collage-detector.schema.json') \ as jsonfile: data_schema = json.load(jsonfile) @@ -54,9 +56,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 +83,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 +97,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 6bf687572..78396e210 100644 --- a/preprocessors/content-categoriser/categoriser.py +++ b/preprocessors/content-categoriser/categoriser.py @@ -22,9 +22,11 @@ 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) @app.route("/preprocessor", methods=['POST', ]) @@ -55,7 +57,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) @@ -80,8 +83,8 @@ def categorise(): logging.debug("OLLAMA_URL " + api_url) if api_key.startswith("sk-"): - logging.debug("OLLAMA_API_KEY looks properly formatted: " + - api_key[:3] + "[redacted]") + logging.pii("OLLAMA_API_KEY looks properly formatted: " + + api_key[:3] + "[redacted]") else: logging.warn("OLLAMA_API_KEY usually starts with sk-, " "but this one starts with: " + api_key[:3]) @@ -135,9 +138,9 @@ def categorise(): ollama_error_msg = "unknown error decoding json. investigate!" finally: if ollama_error_msg is not None: - logging.error(ollama_error_msg) - # TODO: add back next line once IMAGE-server #912 is complete - # logging.debug(f"response (pii) [{graphic_category_json}]") + logging.pii( + f"{ollama_error_msg}. Raw response: \ + {graphic_category_json}") return jsonify("Invalid LLM results"), 204 # is the found category one of the ones we require? @@ -157,7 +160,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 @@ -171,7 +175,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..6c7fd40de 100644 --- a/preprocessors/depth-map-gen/Dockerfile +++ b/preprocessors/depth-map-gen/Dockerfile @@ -21,6 +21,8 @@ RUN pip3 install --upgrade pip && \ #schema COPY /schemas /app/schemas +#config for pii +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 1a59d09eb..d689d37ae 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) @@ -83,16 +87,13 @@ def categorise(): logging.debug("OLLAMA_API_KEY looks properly formatted: " + api_key[:3] + "[redacted]") else: - logging.warning("OLLAMA_API_KEY usually starts with sk-, " - "but this one starts with: " + api_key[:3]) + logging.warn("OLLAMA_API_KEY usually starts with sk-, " + "but this one starts with: " + api_key[:3]) prompt = "I am blind, so I cannot see this image. " \ "Tell me the most important aspects of it, including " \ "style, content, and the most significant aspect of the image." \ "Answer with maximum one sentence. " - prompt = os.getenv('GRAPHIC_CAPTION_PROMPT_OVERRIDE', prompt) - logging.debug("prompt: " + prompt) - request_data = { "model": ollama_model, "prompt": prompt, @@ -128,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 @@ -144,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..e7b1c1e58 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,16 @@ 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 + logging.debug("Sending response") + response = { "title": "Grouping Data", "description": "Grouped data for objects", @@ -127,13 +136,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/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 ae4a3938e..b3c7cef20 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 1afa5b739..3e4faa8f6 100644 --- a/preprocessors/mmsemseg/segment.py +++ b/preprocessors/mmsemseg/segment.py @@ -34,9 +34,11 @@ from time import time import logging +from config.logging_utils import configure_logging from datetime import datetime import subprocess +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" @@ -46,7 +48,6 @@ CLASS_NAMES = mmseg.core.evaluation.get_classes("ade20k") app = Flask(__name__) -logging.basicConfig(level=logging.DEBUG) def run_segmentation(url, model, dictionary): @@ -55,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 @@ -154,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: @@ -190,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 @@ -200,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 @@ -210,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() @@ -220,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 = { @@ -235,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..2e669bb44 100644 --- a/preprocessors/nominatim/package-lock.json +++ b/preprocessors/nominatim/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "ajv": "^8.9.0", "express": "^4.19.2", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", @@ -31,6 +32,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", @@ -276,6 +295,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 +586,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", @@ -677,6 +706,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 +730,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", @@ -832,6 +900,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", @@ -1198,6 +1271,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", @@ -1287,6 +1365,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", @@ -1555,6 +1638,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 +1682,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 +1732,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 +1771,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", @@ -1767,8 +1887,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", @@ -1818,6 +1937,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", @@ -2023,6 +2150,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 +2247,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", @@ -2241,6 +2389,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", @@ -2250,6 +2406,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 +2422,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 +2466,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 +2497,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", @@ -2406,6 +2591,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", @@ -2445,6 +2635,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..689860adb 100644 --- a/preprocessors/nominatim/package.json +++ b/preprocessors/nominatim/package.json @@ -13,7 +13,8 @@ "dependencies": { "ajv": "^8.9.0", "express": "^4.19.2", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "winston": "^3.17.0" }, "devDependencies": { "@types/express": "^4.17.13", diff --git a/preprocessors/nominatim/src/server.ts b/preprocessors/nominatim/src/server.ts index 435ca5f1e..6b86070c1 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}); } }); @@ -94,4 +99,4 @@ app.get("/health", (req, res) => { app.listen(port, () => { console.log("Started server on port " + port); -}); +}); \ No newline at end of file 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/text-followup/text-followup.py b/preprocessors/text-followup/text-followup.py index 7a09f15c2..35ed5b42e 100644 --- a/preprocessors/text-followup/text-followup.py +++ b/preprocessors/text-followup/text-followup.py @@ -22,9 +22,11 @@ import logging import os from datetime import datetime +from config.logging_utils import configure_logging app = Flask(__name__) -logging.basicConfig(level=logging.DEBUG) + +configure_logging() # Dictionary to store conversation history by request_uuid # Maintains conversation context between requests @@ -89,7 +91,8 @@ def followup(): 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 # check we received a graphic (e.g., not a map or chart request) @@ -121,14 +124,6 @@ def followup(): f"Current history length for {request_uuid}: {msg_count}" ) - # debugging this preprocessor is really difficult without seeing what - # ollama is returning, but this can contain PII. Until we have a safe - # way of logging PII, using manually set LOG_PII env variable - # to say whether or not we should go ahead and log potential PII - log_pii = os.getenv('LOG_PII', "false").lower() == "true" - if log_pii: - logging.warning("LOG_PII is True: potential PII will be logged!") - # convert the uri to processable image # source.split code referred from # https://gist.github.com/daino3/b671b2d171b3948692887e4c484caf47 @@ -175,8 +170,7 @@ def followup(): logging.debug("OLLAMA_URL " + api_url) if api_key.startswith("sk-"): - logging.debug("OLLAMA_API_KEY looks properly formatted: " + - "sk-[redacted]") + logging.pii("OLLAMA_API_KEY looks properly formatted: sk-[redacted]") else: logging.warning("OLLAMA_API_KEY does not start with sk-") @@ -218,23 +212,21 @@ def followup(): ) # Create log-friendly version without full base64 content - if log_pii: - log_friendly_messages = [] - for msg in messages: - # Create a copy to avoid modifying the original - log_msg = msg.copy() - if 'images' in log_msg: - # Replace image content with placeholder or truncate it - log_msg['images'] = [ + log_friendly_messages = [] + for msg in messages: + # Create a copy to avoid modifying the original + log_msg = msg.copy() + if 'images' in log_msg: + # Replace image content with placeholder or truncate it + log_msg['images'] = [ f"[BASE64_IMAGE:{len(img)} bytes]" for img in log_msg['images'] ] - log_friendly_messages.append(log_msg) - logging.debug( - f"Message history: {json.dumps(log_friendly_messages, indent=2)}" - ) - else: - logging.debug(f"User followup prompt: {general_prompt} [redacted]") + log_friendly_messages.append(log_msg) + logging.pii( + f"Message history: {json.dumps(log_friendly_messages, indent=2)}" + ) + logging.debug(f"User followup prompt: {general_prompt} [redacted]") # Create request data for chat endpoint request_data = { @@ -272,8 +264,7 @@ def followup(): response_json = json.loads(response.text) # strip() at end since llama often puts a newline before json response_text = response_json['message']['content'].strip() - if log_pii: - logging.debug("raw ollama response: " + response_text) + logging.pii("raw ollama response: " + response_text) followup_response_json = json.loads(response_text) # Format assistant response for history @@ -307,21 +298,16 @@ def followup(): logging.error(ollama_error_msg + " returning 204") return jsonify("Invalid LLM results"), 204 else: - if log_pii: - logging.error("Error {response.status_code}: {response.text}") - else: - logging.error("Error {response.status_code}: " - "[response text redacted]") + logging.error(f"Error {response.status_code}: \ + [response text redacted]") return jsonify("Invalid response from ollama"), 204 - # check if ollama returned valid json that follows schema try: validator = jsonschema.Draft7Validator(data_schema) validator.validate(followup_response_json) except jsonschema.exceptions.ValidationError as e: logging.error(f"JSON schema validation fail: {e.validator} {e.schema}") - if log_pii: - logging.debug(e) + logging.pii(e) return jsonify("Invalid Preprocessor JSON format"), 500 # create full response & check meets overall preprocessor response schema @@ -336,15 +322,11 @@ def followup(): validator.validate(response) except jsonschema.exceptions.ValidationError as e: logging.error(f"JSON schema validation fail: {e.validator} {e.schema}") - if log_pii: - logging.debug(e) # print full error only in debug, due to PII + logging.pii(e) return jsonify("Invalid Preprocessor JSON format"), 500 - # all done; return to orchestrator logging.debug("full response length: " + str(len(response))) - if log_pii: - logging.debug(response) - + logging.pii(response) return response diff --git a/preprocessors/yolov8/Dockerfile b/preprocessors/yolov8/Dockerfile index 3177f3d1f..4a8b9df86 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 # Set environment variable for model path ENV YOLO_MODEL_PATH=/usr/src/app/models/yolo11x.pt diff --git a/preprocessors/yolov8/detect.py b/preprocessors/yolov8/detect.py index 5b9b10790..3d90d609a 100644 --- a/preprocessors/yolov8/detect.py +++ b/preprocessors/yolov8/detect.py @@ -28,13 +28,12 @@ from PIL import Image from ultralytics import YOLO import torch +from config.logging_utils import configure_logging # Create Flask app app = Flask(__name__) -# Configure logging -logging.basicConfig(level=logging.DEBUG) -log_pii = True +configure_logging() # Environment variables and constants MODEL_PATH = os.environ.get('YOLO_MODEL_PATH') @@ -91,8 +90,7 @@ def decode_image(graphic_data): return image except Exception as e: logging.error(f"Failed to decode image: {str(e)}") - if log_pii: - logging.debug(traceback.format_exc()) + logging.pii(traceback.format_exc()) return None @@ -134,8 +132,7 @@ def format_detection_results(results): objects.append(obj) except Exception as e: logging.error(f"Error formatting detection results: {str(e)}") - if log_pii: - logging.debug(traceback.format_exc()) + logging.pii(traceback.format_exc()) return {"objects": objects} @@ -151,7 +148,8 @@ def detect(): ) 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 # Check if there is graphic content to process @@ -185,7 +183,7 @@ def detect(): device=device, conf=CONF_THRESHOLD, imgsz=MAX_IMAGE_SIZE, - verbose=log_pii + verbose=False ) # Format results according to schema @@ -196,9 +194,8 @@ def detect(): validator = jsonschema.Draft7Validator(DATA_SCHEMA) validator.validate(objects) except jsonschema.exceptions.ValidationError as e: - logging.error(f"JSON schema validation fail: {e.validator} {e.schema}") - if log_pii: - logging.debug(e) + logging.error("Validation failed for detection data") + logging.pii(f"Validation error: {e.message} | Data: {objects}") return jsonify("Invalid Preprocessor JSON format"), 500 # Create full response following preprocessor response schema @@ -214,14 +211,11 @@ def detect(): ) validator.validate(response) except jsonschema.exceptions.ValidationError as e: - logging.error(f"JSON schema validation fail: {e.validator} {e.schema}") - if log_pii: - logging.debug(e) + logging.error("Validation failed for full response") + logging.pii(f"Validation error: {e.message} | Response: {response}") return jsonify("Invalid Preprocessor JSON format"), 500 - if log_pii: - logging.debug(response) - + logging.pii(response) return jsonify(response), 200 diff --git a/production.env b/production.env index 423b10c98..d3848fe03 100644 --- a/production.env +++ b/production.env @@ -1,5 +1,6 @@ # Do not add any secrets in this file -COMPOSE_PROFILES = production -COMPOSE_FILE = docker-compose.yml:prod-docker-compose.yml -REGISTRY_TAG = latest -DOCKER_GID = 999 \ No newline at end of file +COMPOSE_PROFILES=production +COMPOSE_FILE=docker-compose.yml:prod-docker-compose.yml +REGISTRY_TAG=latest +DOCKER_GID=999 +PII_LOGGING_ENABLED=false 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 diff --git a/test.env b/test.env index ff8daa1a6..e1473d2a8 100644 --- a/test.env +++ b/test.env @@ -1,5 +1,6 @@ # Do not add any secrets in this file -COMPOSE_PROFILES = test -COMPOSE_FILE = docker-compose.yml:test-docker-compose.yml:docker-compose.override.yml -REGISTRY_TAG = unstable -DOCKER_GID = 134 \ No newline at end of file +COMPOSE_PROFILES=test +COMPOSE_FILE=docker-compose.yml:test-docker-compose.yml:docker-compose.override.yml +REGISTRY_TAG=unstable +DOCKER_GID=134 +PII_LOGGING_ENABLED=true