diff --git a/.env.template b/.env.template index c6e2c34a..5cf926be 100644 --- a/.env.template +++ b/.env.template @@ -49,7 +49,14 @@ SERVER_SSL_KEY=../ssl/key.pem # Path to SSL private key CORS_ORIGIN=* # Allowed CORS origins (comma-separated) # ---------------------------------------------------- -# 3. Media Handling +# 3. Logging Configuration +# ---------------------------------------------------- + +LOGS_JSON=false # Log output in JSON format (true|false) +LOGS_JSON_PRETTY=false # Pretty-print JSON logs (true|false) + +# ---------------------------------------------------- +# 4. Media Handling # ---------------------------------------------------- # Recording @@ -119,7 +126,7 @@ PRESENTERS=Miroslav Pejic,miroslav.pejic.85@gmail.com, # Presenter usernames (co PRESENTER_JOIN_FIRST=true # First joiner becomes presenter (true|false) # ---------------------------------------------------- -# 5. API Configuration +# 6. API Configuration # ---------------------------------------------------- API_KEY_SECRET=mirotalksfu_default_secret # Secret for API authentication @@ -132,7 +139,7 @@ API_ALLOW_SLACK=true # Allow Slack integration via API_ALLOW_MATTERMOST=true # Allow Mattermost integration via API (true|false) # ---------------------------------------------------- -# 6. Third-Party Integrations +# 7. Third-Party Integrations # ---------------------------------------------------- # ChatGPT Integration @@ -210,7 +217,7 @@ AWS_SECRET_ACCESS_KEY= # AWS Secret Access Key (leave AWS_REGION= # AWS region (e.g., us-east-2, eu-west-2) # ---------------------------------------------------- -# 7. UI Customization +# 8. UI Customization # ---------------------------------------------------- # App @@ -268,7 +275,7 @@ EMAIL_SUBJECT=MiroTalk SFU info # Email subject COPYRIGHT_TEXT=MiroTalk SFU, all rights reserved # Copyright text # ---------------------------------------------------- -# 8. UI Button Configuration +# 9. UI Button Configuration # ---------------------------------------------------- # Main Control Buttons @@ -349,7 +356,7 @@ SHOW_EJECT_ALL=true # Show eject all button (true| SHOW_WB_LOCK=true # Show whiteboard lock button (true|false) # ---------------------------------------------------- -# 9. Feature Flags +# 10. Feature Flags # ---------------------------------------------------- SURVEY_ENABLED=false # Enable post-call survey (true|false) @@ -365,7 +372,7 @@ STATS_SRC=https://stats.mirotalk.com/script.js # Stats script URL STATS_ID=41d26670-f275-45bb-af82-3ce91fe57756 # Stats tracking ID # ---------------------------------------------------- -# 10. Mediasoup Configuration +# 11. Mediasoup Configuration # ---------------------------------------------------- MEDIASOUP_ROUTER_AUDIO_LEVEL_OBSERVER_ENABLED=true # Enable audio level observer (true|false) diff --git a/app/src/Logger.js b/app/src/Logger.js index fe7f4881..5712b79d 100644 --- a/app/src/Logger.js +++ b/app/src/Logger.js @@ -1,9 +1,7 @@ 'use strict'; const util = require('util'); - const colors = require('colors'); - const config = require('./config'); config.system?.console?.colors ? colors.enable() : colors.disable(); @@ -12,6 +10,10 @@ const options = { depth: null, colors: config.system?.console?.colors || false, }; + +const LOGS_JSON = config.system?.console?.json; +const LOGS_JSON_PRETTY = config.system?.console?.json_pretty; + module.exports = class Logger { constructor(appName = 'miroTalkSfu') { this.appName = colors.yellow(appName); @@ -25,42 +27,76 @@ module.exports = class Logger { }; } + jsonLog(level, appName, msg, op, extra = {}) { + const logObj = { + timestamp: new Date().toISOString(), + level, + app: appName, + message: msg, + ...extra, + }; + if (op && typeof op === 'object' && Object.keys(op).length > 0) { + logObj.data = op; + } + LOGS_JSON_PRETTY ? console.log(JSON.stringify(logObj, null, 2)) : console.log(JSON.stringify(logObj)); + } + debug(msg, op = '') { if (this.debugOn) { this.timeEnd = Date.now(); this.timeElapsedMs = this.getFormatTime(Math.floor(this.timeEnd - this.timeStart)); - console.debug( - '[' + this.getDateTime() + '] [' + this.appName + '] ' + msg, - util.inspect(op, options), - this.timeElapsedMs - ); + if (LOGS_JSON) { + this.jsonLog('debug', this.appName, msg, op, { elapsed: this.timeElapsedMs }); + } else { + console.debug( + '[' + this.getDateTime() + '] [' + this.appName + '] ' + msg, + util.inspect(op, options), + this.timeElapsedMs + ); + } this.timeStart = Date.now(); } } log(msg, op = '') { - console.log('[' + this.getDateTime() + '] [' + this.appName + '] ' + msg, util.inspect(op, options)); + if (LOGS_JSON) { + this.jsonLog('log', this.appName, msg, op); + } else { + console.log('[' + this.getDateTime() + '] [' + this.appName + '] ' + msg, util.inspect(op, options)); + } } info(msg, op = '') { - console.info( - '[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.green(msg), - util.inspect(op, options) - ); + if (LOGS_JSON) { + this.jsonLog('info', this.appName, msg, op); + } else { + console.info( + '[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.green(msg), + util.inspect(op, options) + ); + } } warn(msg, op = '') { - console.warn( - '[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.yellow(msg), - util.inspect(op, options) - ); + if (LOGS_JSON) { + this.jsonLog('warn', this.appName, msg, op); + } else { + console.warn( + '[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.yellow(msg), + util.inspect(op, options) + ); + } } error(msg, op = '') { - console.error( - '[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.red(msg), - util.inspect(op, options) - ); + if (LOGS_JSON) { + this.jsonLog('error', this.appName, msg, op); + } else { + console.error( + '[' + this.getDateTime() + '] [' + this.appName + '] ' + colors.red(msg), + util.inspect(op, options) + ); + } } getDateTime(color = true) { diff --git a/app/src/config.template.js b/app/src/config.template.js index 8b572ae4..42bb26fe 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -90,11 +90,15 @@ module.exports = { * - timeZone: IANA timezone (e.g., 'Europe/Rome') * - debug: Enable debug logging in non-production * - colors: Colorized console output + * - json: Log output in JSON format + * - json_pretty: Pretty-print JSON logs */ console: { timeZone: 'UTC', debug: ENVIRONMENT !== 'production', - colors: true, + json: process.env.LOGS_JSON === 'true', + json_pretty: process.env.LOGS_JSON_PRETTY === 'true', + colors: process.env.LOGS_JSON === 'true' ? false : true, }, /** diff --git a/package-lock.json b/package-lock.json index 6d126b67..840d7576 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "mirotalksfu", - "version": "1.8.91", + "version": "1.8.92", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mirotalksfu", - "version": "1.8.91", + "version": "1.8.92", "license": "AGPL-3.0", "dependencies": { "@aws-sdk/client-s3": "^3.844.0", "@aws-sdk/lib-storage": "^3.844.0", "@mattermost/client": "10.8.0", "@ngrok/ngrok": "1.5.1", - "@sentry/node": "^9.37.0", + "@sentry/node": "^9.38.0", "async-mutex": "^0.5.0", "axios": "^1.10.0", "chokidar": "^4.0.3", @@ -54,7 +54,7 @@ "proxyquire": "^2.1.3", "should": "^13.2.3", "sinon": "^21.0.0", - "webpack": "^5.100.0", + "webpack": "^5.100.1", "webpack-cli": "^6.0.1" }, "engines": { @@ -3745,18 +3745,18 @@ "license": "Apache-2.0" }, "node_modules/@sentry/core": { - "version": "9.37.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.37.0.tgz", - "integrity": "sha512-RyIsIIcIzEngvvNRr+0oAHJpeAgT5sP12qQXAY6DpeBfFJc9tRTdvxaTURNTkfh+WWO35eIqr4XEB4Hp7Q81IA==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.38.0.tgz", + "integrity": "sha512-dUwSv1VXDfsrcY69a/cgZNDsFal6iYOf0C4T+/ylpmgYp5SVe3vQK+2FLXUMuvgnOf+kHO6IeW0RhnhSyUflmA==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@sentry/node": { - "version": "9.37.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-9.37.0.tgz", - "integrity": "sha512-wj0y6Yo4u3qa/qzTW6Xwvf9G6njxSkPxJ91Bpb/iqhf8JGWJnigXkyq9R2qnelXazCX44TYqqC+zHpaBiX9pLg==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-9.38.0.tgz", + "integrity": "sha512-OhfRTge6hncSehrTBHpnz5R66OWRd8WMKn6ZoS0nwBmTfREjPkNRfOADIUqEElfyuaNj+gWsqTM1/E915pnZew==", "license": "MIT", "dependencies": { "@opentelemetry/api": "^1.9.0", @@ -3789,9 +3789,9 @@ "@opentelemetry/sdk-trace-base": "^1.30.1", "@opentelemetry/semantic-conventions": "^1.34.0", "@prisma/instrumentation": "6.11.1", - "@sentry/core": "9.37.0", - "@sentry/node-core": "9.37.0", - "@sentry/opentelemetry": "9.37.0", + "@sentry/core": "9.38.0", + "@sentry/node-core": "9.38.0", + "@sentry/opentelemetry": "9.38.0", "import-in-the-middle": "^1.14.2", "minimatch": "^9.0.0" }, @@ -3800,22 +3800,22 @@ } }, "node_modules/@sentry/node/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.35.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.35.0.tgz", - "integrity": "sha512-3R+blYJd3PNevNDl9co0u+VuDaQH7cGikkMDG6VcDSJF9kisMqyIKMVl5HLkyXh3sw0XhMkAFO+TTM1fnX0eXQ==", + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.36.0.tgz", + "integrity": "sha512-TtxJSRD8Ohxp6bKkhrm27JRHAxPczQA7idtcTOMYI+wQRRrfgqxHv1cFbCApcSnNjtXkmzFozn6jQtFrOmbjPQ==", "license": "Apache-2.0", "engines": { "node": ">=14" } }, "node_modules/@sentry/node/node_modules/@sentry/node-core": { - "version": "9.37.0", - "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-9.37.0.tgz", - "integrity": "sha512-j/DM2jb2egZQyTJx76QtOh4qskL9kduIPMy9OXC+6m6nY+rVbRhIgs9aDjn3GE+DdUU79OMIoy10g8basGjM5Q==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-9.38.0.tgz", + "integrity": "sha512-G0JmsntsvALoqS9iLTi4Jn1DcQB7gw9PY1Fmkdcdcf7i4EJEdRDX0tiD9ssDrcjgzzFPnm0PCrSAkIfTtd3Zyg==", "license": "MIT", "dependencies": { - "@sentry/core": "9.37.0", - "@sentry/opentelemetry": "9.37.0", + "@sentry/core": "9.38.0", + "@sentry/opentelemetry": "9.38.0", "import-in-the-middle": "^1.14.2" }, "engines": { @@ -3832,12 +3832,12 @@ } }, "node_modules/@sentry/node/node_modules/@sentry/opentelemetry": { - "version": "9.37.0", - "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-9.37.0.tgz", - "integrity": "sha512-vJfy7TyYIvKYzzqFlVDZNHm3gzPmr14eyyXYmCVkpWKsqZWdJChg5zfGJTXujLKwMsTFVOt08RMw2DF1s9r5jA==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-9.38.0.tgz", + "integrity": "sha512-Oa0kk4EiBMwCvHS5ZI50M/SMNfGM9ztsmedFEfpS+mZz8y9C5Artd0ukGK4OAYcSBggNVQkhmmhWbwpNnRNQiw==", "license": "MIT", "dependencies": { - "@sentry/core": "9.37.0" + "@sentry/core": "9.38.0" }, "engines": { "node": ">=18" @@ -10538,9 +10538,9 @@ } }, "node_modules/webpack": { - "version": "5.100.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.100.0.tgz", - "integrity": "sha512-H8yBSBTk+BqxrINJnnRzaxU94SVP2bjd7WmA+PfCphoIdDpeQMJ77pq9/4I7xjLq38cB1bNKfzYPZu8pB3zKtg==", + "version": "5.100.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.100.1.tgz", + "integrity": "sha512-YJB/ESPUe2Locd0NKXmw72Dx8fZQk1gTzI6rc9TAT4+Sypbnhl8jd8RywB1bDsDF9Dy1RUR7gn3q/ZJTd0OZZg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 1455058e..77ca955b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.8.91", + "version": "1.8.92", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -61,7 +61,7 @@ "@aws-sdk/lib-storage": "^3.844.0", "@mattermost/client": "10.8.0", "@ngrok/ngrok": "1.5.1", - "@sentry/node": "^9.37.0", + "@sentry/node": "^9.38.0", "async-mutex": "^0.5.0", "axios": "^1.10.0", "chokidar": "^4.0.3", @@ -102,7 +102,7 @@ "proxyquire": "^2.1.3", "should": "^13.2.3", "sinon": "^21.0.0", - "webpack": "^5.100.0", + "webpack": "^5.100.1", "webpack-cli": "^6.0.1" } } diff --git a/public/js/Brand.js b/public/js/Brand.js index 0d9dcd86..f8ace5f2 100644 --- a/public/js/Brand.js +++ b/public/js/Brand.js @@ -76,7 +76,7 @@ let BRAND = { }, about: { imageUrl: '../images/mirotalk-logo.gif', - title: 'WebRTC SFU v1.8.91', + title: 'WebRTC SFU v1.8.92', html: `