forked from EVOgeek/Vmeda.Online
		
	Merge pull request #3849 from alfonso-salces/MOBILE-4451
MOBILE-4451 settings: Create error log page
This commit is contained in:
		
						commit
						1624256ffb
					
				| @ -64,6 +64,7 @@ import { CoreSiteError } from '@classes/errors/siteerror'; | ||||
| import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config'; | ||||
| import { CoreLoginHelper } from '@features/login/services/login-helper'; | ||||
| import { CorePath } from '@singletons/path'; | ||||
| import { CoreErrorLogs } from '@singletons/error-logs'; | ||||
| 
 | ||||
| /** | ||||
|  * QR Code type enumeration. | ||||
| @ -1156,7 +1157,15 @@ export class CoreSite { | ||||
|                     // Request not executed, enqueue again.
 | ||||
|                     this.enqueueRequest(request); | ||||
|                 } else if (response.error) { | ||||
|                     request.deferred.reject(CoreTextUtils.parseJSON(response.exception || '')); | ||||
|                     const rejectReason = CoreTextUtils.parseJSON(response.exception || '') as Error | undefined; | ||||
|                     request.deferred.reject(rejectReason); | ||||
|                     CoreErrorLogs.addErrorLog({ | ||||
|                         method: request.method, | ||||
|                         type: 'CoreSiteError', | ||||
|                         message: response.exception ?? '', | ||||
|                         time: new Date().getTime(), | ||||
|                         data: request.data, | ||||
|                     }); | ||||
|                 } else { | ||||
|                     let responseData = response.data ? CoreTextUtils.parseJSON(response.data) : {}; | ||||
|                     // Match the behaviour of CoreWSProvider.call when no response is expected.
 | ||||
| @ -1170,6 +1179,13 @@ export class CoreSite { | ||||
|         } catch (error) { | ||||
|             // Error not specific to a single request, reject all promises.
 | ||||
|             requests.forEach((request) => { | ||||
|                 CoreErrorLogs.addErrorLog({ | ||||
|                     method: request.method, | ||||
|                     type: 'CoreSiteError', | ||||
|                     message: String(error) ?? '', | ||||
|                     time: new Date().getTime(), | ||||
|                     data: request.data, | ||||
|                 }); | ||||
|                 request.deferred.reject(error); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
| @ -34,8 +34,9 @@ | ||||
|             <ion-label> | ||||
|                 <h2>Enable staging sites ({{stagingSitesCount}})</h2> | ||||
|             </ion-label> | ||||
|             <ion-toggle [(ngModel)]="enableStagingSites" (ionChange)="setEnabledStagingSites($event.detail.checked)" | ||||
|                 slot="end"></ion-toggle> | ||||
|             <ion-toggle [(ngModel)]="enableStagingSites" (ionChange)="setEnabledStagingSites($event.detail.checked)" slot="end"> | ||||
|             </ion-toggle> | ||||
| 
 | ||||
|         </ion-item> | ||||
|         <ng-container *ngIf="siteId"> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
| @ -61,6 +62,12 @@ | ||||
|                 </ion-button> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <ion-item class="ion-text-wrap" (click)="openErrorLog()" [detail]="true" button> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">Error log</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <ion-item-divider> | ||||
|                 <ion-label> | ||||
|                     <h2>Disabled features</h2> | ||||
|  | ||||
| @ -19,6 +19,7 @@ import { CoreSettingsHelper } from '@features/settings/services/settings-helper' | ||||
| import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins'; | ||||
| import { CoreUserTours } from '@features/usertours/services/user-tours'; | ||||
| import { CoreConfig } from '@services/config'; | ||||
| import { CoreNavigator } from '@services/navigator'; | ||||
| import { CorePlatform } from '@services/platform'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| @ -151,6 +152,13 @@ export class CoreSettingsDevPage implements OnInit { | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Open error log. | ||||
|      */ | ||||
|     openErrorLog(): void { | ||||
|         CoreNavigator.navigate('error-log'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Copies site info. | ||||
|      */ | ||||
|  | ||||
							
								
								
									
										51
									
								
								src/core/features/settings/pages/error-log/error-log.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/core/features/settings/pages/error-log/error-log.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
| 
 | ||||
|         <ion-title> | ||||
|             <h1>Error log</h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end" *ngIf="errorLogs.length"> | ||||
|             <ion-button fill="clear" (click)="copyInfo()" [attr.aria-label]="'core.settings.copyinfo' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-clipboard" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| 
 | ||||
| <ion-content> | ||||
|     <ion-list *ngIf="errorLogs.length; else noLogs"> | ||||
|         <ion-item button lines="full" class="ion-text-wrap" *ngFor="let error of errorLogs"> | ||||
|             <div class="ion-padding" [collapsible-item]="96"> | ||||
|                 <p class="item-heading">Trace</p> | ||||
|                 <p class="ion-text-wrap">{{ error.message }}</p> | ||||
| 
 | ||||
|                 <ng-container *ngIf="error.method"> | ||||
|                     <p class="item-heading">Method</p> | ||||
|                     <p class="ion-text-wrap">{{ error.method }}</p> | ||||
|                 </ng-container> | ||||
| 
 | ||||
|                 <ng-container *ngIf="error.type"> | ||||
|                     <p class="item-heading">Type</p> | ||||
|                     <p class="ion-text-wrap">{{ error.type }}</p> | ||||
|                 </ng-container> | ||||
| 
 | ||||
|                 <ng-container *ngIf="error.data"> | ||||
|                     <p class="item-heading">Data</p> | ||||
|                     <p class="ion-text-wrap">{{ error.data | json }}</p> | ||||
|                 </ng-container> | ||||
| 
 | ||||
|                 <div *ngIf="error.time"> | ||||
|                     <span class="ion-text-end">{{ error.time | coreFormatDate :'strftimedatetimeshort' }}</span> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </ion-item> | ||||
|     </ion-list> | ||||
|     <ng-template #noLogs> | ||||
|         <core-empty-box message="No logs available" icon="fas-clipboard-question"> | ||||
|         </core-empty-box> | ||||
|     </ng-template> | ||||
| </ion-content> | ||||
| @ -0,0 +1,4 @@ | ||||
| .timestamp { | ||||
|     display: flex; | ||||
|     justify-content: end; | ||||
| } | ||||
							
								
								
									
										39
									
								
								src/core/features/settings/pages/error-log/error-log.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/core/features/settings/pages/error-log/error-log.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { CoreErrorLogs, CoreSettingsErrorLog } from '@singletons/error-logs'; | ||||
| 
 | ||||
| /** | ||||
|  * Page that displays the error logs. | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: 'page-core-app-settings-error-log', | ||||
|     templateUrl: 'error-log.html', | ||||
|     styleUrls: ['./error-log.scss'], | ||||
| }) | ||||
| export class CoreSettingsErrorLogPage implements OnInit { | ||||
| 
 | ||||
|     errorLogs: CoreSettingsErrorLog[] = []; | ||||
| 
 | ||||
|     ngOnInit(): void { | ||||
|         this.errorLogs = CoreErrorLogs.getErrorLogs(); | ||||
|     } | ||||
| 
 | ||||
|     copyInfo(): void { | ||||
|         CoreUtils.copyToClipboard(JSON.stringify({ errors: this.errorLogs })); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -28,6 +28,7 @@ import { CoreSettingsAboutPage } from '@features/settings/pages/about/about'; | ||||
| import { CoreSettingsLicensesPage } from '@features/settings/pages/licenses/licenses'; | ||||
| import { CoreSettingsDeviceInfoPage } from '@features/settings/pages/deviceinfo/deviceinfo'; | ||||
| import { CoreSettingsDevPage } from '@features/settings/pages/dev/dev'; | ||||
| import { CoreSettingsErrorLogPage } from '@features/settings/pages/error-log/error-log'; | ||||
| 
 | ||||
| const sectionRoutes: Routes = [ | ||||
|     { | ||||
| @ -86,6 +87,10 @@ const routes: Routes = [ | ||||
|         path: 'about/deviceinfo/dev', | ||||
|         component: CoreSettingsDevPage, | ||||
|     }, | ||||
|     { | ||||
|         path: 'about/deviceinfo/dev/error-log', | ||||
|         component: CoreSettingsErrorLogPage, | ||||
|     }, | ||||
|     { | ||||
|         path: 'about/licenses', | ||||
|         component: CoreSettingsLicensesPage, | ||||
| @ -106,6 +111,7 @@ const routes: Routes = [ | ||||
|         CoreSettingsLicensesPage, | ||||
|         CoreSettingsDeviceInfoPage, | ||||
|         CoreSettingsDevPage, | ||||
|         CoreSettingsErrorLogPage, | ||||
|     ], | ||||
| }) | ||||
| export class CoreSettingsLazyModule {} | ||||
|  | ||||
| @ -60,6 +60,7 @@ import { CoreCancellablePromise } from '@classes/cancellable-promise'; | ||||
| import { CoreLang } from '@services/lang'; | ||||
| import { CorePasswordModalParams, CorePasswordModalResponse } from '@components/password-modal/password-modal'; | ||||
| import { CoreWSError } from '@classes/errors/wserror'; | ||||
| import { CoreErrorLogs } from '@singletons/error-logs'; | ||||
| 
 | ||||
| /* | ||||
|  * "Utils" service with helper functions for UI, DOM elements and HTML code. | ||||
| @ -613,6 +614,7 @@ export class CoreDomUtilsProvider { | ||||
| 
 | ||||
|             // We received an object instead of a string. Search for common properties.
 | ||||
|             errorMessage = CoreTextUtils.getErrorMessageFromError(error); | ||||
|             CoreErrorLogs.addErrorLog({ message: JSON.stringify(error), type: errorMessage || '', time: new Date().getTime() }); | ||||
|             if (!errorMessage) { | ||||
|                 // No common properties found, just stringify it.
 | ||||
|                 errorMessage = JSON.stringify(error); | ||||
|  | ||||
| @ -43,6 +43,7 @@ import { CoreSiteError, CoreSiteErrorOptions } from '@classes/errors/siteerror'; | ||||
| import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreLang, CoreLangFormat } from './lang'; | ||||
| import { CoreErrorLogs } from '@singletons/error-logs'; | ||||
| 
 | ||||
| /** | ||||
|  * This service allows performing WS calls and download/upload files. | ||||
| @ -412,9 +413,25 @@ export class CoreWSProvider { | ||||
|         let promise: Promise<HttpResponse<any>>; | ||||
| 
 | ||||
|         if (preSets.siteUrl === undefined) { | ||||
|             throw new CoreAjaxError(Translate.instant('core.unexpectederror')); | ||||
|             const unexpectedError = new CoreAjaxError(Translate.instant('core.unexpectederror')); | ||||
|             CoreErrorLogs.addErrorLog({ | ||||
|                 method, | ||||
|                 type: 'CoreAjaxError', | ||||
|                 message: Translate.instant('core.unexpectederror'), | ||||
|                 time: new Date().getTime(), | ||||
|                 data, | ||||
|             }); | ||||
|             throw unexpectedError; | ||||
|         } else if (!CoreNetwork.isOnline()) { | ||||
|             throw new CoreAjaxError(Translate.instant('core.networkerrormsg')); | ||||
|             const networkError = new CoreAjaxError(Translate.instant('core.networkerrormsg')); | ||||
|             CoreErrorLogs.addErrorLog({ | ||||
|                 method, | ||||
|                 type: 'CoreAjaxError', | ||||
|                 message: Translate.instant('core.networkerrormsg'), | ||||
|                 time: new Date().getTime(), | ||||
|                 data, | ||||
|             }); | ||||
|             throw networkError; | ||||
|         } | ||||
| 
 | ||||
|         if (preSets.responseExpected === undefined) { | ||||
| @ -552,6 +569,10 @@ export class CoreWSProvider { | ||||
|             } | ||||
| 
 | ||||
|             throw new CoreAjaxError(options, 1, data.status); | ||||
|         }).catch(error => { | ||||
|             const type = `CoreAjaxError - ${error.errorcode}`; | ||||
|             CoreErrorLogs.addErrorLog({ method, type, message: error, time: new Date().getTime(), data }); | ||||
|             throw error; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -782,6 +803,15 @@ export class CoreWSProvider { | ||||
|             throw new CoreError(Translate.instant('core.serverconnection', { | ||||
|                 details: CoreTextUtils.getErrorMessageFromError(error) ?? 'Unknown error', | ||||
|             })); | ||||
|         }).catch(err => { | ||||
|             CoreErrorLogs.addErrorLog({ | ||||
|                 method, | ||||
|                 type: String(err), | ||||
|                 message: String(err.exception), | ||||
|                 time: new Date().getTime(), | ||||
|                 data: ajaxData, | ||||
|             }); | ||||
|             throw err; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -847,71 +877,84 @@ export class CoreWSProvider { | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | ||||
|     syncCall<T = unknown>(method: string, data: any, preSets: CoreWSPreSets): T { | ||||
|         if (!preSets) { | ||||
|             throw new CoreError(Translate.instant('core.unexpectederror')); | ||||
|         } else if (!CoreNetwork.isOnline()) { | ||||
|             throw new CoreNetworkError(); | ||||
|         try { | ||||
|             if (!preSets) { | ||||
|                 throw new CoreError(Translate.instant('core.unexpectederror')); | ||||
|             } else if (!CoreNetwork.isOnline()) { | ||||
|                 throw new CoreNetworkError(); | ||||
|             } | ||||
| 
 | ||||
|             preSets.typeExpected = preSets.typeExpected || 'object'; | ||||
|             if (preSets.responseExpected === undefined) { | ||||
|                 preSets.responseExpected = true; | ||||
|             } | ||||
| 
 | ||||
|             data = this.convertValuesToString(data || {}, preSets.cleanUnicode); | ||||
|             if (data == null) { | ||||
|                 // Empty cleaned text found.
 | ||||
|                 throw new CoreError(Translate.instant('core.unicodenotsupportedcleanerror')); | ||||
|             } | ||||
| 
 | ||||
|             data.wsfunction = method; | ||||
|             data.wstoken = preSets.wsToken; | ||||
|             const siteUrl = preSets.siteUrl + '/webservice/rest/server.php?moodlewsrestformat=json'; | ||||
| 
 | ||||
|             // Serialize data.
 | ||||
|             data = CoreInterceptor.serialize(data); | ||||
| 
 | ||||
|             // Perform sync request using XMLHttpRequest.
 | ||||
|             const xhr = new XMLHttpRequest(); | ||||
|             xhr.open('post', siteUrl, false); | ||||
|             xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8'); | ||||
| 
 | ||||
|             xhr.send(data); | ||||
| 
 | ||||
|             // Get response.
 | ||||
|             // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | ||||
|             data = ('response' in xhr) ? xhr.response : (<any> xhr).responseText; | ||||
| 
 | ||||
|             // Check status.
 | ||||
|             const status = Math.max(xhr.status === 1223 ? 204 : xhr.status, 0); | ||||
|             if (status < 200 || status >= 300) { | ||||
|                 // Request failed.
 | ||||
|                 throw new CoreError(data); | ||||
|             } | ||||
| 
 | ||||
|             // Treat response.
 | ||||
|             data = CoreTextUtils.parseJSON(data); | ||||
| 
 | ||||
|             // Some moodle web services return null.
 | ||||
|             // If the responseExpected value is set then so long as no data is returned, we create a blank object.
 | ||||
|             if ((!data || !data.data) && !preSets.responseExpected) { | ||||
|                 data = {}; | ||||
|             } | ||||
| 
 | ||||
|             if (!data) { | ||||
|                 throw new CoreError(Translate.instant('core.serverconnection', { | ||||
|                     details: Translate.instant('core.errorinvalidresponse', { method }), | ||||
|                 })); | ||||
|             } else if (typeof data != preSets.typeExpected) { | ||||
|                 this.logger.warn('Response of type "' + typeof data + '" received, expecting "' + preSets.typeExpected + '"'); | ||||
|                 throw new CoreError(Translate.instant('core.errorinvalidresponse', { method })); | ||||
|             } | ||||
| 
 | ||||
|             if (data.exception !== undefined || data.debuginfo !== undefined) { | ||||
|                 throw new CoreWSError(data); | ||||
|             } | ||||
| 
 | ||||
|             return data; | ||||
|         } catch (err) { | ||||
|             let errorType = ''; | ||||
| 
 | ||||
|             if (err instanceof CoreError) { | ||||
|                 errorType = 'CoreError'; | ||||
|             } else if (err instanceof CoreWSError) { | ||||
|                 errorType = 'CoreWSError'; | ||||
|             } | ||||
| 
 | ||||
|             CoreErrorLogs.addErrorLog({ method, type: errorType, message: String(err), time: new Date().getTime(), data }); | ||||
|             throw err; | ||||
|         } | ||||
| 
 | ||||
|         preSets.typeExpected = preSets.typeExpected || 'object'; | ||||
|         if (preSets.responseExpected === undefined) { | ||||
|             preSets.responseExpected = true; | ||||
|         } | ||||
| 
 | ||||
|         data = this.convertValuesToString(data || {}, preSets.cleanUnicode); | ||||
|         if (data == null) { | ||||
|             // Empty cleaned text found.
 | ||||
|             throw new CoreError(Translate.instant('core.unicodenotsupportedcleanerror')); | ||||
|         } | ||||
| 
 | ||||
|         data.wsfunction = method; | ||||
|         data.wstoken = preSets.wsToken; | ||||
|         const siteUrl = preSets.siteUrl + '/webservice/rest/server.php?moodlewsrestformat=json'; | ||||
| 
 | ||||
|         // Serialize data.
 | ||||
|         data = CoreInterceptor.serialize(data); | ||||
| 
 | ||||
|         // Perform sync request using XMLHttpRequest.
 | ||||
|         const xhr = new XMLHttpRequest(); | ||||
|         xhr.open('post', siteUrl, false); | ||||
|         xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8'); | ||||
| 
 | ||||
|         xhr.send(data); | ||||
| 
 | ||||
|         // Get response.
 | ||||
|         // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | ||||
|         data = ('response' in xhr) ? xhr.response : (<any> xhr).responseText; | ||||
| 
 | ||||
|         // Check status.
 | ||||
|         const status = Math.max(xhr.status === 1223 ? 204 : xhr.status, 0); | ||||
|         if (status < 200 || status >= 300) { | ||||
|             // Request failed.
 | ||||
|             throw new CoreError(data); | ||||
|         } | ||||
| 
 | ||||
|         // Treat response.
 | ||||
|         data = CoreTextUtils.parseJSON(data); | ||||
| 
 | ||||
|         // Some moodle web services return null.
 | ||||
|         // If the responseExpected value is set then so long as no data is returned, we create a blank object.
 | ||||
|         if ((!data || !data.data) && !preSets.responseExpected) { | ||||
|             data = {}; | ||||
|         } | ||||
| 
 | ||||
|         if (!data) { | ||||
|             throw new CoreError(Translate.instant('core.serverconnection', { | ||||
|                 details: Translate.instant('core.errorinvalidresponse', { method }), | ||||
|             })); | ||||
|         } else if (typeof data != preSets.typeExpected) { | ||||
|             this.logger.warn('Response of type "' + typeof data + '" received, expecting "' + preSets.typeExpected + '"'); | ||||
|             throw new CoreError(Translate.instant('core.errorinvalidresponse', { method })); | ||||
|         } | ||||
| 
 | ||||
|         if (data.exception !== undefined || data.debuginfo !== undefined) { | ||||
|             throw new CoreWSError(data); | ||||
|         } | ||||
| 
 | ||||
|         return data; | ||||
|     } | ||||
| 
 | ||||
|     /* | ||||
|  | ||||
							
								
								
									
										53
									
								
								src/core/singletons/error-logs.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/core/singletons/error-logs.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Service that stores error logs in memory. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreErrorLogsService { | ||||
| 
 | ||||
|     protected errorLogs: CoreSettingsErrorLog[] = []; | ||||
| 
 | ||||
|     /** | ||||
|      * Retrieve error logs displayed in the DOM. | ||||
|      * | ||||
|      * @returns Error logs | ||||
|      */ | ||||
|     getErrorLogs(): CoreSettingsErrorLog[] { | ||||
|         return this.errorLogs; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Add an error to error logs list. | ||||
|      * | ||||
|      * @param error Error. | ||||
|      */ | ||||
|     addErrorLog(error: CoreSettingsErrorLog): void { | ||||
|         this.errorLogs.push(error); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export const CoreErrorLogs = makeSingleton(CoreErrorLogsService); | ||||
| 
 | ||||
| export type CoreSettingsErrorLog = { | ||||
|     data?: unknown; | ||||
|     message: string; | ||||
|     method?: string; | ||||
|     time: number; | ||||
|     type: string; | ||||
| }; | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user