Skip to content

Commit

Permalink
feat: Allow the user to choose to save debug traces on error
Browse files Browse the repository at this point in the history
This feature is still behind the `clisk.automatic.html-on-error` flag
because it still needs some UI work.

When an unexpected error is raised from a clisk konnector, the current
page in the worker is displayed to user and a button to send traces is
proposed which does exactly the same as the `clisk.html-on-error` flag.
  • Loading branch information
doubleface committed Oct 11, 2024
1 parent f9c42b6 commit 6cad3bd
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 18 deletions.
4 changes: 3 additions & 1 deletion src/constants/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"authLogin": "/auth/login?redirect=",
"konnectors": {
"worker": {
"backButton": "RETOUR À MON COZY"
"backButton": "RETOUR À MON COZY",
"sendTraces": "Envoyer les traces"

}
},
"cloudery": {
Expand Down
46 changes: 36 additions & 10 deletions src/libs/ReactNativeLauncher.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,15 +369,20 @@ class ReactNativeLauncher extends Launcher {
await this.stop()
} catch (err) {
log.error(JSON.stringify(err), 'start error')
await this.fetchAndSaveDebugData()
await this.stop({ message: err.message })
const automaticDebugTraceFlag = flag('clisk.automatic.html-on-error')
if (automaticDebugTraceFlag) {
this.emit('SHOW_TRACE_DEBUG_VIEW', err)
} else {
await this.fetchAndSaveDebugData()
await this.stop({ message: err.message })
}
}
this.emit('KONNECTOR_EXECUTION_END')
}

async fetchAndSaveDebugData() {
async fetchAndSaveDebugData(force) {
const flagvalue = flag('clisk.html-on-error')
if (!flagvalue) {
if (!flagvalue && !force) {
return true
}
try {
Expand Down Expand Up @@ -409,11 +414,8 @@ class ReactNativeLauncher extends Launcher {
.collection('io.cozy.files')
.ensureDirectoryExists('/Settings/Logs')

await client.save({
_type: 'io.cozy.files',
type: 'file',
data:
`<!-- ${url} -->
const traceFileContent = await this.hideCredentials(
`<!-- ${url} -->
` +
html +
`
Expand All @@ -424,7 +426,13 @@ class ReactNativeLauncher extends Launcher {
line[2][0]
)} : ${JSON.stringify(line[2].slice(1))}`
)
.join('\n')} -->`,
.join('\n')} -->`
)

await client.save({
_type: 'io.cozy.files',
type: 'file',
data: traceFileContent,
dirId: existingLogsFolderId,
name
})
Expand All @@ -445,6 +453,24 @@ class ReactNativeLauncher extends Launcher {
}
}

/**
* Removes user's credentials from debug trace file content
*
* @param {String} traceFileContent - content of the trace file
* @returns
*/
async hideCredentials(traceFileContent) {
let result = traceFileContent
const credentials = await this.getCredentials()
if (credentials) {
const toHide = Object.values(credentials)
for (const value of toHide) {
result = result.replace(value, '******')
}
}
return result
}

/**
* Clean all remaining active objects when closing the connector
* @returns {Promise<void>}
Expand Down
47 changes: 40 additions & 7 deletions src/screens/konnectors/LauncherView.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export class LauncherView extends Component {
this.onWorkerLoad = this.onWorkerLoad.bind(this)
this.onWorkerOpenWindow = this.onWorkerOpenWindow.bind(this)
this.onStopExecution = this.onStopExecution.bind(this)
this.onSendTraces = this.onSendTraces.bind(this)
this.onCreatedAccount = this.onCreatedAccount.bind(this)
this.onCreatedJob = this.onCreatedJob.bind(this)
this.onStoppedJob = this.onStoppedJob.bind(this)
Expand All @@ -60,19 +61,31 @@ export class LauncherView extends Component {
workerInnerUrl: null,
worker: {},
workerKey: 0,
workerInteractionBlockerVisible: false
workerInteractionBlockerVisible: false,
traceDebugView: false
}
this.DEBUG = false
}

/**
* Run when the job is stopped by the user
*/
onStopExecution() {
this.launcher.stop({ message: 'stopped by user', invisible: true })
onStopExecution(err) {
this.launcher.stop({
message: err ? err.message : 'stopped by user',
invisible: !err
})
this.props.setLauncherContext({ state: 'default' })
}

/**
* Run when the user wants to save debug traces on failed execution
*/
async onSendTraces(err) {
await this.launcher.fetchAndSaveDebugData(true)
this.onStopExecution(err)
}

/**
* Run when a job is created by the launcher. Update the current job id in the redux store.
*/
Expand Down Expand Up @@ -194,6 +207,9 @@ export class LauncherView extends Component {
})
})

this.launcher.on('SHOW_TRACE_DEBUG_VIEW', err =>
this.setState({ traceDebugView: err })
)
this.launcher.on('BLOCK_WORKER_INTERACTIONS', () =>
this.setState({ workerInteractionBlockerVisible: true })
)
Expand All @@ -220,8 +236,8 @@ export class LauncherView extends Component {
stopTimeout()

// in DEBUG mode, do not hide the worker in the end of the konnector execution
// this allows to make it easier to try pilot commands in web inspector
if (!this.DEBUG) this.props.setLauncherContext({ state: 'default' })
if (!this.DEBUG && !this.state.traceDebugView)
this.props.setLauncherContext({ state: 'default' })
}

componentWillUnmount() {
Expand All @@ -235,7 +251,9 @@ export class LauncherView extends Component {
}

render() {
const workerVisible = this.state.worker.visible || this.DEBUG
const traceDebugView = this.state.traceDebugView
const workerVisible =
this.state.worker.visible || this.DEBUG || traceDebugView
const workerStyle = workerVisible
? styles.workerVisible
: styles.workerHidden
Expand Down Expand Up @@ -297,10 +315,12 @@ export class LauncherView extends Component {
javaScriptCanOpenWindowsAutomatically={true}
onOpenWindow={this.onWorkerOpenWindow}
onStopExecution={this.onStopExecution}
onSendTraces={() => this.onSendTraces(traceDebugView)}
showInteractionBlocker={
workerVisible && this.state.workerInteractionBlockerVisible
}
workerVisible={workerVisible}
traceDebugView={traceDebugView}
isDebug={this.DEBUG}
/>
</View>
Expand Down Expand Up @@ -434,8 +454,10 @@ const WorkerView = React.forwardRef((props, ref) => {
const {
isDebug,
onStopExecution,
onSendTraces,
showInteractionBlocker,
workerVisible,
traceDebugView,
...webViewProps
} = props

Expand All @@ -455,14 +477,25 @@ const WorkerView = React.forwardRef((props, ref) => {
<View style={styles.headerStyle}>
<TouchableOpacity
activeOpacity={0.5}
onPress={onStopExecution}
onPress={() => onStopExecution(traceDebugView)}
style={styles.headerTouchableStyle}
>
<BackTo color={colors.primaryColor} width={16} height={16} />
<Text style={styles.headerTextStyle}>
{strings.konnectors.worker.backButton}
</Text>
</TouchableOpacity>
{traceDebugView ? (
<TouchableOpacity
activeOpacity={0.5}
onPress={onSendTraces}
style={styles.headerTouchableStyle}
>
<Text style={styles.headerTextStyle}>
{strings.konnectors.worker.sendTraces}
</Text>
</TouchableOpacity>
) : null}
</View>
<WebView ref={ref} {...webViewProps} />
{showInteractionBlocker ? <InteractionBlocker isDebug={isDebug} /> : null}
Expand Down

0 comments on commit 6cad3bd

Please sign in to comment.