1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { BuildConfig } from './types'; 17import { 18 ErrorCode, 19 SubsystemCode 20} from './error_code'; 21 22export class Logger { 23 private static instance: Logger | undefined; 24 private loggerMap: { [key in SubsystemCode]?: ILogger }; 25 private hasErrorOccurred: boolean = false; 26 27 private constructor(projectConfig: BuildConfig) { 28 if (typeof projectConfig.getHvigorConsoleLogger !== 'function') { 29 projectConfig.getHvigorConsoleLogger = getConsoleLogger; 30 } 31 let getHvigorConsoleLogger = projectConfig.getHvigorConsoleLogger as Function; 32 this.loggerMap = {}; 33 this.loggerMap[SubsystemCode.BUILDSYSTEM] = getHvigorConsoleLogger(SubsystemCode.BUILDSYSTEM); 34 this.loggerMap[SubsystemCode.ES2PANDA] = getHvigorConsoleLogger(SubsystemCode.ES2PANDA); 35 } 36 37 public static getInstance(projectConfig?: BuildConfig): Logger { 38 if (!Logger.instance) { 39 if (!projectConfig) { 40 throw new Error('projectConfig is required for the first instantiation.'); 41 } 42 Logger.instance = new Logger(projectConfig); 43 } 44 return Logger.instance; 45 } 46 47 public static destroyInstance(): void { 48 Logger.instance = undefined; 49 } 50 51 public printInfo(message: string, subsystemCode: SubsystemCode = SubsystemCode.BUILDSYSTEM): void { 52 const logger: ILogger = this.getLoggerFromSubsystemCode(subsystemCode); 53 logger.printInfo(message); 54 } 55 56 public printWarn(message: string, subsystemCode: SubsystemCode = SubsystemCode.BUILDSYSTEM): void { 57 const logger: ILogger = this.getLoggerFromSubsystemCode(subsystemCode); 58 logger.printWarn(message); 59 } 60 61 public printDebug(message: string, subsystemCode: SubsystemCode = SubsystemCode.BUILDSYSTEM): void { 62 const logger: ILogger = this.getLoggerFromSubsystemCode(subsystemCode); 63 logger.printDebug(message); 64 } 65 66 public printError(error: LogData): void { 67 this.hasErrorOccurred = true; 68 const logger: ILogger = this.getLoggerFromErrorCode(error.code); 69 logger.printError(error); 70 } 71 72 public printErrorAndExit(error: LogData): void { 73 this.hasErrorOccurred = true; 74 const logger: ILogger = this.getLoggerFromErrorCode(error.code); 75 logger.printErrorAndExit(error); 76 } 77 78 private isValidErrorCode(errorCode: ErrorCode): boolean { 79 return /^\d{8}$/.test(errorCode); 80 } 81 82 private getLoggerFromErrorCode(errorCode: ErrorCode): ILogger { 83 if (!this.isValidErrorCode(errorCode)) { 84 throw new Error('Invalid errorCode.'); 85 } 86 const subsystemCode = errorCode.slice(0, 3) as SubsystemCode; 87 const logger = this.getLoggerFromSubsystemCode(subsystemCode); 88 return logger; 89 } 90 91 private getLoggerFromSubsystemCode(subsystemCode: SubsystemCode): ILogger { 92 if (!this.loggerMap[subsystemCode]) { 93 throw new Error('Invalid subsystemCode.'); 94 } 95 return this.loggerMap[subsystemCode]; 96 } 97 98 public hasErrors(): boolean { 99 return this.hasErrorOccurred; 100 } 101 102 public resetErrorFlag(): void { 103 this.hasErrorOccurred = false; 104 } 105} 106 107interface ILogger { 108 printInfo(message: string): void; 109 printWarn(message: string): void; 110 printDebug(message: string): void; 111 printError(error: LogData): void; 112 printErrorAndExit(error: LogData): void; 113} 114 115export class LogDataFactory { 116 117 static newInstance( 118 code: ErrorCode, 119 description: string, 120 cause: string = '', 121 position: string = '', 122 solutions: string[] = [], 123 moreInfo?: Object 124 ): LogData { 125 const data: LogData = new LogData(code, description, cause, position, solutions, moreInfo); 126 return data; 127 } 128} 129 130export class LogData { 131 132 code: ErrorCode; 133 description: string; 134 cause: string; 135 position: string; 136 solutions: string[]; 137 moreInfo?: Object; 138 139 constructor( 140 code: ErrorCode, 141 description: string, 142 cause: string = '', 143 position: string = '', 144 solutions: string[], 145 moreInfo?: Object 146 ) { 147 this.code = code; 148 this.description = description; 149 this.cause = cause; 150 this.position = position; 151 this.solutions = solutions; 152 if (moreInfo) { 153 this.moreInfo = moreInfo; 154 } 155 } 156 157 toString(): string { 158 let errorString = `ERROR Code: ${this.code} ${this.description}\n`; 159 160 if (this.cause || this.position) { 161 errorString += `Error Message: ${this.cause}`; 162 if (this.position) { 163 errorString += ` ${this.position}`; 164 } 165 errorString += '\n\n'; 166 } 167 168 if (this.solutions.length > 0 && this.solutions[0] !== '') { 169 errorString += `* Try the following: \n${this.solutions.map(str => ` > ${str}`).join('\n')}\n`; 170 } 171 172 if (this.moreInfo) { 173 errorString += `\nMore Info:\n`; 174 for (const [key, value] of Object.entries(this.moreInfo)) { 175 errorString += ` - ${key.toUpperCase()}: ${value}\n`; 176 } 177 } 178 179 return errorString; 180 } 181} 182 183class ConsoleLogger { 184 private static instances: { [key: string]: ConsoleLogger } = {}; 185 186 private constructor() {} 187 188 public printInfo(message: string): void { 189 console.info(message); 190 } 191 192 public printWarn(message: string): void { 193 console.warn(message); 194 } 195 196 public printDebug(message: string): void { 197 console.debug(message); 198 } 199 200 public printError(error: LogData): void { 201 console.error(error.toString()); 202 } 203 204 public printErrorAndExit(error: LogData): void { 205 console.error(error.toString()); 206 process.exit(1); 207 } 208 209 public static createLogger(subsystemCode: string): ConsoleLogger { 210 if (!ConsoleLogger.instances[subsystemCode]) { 211 ConsoleLogger.instances[subsystemCode] = new ConsoleLogger(); 212 } 213 return ConsoleLogger.instances[subsystemCode]; 214 } 215} 216 217function getConsoleLogger(subsystemCode: string): ConsoleLogger { 218 return ConsoleLogger.createLogger(subsystemCode); 219} 220