1# Development of Error Manager 2 3## Overview 4 5If coding specification issues or errors exist in the code of an application, the application may encounter unexpected errors, for example, uncaught exceptions or application lifecycle timeouts, while it is running. In such a case, the application may exit unexpectedly. Error logs, however, are usually stored on users' local storage, making it inconvenient to locate faults. With the APIs provided by the **errorManager** module, the related errors and logs will be reported to your service platform for fault locating before application exits. 6 7After the errormanager API is used to listen for exceptions and errors, the application does not exit. You are advised to add the synchronous exit operation after the callback is executed. If you only want to obtain error logs, you are advised to use [Subscribing to Crash Events (ArkTS)](hiappevent-watcher-crash-events-arkts.md). 8 9## Available APIs 10 11Application error management APIs are provided by the [errorManager](../reference/apis-ability-kit/js-apis-app-ability-errorManager.md#) module. For details about how to import the module, see [Development Example](#development-example). 12 13**Application Error Management APIs** 14 15| API | Description | 16| ------------------------------------------------------------ | ---------------------------------------------------- | 17| on(type: "error", observer: ErrorObserver): number | Registers an observer for application errors. A callback will be invoked when an application error is detected. This API works in a synchronous manner. The return value is the serial number (SN) of the registered observer. | 18| off(type: "error", observerId: number, callback: AsyncCallback\<void\>): void | Unregisters an observer in callback mode. The number is the SN of the registered observer. | 19| off(type: "error", observerId: number): Promise\<void\> | Unregisters an observer in promise mode. The number is the SN of the registered observer. | 20| on(type: 'globalErrorOccurred', observer: GlobalObserver): void | Registers a global observer for process errors. When the system detects an application exception, the observer is called. (**Recommended**) | 21| off(type: 'globalErrorOccurred', observer?: GlobalObserver): void | Unregisters the previously registered callback observer. (**Recommended**) | 22| on(type: 'globalUnhandledRejectionDetected', observer: GlobalObserver): void | Registers a global observer for process errors. When the system detects an application promise exception, the observer is called. (**Recommended**) | 23| off(type: 'globalUnhandledRejectionDetected', observer?: GlobalObserver): void | Unregisters the previously registered callback observer. (**Recommended**) | 24| on(type: 'loopObserver', timeout: number, observer: LoopObserver): void<sup>12+</sup> | Registers an observer for the message processing duration of the main thread. A callback will be invoked if a main thread jank event occurs. This API can be called only in the main thread. A new observer will overwrite the previous one. | 25| off(type: 'loopObserver', observer?: LoopObserver): void<sup>12+</sup> | Unregisters the observer for message processing timeouts of the main thread. | 26| on(type: 'freeze', observer: FreezeObserver): void<sup>18+</sup> | Registers an observer for the main thread freeze event of the application. This API can be called only in the main thread. A new observer will overwrite the previous one. | 27| off(type: 'freeze', observer?: FreezeObserver): void<sup>18+</sup> | Unregisters an observer for the main thread freeze event of the application. This API can be called only in the main thread. | 28 29When an asynchronous callback is used, the return value can be processed directly in the callback. If a promise is used, the return value can also be processed in the promise in a similar way. For details about the result codes, see [Result Codes for Unregistering an Observer](#result-codes-for-unregistering-an-observer). 30 31 32**ErrorObserver APIs** 33 34| API | Description | 35| ------------------------------ | ------------------------------------------------------------ | 36| onUnhandledException(errMsg: string): void | Called when an uncaught exception is reported after the application is registered.| 37| onException?(errObject: Error): void | Called when an application exception is reported to the JavaScript layer after the application is registered.| 38 39 40**LoopObserver APIs** 41 42| API | Description | 43| ------------------------------ | ------------------------------------------------------------ | 44| onLoopTimeOut?(timeout: number): void<sup>12+</sup> | Called when the message processing of the main thread times out.| 45 46 47### Result Codes for Unregistering an Observer 48 49| Result Code| Description | 50| ------ | --------------------------- | 51| 0 | Normal. | 52| -1 | Input number not exist. | 53| -2 | Invalid parameter. | 54 55## Development Example 56 57> **NOTE** 58> 59> You are advised to add a synchronous exit function at the end of the exception callback. Otherwise, multiple exception callbacks may be invoked. 60 61### Listening for A Single Thread 62 63```ts 64import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit'; 65import { window } from '@kit.ArkUI'; 66import process from '@ohos.process'; 67 68let registerId = -1; 69let callback: errorManager.ErrorObserver = { 70 onUnhandledException: (errMsg) => { 71 console.log(errMsg); 72 }, 73 onException: (errorObj) => { 74 console.log('onException, name: ', errorObj.name); 75 console.log('onException, message: ', errorObj.message); 76 if (typeof(errorObj.stack) === 'string') { 77 console.log('onException, stack: ', errorObj.stack); 78 } 79 //After the callback is executed, exit the process synchronously to avoid triggering exceptions for multiple times. 80 let pro = new process.ProcessManager(); 81 pro.exit(0); 82 } 83} 84 85let abilityWant: Want; 86 87export default class EntryAbility extends UIAbility { 88 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 89 console.log("[Demo] EntryAbility onCreate"); 90 registerId = errorManager.on("error", callback); 91 abilityWant = want; 92 } 93 94 onDestroy() { 95 console.log("[Demo] EntryAbility onDestroy"); 96 errorManager.off("error", registerId, (result) => { 97 console.log("[Demo] result " + result.code + ";" + result.message); 98 }); 99 } 100 101 onWindowStageCreate(windowStage: window.WindowStage) { 102 // Main window is created, set main page for this ability 103 console.log("[Demo] EntryAbility onWindowStageCreate"); 104 105 windowStage.loadContent("pages/index", (err, data) => { 106 if (err.code) { 107 console.error('Failed to load the content. Cause:' + JSON.stringify(err)); 108 return; 109 } 110 console.info('Succeeded in loading the content. Data: ' + JSON.stringify(data)); 111 }); 112 } 113 114 onWindowStageDestroy() { 115 // Main window is destroyed, release UI related resources 116 console.log("[Demo] EntryAbility onWindowStageDestroy"); 117 } 118 119 onForeground() { 120 // Ability has brought to foreground 121 console.log("[Demo] EntryAbility onForeground"); 122 } 123 124 onBackground() { 125 // Ability has back to background 126 console.log("[Demo] EntryAbility onBackground"); 127 } 128}; 129``` 130 131### Listening for Process Exceptions 132 133```ts 134import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit'; 135import { window } from '@kit.ArkUI'; 136import process from '@ohos.process'; 137 138function errorFunc(observer: errorManager.GlobalError) { 139 console.log("[Demo] result name :" + observer.name); 140 console.log("[Demo] result message :" + observer.message); 141 console.log("[Demo] result stack :" + observer.stack); 142 console.log("[Demo] result instanceName :" + observer.instanceName); 143 console.log("[Demo] result instaceType :" + observer.instanceType); 144 //After the callback is executed, exit the process synchronously to avoid triggering exceptions for multiple times. 145 let pro = new process.ProcessManager(); 146 pro.exit(0); 147} 148 149let abilityWant: Want; 150 151export default class EntryAbility extends UIAbility { 152 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 153 console.log("[Demo] EntryAbility onCreate"); 154 errorManager.on("globalErrorOccurred", errorFunc); 155 abilityWant = want; 156 } 157 158 onDestroy() { 159 console.log("[Demo] EntryAbility onDestroy"); 160 errorManager.off("globalErrorOccurred", errorFunc); 161 } 162 163 onWindowStageCreate(windowStage: window.WindowStage) { 164 // Main window is created, set main page for this ability 165 console.log("[Demo] EntryAbility onWindowStageCreate"); 166 167 windowStage.loadContent("pages/index", (err, data) => { 168 if (err.code) { 169 console.error('Failed to load the content. Cause:' + JSON.stringify(err)); 170 return; 171 } 172 console.info('Succeeded in loading the content. Data: ' + JSON.stringify(data)); 173 }); 174 } 175 176 onWindowStageDestroy() { 177 // Main window is destroyed, release UI related resources 178 console.log("[Demo] EntryAbility onWindowStageDestroy"); 179 } 180 181 onForeground() { 182 // Ability has brought to foreground 183 console.log("[Demo] EntryAbility onForeground"); 184 } 185 186 onBackground() { 187 // Ability has back to background 188 console.log("[Demo] EntryAbility onBackground"); 189 } 190}; 191``` 192 193### Listening for Process Promise Exceptions 194 195```ts 196import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit'; 197import { window } from '@kit.ArkUI'; 198import process from '@ohos.process'; 199 200function promiseFunc(observer: errorManager.GlobalError) { 201 console.log("[Demo] result name :" + observer.name); 202 console.log("[Demo] result message :" + observer.message); 203 console.log("[Demo] result stack :" + observer.stack); 204 console.log("[Demo] result instanceName :" + observer.instanceName); 205 console.log("[Demo] result instaceType :" + observer.instanceType); 206 //After the callback is executed, exit the process synchronously to avoid triggering exceptions for multiple times. 207 let pro = new process.ProcessManager(); 208 pro.exit(0); 209} 210 211 212let abilityWant: Want; 213 214export default class EntryAbility extends UIAbility { 215 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 216 console.log("[Demo] EntryAbility onCreate"); 217 errorManager.on("globalUnhandledRejectionDetected", errorFunc); 218 abilityWant = want; 219 } 220 221 onDestroy() { 222 console.log("[Demo] EntryAbility onDestroy"); 223 errorManager.off("globalUnhandledRejectionDetected", errorFunc); 224 } 225 226 onWindowStageCreate(windowStage: window.WindowStage) { 227 // Main window is created, set main page for this ability 228 console.log("[Demo] EntryAbility onWindowStageCreate"); 229 230 windowStage.loadContent("pages/index", (err, data) => { 231 if (err.code) { 232 console.error('Failed to load the content. Cause:' + JSON.stringify(err)); 233 return; 234 } 235 console.info('Succeeded in loading the content. Data: ' + JSON.stringify(data)); 236 }); 237 } 238 239 onWindowStageDestroy() { 240 // Main window is destroyed, release UI related resources 241 console.log("[Demo] EntryAbility onWindowStageDestroy"); 242 } 243 244 onForeground() { 245 // Ability has brought to foreground 246 console.log("[Demo] EntryAbility onForeground"); 247 } 248 249 onBackground() { 250 // Ability has back to background 251 console.log("[Demo] EntryAbility onBackground"); 252 } 253}; 254``` 255 256### Listening for Main Thread Freeze Exceptions 257 258```ts 259import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit'; 260import { window } from '@kit.ArkUI'; 261import process from '@ohos.process'; 262 263// Define freezeCallback 264function freezeCallback() { 265 console.log("freezecallback"); 266} 267 268 269let abilityWant: Want; 270 271export default class EntryAbility extends UIAbility { 272 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 273 console.log("[Demo] EntryAbility onCreate"); 274 errorManager.on("freeze", freezeCallback); 275 abilityWant = want; 276 } 277 278 onDestroy() { 279 console.log("[Demo] EntryAbility onDestroy"); 280 errorManager.off("freeze", freezeCallback); 281 } 282 283 onWindowStageCreate(windowStage: window.WindowStage) { 284 // Main window is created, set main page for this ability 285 console.log("[Demo] EntryAbility onWindowStageCreate"); 286 287 windowStage.loadContent("pages/index", (err, data) => { 288 if (err.code) { 289 console.error('Failed to load the content. Cause:' + JSON.stringify(err)); 290 return; 291 } 292 console.info('Succeeded in loading the content. Data: ' + JSON.stringify(data)); 293 }); 294 } 295 296 onWindowStageDestroy() { 297 // Main window is destroyed, release UI related resources 298 console.log("[Demo] EntryAbility onWindowStageDestroy"); 299 } 300 301 onForeground() { 302 // Ability has brought to foreground 303 console.log("[Demo] EntryAbility onForeground"); 304 } 305 306 onBackground() { 307 // Ability has back to background 308 console.log("[Demo] EntryAbility onBackground"); 309 } 310}; 311``` 312