You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	All: Log last requests in case of a sync error
This commit is contained in:
		| @@ -16,6 +16,38 @@ class WebDavApi { | ||||
| 	constructor(options) { | ||||
| 		this.logger_ = new Logger(); | ||||
| 		this.options_ = options; | ||||
| 		this.lastRequests_ = []; | ||||
| 	} | ||||
|  | ||||
| 	logRequest_(request, responseText) { | ||||
| 		if (this.lastRequests_.length > 10) this.lastRequests_.splice(0, 1); | ||||
|  | ||||
| 		const serializeRequest = (r) => { | ||||
| 			const options = Object.assign({}, r.options); | ||||
| 			if (typeof options.body === 'string') options.body = options.body.substr(0, 4096); | ||||
| 			const output = []; | ||||
| 			output.push(options.method ? options.method : 'GET'); | ||||
| 			output.push(r.url); | ||||
| 			options.headers = Object.assign({}, options.headers); | ||||
| 			if (options.headers['Authorization']) options.headers['Authorization'] = '********'; | ||||
| 			delete options.method; | ||||
| 			output.push(JSON.stringify(options)); | ||||
| 			return output.join(' '); | ||||
| 		}; | ||||
|  | ||||
| 		this.lastRequests_.push({ | ||||
| 			timestamp: Date.now(), | ||||
| 			request: serializeRequest(request), | ||||
| 			response: responseText ? responseText.substr(0, 4096) : '', | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	lastRequests() { | ||||
| 		return this.lastRequests_; | ||||
| 	} | ||||
|  | ||||
| 	clearLastRequests() { | ||||
| 		this.lastRequests_ = []; | ||||
| 	} | ||||
|  | ||||
| 	setLogger(l) { | ||||
| @@ -340,6 +372,8 @@ class WebDavApi { | ||||
|  | ||||
| 		const responseText = await response.text(); | ||||
|  | ||||
| 		this.logRequest_({ url: url, options: fetchOptions }, responseText); | ||||
|  | ||||
| 		// console.info('WebDAV Response', responseText); | ||||
|  | ||||
| 		// Creates an error object with as much data as possible as it will appear in the log, which will make debugging easier | ||||
|   | ||||
| @@ -15,6 +15,14 @@ class FileApiDriverWebDav { | ||||
| 		return 3; | ||||
| 	} | ||||
|  | ||||
| 	lastRequests() { | ||||
| 		return this.api().lastRequests(); | ||||
| 	} | ||||
|  | ||||
| 	clearLastRequests() { | ||||
| 		return this.api().clearLastRequests(); | ||||
| 	} | ||||
|  | ||||
| 	async stat(path) { | ||||
| 		try { | ||||
| 			const result = await this.api().execPropFind(path, 0, ['d:getlastmodified', 'd:resourcetype']); | ||||
|   | ||||
| @@ -9,8 +9,15 @@ const { time } = require('lib/time-utils.js'); | ||||
| function requestCanBeRepeated(error) { | ||||
| 	const errorCode = typeof error === 'object' && error.code ? error.code : null; | ||||
|  | ||||
| 	// The target is explicitely rejecting the item so repeating wouldn't make a difference. | ||||
| 	if (errorCode === 'rejectedByTarget') return false; | ||||
|  | ||||
| 	// We don't repeat failSafe errors because it's an indication of an issue at the | ||||
| 	// server-level issue which usually cannot be fixed by repeating the request. | ||||
| 	// Also we print the previous requests and responses to the log in this case, | ||||
| 	// so not repeating means there will be less noise in the log. | ||||
| 	if (errorCode === 'failSafe') return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @@ -60,6 +67,14 @@ class FileApi { | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	lastRequests() { | ||||
| 		return this.driver_.lastRequests ? this.driver_.lastRequests() : []; | ||||
| 	} | ||||
|  | ||||
| 	clearLastRequests() { | ||||
| 		if (this.driver_.clearLastRequests) this.driver_.clearLastRequests(); | ||||
| 	} | ||||
|  | ||||
| 	baseDir() { | ||||
| 		return this.baseDir_; | ||||
| 	} | ||||
|   | ||||
| @@ -173,6 +173,17 @@ class Synchronizer { | ||||
| 		return this.cancelling_; | ||||
| 	} | ||||
|  | ||||
| 	logLastRequests() { | ||||
| 		const lastRequests = this.api().lastRequests(); | ||||
| 		if (!lastRequests || !lastRequests.length) return; | ||||
|  | ||||
| 		for (const r of lastRequests) { | ||||
| 			const timestamp = time.unixMsToLocalHms(r.timestamp); | ||||
| 			this.logger().info(`Req ${timestamp}: ${r.request}`); | ||||
| 			this.logger().info(`Res ${timestamp}: ${r.response}`); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static stateToLabel(state) { | ||||
| 		if (state === 'idle') return _('Idle'); | ||||
| 		if (state === 'in_progress') return _('In progress'); | ||||
| @@ -703,6 +714,8 @@ class Synchronizer { | ||||
| 				// in the application, and needs to be resolved by the user. | ||||
| 				// Or it's a temporary issue that will be resolved on next sync. | ||||
| 				this.logger().info(error.message); | ||||
|  | ||||
| 				if (error.code === 'failSafe') this.logLastRequests(); | ||||
| 			} else if (error.code === 'unknownItemType') { | ||||
| 				this.progressReport_.errors.push(_('Unknown item type downloaded - please upgrade Joplin to the latest version')); | ||||
| 				this.logger().error(error); | ||||
| @@ -710,7 +723,10 @@ class Synchronizer { | ||||
| 				this.logger().error(error); | ||||
|  | ||||
| 				// Don't save to the report errors that are due to things like temporary network errors or timeout. | ||||
| 				if (!shim.fetchRequestCanBeRetried(error)) this.progressReport_.errors.push(error); | ||||
| 				if (!shim.fetchRequestCanBeRetried(error)) { | ||||
| 					this.progressReport_.errors.push(error); | ||||
| 					this.logLastRequests(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -74,6 +74,10 @@ class Time { | ||||
| 		return moment.unix(ms / 1000).format('DD/MM/YYYY HH:mm'); | ||||
| 	} | ||||
|  | ||||
| 	unixMsToLocalHms(ms) { | ||||
| 		return moment.unix(ms / 1000).format('HH:mm:ss'); | ||||
| 	} | ||||
|  | ||||
| 	formatMsToLocal(ms, format = null) { | ||||
| 		if (format === null) format = this.dateTimeFormat(); | ||||
| 		return moment(ms).format(format); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user