Add Logger Component
This commit is contained in:
parent
70cf5cb1f5
commit
28ed5ad0c4
@ -1,4 +1,7 @@
|
||||
// app.ts
|
||||
import {Logger} from "./utils/Logger";
|
||||
import * as label from "./utils/LogLabel";
|
||||
|
||||
|
||||
App<IAppOption>({
|
||||
|
||||
/**
|
||||
@ -10,5 +13,15 @@ App<IAppOption>({
|
||||
* 小程序加载时
|
||||
*/
|
||||
onLaunch() {
|
||||
},
|
||||
|
||||
Logger.log("hh",
|
||||
label.FatalLabel,label.ErrorLabel,label.WarnLabel,
|
||||
label.InfoLabel,label.DebugLabel,label.TraceLabel
|
||||
);
|
||||
|
||||
Logger.logM(
|
||||
[label.FatalLabel,label.ErrorLabel,label.WarnLabel,
|
||||
label.InfoLabel,label.DebugLabel,label.TraceLabel], "hh"
|
||||
);
|
||||
}
|
||||
})
|
31
miniprogram/utils/Config.ts
Normal file
31
miniprogram/utils/Config.ts
Normal file
@ -0,0 +1,31 @@
|
||||
// APP 全局配置文件
|
||||
|
||||
/**
|
||||
* 是否在控制台输出调试信息
|
||||
* 生产模式下一定要关闭此选项
|
||||
*
|
||||
* 注意:
|
||||
* 1、Release 时必须置为 false
|
||||
* 2、调试模式将造成性能损失
|
||||
*/
|
||||
export const LOGGER_CONSOLE:boolean = true;
|
||||
|
||||
/**
|
||||
* 调试过滤器
|
||||
* 按照 LogLabel 进行过滤
|
||||
*
|
||||
* 注意:
|
||||
* 1、行与行是之间是 || 关系
|
||||
* 2、每行的元素之间是 && 关系
|
||||
* 3、支持正则表达式
|
||||
* 4、字符串使用 === 严格匹配
|
||||
* 5、尽量将范围大的 Filter 写在前面以提高性能
|
||||
*/
|
||||
export const LOGGER_FILTER:Array<RegExp | string>[] = [
|
||||
|
||||
// 调试输出全部内容
|
||||
[/.*/],
|
||||
|
||||
// 输出警告和错误
|
||||
// ["WARN", "ERROR", "FATAL"],
|
||||
];
|
43
miniprogram/utils/LogLabel.ts
Normal file
43
miniprogram/utils/LogLabel.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import {LogLabel, LogStyle} from "./Logger";
|
||||
|
||||
// 成功
|
||||
export const SuccessLabel = new LogLabel(
|
||||
"SUCCESS", new LogStyle().setColor("#FFFFFF", "#EE113D").setBorder("5px")
|
||||
);
|
||||
|
||||
// 失败
|
||||
export const FailedLabel = new LogLabel(
|
||||
"SUCCESS", new LogStyle().setColor("#FFFFFF", "#33ff66").setBorder("3px")
|
||||
);
|
||||
|
||||
|
||||
|
||||
// 致命
|
||||
export const FatalLabel = new LogLabel(
|
||||
"FATAL", new LogStyle().setColor("#FFFFFF", "#FF00CC").setBorder("3px")
|
||||
);
|
||||
|
||||
// 错误
|
||||
export const ErrorLabel = new LogLabel(
|
||||
"ERROR", new LogStyle().setColor("#FFFFFF", "#FF0000").setBorder("3px")
|
||||
);
|
||||
|
||||
// 警告
|
||||
export const WarnLabel = new LogLabel(
|
||||
"WARN", new LogStyle().setColor("#FFFFFF", "#FF9900").setBorder("3px")
|
||||
);
|
||||
|
||||
// 消息
|
||||
export const InfoLabel = new LogLabel(
|
||||
"INFO", new LogStyle().setColor("#FFFFFF", "#99FF00").setBorder("3px")
|
||||
);
|
||||
|
||||
// 调试
|
||||
export const DebugLabel = new LogLabel(
|
||||
"DEBUG", new LogStyle().setColor("#FFFFFF", "#00FF99").setBorder("3px")
|
||||
);
|
||||
|
||||
// 追踪
|
||||
export const TraceLabel = new LogLabel(
|
||||
"TRACE", new LogStyle().setColor("#FFFFFF", "#00CCFF").setBorder("3px")
|
||||
);
|
391
miniprogram/utils/Logger.ts
Normal file
391
miniprogram/utils/Logger.ts
Normal file
@ -0,0 +1,391 @@
|
||||
import {LOGGER_CONSOLE, LOGGER_FILTER} from "./Config";
|
||||
|
||||
/**
|
||||
* 调试输出样式
|
||||
*/
|
||||
class LogStyle {
|
||||
|
||||
/**
|
||||
* 日志文字颜色
|
||||
*/
|
||||
private color:string | undefined;
|
||||
|
||||
/**
|
||||
* 日志背景颜色
|
||||
*/
|
||||
private backgroundColor:string | undefined;
|
||||
|
||||
/**
|
||||
* 日志文字粗细
|
||||
*/
|
||||
private weight:string | undefined;
|
||||
|
||||
/**
|
||||
* 日志文字大小
|
||||
*/
|
||||
private size:string | undefined;
|
||||
|
||||
/**
|
||||
* 日志文字字体
|
||||
*/
|
||||
private family:string | undefined;
|
||||
|
||||
/**
|
||||
* 日志文字圆角
|
||||
*/
|
||||
private borderRadius:string | undefined;
|
||||
|
||||
/**
|
||||
* 日志文字边框
|
||||
*/
|
||||
private border:string | undefined;
|
||||
|
||||
/**
|
||||
* 设置颜色
|
||||
* @param color 日志文字颜色
|
||||
* @param backgroundColor 日志背景颜色
|
||||
*/
|
||||
public setColor(color:string, backgroundColor?:string):LogStyle {
|
||||
this.color = color;
|
||||
this.backgroundColor = backgroundColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置边框
|
||||
* @param borderRadius 日志文字圆角
|
||||
* @param border 日志文字边框
|
||||
*/
|
||||
public setBorder(borderRadius:string, border?:string):LogStyle {
|
||||
this.borderRadius = borderRadius;
|
||||
this.border = border;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文字
|
||||
* @param weight 日志文字粗细
|
||||
* @param family 日志文字字体
|
||||
*/
|
||||
public setFont(weight:string, family:string):LogStyle {
|
||||
this.weight = weight;
|
||||
this.family = family;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文字大小
|
||||
* @param size 日志文字大小
|
||||
*/
|
||||
public setSize(size:string):LogStyle {
|
||||
this.size = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符化转义样式
|
||||
*/
|
||||
public stringify():string {
|
||||
let stringArr:string[] = [];
|
||||
|
||||
this.color && stringArr.push(`color:${ this.color }`);
|
||||
this.backgroundColor && stringArr.push(`background-color:${ this.backgroundColor }`);
|
||||
this.weight && stringArr.push(`font-weight:${ this.weight }`);
|
||||
this.family && stringArr.push(`font-family:${ this.family }`);
|
||||
this.borderRadius && stringArr.push(`border-radius:${ this.borderRadius }`);
|
||||
this.border && stringArr.push(`border:${ this.border }`);
|
||||
this.size && stringArr.push(`font-size:${ this.size }`);
|
||||
|
||||
stringArr.push(`margin-bottom:5px`);
|
||||
|
||||
return stringArr.join(";");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志标签
|
||||
*/
|
||||
class LogLabel {
|
||||
|
||||
/**
|
||||
* 关键字
|
||||
* 用于标识这个类别
|
||||
*/
|
||||
public key:string;
|
||||
|
||||
/**
|
||||
* 文字样式
|
||||
*/
|
||||
public style:LogStyle;
|
||||
|
||||
/**
|
||||
* @param key 关键字
|
||||
* @param style 文字样式
|
||||
*/
|
||||
constructor(key:string, style:LogStyle) {
|
||||
this.key = key;
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 Logger 输出使用的内容
|
||||
*/
|
||||
public getLoggerOutput():string {
|
||||
return `%c ${ this.key } `;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 Text 输出内容
|
||||
*/
|
||||
public getTextOutput():string {
|
||||
return `[${ this.key }]`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 style 格式化
|
||||
*/
|
||||
public getStyleOutput():string {
|
||||
return this.style.stringify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 栈信息
|
||||
*/
|
||||
class StackInfo {
|
||||
|
||||
/**
|
||||
* 函数名
|
||||
*/
|
||||
public functionName:string | undefined;
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
public fileName:string | undefined;
|
||||
|
||||
/**
|
||||
* 文件路径
|
||||
*/
|
||||
public url:string | undefined;
|
||||
|
||||
public setInfo(functionName:string, fileName:string, url:string):StackInfo {
|
||||
this.functionName = functionName;
|
||||
this.fileName = fileName;
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取函数调用栈列表
|
||||
*/
|
||||
static getCallStack():StackInfo[] {
|
||||
|
||||
// 获取堆栈信息
|
||||
let stack:string | undefined = new Error().stack;
|
||||
|
||||
if (stack === void 0) return [];
|
||||
|
||||
// 去除 Error
|
||||
stack = stack.replace(/^(Error)\s/, "");
|
||||
|
||||
// 获取堆栈信息
|
||||
let stackList:string[] = stack.split(/\n/);
|
||||
|
||||
let callStack:StackInfo[] = [];
|
||||
|
||||
for(let i = 0; i < stackList.length; i++) {
|
||||
|
||||
let matcher = stackList[i].match(/^\s+at\s+(.+)\s(\(.+\))/);
|
||||
if (matcher === null || matcher.length < 3) continue;
|
||||
|
||||
let fileName = matcher[2].match(/.+\/(.+\..+:\d+:\d+)\)/);
|
||||
if (fileName === null || matcher.length < 2) continue;
|
||||
|
||||
callStack.push(new StackInfo().setInfo(
|
||||
matcher[1], fileName[1], matcher[2]
|
||||
))
|
||||
}
|
||||
|
||||
return callStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* 排除的
|
||||
*/
|
||||
static readonly excludeFile:RegExp = /^Logger\.js:\d+:\d+/;
|
||||
|
||||
/**
|
||||
* 获取第一个调用栈
|
||||
*/
|
||||
static getFirstStack():StackInfo | undefined {
|
||||
|
||||
let callStack = this.getCallStack();
|
||||
|
||||
for(let i = 0; i < callStack.length; i++) {
|
||||
|
||||
if(!callStack[i].fileName) continue;
|
||||
|
||||
if(!StackInfo.excludeFile.test(callStack[i].fileName ?? "")) {
|
||||
return callStack[i];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 多重内容捆绑
|
||||
* 用于 log 输出
|
||||
*/
|
||||
class MultipleLogContent {
|
||||
|
||||
/**
|
||||
* 输出内容
|
||||
*/
|
||||
private content:any[];
|
||||
|
||||
/**
|
||||
* @param content 输出内容
|
||||
*/
|
||||
public constructor(...content:any[]) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内容
|
||||
*/
|
||||
public getContent():any[] {
|
||||
return this.content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日志输出
|
||||
*/
|
||||
class Logger {
|
||||
|
||||
/**
|
||||
* 堆栈路径样式
|
||||
*/
|
||||
static readonly pathStyle:LogStyle = new LogStyle().setColor("#CCCCCC");
|
||||
|
||||
/**
|
||||
* 标签过滤
|
||||
*/
|
||||
static filterLog(filter:Array<RegExp | string>, labels:LogLabel[]):boolean {
|
||||
|
||||
let passNum:number = 0;
|
||||
|
||||
for(let i = 0; i < filter.length; i++) {
|
||||
|
||||
let pass:boolean = false;
|
||||
for(let j = 0; j < labels.length; j++) {
|
||||
|
||||
if(filter[i] instanceof RegExp) {
|
||||
pass = (filter[i] as RegExp).test(labels[j].key)
|
||||
} else {
|
||||
pass = (filter[i] as String) === labels[j].key;
|
||||
}
|
||||
|
||||
if(pass) break;
|
||||
}
|
||||
|
||||
if(pass) passNum ++;
|
||||
}
|
||||
|
||||
return passNum === filter.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否应该输出
|
||||
* @param labels 使用标签
|
||||
*/
|
||||
static testLog(...labels:LogLabel[]):boolean {
|
||||
|
||||
if(!LOGGER_CONSOLE) return false;
|
||||
|
||||
let isLogging = false;
|
||||
for(let i = 0; i < LOGGER_FILTER.length; i++) {
|
||||
|
||||
// 判断是否进行输出
|
||||
isLogging = Logger.filterLog(LOGGER_FILTER[i], labels);
|
||||
|
||||
if(isLogging) break;
|
||||
}
|
||||
|
||||
return isLogging;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param styledLabel calcStyle的处理结果
|
||||
*/
|
||||
static addFileNameLabel():LogLabel {
|
||||
|
||||
// 获得调用堆栈
|
||||
let stack = StackInfo.getFirstStack();
|
||||
|
||||
return new LogLabel(stack?.fileName ?? "", Logger.pathStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集计算样式
|
||||
* @param labels 使用标签
|
||||
*/
|
||||
static calcStyle(...labels:LogLabel[]):[string[], string[]] {
|
||||
|
||||
let consoleLabels:string[] = [];
|
||||
let consoleStyles:string[] = [];
|
||||
|
||||
// 放置标签
|
||||
for(let i = 0; i < labels.length; i++) {
|
||||
consoleLabels.push(labels[i].getLoggerOutput());
|
||||
|
||||
if (i !== ( labels.length - 1))
|
||||
consoleLabels.push("%c ");
|
||||
|
||||
consoleStyles.push(labels[i].getStyleOutput());
|
||||
|
||||
if (i !== ( labels.length - 1))
|
||||
consoleStyles.push("");
|
||||
}
|
||||
|
||||
return [consoleLabels, consoleStyles];
|
||||
}
|
||||
|
||||
/**
|
||||
* 调试输出
|
||||
* @param content 输出内容
|
||||
* @param label 使用标签
|
||||
*/
|
||||
static log<T>(content:T, ...labels:LogLabel[]):T {
|
||||
|
||||
let fileNameLabel = Logger.addFileNameLabel();
|
||||
|
||||
if(!Logger.testLog(...labels, fileNameLabel)) return content;
|
||||
|
||||
let styledLabel = Logger.calcStyle(...labels);
|
||||
|
||||
console.log(
|
||||
styledLabel[0].join("") + fileNameLabel.getLoggerOutput(),
|
||||
...[...styledLabel[1], fileNameLabel.getStyleOutput()],
|
||||
content
|
||||
);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多重调试输出
|
||||
* @param labels 输出内容
|
||||
* @param content 使用标签
|
||||
*/
|
||||
static logM<T>(labels:LogLabel[], ...content:T[]):T[] {
|
||||
return Logger.log<T[]>(content, ...labels);
|
||||
}
|
||||
}
|
||||
|
||||
export default Logger;
|
||||
export {Logger, LogStyle, LogLabel}
|
@ -17,7 +17,7 @@
|
||||
"newFeature": false,
|
||||
"coverView": true,
|
||||
"nodeModules": false,
|
||||
"autoAudits": true,
|
||||
"autoAudits": false,
|
||||
"showShadowRootInWxmlPanel": true,
|
||||
"scopeDataCheck": false,
|
||||
"uglifyFileName": true,
|
||||
|
Loading…
Reference in New Issue
Block a user