feat(xen-api): optional sync traces (#5091)

Initial actions call stacks are often missing from the resulting error for the following reasons:

- low level Node functions don't have proper stack traces
- replies handling maybe separate from requests (eg watchers)

This commit adds the option `syncStackTraces` that works around this, it has a performance impact but is useful for debugging.
This commit is contained in:
Julien Fontanet 2020-06-18 17:19:21 +02:00 committed by GitHub
parent ce53128657
commit 857a9f3efc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 3 deletions

View File

@ -87,6 +87,7 @@ const main = async args => {
auth,
debounce: opts.debounce != null ? +opts.debounce : null,
readOnly: opts.ro,
syncStackTraces: true,
})
await xapi.connect()

View File

@ -63,10 +63,34 @@ const DISCONNECTED = 'disconnected'
// -------------------------------------------------------------------
const identity = value => value
// save current stack trace and add it to any rejected error
//
// This is especially useful when the resolution is separate from the initial
// call, which is often the case with RPC libs.
//
// There is a perf impact and it should be avoided in production.
const addSyncStackTrace = async promise => {
const stackContainer = new Error()
try {
return await promise
} catch (error) {
error.stack = stackContainer.stack
throw error
}
}
// -------------------------------------------------------------------
export class Xapi extends EventEmitter {
constructor(opts) {
super()
this._addSyncStackTrace =
opts.syncStackTraces ?? process.env.NODE_ENV === 'development'
? addSyncStackTrace
: identity
this._callTimeout = makeCallSetting(opts.callTimeout, 60 * 60 * 1e3) // 1 hour but will be reduced in the future
this._httpInactivityTimeout = opts.httpInactivityTimeout ?? 5 * 60 * 1e3 // 5 mins
this._eventPollDelay = opts.eventPollDelay ?? 60 * 1e3 // 1 min
@ -531,7 +555,7 @@ export class Xapi extends EventEmitter {
String(Date.now()),
])
await promise
await this._addSyncStackTrace(promise)
ignoreErrors.call(
this._sessionCall('pool.remove_from_other_config', [poolRef, key])
@ -629,7 +653,7 @@ export class Xapi extends EventEmitter {
watcher = watchers[ref] = defer()
}
return watcher.promise
return this._addSyncStackTrace(watcher.promise)
}
// ===========================================================================
@ -639,7 +663,10 @@ export class Xapi extends EventEmitter {
async _call(method, args, timeout = this._callTimeout(method, args)) {
const startTime = Date.now()
try {
const result = await pTimeout.call(this._transport(method, args), timeout)
const result = await pTimeout.call(
this._addSyncStackTrace(this._transport(method, args)),
timeout
)
debug(
'%s: %s(...) [%s] ==> %s',
this._humanId,