diff --git a/client/package-lock.json b/client/package-lock.json index 7e8010d..b0a7f45 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -15,6 +15,7 @@ "@fortawesome/react-fontawesome": "^0.1.12", "@headlessui/react": "^1.4.2", "@heroicons/react": "^1.0.5", + "@types/winston": "^2.4.4", "chokidar": "^3.4.3", "classnames": "^2.3.1", "codemirror-minified": "^5.63.3", @@ -36,6 +37,8 @@ "serenade-driver": "1.1.13", "speech-recorder": "2.1.0", "uuid": "^8.3.1", + "winston": "^3.14.2", + "winston-format": "^1.0.1", "ws": "^8.2.2" }, "devDependencies": { @@ -192,6 +195,14 @@ "node": ">=6.9.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/@cspotcode/source-map-consumer": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", @@ -213,6 +224,16 @@ "node": ">=12" } }, + "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/@develar/schema-utils": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", @@ -927,6 +948,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", @@ -940,6 +966,15 @@ "dev": true, "optional": true }, + "node_modules/@types/winston": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz", + "integrity": "sha512-BVGCztsypW8EYwJ+Hq+QNYiT/MUyCif0ouBH+flrY66O5W+KIXAMML6E/0fJpm7VjIzgangahl5S03bJJQGrZw==", + "deprecated": "This is a stub types definition. winston provides its own type definitions, so you do not need this installed.", + "dependencies": { + "winston": "*" + } + }, "node_modules/@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", @@ -1484,8 +1519,7 @@ "node_modules/async": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, "node_modules/async-exit-hook": { "version": "2.0.1", @@ -2201,6 +2235,15 @@ "resolved": "https://registry.npmjs.org/codemirror-minified/-/codemirror-minified-5.65.2.tgz", "integrity": "sha512-+P++u4yR4gSqXxjAzhii0s4dVwAL51sEKK7GOkt6gaqSvRx66J8EqPFtxFXBkpl+YyH4tVuXhHu3ASztEGsWPw==" }, + "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", @@ -2216,8 +2259,29 @@ "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/colorette": { "version": "2.0.16", @@ -2234,6 +2298,15 @@ "node": ">=0.1.90" } }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3306,6 +3379,11 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "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", @@ -3800,6 +3878,11 @@ "pend": "~1.2.0" } }, + "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-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -3892,6 +3975,11 @@ "node": ">=8" } }, + "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/follow-redirects": { "version": "1.14.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", @@ -5046,7 +5134,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { "node": ">=8" }, @@ -5331,6 +5418,11 @@ "node": ">= 8" } }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -5421,6 +5513,22 @@ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, + "node_modules/logform": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", + "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", + "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", @@ -6151,6 +6259,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/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -7397,6 +7513,14 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "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", @@ -7846,6 +7970,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/simple-swizzle/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/slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", @@ -8018,6 +8155,14 @@ "dev": true, "optional": 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/stat-mode": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", @@ -8407,6 +8552,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/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -8483,6 +8633,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/truncate-utf8-bytes": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", @@ -9276,6 +9434,71 @@ "resolved": "https://registry.npmjs.org/windows-shortcuts/-/windows-shortcuts-0.1.6.tgz", "integrity": "sha1-J5cMXDRv/YGCHD4SUowLq8oKWpk=" }, + "node_modules/winston": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.14.2.tgz", + "integrity": "sha512-CO8cdpBB2yqzEf8v895L+GNKYJiEq8eKlHU38af3snQBQ+sdAIUepjMSguOIJC7ICbzm0ZI+Af2If4vIJrtmOg==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.6.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.7.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/winston-format/-/winston-format-1.0.1.tgz", + "integrity": "sha512-wzFuOlXTbjoqSXL7PoDTSSnnhV1+89sv2dTQ6DRxWRBiyquB6TXeFbEJcLTOMqeWgWVkwSpsVJGchHb6BguTXQ==" + }, + "node_modules/winston-transport": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.1.tgz", + "integrity": "sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA==", + "dependencies": { + "logform": "^2.6.1", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport/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/winston/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/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -9521,6 +9744,11 @@ "regenerator-runtime": "^0.13.4" } }, + "@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==" + }, "@cspotcode/source-map-consumer": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", @@ -9536,6 +9764,16 @@ "@cspotcode/source-map-consumer": "0.8.0" } }, + "@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" + } + }, "@develar/schema-utils": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", @@ -10163,6 +10401,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", @@ -10176,6 +10419,14 @@ "dev": true, "optional": true }, + "@types/winston": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz", + "integrity": "sha512-BVGCztsypW8EYwJ+Hq+QNYiT/MUyCif0ouBH+flrY66O5W+KIXAMML6E/0fJpm7VjIzgangahl5S03bJJQGrZw==", + "requires": { + "winston": "*" + } + }, "@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", @@ -10634,8 +10885,7 @@ "async": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, "async-exit-hook": { "version": "2.0.1", @@ -11169,6 +11419,30 @@ "resolved": "https://registry.npmjs.org/codemirror-minified/-/codemirror-minified-5.65.2.tgz", "integrity": "sha512-+P++u4yR4gSqXxjAzhii0s4dVwAL51sEKK7GOkt6gaqSvRx66J8EqPFtxFXBkpl+YyH4tVuXhHu3ASztEGsWPw==" }, + "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", @@ -11181,8 +11455,16 @@ "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" + } }, "colorette": { "version": "2.0.16", @@ -11196,6 +11478,15 @@ "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", "dev": true }, + "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" + } + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -12028,6 +12319,11 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "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", @@ -12423,6 +12719,11 @@ "pend": "~1.2.0" } }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -12507,6 +12808,11 @@ "path-exists": "^4.0.0" } }, + "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==" + }, "follow-redirects": { "version": "1.14.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", @@ -13315,8 +13621,7 @@ "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, "is-string": { "version": "1.0.7", @@ -13534,6 +13839,11 @@ "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", "dev": true }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -13608,6 +13918,19 @@ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, + "logform": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", + "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", + "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", @@ -14169,6 +14492,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" + } + }, "onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -15075,6 +15406,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "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", @@ -15432,6 +15768,21 @@ } } }, + "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" + }, + "dependencies": { + "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==" + } + } + }, "slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", @@ -15582,6 +15933,11 @@ "dev": true, "optional": 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==" + }, "stat-mode": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", @@ -15856,6 +16212,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==" + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -15920,6 +16281,11 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, + "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==" + }, "truncate-utf8-bytes": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", @@ -16499,6 +16865,63 @@ "resolved": "https://registry.npmjs.org/windows-shortcuts/-/windows-shortcuts-0.1.6.tgz", "integrity": "sha1-J5cMXDRv/YGCHD4SUowLq8oKWpk=" }, + "winston": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.14.2.tgz", + "integrity": "sha512-CO8cdpBB2yqzEf8v895L+GNKYJiEq8eKlHU38af3snQBQ+sdAIUepjMSguOIJC7ICbzm0ZI+Af2If4vIJrtmOg==", + "requires": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.6.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.7.0" + }, + "dependencies": { + "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" + } + } + } + }, + "winston-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/winston-format/-/winston-format-1.0.1.tgz", + "integrity": "sha512-wzFuOlXTbjoqSXL7PoDTSSnnhV1+89sv2dTQ6DRxWRBiyquB6TXeFbEJcLTOMqeWgWVkwSpsVJGchHb6BguTXQ==" + }, + "winston-transport": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.1.tgz", + "integrity": "sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA==", + "requires": { + "logform": "^2.6.1", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "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" + } + } + } + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/client/package.json b/client/package.json index 27d4dd1..62461ae 100644 --- a/client/package.json +++ b/client/package.json @@ -25,11 +25,15 @@ "target": [ { "target": "dmg", - "arch": ["x64"] + "arch": [ + "x64" + ] }, { "target": "zip", - "arch": ["x64"] + "arch": [ + "x64" + ] } ] }, @@ -37,7 +41,9 @@ "target": [ { "target": "nsis", - "arch": ["x64"] + "arch": [ + "x64" + ] } ] }, @@ -45,7 +51,9 @@ "target": [ { "target": "AppImage", - "arch": ["x64"] + "arch": [ + "x64" + ] } ] }, @@ -54,7 +62,9 @@ }, "protocols": { "name": "serenade-protocol", - "schemes": ["serenade"] + "schemes": [ + "serenade" + ] }, "publish": { "provider": "generic", @@ -80,7 +90,9 @@ "start:electron": "electron ." }, "electronWebpack": { - "whiteListedModules": ["react-redux"] + "whiteListedModules": [ + "react-redux" + ] }, "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.32", @@ -89,6 +101,7 @@ "@fortawesome/react-fontawesome": "^0.1.12", "@headlessui/react": "^1.4.2", "@heroicons/react": "^1.0.5", + "@types/winston": "^2.4.4", "chokidar": "^3.4.3", "classnames": "^2.3.1", "codemirror-minified": "^5.63.3", @@ -110,6 +123,8 @@ "serenade-driver": "1.1.13", "speech-recorder": "2.1.0", "uuid": "^8.3.1", + "winston": "^3.14.2", + "winston-format": "^1.0.1", "ws": "^8.2.2" }, "devDependencies": { diff --git a/client/src/main/api.ts b/client/src/main/api.ts index a206b10..4f7297d 100644 --- a/client/src/main/api.ts +++ b/client/src/main/api.ts @@ -10,15 +10,17 @@ import SettingsWindow from "./windows/settings"; import { Endpoint } from "../shared/endpoint"; export default class API { + private log: Log; + constructor( private active: Active, private bridge: RendererBridge, - private log: Log, private mainWindow: MainWindow, private metadata: Metadata, private settings: Settings, private settingsWindow: () => Promise | undefined ) { + this.log = new Log(settings, "API"); setInterval(() => { this.ping(this.settings.getStreamingEndpoint()); }, 60000); @@ -54,7 +56,8 @@ export default class API { const buffer = await response.buffer(); return responseClass.toObject(responseClass.decode(buffer), { defaults: true }); } catch (e) { - this.log.logError(e); + let message = "Exception while trying to POST to " + url; + this.log.error(message, e); } } diff --git a/client/src/main/app.ts b/client/src/main/app.ts index d8909b0..0ae0dc9 100644 --- a/client/src/main/app.ts +++ b/client/src/main/app.ts @@ -72,7 +72,9 @@ export default class App { const settings = (instance.settings = new Settings()); const bridge = (instance.bridge = new RendererBridge(settings)); const system = new System(settings); - const log = (instance.log = new Log(settings)); + const log = (instance.log = new Log(settings, "Main")); + + log.info("App created! Starting initialization..."); instance.updateDarkModeForAllWindows(); const custom = (instance.custom = await Custom.create(settings)); @@ -147,9 +149,9 @@ export default class App { ); const nativeCommands = new NativeCommands(active, insertHistory, revisionBoxWindow, system); - const api = new API(active, bridge, log, mainWindow, metadata, settings, () => settingsWindow); - const stream = (instance.stream = new Stream(active, api, log, settings)); - const local = (instance.local = new Local(bridge, log, mainWindow, metadata, settings)); + const api = new API(active, bridge, mainWindow, metadata, settings, () => settingsWindow); + const stream = (instance.stream = new Stream(active, api, settings)); + const local = (instance.local = new Local(bridge, mainWindow, metadata, settings)); const nux = new NUX( active, instance, @@ -168,7 +170,7 @@ export default class App { miniModeWindow, pluginManager, stream, - log + settings ); await custom.start(); @@ -177,7 +179,6 @@ export default class App { api, bridge, insertHistory, - log, mainWindow, miniModeWindow, nativeCommands, @@ -198,7 +199,6 @@ export default class App { chunkQueue, custom, executor, - log, mainWindow, microphone, miniModeWindow, @@ -407,6 +407,7 @@ export default class App { useMiniModeFewerAlternatives: settings.getUseMiniModeFewerAlternatives(), useMiniModeHideTimeout: settings.getUseMiniModeHideTimeout(), useVerboseLogging: settings.getUseVerboseLogging(), + loggingLevel: settings.getLoggingLevel(), }, windows ? windows : [this.mainWindow, this.miniModeWindow, this.settingsWindow] ); diff --git a/client/src/main/execute/executor.ts b/client/src/main/execute/executor.ts index a409514..819a2cd 100644 --- a/client/src/main/execute/executor.ts +++ b/client/src/main/execute/executor.ts @@ -22,13 +22,13 @@ export default class Executor { private miniModeHideTimeout?: NodeJS.Timeout; private pending?: core.ICommandsResponse; private resolveChainFinished = () => {}; + private log: Log; constructor( private active: Active, private api: API, private bridge: RendererBridge, private insertHistory: InsertHistory, - private log: Log, private mainWindow: MainWindow, private miniModeWindow: MiniModeWindow, private nativeCommands: NativeCommands, @@ -41,6 +41,7 @@ export default class Executor { private commandHandler: () => any ) { this.newChainFinishedPromise(); + this.log = new Log(this.settings, "Executor"); } private addToHistory(response: core.ICommandsResponse) { @@ -514,7 +515,7 @@ export default class Executor { } async executeChain(text: string) { - this.log.logVerbose(`Executing chain: ${text}`); + this.log.debug(`Executing chain: ${text}`); await this.stream.sendInitializeRequest(); this.stream.sendCallbackRequest({ type: core.CallbackType.CALLBACK_TYPE_CHAIN, @@ -561,7 +562,7 @@ export default class Executor { } if (response.alternatives && response.alternatives.length > 0) { - this.log.logVerbose( + this.log.debug( `Showing alternatives [${response.alternatives.map((e: any) => e.transcript).join(", ")}]` ); diff --git a/client/src/main/index.ts b/client/src/main/index.ts index b101b71..74926fb 100644 --- a/client/src/main/index.ts +++ b/client/src/main/index.ts @@ -6,6 +6,8 @@ import * as os from "os"; import * as path from "path"; import App from "./app"; import Metadata from "../shared/metadata"; +import Log from "./log"; +import Settings from "./settings"; let instance: App | null = null; const lock = app.requestSingleInstanceLock(); @@ -20,9 +22,11 @@ process.env["NODE_" + "ENV"] = "production"; process.on("uncaughtException", (e) => { if (instance && instance.log) { - instance.log.logError(e); + instance.log.error("uncaughtException", e); } else { - console.error(e); + let settings = new Settings(); + let log = new Log(settings, "Main"); + log.error("uncaughtException", e); } }); diff --git a/client/src/main/ipc/custom.ts b/client/src/main/ipc/custom.ts index 753be41..f25b518 100644 --- a/client/src/main/ipc/custom.ts +++ b/client/src/main/ipc/custom.ts @@ -118,7 +118,7 @@ For more information, check out the Serenade API documentation: https://serenade return new Promise((resolve) => { this.resolveStart = resolve; this.stop(); - const stream = fs.createWriteStream(path.join(this.settings.path(), "serenade.log")); + const stream = fs.createWriteStream(path.join(this.settings.path(), "custom-command-server.log")); this.process = child_process.fork("serenade-custom-commands-server.min.js", [], { cwd: path.join(this.settings.path(), "ipc"), stdio: "pipe", diff --git a/client/src/main/ipc/local.ts b/client/src/main/ipc/local.ts index c93fedd..b65428b 100644 --- a/client/src/main/ipc/local.ts +++ b/client/src/main/ipc/local.ts @@ -18,14 +18,16 @@ export default class Local { private logStreams: { [key in RunnableService]?: fs.WriteStream } = {}; private pollingInterval?: NodeJS.Timeout; private started: boolean = false; + private log: Log; constructor( private bridge: RendererBridge, - private log: Log, private mainWindow: MainWindow, private metadata: Metadata, private settings: Settings - ) {} + ) { + this.log = new Log(settings, "Local"); + } private captureOutput(service: RunnableService, child: child_process.ChildProcess) { if (this.logStreams[service]) { @@ -129,10 +131,10 @@ export default class Local { this.pollUntilRunning(); let speechEngineModels = path.join(__dirname, "..", "static", "local", "speech-engine-models"); - this.log.logVerbose("Initial speech engine model path: " + speechEngineModels); + this.log.info("Initial speech engine model path: " + speechEngineModels); let codeEngineModels = path.join(__dirname, "..", "static", "local", "code-engine-models"); - this.log.logVerbose("Initial code engine model path: " + codeEngineModels); + this.log.info("Initial code engine model path: " + codeEngineModels); if (os.platform() == "win32") { speechEngineModels = @@ -145,7 +147,7 @@ export default class Local { ]) .stdout.toString() .trim(); - this.log.logVerbose("WSL speech engine path: " + speechEngineModels); + this.log.info("WSL speech engine path: " + speechEngineModels); codeEngineModels = "/" + @@ -157,7 +159,7 @@ export default class Local { ]) .stdout.toString() .trim(); - this.log.logVerbose("WSL code engine path: " + codeEngineModels); + this.log.info("WSL code engine path: " + codeEngineModels); } // here and below: WSL doesn't deal well with paths, so set the cwd to be the same as the binary diff --git a/client/src/main/ipc/server.ts b/client/src/main/ipc/server.ts index a384be2..4742f52 100644 --- a/client/src/main/ipc/server.ts +++ b/client/src/main/ipc/server.ts @@ -8,11 +8,13 @@ import RendererBridge from "../bridge"; import Stream from "../stream/stream"; import { core } from "../../gen/core"; import Log from "../log"; +import Settings from "../settings"; const maximumIconLength = 20000; export default class IPCServer { private server: WebSocket.Server; + private log: Log; constructor( private active: Active, @@ -22,8 +24,9 @@ export default class IPCServer { private miniModeWindow: MiniModeWindow, private pluginManager: PluginManager, private stream: Stream, - private log: Log + private settings: Settings ) { + this.log = new Log(this.settings, "IPCServer"); this.server = new WebSocket.Server({ host: "localhost", port: 17373 }); this.server.on("connection", (websocket) => { websocket.on("message", (message) => { @@ -40,7 +43,7 @@ export default class IPCServer { icon.length <= maximumIconLength); if (!iconValid) { - this.log.logVerbose("Plugin provided an app icon that does not adhere to requirements"); + this.log.warn("Plugin provided an app icon that does not adhere to requirements"); icon = undefined; } @@ -60,7 +63,7 @@ export default class IPCServer { } // custom commands messages from custom commands servers if (request.message == "customCommands") { - this.log.logVerbose( + this.log.debug( "Received " + request.data.commands.length + " commands, " + diff --git a/client/src/main/log.ts b/client/src/main/log.ts index 85ade2f..c77365a 100644 --- a/client/src/main/log.ts +++ b/client/src/main/log.ts @@ -2,35 +2,69 @@ import * as fs from "fs-extra"; import * as os from "os"; import * as path from "path"; import Settings from "./settings"; +import * as wiston from "winston"; export default class Log { + private logger: wiston.Logger; + private label: string; private errorStream?: fs.WriteStream; private verboseStream?: fs.WriteStream; + private defaultLevel: string = "info"; - constructor(private settings: Settings) {} - - logError(e: any) { - if (!this.errorStream) { - this.errorStream = fs.createWriteStream(path.join(os.homedir(), ".serenade", "error.log")); + constructor(private settings: Settings, label?: string) { + if (label) { + this.label = label; + } else { + this.label = "serenade"; } - console.error(e); - this.errorStream.write(`${e.stack}\n`); + const myFmt = wiston.format.printf(({ level, label, message, timestamp }) => { + return `${timestamp} [${label}] ${level}: ${message}`; + }); + + this.logger = wiston.createLogger({ + level: this.validateLogLevel(this.settings.getLoggingLevel()), + format: wiston.format.combine( + wiston.format.label({ label: this.label }), + wiston.format.timestamp(), + myFmt + ), + transports: [ + new wiston.transports.Console(), + new wiston.transports.File({ + filename: path.join(os.homedir(), ".serenade", "serenade.log"), + }), + ] + }); } - logVerbose(message: string, includeDate: boolean = true) { - if (!this.settings.getUseVerboseLogging()) { - return; + validateLogLevel(level: string): string { + if (wiston.config.syslog.levels[level]) { + return level; + } else { + return this.defaultLevel; } + } - if (!this.verboseStream) { - this.verboseStream = fs.createWriteStream( - path.join(os.homedir(), ".serenade", "verbose.log") - ); - } + debug(message: string) { + this.logger.debug(message); + } - const data = `${includeDate ? Date.now() + " " : ""}${message}`; - console.log(data); - this.verboseStream.write(`${data}\n`); + info(message: string) { + this.logger.info(message); + } + + warn(message: string) { + this.logger.warn(message); + } + + error(message: string, e?: any) { + if (e) { + message = `${message}: ${e.message}`; + this.logger.error(message); + this.logger.error(e.stack); + } else { + this.logger.error(message); + } } } diff --git a/client/src/main/settings.ts b/client/src/main/settings.ts index cc4200f..729fde8 100644 --- a/client/src/main/settings.ts +++ b/client/src/main/settings.ts @@ -372,6 +372,15 @@ export default class Settings { return this.get("user", "verbose_logging", false); } + getLoggingLevel(): string { + let verbose = this.getUseVerboseLogging(); + if (verbose) { + return "debug"; + } else { + return "info"; + } + } + async loadWordsFileIfNeeded() { const modified = (await fs.stat(this.wordsFile())).mtime.getTime(); if (modified > this.wordsLastLoad) { diff --git a/client/src/main/stream/chunk-manager.ts b/client/src/main/stream/chunk-manager.ts index 202f9a6..b567ca5 100644 --- a/client/src/main/stream/chunk-manager.ts +++ b/client/src/main/stream/chunk-manager.ts @@ -46,6 +46,7 @@ export default class ChunkManager { private speaking: boolean = false; private timeToWaitBeforeClassifyingAsNoise: number = 200; private timeToWaitBeforeStartingNewCommand: number = 5000; + private log: Log; listening: boolean = false; @@ -57,13 +58,14 @@ export default class ChunkManager { private chunkQueue: ChunkQueue, private custom: Custom, private executor: Executor, - private log: Log, private mainWindow: MainWindow, private microphone: Microphone, private miniModeWindow: MiniModeWindow, private settings: Settings, private stream: Stream - ) {} + ) { + this.log = new Log(settings, "ChunkManager"); + } private async enqueue(request: Request, flush: boolean = true) { this.buffer.push(request); @@ -80,7 +82,7 @@ export default class ChunkManager { while (this.buffer.length > 0) { const request = this.buffer.shift()!; if (request.requestType != "audio") { - this.log.logVerbose(`Flushing ${request.requestType}`); + this.log.debug(`Flushing ${request.requestType}`); } await this.send(request); @@ -227,45 +229,45 @@ export default class ChunkManager { async attemptToEvaluateChunk(chunk: Chunk): Promise { if (this.chunkQueue.size() == 0) { - this.log.logVerbose(`Attempt to evaluate chunk, but empty chunk queue`); + this.log.debug(`Attempt to evaluate chunk, but empty chunk queue`); return; } const current = this.chunkQueue.getIndex(0); - this.log.logVerbose( - `Attempt to evaluate chunk\n chunk.id: ${chunk.id}\n chunk.executed: ${ + this.log.debug( + `Attempt to evaluate chunk chunk.id: ${chunk.id} chunk.executed: ${ chunk.executed - }\n chunk.reverted: ${ + } chunk.reverted: ${ chunk.reverted - }\n chunk.response: ${!!chunk.response}\n chunk.silence: ${ + } chunk.response: ${!!chunk.response} chunk.silence: ${ chunk.silence - } (${this.reachedSilenceThreshold(chunk)})\n current.id: ${ + } (${this.reachedSilenceThreshold(chunk)}) current.id: ${ current.id - }\n current.audioSize: ${current.audioSize}` + } current.audioSize: ${current.audioSize}` ); if (!chunk.reverted && chunk.executed) { - this.log.logVerbose(`Not executing chunk ${chunk.id}: already executed`); + this.log.debug(`Not executing chunk ${chunk.id}: already executed`); return; } if (chunk.id != current.id) { - this.log.logVerbose(`Not executing chunk ${chunk.id}: new chunk started`); + this.log.debug(`Not executing chunk ${chunk.id}: new chunk started`); return; } if (!chunk.reverted && !chunk.response) { - this.log.logVerbose(`Not executing chunk ${chunk.id}: no final response yet`); + this.log.debug(`Not executing chunk ${chunk.id}: no final response yet`); return; } if (chunk.reverted && !chunk.revertedResponse) { - this.log.logVerbose(`Not executing chunk ${chunk.id}: no reverted response yet`); + this.log.debug(`Not executing chunk ${chunk.id}: no reverted response yet`); return; } if (!this.reachedSilenceThreshold(chunk)) { - this.log.logVerbose(`Not executing chunk ${chunk.id}: waiting for silence`); + this.log.debug(`Not executing chunk ${chunk.id}: waiting for silence`); return; } @@ -276,7 +278,7 @@ export default class ChunkManager { (!chunk.response.alternatives || chunk.response.alternatives.length == 0) && !chunk.response.execute ) { - this.log.logVerbose(`Not executing chunk ${chunk.id}: no alternatives or execute`); + this.log.debug(`Not executing chunk ${chunk.id}: no alternatives or execute`); this.deadlineToMakeNewInitializeRequest = chunk.audioSize < this.audioSizeForDelayedInitialize ? Date.now() + this.timeToWaitBeforeClassifyingAsNoise @@ -285,7 +287,7 @@ export default class ChunkManager { } if (chunk.response && chunk.response.final && this.shouldAppendToPrevious(chunk.response)) { - this.log.logVerbose(`Appending to previous ${chunk.id}`); + this.log.debug(`Appending to previous ${chunk.id}`); chunk.reverted = Date.now(); chunk.executed = 0; chunk.silence = 0; @@ -294,7 +296,7 @@ export default class ChunkManager { return; } - this.log.logVerbose(`Setting partial to false`); + this.log.debug(`Setting partial to false`); this.bridge.setState( { partial: false, @@ -302,7 +304,7 @@ export default class ChunkManager { [this.mainWindow, this.miniModeWindow] ); - this.log.logVerbose(`Executing chunk ${chunk.id}`); + this.log.debug(`Executing chunk ${chunk.id}`); this.deadlineToMakeNewInitializeRequest = 0; chunk.executed = Date.now(); this.startBuffering(); @@ -313,11 +315,11 @@ export default class ChunkManager { async onCommandsResponse(response: core.ICommandsResponse) { const chunk = this.chunkQueue.getChunk(response.chunkId!); if (!chunk) { - this.log.logVerbose(`No chunk found for ${response.chunkId!}`); + this.log.debug(`No chunk found for ${response.chunkId!}`); return; } - this.log.logVerbose( + this.log.debug( `Received ${response.final ? "final" : "partial"} response for ${chunk.id}: [${( response.alternatives || [] ) @@ -337,7 +339,7 @@ export default class ChunkManager { if (!this.shouldAppendToPrevious(response)) { const partial = !chunk.executed && (!response.final || !this.reachedSilenceThreshold(chunk)); if (!isMetaResponse(response) && response.alternatives && response.alternatives.length > 0) { - this.log.logVerbose(`Setting partial = ${partial}`); + this.log.debug(`Setting partial = ${partial}`); this.bridge.setState( { partial, @@ -391,7 +393,7 @@ export default class ChunkManager { if ( current.silence == Math.ceil(this.settings.getExecuteSilenceThreshold() * silenceThreshold) ) { - this.log.logVerbose(`Silence hit for ${current.id}`); + this.log.debug(`Silence hit for ${current.id}`); this.attemptToEvaluateChunk(current); } } @@ -412,7 +414,7 @@ export default class ChunkManager { return; } - this.log.logVerbose(`Chunk end for ${current.id}`); + this.log.debug(`Chunk end for ${current.id}`); this.enqueue({ requestType: "editor" }, false); this.enqueue({ requestType: "endpoint", chunkId: current.id, finalize: true }); } @@ -420,7 +422,7 @@ export default class ChunkManager { async onChunkStart(audio: any) { const id = uuid(); this.chunkQueue.add(id); - this.log.logVerbose(`Chunk start for ${id}`); + this.log.debug(`Chunk start for ${id}`); if (!this.speaking) { this.bridge.setState( @@ -445,12 +447,12 @@ export default class ChunkManager { } startBuffering() { - this.log.logVerbose("Buffering started"); + this.log.debug("Buffering started"); this.buffering = true; } async stopBufferingAndFlush() { - this.log.logVerbose("Buffering stopped"); + this.log.debug("Buffering stopped"); this.buffering = false; await this.flush(); } @@ -472,7 +474,7 @@ export default class ChunkManager { [this.mainWindow, this.miniModeWindow] ); - this.log.logVerbose(`Toggling listening to ${listening}`); + this.log.debug(`Toggling listening to ${listening}`); setTimeout(async () => { this.mainWindow.updateTray(); if (listening) { diff --git a/client/src/main/stream/stream.ts b/client/src/main/stream/stream.ts index ba4f5bb..e3e0a7d 100644 --- a/client/src/main/stream/stream.ts +++ b/client/src/main/stream/stream.ts @@ -15,13 +15,14 @@ export default class Stream { private keepAliveTimeout?: NodeJS.Timeout; private loggingBuffer: Buffer[] = []; private coreSocket?: WebSocket; + private log: Log; constructor( private active: Active, private api: API, - private log: Log, private settings: Settings ) { + this.log = new Log(settings, "Stream"); // disconnect after an hour with no commands setInterval(() => { if (this.connected() && Date.now() > this.lastActivity + 3600000) { @@ -35,7 +36,7 @@ export default class Stream { return; } - this.log.logVerbose("Sending keepalive"); + this.log.debug("Sending keepalive"); this.send(this.coreSocket, { keepAliveRequest: {}, }); @@ -75,7 +76,7 @@ export default class Stream { ); this.coreSocket.on("open", () => { - this.log.logVerbose("Stream connected"); + this.log.info("Stream connected"); this.isConnected = true; resolve(true); }); @@ -107,7 +108,7 @@ export default class Stream { this.coreSocket.on("error", (e) => { chunkManager.toggle(false); - this.log.logError(e); + this.log.error("Error during socket operation", e); }); }); } @@ -121,7 +122,7 @@ export default class Stream { return; } - this.log.logVerbose("Stream disconnected"); + this.log.info("Stream disconnected"); this.isConnected = false; this.coreSocket?.close(); this.loggingBuffer = []; @@ -168,7 +169,7 @@ export default class Stream { } sendCallbackRequest(callbackRequest: core.ICallbackRequest) { - this.log.logVerbose(`Sending callback request: ${callbackRequest.type}`); + this.log.debug(`Sending callback request: ${callbackRequest.type}`); this.send(this.coreSocket, { callbackRequest, }); @@ -181,7 +182,7 @@ export default class Stream { } async sendEditorStateRequest(clipboard: boolean = false, editorState?: any): Promise { - this.log.logVerbose("Sending editor state"); + this.log.debug("Sending editor state"); if (!editorState) { editorState = await this.active.getEditorState(clipboard); } @@ -206,7 +207,7 @@ export default class Stream { } const endpointId = uuid(); - this.log.logVerbose( + this.log.debug( `Sending ${finalize ? "final" : "partial"} endpoint request for ${chunkId}` ); this.send(this.coreSocket, { @@ -219,7 +220,7 @@ export default class Stream { } async sendInitializeRequest(): Promise { - this.log.logVerbose("Sending initialize request"); + this.log.debug("Sending initialize request"); this.send(this.coreSocket, { initializeRequest: { editorState: await this.active.getEditorState(), @@ -228,7 +229,7 @@ export default class Stream { } async sendTextRequest(text: string, includeAlternatives: boolean) { - this.log.logVerbose(`Sending text request: ${text}, ${includeAlternatives}`); + this.log.debug(`Sending text request: ${text}, ${includeAlternatives}`); await this.sendInitializeRequest(); this.send(this.coreSocket, { textRequest: {