(
entryToAppend: LogEntry,
)
| 161 | } |
| 162 | |
| 163 | private async _updateLogFile( |
| 164 | entryToAppend: LogEntry, |
| 165 | ): Promise<LogEntry | null> { |
| 166 | if (!this.logFilePath) { |
| 167 | console.debug('Log file path not set. Cannot persist log entry.'); |
| 168 | throw new Error('Log file path not set during update attempt.'); |
| 169 | } |
| 170 | |
| 171 | let currentLogsOnDisk: LogEntry[]; |
| 172 | try { |
| 173 | currentLogsOnDisk = await this._readLogFile(); |
| 174 | } catch (readError) { |
| 175 | console.debug( |
| 176 | 'Critical error reading log file before append:', |
| 177 | readError, |
| 178 | ); |
| 179 | throw readError; |
| 180 | } |
| 181 | |
| 182 | // Determine the correct messageId for the new entry based on current disk state for its session |
| 183 | const sessionLogsOnDisk = currentLogsOnDisk.filter( |
| 184 | (e) => e.sessionId === entryToAppend.sessionId, |
| 185 | ); |
| 186 | const nextMessageIdForSession = |
| 187 | sessionLogsOnDisk.length > 0 |
| 188 | ? Math.max(...sessionLogsOnDisk.map((e) => e.messageId)) + 1 |
| 189 | : 0; |
| 190 | |
| 191 | // Update the messageId of the entry we are about to append |
| 192 | entryToAppend.messageId = nextMessageIdForSession; |
| 193 | |
| 194 | // Check if this entry (same session, same *recalculated* messageId, same content) might already exist |
| 195 | // This is a stricter check for true duplicates if multiple instances try to log the exact same thing |
| 196 | // at the exact same calculated messageId slot. |
| 197 | const entryExists = currentLogsOnDisk.some( |
| 198 | (e) => |
| 199 | e.sessionId === entryToAppend.sessionId && |
| 200 | e.messageId === entryToAppend.messageId && |
| 201 | e.timestamp === entryToAppend.timestamp && // Timestamps are good for distinguishing |
| 202 | e.message === entryToAppend.message, |
| 203 | ); |
| 204 | |
| 205 | if (entryExists) { |
| 206 | console.debug( |
| 207 | `Duplicate log entry detected and skipped: session ${entryToAppend.sessionId}, messageId ${entryToAppend.messageId}`, |
| 208 | ); |
| 209 | this.logs = currentLogsOnDisk; // Ensure in-memory is synced with disk |
| 210 | return null; // Indicate that no new entry was actually added |
| 211 | } |
| 212 | |
| 213 | currentLogsOnDisk.push(entryToAppend); |
| 214 | |
| 215 | try { |
| 216 | await fs.writeFile( |
| 217 | this.logFilePath, |
| 218 | JSON.stringify(currentLogsOnDisk, null, 2), |
| 219 | 'utf-8', |
| 220 | ); |
no test coverage detected