@harperfast/harper 5.3.0-alpha.1 → 5.3.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cliOperations.ts +12 -0
- package/bin/restart.ts +66 -6
- package/components/Application.ts +1134 -112
- package/components/DESIGN.md +421 -0
- package/components/OptionsWatcher.ts +368 -102
- package/components/Scope.ts +20 -1
- package/components/componentLoader.ts +43 -4
- package/components/deploymentOperations.ts +4 -1
- package/components/deploymentRecorder.ts +9 -2
- package/components/mcp/DESIGN.md +109 -0
- package/components/mcp/audit.ts +21 -17
- package/components/operations.js +284 -52
- package/components/operationsValidation.js +49 -2
- package/components/packageComponent.ts +25 -1
- package/components/requestRestart.ts +11 -0
- package/config/DESIGN.md +306 -0
- package/config/RootConfigWatcher.ts +191 -37
- package/config/configReadRetry.ts +62 -0
- package/config/configUtils.ts +78 -26
- package/config/parseConfigFile.ts +34 -0
- package/config/readConfigFileSync.ts +44 -0
- package/config/watcherArming.ts +59 -0
- package/config-root.schema.json +4 -0
- package/dataLayer/DESIGN.md +179 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +28 -2
- package/dataLayer/restoreMarker.ts +92 -25
- package/dist/bin/cliOperations.js +13 -0
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/restart.js +42 -6
- package/dist/bin/restart.js.map +1 -1
- package/dist/components/Application.d.ts +104 -9
- package/dist/components/Application.js +954 -102
- package/dist/components/Application.js.map +1 -1
- package/dist/components/OptionsWatcher.d.ts +4 -1
- package/dist/components/OptionsWatcher.js +378 -104
- package/dist/components/OptionsWatcher.js.map +1 -1
- package/dist/components/Scope.js +15 -1
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +35 -3
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/deploymentOperations.js +4 -1
- package/dist/components/deploymentOperations.js.map +1 -1
- package/dist/components/deploymentRecorder.d.ts +4 -2
- package/dist/components/deploymentRecorder.js +1 -0
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/mcp/audit.d.ts +2 -1
- package/dist/components/mcp/audit.js +21 -17
- package/dist/components/mcp/audit.js.map +1 -1
- package/dist/components/operations.d.ts +28 -0
- package/dist/components/operations.js +263 -54
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +48 -2
- package/dist/components/operationsValidation.js.map +1 -1
- package/dist/components/packageComponent.js +24 -0
- package/dist/components/packageComponent.js.map +1 -1
- package/dist/components/requestRestart.d.ts +1 -0
- package/dist/components/requestRestart.js +7 -0
- package/dist/components/requestRestart.js.map +1 -1
- package/dist/config/RootConfigWatcher.d.ts +2 -0
- package/dist/config/RootConfigWatcher.js +189 -35
- package/dist/config/RootConfigWatcher.js.map +1 -1
- package/dist/config/configReadRetry.d.ts +8 -0
- package/dist/config/configReadRetry.js +62 -0
- package/dist/config/configReadRetry.js.map +1 -0
- package/dist/config/configUtils.d.ts +10 -9
- package/dist/config/configUtils.js +63 -27
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/parseConfigFile.d.ts +4 -0
- package/dist/config/parseConfigFile.js +35 -0
- package/dist/config/parseConfigFile.js.map +1 -0
- package/dist/config/readConfigFileSync.d.ts +1 -0
- package/dist/config/readConfigFileSync.js +47 -0
- package/dist/config/readConfigFileSync.js.map +1 -0
- package/dist/config/watcherArming.d.ts +15 -0
- package/dist/config/watcherArming.js +59 -0
- package/dist/config/watcherArming.js.map +1 -0
- package/dist/dataLayer/harperBridge/ResourceBridge.js +21 -2
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/restoreMarker.d.ts +21 -8
- package/dist/dataLayer/restoreMarker.js +94 -27
- package/dist/dataLayer/restoreMarker.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +3 -0
- package/dist/resources/DatabaseTransaction.d.ts +25 -0
- package/dist/resources/DatabaseTransaction.js +224 -18
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +2 -1
- package/dist/resources/LMDBTransaction.js +22 -3
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.js +22 -6
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +1 -1
- package/dist/resources/RecordEncoder.js +46 -10
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/Resource.js +97 -13
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +8 -0
- package/dist/resources/RocksIndexStore.js +2 -1
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.d.ts +10 -0
- package/dist/resources/RocksTransactionLogStore.js +104 -33
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.d.ts +58 -7
- package/dist/resources/Table.js +1143 -348
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.d.ts +3 -0
- package/dist/resources/analytics/write.js +49 -16
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +170 -0
- package/dist/resources/auditStore.js +457 -11
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/crdt.d.ts +10 -0
- package/dist/resources/crdt.js +22 -0
- package/dist/resources/crdt.js.map +1 -1
- package/dist/resources/dataLoader.js +3 -4
- package/dist/resources/dataLoader.js.map +1 -1
- package/dist/resources/databases.d.ts +16 -13
- package/dist/resources/databases.js +625 -177
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/derivedIndexRegistry.d.ts +5 -0
- package/dist/resources/derivedIndexRegistry.js +68 -0
- package/dist/resources/derivedIndexRegistry.js.map +1 -0
- package/dist/resources/derivedIndexRuntime.d.ts +215 -0
- package/dist/resources/derivedIndexRuntime.js +2027 -0
- package/dist/resources/derivedIndexRuntime.js.map +1 -0
- package/dist/resources/graphql.js +3 -2
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +102 -9
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +867 -39
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/indexes/fullTextDerivedIndex.d.ts +81 -0
- package/dist/resources/indexes/fullTextDerivedIndex.js +1004 -0
- package/dist/resources/indexes/fullTextDerivedIndex.js.map +1 -0
- package/dist/resources/indexes/fullTextNativeBinding.d.ts +78 -0
- package/dist/resources/indexes/fullTextNativeBinding.js +85 -0
- package/dist/resources/indexes/fullTextNativeBinding.js.map +1 -0
- package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
- package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
- package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
- package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
- package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
- package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.d.ts +24 -0
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js +149 -0
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js.map +1 -0
- package/dist/resources/nodeIdMapping.d.ts +5 -0
- package/dist/resources/nodeIdMapping.js +49 -0
- package/dist/resources/nodeIdMapping.js.map +1 -1
- package/dist/resources/recordLock.d.ts +47 -4
- package/dist/resources/recordLock.js +138 -7
- package/dist/resources/recordLock.js.map +1 -1
- package/dist/resources/recordLockCoordinator.d.ts +557 -0
- package/dist/resources/recordLockCoordinator.js +2597 -0
- package/dist/resources/recordLockCoordinator.js.map +1 -0
- package/dist/resources/replayLogs.js +5 -0
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/replicatedApplyFailure.d.ts +16 -0
- package/dist/resources/replicatedApplyFailure.js +63 -0
- package/dist/resources/replicatedApplyFailure.js.map +1 -0
- package/dist/resources/scheduler/scheduler.js +3 -3
- package/dist/resources/scheduler/scheduler.js.map +1 -1
- package/dist/resources/search.d.ts +10 -4
- package/dist/resources/search.js +160 -40
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/tracked.d.ts +5 -1
- package/dist/resources/tracked.js +74 -23
- package/dist/resources/tracked.js.map +1 -1
- package/dist/resources/transactionBroadcast.js +4 -6
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/auth.js +59 -23
- package/dist/security/auth.js.map +1 -1
- package/dist/security/deferredAuthentication.d.ts +11 -0
- package/dist/security/deferredAuthentication.js +25 -3
- package/dist/security/deferredAuthentication.js.map +1 -1
- package/dist/security/jsLoader.js +9 -4
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/server/REST.js +39 -5
- package/dist/server/REST.js.map +1 -1
- package/dist/server/http.d.ts +5 -1
- package/dist/server/http.js +34 -2
- package/dist/server/http.js.map +1 -1
- package/dist/server/mqtt.js +5 -1
- package/dist/server/mqtt.js.map +1 -1
- package/dist/server/serverHelpers/Headers.d.ts +2 -0
- package/dist/server/serverHelpers/Headers.js +6 -0
- package/dist/server/serverHelpers/Headers.js.map +1 -1
- package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
- package/dist/server/serverHelpers/Request.d.ts +5 -10
- package/dist/server/serverHelpers/Request.js +38 -136
- package/dist/server/serverHelpers/Request.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +2 -0
- package/dist/server/serverHelpers/contentTypes.js +189 -15
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +3 -3
- package/dist/server/serverHelpers/serverUtilities.js +110 -20
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/serverHelpers/uwsServer.js +4 -1
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/serverHelpers/webSocketCloseReason.d.ts +2 -0
- package/dist/server/serverHelpers/webSocketCloseReason.js +29 -0
- package/dist/server/serverHelpers/webSocketCloseReason.js.map +1 -0
- package/dist/server/storageReclamation.js +1 -1
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/isolatedApplications.d.ts +47 -0
- package/dist/server/threads/isolatedApplications.js +171 -0
- package/dist/server/threads/isolatedApplications.js.map +1 -0
- package/dist/server/threads/logRotationTransport.d.ts +1 -0
- package/dist/server/threads/logRotationTransport.js +33 -0
- package/dist/server/threads/logRotationTransport.js.map +1 -0
- package/dist/server/threads/manageThreads.d.ts +64 -6
- package/dist/server/threads/manageThreads.js +261 -12
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -0
- package/dist/server/threads/socketRouter.js +196 -13
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadServer.js +30 -7
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +24 -0
- package/dist/utility/errors/hdbError.js +58 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/hdbTerms.d.ts +2 -0
- package/dist/utility/hdbTerms.js +2 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/logging/harper_logger.js +218 -38
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
- package/dist/utility/logging/logGenerationCoordinator.js +184 -0
- package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
- package/dist/utility/logging/logRotation.d.ts +46 -0
- package/dist/utility/logging/logRotation.js +365 -0
- package/dist/utility/logging/logRotation.js.map +1 -0
- package/dist/utility/logging/logRotator.d.ts +1 -1
- package/dist/utility/logging/logRotator.js +172 -92
- package/dist/utility/logging/logRotator.js.map +1 -1
- package/dist/utility/npmUtilities.js +6 -4
- package/dist/utility/npmUtilities.js.map +1 -1
- package/dist/utility/watcherFallback.d.ts +0 -45
- package/dist/utility/watcherFallback.js +1 -125
- package/dist/utility/watcherFallback.js.map +1 -1
- package/dist/validation/configValidator.js +6 -3
- package/dist/validation/configValidator.js.map +1 -1
- package/index.ts +9 -0
- package/json/systemSchema.json +3 -0
- package/npm-shrinkwrap.json +177 -87
- package/package.json +13 -5
- package/resources/DESIGN.md +689 -19
- package/resources/DatabaseTransaction.ts +230 -17
- package/resources/LMDBTransaction.ts +21 -3
- package/resources/PrimaryRocksDatabase.ts +20 -7
- package/resources/RecordEncoder.ts +52 -10
- package/resources/Resource.ts +97 -13
- package/resources/ResourceInterface.ts +8 -0
- package/resources/RocksIndexStore.ts +2 -1
- package/resources/RocksTransactionLogStore.ts +111 -31
- package/resources/Table.ts +1273 -396
- package/resources/analytics/DESIGN.md +38 -0
- package/resources/analytics/write.ts +50 -17
- package/resources/auditStore.ts +460 -11
- package/resources/crdt.ts +22 -0
- package/resources/dataLoader.ts +3 -4
- package/resources/databases.ts +611 -147
- package/resources/derivedIndexRegistry.ts +56 -0
- package/resources/derivedIndexRuntime.ts +2292 -0
- package/resources/graphql.ts +3 -2
- package/resources/indexes/DESIGN.md +833 -0
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +924 -46
- package/resources/indexes/fullTextDerivedIndex.ts +1165 -0
- package/resources/indexes/fullTextNativeBinding.ts +146 -0
- package/resources/indexes/hnswDerivedIndex.ts +531 -0
- package/resources/indexes/hnswPlaneBinding.ts +174 -0
- package/resources/indexes/nativeFullTextDerivedIndexLifecycle.ts +181 -0
- package/resources/nodeIdMapping.ts +50 -0
- package/resources/record-locks.md +1407 -0
- package/resources/recordLock.ts +173 -7
- package/resources/recordLockCoordinator.ts +3082 -0
- package/resources/replayLogs.ts +5 -0
- package/resources/replicatedApplyFailure.ts +77 -0
- package/resources/scheduler/DESIGN.md +40 -0
- package/resources/scheduler/scheduler.ts +4 -4
- package/resources/search.ts +169 -49
- package/resources/tracked.ts +73 -22
- package/resources/transactionBroadcast.ts +4 -4
- package/security/DESIGN.md +175 -0
- package/security/auth.ts +53 -24
- package/security/deferredAuthentication.ts +24 -2
- package/security/jsLoader.ts +9 -4
- package/server/DESIGN.md +275 -0
- package/server/REST.ts +42 -6
- package/server/http.ts +34 -2
- package/server/mqtt.ts +6 -4
- package/server/serverHelpers/Headers.ts +5 -1
- package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
- package/server/serverHelpers/Request.ts +33 -131
- package/server/serverHelpers/contentTypes.ts +188 -15
- package/server/serverHelpers/serverUtilities.ts +157 -27
- package/server/serverHelpers/uwsServer.ts +4 -1
- package/server/serverHelpers/webSocketCloseReason.ts +25 -0
- package/server/storageReclamation.ts +2 -2
- package/server/threads/isolatedApplications.ts +157 -0
- package/server/threads/logRotationTransport.ts +40 -0
- package/server/threads/manageThreads.js +254 -12
- package/server/threads/socketRouter.ts +217 -11
- package/server/threads/threadServer.js +30 -7
- package/studio/web/assets/{Chat-BnCBegQz.js → Chat-DADFFGe_.js} +1 -1
- package/studio/web/assets/{FloatingChat-CoDW1ySS.js → FloatingChat-D_mI-rZ7.js} +3 -3
- package/studio/web/assets/{apiToken-Bwk5BLXW.js → apiToken-c2NiSDHa.js} +1 -1
- package/studio/web/assets/{applications-DHxGi7JH.js → applications-DktUqh7G.js} +1 -1
- package/studio/web/assets/{cssMode-s0cWI-_M.js → cssMode-Cs_75Xhw.js} +1 -1
- package/studio/web/assets/{editor-DNcRHK54.js → editor-19b-Y1IN.js} +1 -1
- package/studio/web/assets/{html-Bdssedlg.js → html-DiYEQMpB.js} +1 -1
- package/studio/web/assets/{htmlMode-CoDlJ3fw.js → htmlMode-CmR0y7P_.js} +1 -1
- package/studio/web/assets/{index-D6sxmFLR.js → index-Dm0rfkJ7.js} +5 -5
- package/studio/web/assets/{index.lazy-tmU5BS8s.js → index.lazy-7vqt2CC3.js} +1 -1
- package/studio/web/assets/{javascript-B8meVSTH.js → javascript-BWtCFuOt.js} +1 -1
- package/studio/web/assets/{jsonMode-DpIPd35T.js → jsonMode-Buzzbv9y.js} +1 -1
- package/studio/web/assets/{languageServices-C_5FMJzQ.js → languageServices-SqsFWfTM.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-BIzNBzPK.js → lspLanguageFeatures-EMV5cmjo.js} +1 -1
- package/studio/web/assets/{notifications-CvZivSbh.js → notifications-CAB-LZWT.js} +1 -1
- package/studio/web/assets/{notifications-CQf18QKb.js → notifications-DRzmSRxM.js} +1 -1
- package/studio/web/assets/{profile-DdOwtntb.js → profile-BNKAl79n.js} +1 -1
- package/studio/web/assets/{regions-n69fwagr.js → regions-CUow_Zw2.js} +1 -1
- package/studio/web/assets/{register-PfWTCXWB.js → register-Dkt3WUMp.js} +2 -2
- package/studio/web/assets/{setComponentFile-Bg6O7X0S.js → setComponentFile-BZRfMD0N.js} +1 -1
- package/studio/web/assets/{setup-CUx_aUDl.js → setup-D_yiEPO2.js} +2 -2
- package/studio/web/assets/{status-D7BVKqX9.js → status-DhHh1Ge-.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-DBSyXzMr.js → toggleHighContrast-D7L1PDtV.js} +1 -1
- package/studio/web/assets/{tsMode-BByKCjBS.js → tsMode-CCwLk1YS.js} +1 -1
- package/studio/web/assets/{typescript-DDLnLpw9.js → typescript-BP1j1mjn.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-31CHGaHk.js → useEntityRestURL-D7bnYxLw.js} +1 -1
- package/studio/web/assets/{workers-pR3jRY9D.js → workers-tOuCNT17.js} +1 -1
- package/studio/web/assets/{xml-2iRnMhQO.js → xml-BSG_3mQT.js} +1 -1
- package/studio/web/assets/{yaml-Bf92gJpd.js → yaml-DxiLprBB.js} +1 -1
- package/studio/web/index.html +1 -1
- package/utility/DESIGN.md +55 -0
- package/utility/errors/hdbError.ts +54 -0
- package/utility/hdbTerms.ts +2 -0
- package/utility/logging/harper_logger.ts +210 -30
- package/utility/logging/logGenerationCoordinator.ts +196 -0
- package/utility/logging/logRotation.ts +367 -0
- package/utility/logging/logRotator.ts +196 -91
- package/utility/npmUtilities.ts +6 -4
- package/utility/watcherFallback.ts +0 -122
- package/validation/configValidator.ts +6 -3
|
@@ -73,6 +73,8 @@ const packageUtils_js_1 = require("../../utility/packageUtils.js");
|
|
|
73
73
|
const globals_js_1 = require("../../globals.js");
|
|
74
74
|
const console_1 = require("console");
|
|
75
75
|
const node_util_1 = require("node:util");
|
|
76
|
+
const logRotation_ts_1 = require("./logRotation.js");
|
|
77
|
+
const logGenerationCoordinator_ts_1 = require("./logGenerationCoordinator.js");
|
|
76
78
|
const { isNativeError } = node_util_1.types;
|
|
77
79
|
// store the native write function so we can call it after we write to the log file (and store it on process.stdout
|
|
78
80
|
// because unit tests will create multiple instances of this module)
|
|
@@ -101,6 +103,17 @@ exports.OUTPUTS = {
|
|
|
101
103
|
// Location of default config YAML.
|
|
102
104
|
const DEFAULT_CONFIG_FILE = join(packageUtils_js_1.PACKAGE_ROOT, 'static', hdbTerms.HDB_DEFAULT_CONFIG_FILE);
|
|
103
105
|
const CLOSE_LOG_FD_TIMEOUT = 10000;
|
|
106
|
+
// Above the module-scope initLogSettings() call below, which reaches getFileLogger: a const
|
|
107
|
+
// declared after it is still in its temporal dead zone when the file sink first reads one.
|
|
108
|
+
const LOG_TIME_USAGE_THRESHOLD = 100;
|
|
109
|
+
// How long to write straight to stdio after the log file refuses an append.
|
|
110
|
+
const APPEND_RETRY_COOLDOWN = 5000;
|
|
111
|
+
// Ceiling on how often a failing rotation may report itself; the failure repeats every check point.
|
|
112
|
+
const ROTATION_REPORT_INTERVAL = 60000;
|
|
113
|
+
const SET_ROTATION_POLICY = Symbol('setRotationPolicy');
|
|
114
|
+
const GET_ROTATION_POLICY = Symbol('getRotationPolicy');
|
|
115
|
+
const FILE_ROTATION_SOURCE = Symbol('fileRotationSource');
|
|
116
|
+
const SERVICE_NAME = worker_threads_1.workerData?.name?.replace(/ /g, '-') || 'main';
|
|
104
117
|
let logConsole;
|
|
105
118
|
let log_to_file;
|
|
106
119
|
let logToStdstreams;
|
|
@@ -159,7 +172,24 @@ function updateLogger(logger, logOptions, name, mainLoggerRef = mainLogger) {
|
|
|
159
172
|
// rotation entirely (#1877). Excluded when `logger` IS mainLoggerRef: the fallback would just
|
|
160
173
|
// reassign mainLogger.rotation to itself, making it impossible to ever clear main's rotation.
|
|
161
174
|
const inheritedRotation = logOptions.rotation ?? (logger === mainLoggerRef ? undefined : mainLoggerRef?.rotation);
|
|
162
|
-
|
|
175
|
+
const loggerPolicy = logger[GET_ROTATION_POLICY]?.();
|
|
176
|
+
const mainPolicy = mainLoggerRef?.[GET_ROTATION_POLICY]?.();
|
|
177
|
+
const inheritsRotation = logOptions.rotation == null && logger !== mainLoggerRef;
|
|
178
|
+
const rotationSource = inheritsRotation ? mainPolicy?.source : loggerPolicy?.ownSource;
|
|
179
|
+
let path = logOptions.path;
|
|
180
|
+
if (path) {
|
|
181
|
+
if (!logOptions.root)
|
|
182
|
+
logOptions.root = pathModule.dirname(path);
|
|
183
|
+
}
|
|
184
|
+
else if (logOptions.root) {
|
|
185
|
+
path = join(logOptions.root, logName);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
path = mainLoggerRef.path;
|
|
189
|
+
if (!logOptions.root)
|
|
190
|
+
logOptions.root = pathModule.dirname(path);
|
|
191
|
+
}
|
|
192
|
+
if (inheritedRotation && inheritedRotation === mainLoggerRef?.rotation && path !== mainLoggerRef?.path) {
|
|
163
193
|
// This logger has no rotation block of its own and is inheriting main's wholesale — but
|
|
164
194
|
// inheriting `rotation.path` too would point this logger's archives at wherever main
|
|
165
195
|
// archives to. If this logger's file lives on a different filesystem/volume than that
|
|
@@ -170,25 +200,18 @@ function updateLogger(logger, logOptions, name, mainLoggerRef = mainLogger) {
|
|
|
170
200
|
// goes through `logOptions.rotation` above, not this fallback. Clone rather than mutate:
|
|
171
201
|
// `inheritedRotation` is the literal object shared by mainLogger.rotation and every other
|
|
172
202
|
// component that inherited it.
|
|
203
|
+
//
|
|
204
|
+
// Only when the paths differ. A logger writing to main's own file shares main's rotation
|
|
205
|
+
// state — file loggers are cached per path — so stripping there discards the operator's
|
|
206
|
+
// configured rotation.path for the main log itself, which no EXDEV risk justifies.
|
|
173
207
|
const { path: _inheritedPath, ...rotationWithoutPath } = inheritedRotation;
|
|
174
|
-
|
|
208
|
+
setRotationPolicy(rotationWithoutPath);
|
|
175
209
|
}
|
|
176
210
|
else {
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
let path = logOptions.path;
|
|
180
|
-
if (path) {
|
|
181
|
-
if (!logOptions.root)
|
|
182
|
-
logOptions.root = pathModule.dirname(path);
|
|
183
|
-
}
|
|
184
|
-
else if (logOptions.root) {
|
|
185
|
-
path = join(logOptions.root, logName);
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
path = mainLoggerRef.path;
|
|
189
|
-
if (!logOptions.root)
|
|
190
|
-
logOptions.root = pathModule.dirname(path);
|
|
211
|
+
setRotationPolicy(inheritedRotation);
|
|
191
212
|
}
|
|
213
|
+
// After the rotation above: assigning `path` goes through the setter that rebuilds this path's
|
|
214
|
+
// file logger, and it reads `logger.rotation` as it stands at that moment.
|
|
192
215
|
if (path)
|
|
193
216
|
logger.path = path;
|
|
194
217
|
else
|
|
@@ -199,6 +222,12 @@ function updateLogger(logger, logOptions, name, mainLoggerRef = mainLogger) {
|
|
|
199
222
|
// if there is a configured tag or if a component is logging to default/main log path, use the component name as the tag
|
|
200
223
|
// to differentiate it
|
|
201
224
|
logger.tag = logOptions.tag ?? ((mainLoggerRef.path === logger.path || exports.externalLogger.path === logger.path) && name);
|
|
225
|
+
function setRotationPolicy(rotation) {
|
|
226
|
+
if (logger[SET_ROTATION_POLICY])
|
|
227
|
+
logger[SET_ROTATION_POLICY](rotation, rotationSource, inheritsRotation);
|
|
228
|
+
else
|
|
229
|
+
logger.rotation = rotation;
|
|
230
|
+
}
|
|
202
231
|
}
|
|
203
232
|
// creates a logger where the methods are only defined if they are within the log level.
|
|
204
233
|
// Using this conditional logger means that every method call must be optional like log.trace?.('message),
|
|
@@ -233,7 +262,19 @@ async function updateLogSettings() {
|
|
|
233
262
|
// TODO: Any way to differentiate changes that we can and can't handle?
|
|
234
263
|
rootConfig.on('change', updateLogSettings);
|
|
235
264
|
}
|
|
236
|
-
|
|
265
|
+
applyLogSettings(rootConfig.config);
|
|
266
|
+
}
|
|
267
|
+
// Separate from the watcher wiring above because the watcher it builds reads a process-wide path,
|
|
268
|
+
// which leaves no way to exercise these settings against a given config.
|
|
269
|
+
function applyLogSettings(rootConfigObject) {
|
|
270
|
+
// `ready` settles on every terminal read outcome, including ones that carry no config at all —
|
|
271
|
+
// see DESIGN.md, "Every terminal read outcome settles the barrier". Applying that as settings
|
|
272
|
+
// would not be "the defaults": `updateLogger` reads an absent `rotation` as rotation off and an
|
|
273
|
+
// absent `console` as console off, so an unreadable config would silently disable logging.
|
|
274
|
+
// What `initLogSettings()` established at startup stands until a real config arrives, which
|
|
275
|
+
// is why the watcher settles those outcomes with no config rather than an empty one.
|
|
276
|
+
if (!rootConfigObject || typeof rootConfigObject !== 'object')
|
|
277
|
+
return;
|
|
237
278
|
const logOptions = rootConfigObject.logging ?? {};
|
|
238
279
|
// Resolve relative paths against rootPath from the same config
|
|
239
280
|
const rootPath = rootConfigObject.rootPath;
|
|
@@ -256,7 +297,9 @@ async function updateLogSettings() {
|
|
|
256
297
|
for (const name in rootConfigObject) {
|
|
257
298
|
// we now scan each component to see if it has logging individual configured
|
|
258
299
|
const component = rootConfigObject[name];
|
|
259
|
-
|
|
300
|
+
// `myComponent:` with nothing under it parses to null, and an async listener's TypeError
|
|
301
|
+
// escapes the watcher's emit guard as an unhandled rejection.
|
|
302
|
+
if (component?.logging) {
|
|
260
303
|
updateLogger(mainLogger.forComponent(name), component.logging, name);
|
|
261
304
|
}
|
|
262
305
|
else if (mainLogger.hasComponent(name)) {
|
|
@@ -456,6 +499,8 @@ module.exports = {
|
|
|
456
499
|
// we can start using the RootConfigWatcher
|
|
457
500
|
start: updateLogSettings,
|
|
458
501
|
startOnMainThread: updateLogSettings,
|
|
502
|
+
// Test-only: applies a config without the process-wide watcher `updateLogSettings` builds.
|
|
503
|
+
_applyLogSettingsForTests: applyLogSettings,
|
|
459
504
|
errorToString,
|
|
460
505
|
errorForLog,
|
|
461
506
|
inspectForLog,
|
|
@@ -516,6 +561,14 @@ function logsAtLevel(level) {
|
|
|
516
561
|
function initLogSettings(forceInit = false) {
|
|
517
562
|
try {
|
|
518
563
|
if (hdbProperties === undefined || forceInit) {
|
|
564
|
+
if (forceInit && mainLogger?.[SET_ROTATION_POLICY]) {
|
|
565
|
+
const currentPath = mainLogger.path;
|
|
566
|
+
if (currentPath) {
|
|
567
|
+
const { ownSource } = mainLogger[GET_ROTATION_POLICY]();
|
|
568
|
+
mainLogger[SET_ROTATION_POLICY](undefined, ownSource, false);
|
|
569
|
+
mainLogger.path = currentPath;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
519
572
|
closeLogFile();
|
|
520
573
|
const bootPropsFilePath = getPropsFilePath();
|
|
521
574
|
let properties = (0, assignCmdEnvVariables_ts_1.default)(['ROOTPATH']);
|
|
@@ -692,14 +745,18 @@ function suppressLogging(callback) {
|
|
|
692
745
|
loggingEnabled = true;
|
|
693
746
|
}
|
|
694
747
|
}
|
|
695
|
-
const SERVICE_NAME = worker_threads_1.workerData?.name?.replace(/ /g, '-') || 'main';
|
|
696
748
|
// these are used to store information about the current service and tag so we can prepend them to the log during
|
|
697
749
|
// the writes, without having to pass the information through the Console instance
|
|
698
750
|
let currentLevel = 'info'; // default is info
|
|
699
751
|
let currentServiceName;
|
|
700
752
|
let currentTag;
|
|
701
753
|
function createLogger(options = {}) {
|
|
702
|
-
let { path: logFilePath, level: logLevel, stdStreams: logToStdstreams, rotation, isExternalInstance, writeToLog, component, } = options;
|
|
754
|
+
let { path: logFilePath, level: logLevel, stdStreams: logToStdstreams, rotation, isExternalInstance, writeToLog, component, rotationSource, rotationInherited = false, } = options;
|
|
755
|
+
const ownRotationSource = Symbol('rotationPolicySource');
|
|
756
|
+
let currentRotationSource = rotationSource ?? ownRotationSource;
|
|
757
|
+
let previousRotationSource;
|
|
758
|
+
let currentRotationInherited = rotationInherited;
|
|
759
|
+
let rotationChangeIsAuthoritative = rotation !== undefined;
|
|
703
760
|
if (!logLevel)
|
|
704
761
|
logLevel = 'info';
|
|
705
762
|
let level = typeof logLevel === 'number' ? logLevel : LOG_LEVEL_HIERARCHY[logLevel];
|
|
@@ -750,7 +807,8 @@ function createLogger(options = {}) {
|
|
|
750
807
|
else if (logToStdstreams)
|
|
751
808
|
process.stderr.write(log);
|
|
752
809
|
}
|
|
753
|
-
let logToFile = logFilePath && getFileLogger(logFilePath, rotation, isExternalInstance);
|
|
810
|
+
let logToFile = logFilePath && getFileLogger(logFilePath, rotation, isExternalInstance, rotationPolicy());
|
|
811
|
+
rotationPolicyApplied();
|
|
754
812
|
function logPrepend(write) {
|
|
755
813
|
return {
|
|
756
814
|
write(log) {
|
|
@@ -772,6 +830,14 @@ function createLogger(options = {}) {
|
|
|
772
830
|
stderr: logPrepend(writeToLog ?? logStdErr),
|
|
773
831
|
colorMode: (logToStdstreams && colorMode) || false,
|
|
774
832
|
}, level);
|
|
833
|
+
logger[SET_ROTATION_POLICY] = function (newRotation, source = ownRotationSource, inherited = false) {
|
|
834
|
+
previousRotationSource = currentRotationSource;
|
|
835
|
+
currentRotationSource = source ?? ownRotationSource;
|
|
836
|
+
currentRotationInherited = inherited;
|
|
837
|
+
rotationChangeIsAuthoritative = true;
|
|
838
|
+
logger.rotation = newRotation;
|
|
839
|
+
};
|
|
840
|
+
logger[GET_ROTATION_POLICY] = () => ({ ownSource: ownRotationSource, source: currentRotationSource });
|
|
775
841
|
updateConditional(logger);
|
|
776
842
|
logger.path = logFilePath;
|
|
777
843
|
Object.defineProperty(logger, 'path', {
|
|
@@ -780,7 +846,11 @@ function createLogger(options = {}) {
|
|
|
780
846
|
},
|
|
781
847
|
set(path) {
|
|
782
848
|
logFilePath = path;
|
|
783
|
-
|
|
849
|
+
if (!logFilePath)
|
|
850
|
+
return;
|
|
851
|
+
logToFile = getFileLogger(logFilePath, logger.rotation, isExternalInstance, rotationPolicy());
|
|
852
|
+
logger.closeLogFile = logToFile.closeLogFile;
|
|
853
|
+
rotationPolicyApplied();
|
|
784
854
|
if (isExternalInstance)
|
|
785
855
|
writeToLogFile = logToFile;
|
|
786
856
|
},
|
|
@@ -794,12 +864,15 @@ function createLogger(options = {}) {
|
|
|
794
864
|
let componentLogger = components.get(name);
|
|
795
865
|
if (!componentLogger) {
|
|
796
866
|
const protoLogger = isExternal ? exports.externalLogger : logger;
|
|
867
|
+
const protoRotationPolicy = protoLogger[GET_ROTATION_POLICY]?.();
|
|
797
868
|
componentLogger = createLogger({
|
|
798
869
|
path: protoLogger.path,
|
|
799
870
|
level: protoLogger.level,
|
|
800
871
|
stdStreams: protoLogger.logToStdstreams,
|
|
801
872
|
isExternalInstance: isExternal || name === 'external',
|
|
802
873
|
rotation: protoLogger.rotation,
|
|
874
|
+
rotationSource: protoRotationPolicy?.source,
|
|
875
|
+
rotationInherited: true,
|
|
803
876
|
writeToLog,
|
|
804
877
|
component: true,
|
|
805
878
|
});
|
|
@@ -816,35 +889,80 @@ function createLogger(options = {}) {
|
|
|
816
889
|
logger.components = components;
|
|
817
890
|
}
|
|
818
891
|
return logger;
|
|
892
|
+
function rotationPolicy() {
|
|
893
|
+
return {
|
|
894
|
+
source: currentRotationSource,
|
|
895
|
+
previousSource: previousRotationSource,
|
|
896
|
+
inherited: currentRotationInherited,
|
|
897
|
+
authoritative: rotationChangeIsAuthoritative,
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
function rotationPolicyApplied() {
|
|
901
|
+
previousRotationSource = currentRotationSource;
|
|
902
|
+
rotationChangeIsAuthoritative = false;
|
|
903
|
+
}
|
|
819
904
|
}
|
|
820
|
-
const LOG_TIME_USAGE_THRESHOLD = 100;
|
|
821
|
-
// How long to write straight to stdio after the log file refuses an append.
|
|
822
|
-
const APPEND_RETRY_COOLDOWN = 5000;
|
|
823
905
|
/**
|
|
824
906
|
* Get the file logger for the given path. If it doesn't exist, create it.
|
|
825
907
|
* @param path
|
|
826
908
|
* @param isExternalInstance
|
|
827
909
|
* @return {any}
|
|
828
910
|
*/
|
|
829
|
-
function getFileLogger(path, rotation, isExternalInstance) {
|
|
911
|
+
function getFileLogger(path, rotation, isExternalInstance, rotationPolicy) {
|
|
830
912
|
let logger = fileLoggers.get(path);
|
|
831
913
|
let logFD, loggedFDError, loggedAppendError, logTimer, retryAppendAfter;
|
|
832
914
|
let logBuffer;
|
|
915
|
+
let rotationProblemNotice;
|
|
833
916
|
let logTimeUsage = 0;
|
|
917
|
+
let rotationGuard, logFDIdentity, nextRotationReport = 0;
|
|
834
918
|
if (!logger) {
|
|
835
919
|
logger = logToFile;
|
|
836
920
|
logger.closeLogFile = closeLogFile;
|
|
921
|
+
// The guard has to be installed through the live closure: later calls for this path get the
|
|
922
|
+
// cached logger back, and their own logFD/logBuffer are dead.
|
|
923
|
+
logger.installRotationGuard = installRotationGuard;
|
|
837
924
|
logger.path = path;
|
|
838
925
|
fileLoggers.set(path, logger);
|
|
839
|
-
|
|
840
|
-
|
|
926
|
+
// Registered by the sink, not by the size guard: a thread that writes this file but has no
|
|
927
|
+
// guard (no maxSize, or rotation driven only by interval) still holds a descriptor, and an
|
|
928
|
+
// answer from it has to mean "released" rather than only "handler ran".
|
|
929
|
+
(0, logGenerationCoordinator_ts_1.registerLogSink)(path, { identity: () => logFDIdentity, close: closeLogFile });
|
|
930
|
+
}
|
|
931
|
+
const currentSource = logger[FILE_ROTATION_SOURCE];
|
|
932
|
+
const sameSource = currentSource === rotationPolicy.source;
|
|
933
|
+
const replacesPreviousSource = currentSource !== undefined && currentSource === rotationPolicy.previousSource;
|
|
934
|
+
const canInstall = rotation !== undefined &&
|
|
935
|
+
(!rotationPolicy.inherited || currentSource === undefined || sameSource || replacesPreviousSource);
|
|
936
|
+
const canClear = rotation === undefined && rotationPolicy.authoritative && (sameSource || replacesPreviousSource);
|
|
937
|
+
let reconfigured = false;
|
|
938
|
+
if (canInstall) {
|
|
939
|
+
logger[FILE_ROTATION_SOURCE] = rotationPolicy.source;
|
|
940
|
+
reconfigured = JSON.stringify(rotation) !== JSON.stringify(logger.rotation);
|
|
941
|
+
}
|
|
942
|
+
if (reconfigured) {
|
|
841
943
|
logger.rotation = rotation;
|
|
944
|
+
// Every writing thread, and synchronously: request logging is produced by the HTTP workers, and
|
|
945
|
+
// at the rates that make maxSize matter a deferred guard misses megabytes before it exists.
|
|
946
|
+
logger.installRotationGuard(rotation);
|
|
947
|
+
}
|
|
948
|
+
else if (canClear) {
|
|
949
|
+
logger.rotation = undefined;
|
|
950
|
+
logger[FILE_ROTATION_SOURCE] = undefined;
|
|
951
|
+
logger.installRotationGuard(undefined);
|
|
952
|
+
reconfigured = true;
|
|
953
|
+
}
|
|
954
|
+
if (worker_threads_1.isMainThread && reconfigured) {
|
|
842
955
|
setTimeout(() => {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
const { logRotator } = require('./logRotator');
|
|
956
|
+
// Everything inside the try: a throw from a timer callback is unhandled, and neither
|
|
957
|
+
// require('./logRotator') (which reaches environmentManager's synchronous init) nor a
|
|
958
|
+
// rotator teardown may take the process down over log rotation (#847).
|
|
847
959
|
try {
|
|
960
|
+
const previousRotator = logger.rotator;
|
|
961
|
+
logger.rotator = undefined;
|
|
962
|
+
previousRotator?.end();
|
|
963
|
+
if (!rotation)
|
|
964
|
+
return;
|
|
965
|
+
const { logRotator } = require('./logRotator');
|
|
848
966
|
logger.rotator = logRotator({
|
|
849
967
|
logger,
|
|
850
968
|
...rotation,
|
|
@@ -856,6 +974,50 @@ function getFileLogger(path, rotation, isExternalInstance) {
|
|
|
856
974
|
}, 100);
|
|
857
975
|
}
|
|
858
976
|
return logger;
|
|
977
|
+
function installRotationGuard(newRotation) {
|
|
978
|
+
rotationGuard = undefined;
|
|
979
|
+
if (!newRotation || newRotation.enabled === false)
|
|
980
|
+
return;
|
|
981
|
+
const maxBytes = (0, logRotation_ts_1.parseMaxSize)(newRotation.maxSize);
|
|
982
|
+
if (!maxBytes) {
|
|
983
|
+
if (newRotation.maxSize != null)
|
|
984
|
+
reportRotationProblem(`logging.rotation.maxSize: ${logRotation_ts_1.INVALID_MAX_SIZE_MSG}`);
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
try {
|
|
988
|
+
rotationGuard = (0, logRotation_ts_1.createRotationGuard)({
|
|
989
|
+
logPath: path,
|
|
990
|
+
maxBytes,
|
|
991
|
+
rotatedLogDir: (0, logRotation_ts_1.resolveRotatedLogDir)(path, newRotation.path),
|
|
992
|
+
// From the rotation block rather than environmentManager (which logRotator still reads):
|
|
993
|
+
// environmentManager imports this module, so it cannot be reached from the write path.
|
|
994
|
+
compress: newRotation.compress,
|
|
995
|
+
getLogIdentity: () => logFDIdentity,
|
|
996
|
+
closeLogFile,
|
|
997
|
+
report: reportRotationProblem,
|
|
998
|
+
onRotated(archivePath) {
|
|
999
|
+
// Same shape as every other line in the file: written straight to the sink, this
|
|
1000
|
+
// bypasses the prefix createLogger's logPrepend adds, and readLog parses by level.
|
|
1001
|
+
logToFile(`[${SERVICE_NAME}/${worker_threads_1.threadId}] [notify]: hdb.log rotated, old log moved to ${archivePath}`);
|
|
1002
|
+
},
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
catch (error) {
|
|
1006
|
+
reportRotationProblem(`log rotation is disabled for ${path}: ${error}`);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
function reportRotationProblem(text) {
|
|
1010
|
+
// Straight to stdio, never back through this sink: the sink is what rotation is failing on.
|
|
1011
|
+
// Rate-limited rather than once-only, so a later, different failure is still reported.
|
|
1012
|
+
if (nextRotationReport > performance.now())
|
|
1013
|
+
return;
|
|
1014
|
+
nextRotationReport = performance.now() + ROTATION_REPORT_INTERVAL;
|
|
1015
|
+
const message = `Harper log rotation problem — ${text}`;
|
|
1016
|
+
// Scripted services discard stdio. Preserve the warning in the active file on the next
|
|
1017
|
+
// successful append as well, without recursing through the rotation guard.
|
|
1018
|
+
rotationProblemNotice = `${new Date().toISOString()} [${SERVICE_NAME}/${worker_threads_1.threadId}] [error]: ${message}\n`;
|
|
1019
|
+
writeToStdioDirectly(process.stderr, `${message}\n`);
|
|
1020
|
+
}
|
|
859
1021
|
function logToFile(log) {
|
|
860
1022
|
let entry = `${new Date().toISOString()} ${log}${log.endsWith('\n') ? '' : '\n'}`;
|
|
861
1023
|
if (logBuffer) {
|
|
@@ -885,18 +1047,29 @@ function getFileLogger(path, rotation, isExternalInstance) {
|
|
|
885
1047
|
}
|
|
886
1048
|
// this is called on a timer, and will write the log buffer to the file
|
|
887
1049
|
function logQueuedData(entry) {
|
|
888
|
-
openLogFile(undefined);
|
|
889
1050
|
const payload = logBuffer ? logBuffer.join('') : entry;
|
|
1051
|
+
// Released before anything can re-enter: the rotation notice is written from inside the append
|
|
1052
|
+
// below, and a re-entrant flush still holding this batch would write it twice.
|
|
1053
|
+
logBuffer = null;
|
|
1054
|
+
if (payload === undefined)
|
|
1055
|
+
return;
|
|
890
1056
|
// A file that just refused a write will refuse the next one too, and every attempt costs a
|
|
891
1057
|
// failed syscall plus a thrown error on whatever path is logging - which, on a full volume,
|
|
892
1058
|
// is the request path at full rate. Go straight to stdio until the cooldown expires.
|
|
893
|
-
|
|
1059
|
+
// Opened after the guard: a guard recovering by rotation closes this descriptor first.
|
|
1060
|
+
const mayAppend = !(retryAppendAfter > performance.now()) && (rotationGuard?.beforeAppend() ?? true);
|
|
1061
|
+
openLogFile(undefined);
|
|
1062
|
+
if (logFD && mayAppend) {
|
|
894
1063
|
let startTime = performance.now();
|
|
895
1064
|
try {
|
|
896
|
-
|
|
1065
|
+
const appendPayload = rotationProblemNotice ? rotationProblemNotice + payload : payload;
|
|
1066
|
+
const appendBuffer = Buffer.from(appendPayload);
|
|
1067
|
+
fs.appendFileSync(logFD, appendBuffer);
|
|
1068
|
+
rotationProblemNotice = undefined;
|
|
897
1069
|
// Both cleared, so a volume that fills again months later reports itself again
|
|
898
1070
|
retryAppendAfter = undefined;
|
|
899
1071
|
loggedAppendError = false;
|
|
1072
|
+
rotationGuard?.recordWrite(appendBuffer.length);
|
|
900
1073
|
}
|
|
901
1074
|
catch (error) {
|
|
902
1075
|
retryAppendAfter = performance.now() + APPEND_RETRY_COOLDOWN;
|
|
@@ -910,7 +1083,6 @@ function getFileLogger(path, rotation, isExternalInstance) {
|
|
|
910
1083
|
writeToStdioDirectly(process.stderr, `Harper cannot write to its log file: ${error}\n`);
|
|
911
1084
|
}
|
|
912
1085
|
writeToStdioDirectly(process.stdout, payload);
|
|
913
|
-
logBuffer = null;
|
|
914
1086
|
return;
|
|
915
1087
|
}
|
|
916
1088
|
let endTime = performance.now();
|
|
@@ -920,8 +1092,6 @@ function getFileLogger(path, rotation, isExternalInstance) {
|
|
|
920
1092
|
}
|
|
921
1093
|
else
|
|
922
1094
|
writeToStdioDirectly(process.stdout, payload);
|
|
923
|
-
if (logBuffer)
|
|
924
|
-
logBuffer = null;
|
|
925
1095
|
}
|
|
926
1096
|
function closeLogFile(_unused) {
|
|
927
1097
|
try {
|
|
@@ -929,6 +1099,7 @@ function getFileLogger(path, rotation, isExternalInstance) {
|
|
|
929
1099
|
}
|
|
930
1100
|
catch { }
|
|
931
1101
|
logFD = null;
|
|
1102
|
+
logFDIdentity = null;
|
|
932
1103
|
if (isExternalInstance)
|
|
933
1104
|
mainLogFd = null;
|
|
934
1105
|
}
|
|
@@ -936,6 +1107,15 @@ function getFileLogger(path, rotation, isExternalInstance) {
|
|
|
936
1107
|
if (!logFD) {
|
|
937
1108
|
try {
|
|
938
1109
|
logFD = fs.openSync(path, 'a');
|
|
1110
|
+
// Which generation this descriptor belongs to, recorded once here so the size guard's
|
|
1111
|
+
// checkpoint needs a single pathname stat to tell whether the file has moved under it.
|
|
1112
|
+
try {
|
|
1113
|
+
const opened = fs.fstatSync(logFD);
|
|
1114
|
+
logFDIdentity = { ino: opened.ino, dev: opened.dev };
|
|
1115
|
+
}
|
|
1116
|
+
catch {
|
|
1117
|
+
logFDIdentity = null;
|
|
1118
|
+
}
|
|
939
1119
|
if (isExternalInstance)
|
|
940
1120
|
mainLogFd = logFD;
|
|
941
1121
|
}
|