mirror of https://github.com/laurent22/joplin.git
All: Log last requests in case of a sync error
parent
820e32ddca
commit
effbf10571
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue