@yolanda-qn/logger
v1.0.2
Published
H5日志库
Downloads
1
Readme
h5实时日志记录
安装
yarn add @yolanda-qn/logger
示例
运行项目根目录下的 index.html
文件
使用
import Logger, {
transpilers,
WebHttp,
WebStorage,
TypeEnum,
LevelEnum,
RunEnvEnum,
} from '@yolanda-qn/logger';
const logger = new Logger({
// 等级顺序为 error > warn > debug > log > info
// 默认 LevelEnum.log
logLevel: LevelEnum.log,
});
const recordToServerTranspiler = new transpilers.RecordToServer({
// 服务器地址, post请求
url: 'https://test.com/api/log',
// 发送数据前的数据转换
transform: (mdatas) => ({ logs: mdatas }),
});
// 提供数据发送能力
recordToServerTranspiler.useHttp(WebHttp);
// 从 localStorage 读取缓存的数据和存储新的数据到 localStorage
recordToServerTranspiler.useStorage(WebStorage);
// 使用 console 打印信息
logger.useTranspiler(new transpilers.Console());
logger.useTranspiler(recordToServerTranspiler);
// 开始记录日志
const mdata = {
app_id: 'test_app', // 标识各类APP。必填
type: TypeEnum.request, // 日志分类。必填
level: LevelEnum.debug, // 日志等级。必填
path: location.href, // 页面地址
message: '发送数据', // 日志信息。必填
context: 'fetchListData', // 上下文。
stack: '这是一个错误堆栈', // 错误日志可能需要这个。
user_id: 12345678, // 用户身份标识。
system_type: 'android', // 系统类型。例如 ios, android等。
system_version: '11', // 系统版本
run_env: RunEnvEnum.webview, // 运行环境
app_version: '', // app版本
h5_version: '1.0.0', // H5版本
user_agent: navigator.userAgent, // 一般浏览器和webview环境是可以拿到ua的
tags: 'test', // 额外标签。多个标签使用 , 分割。可被用于搜索
};
// 除第一个参数外的其他信息会被转为JsonString拼接到message
// 不满足格式的数据会被舍弃
logger.stash(mdata, '其它信息1', { foo: 'foo' });
// level固定为info
logger.info(mdata, '其它信息1', { foo: 'foo' });
// level固定为log
logger.log(mdata, '其它信息1', { foo: 'foo' });
// level固定为debug
logger.debug(mdata, '其它信息1', { foo: 'foo' });
// level固定为warn
logger.warn(mdata, '其它信息1', { foo: 'foo' });
// level固定为error
logger.error(mdata, '其它信息1', { foo: 'foo' });
// 使用方式基本等同于 console
// 下列参数会合并到 message 字段
logger[level](1, 'string', { foo: 1 }, ['2', 3]);
exports
export { default } from './Logger';
export { default as Console } from './Console';
export { default as Metadata } from './Metadata';
export { default as Transpiler } from './Transpiler';
export { default as Http } from './Http';
export { default as WebHttp } from './WebHttp';
export { default as Storage } from './Storage';
export { default as WebStorage } from './WebStorage';
export { TypeEnum } from './enums/type.enum';
export { LevelEnum } from './enums/level.enum';
export { RunEnvEnum } from './enums/run-env.enum';
export { default as transpilers } from './transpilers';
export { default as version } from './version';
Logger
verbose
是否显示调试信息
- 类型: boolean
setDefaultMetadata
设置默认元数据,例如app_id, user_id, run_env, system_type, system_version, app_version, h5_version 等等。传入的日志数据会与之合并
- 参数:Partial<Metadata>
setLogLevel
对于 RecordToServerTranspiler 未满足设定日志等级的数据不会被记录
- 参数: LevelEnum
useTranspiler
- 参数: Transpiler
removeTranspiler
- 参数: Transpiler
clearTranspilers
dispose
释放资源,不再使用Logger时应当调用此方法来消除定时器等资源
stash
- 参数: Metadata
- 参数: ...any[]
info
- 参数: Metadata
- 参数: ...any[]
log
- 参数: Metadata
- 参数: ...any[]
debug
- 参数: Metadata
- 参数: ...any[]
warn
- 参数: Metadata
- 参数: ...any[]
error
- 参数: Metadata
- 参数: ...any[]
Metadata
日志元数据
export default class Metadata {
/**
* 标识各类APP
*/
app_id: string;
/**
* 分类
*/
type: TypeEnum;
/**
* 日志等级
*/
level: LevelEnum;
/**
* 开发人员上传的日志时间戳(毫秒级)
*/
log_time: number;
/**
* 页面地址
*/
path: string;
/**
* 记录的信息
*/
message: string;
/**
* 上下文
*/
context: string;
/**
* 错误日志可能需要这个
*/
stack?: string | undefined;
/**
* 用户身份标识
*/
user_id?: string | number;
/**
* 系统类型。例如 ios, android等
*/
system_type?: string | undefined;
/**
* 系统版本
*/
system_version?: string | undefined;
/**
* 运行环境
*/
run_env: RunEnvEnum;
/**
* app版本
*/
app_version?: string | undefined;
/**
* H5版本
*/
h5_version?: string | undefined;
/**
* 一般浏览器和webview环境是可以拿到ua的
*/
user_agent?: string | undefined;
/**
* 额外标签。多个标签使用 , 分割。可被用于搜索
*/
tags?: string | undefined;
_rawArgs: any[];
_uploaded: boolean;
constructor(params?: Partial<Metadata>);
validate(): {
valid: boolean;
errors: Array<{
field: string;
errors: string[];
}>;
};
}
Transpiler
真正处理日志数据的模块
/**
* Transpiler.ts
*/
import type Logger from './Logger';
import type Metadata from './Metadata';
export default abstract class Transpiler {
abstract name: string;
ctx?: Logger | null;
/**
* Logger收到的数据都会被转发到此函数
*/
abstract receiver(_mdata: Metadata): any;
/**
* 使用 logger.useTranspiler 注册后会回调此方法
*/
installed(ctx: Logger): void;
/**
* 在Logger中移除会触发此方法
*/
uninstalled(_ctx: Logger): void;
setCtx(ctx: Logger | null): void;
/**
* 释放资源
*/
dispose(): void;
}
简单的console打印功能实现
import { Transpiler } from '@yolanda-qn/logger';
class Console {
format(mdata: Metadata): any {
return [
`[${formatTime(new Date(mdata.log_time), 'YYYY-MM-DD HH:mm:ss-S')}][${mdata.level}]`,
...mdata._rawArgs,
];
}
info(mdata: Metadata) {
console.info(...this.format(mdata));
}
log(mdata: Metadata) {
console.log(...this.format(mdata));
}
debug(mdata: Metadata) {
console.debug(...this.format(mdata));
}
warn(mdata: Metadata) {
console.warn(...this.format(mdata));
}
error(mdata: Metadata) {
console.error(...this.format(mdata));
}
}
export default class ConsoleTranspiler extends Transpiler {
name = 'ConsoleTranspiler';
constructor(private readonly console: Console = new Console()) {
super();
}
receiver(mdata: Metadata) {
this.console[mdata.level]?.(mdata);
}
}
RecordToServerTranspiler
将日志数据发送给服务器
import { transpilers } from '@yolanda-qn/logger';
const RecordToServerTranspiler = transpiler.RecordToServer;
new RecordToServerTranspiler({
// 服务器地址。服务器接口应该被设计为接收批量数据
url: 'xxx',
// 发送给服务器数据转换
transform: (mdatas) => mdatas,
// 请求头
headers: {},
});
setSendDataSize
设置一次性发送的数据条数
- 参数: number
- 默认: 50
setStackSize
设置缓存池的大小。超过此大小则不再接收新的数据,除非数据发给了服务器。
- 参数: number
- 默认: 2000
setInterval
设置发送数据给服务器的时间间隔
- 参数: number
- 默认: 3000
useHttp
注册提供通信能力的Http类
- 参数: typeof Http
setUrl
设置服务器接口地址
- 参数: string
setTransform
数据转换
- 参数: (mdatas: Metadata[]) => any
setHeaders
请求头
- 参数: Record<string, string>
clearStack
清除缓存数据
useStorage
注册提供数据缓存能力的Storage类
- 参数: typeof Storage
disposeHttp
移除Http
disposeStorage
移除Storage
clearStorage
清除缓存数据
abortSendToServer
暂停发送数据给服务器。一分钟后自动唤醒重新发送数据
stopSendToServer
停止发送数据给服务器
resumeSendToServer
重新开始定时发送数据给服务器
flushToServer
将数据全部发送给服务器
flushToStorage
将当前stack数据缓存到本地缓存
dispose
释放资源
Http
提供数据通信能力定义
export default abstract class Http {
headers: Record<string, string>;
url: string;
method: 'get' | 'post' | 'put';
data: any;
transform?: (data: any) => any;
/**
* 为0则不设置超时时间
*/
timeout: number;
responseType: 'text' | 'json';
/**
* 如果知道数据类型一定是正确的,可以关闭此项来提升些许性能
*/
useValidate: boolean;
constructor(params: Partial<Pick<Http, 'headers' | 'method' | 'data' | 'transform' | 'timeout' | 'responseType'>> & Required<Pick<Http, 'url'>>);
validate(): boolean;
abstract send(data?: any): Promise<any>;
}
export declare class RequestError extends Error {
xhr: XMLHttpRequest;
status: number;
detail: any;
message: string;
constructor(params: Omit<RequestError, 'name'>);
}
对应环境的实现
import { Http } from '@yolanda-qn/logger';
export default WebHttp extends Http {
async send() {
// 使用 XMLHttpRequest 或 fetch 去实现
}
}
Storage
提供本地日志缓存功能
export default abstract class Storage {
key: string;
setKey(key: string): void;
abstract get(): Promise<Array<Metadata>>;
abstract set(value: Array<Metadata>): Promise<void>;
abstract clear(): Promise<void>;
}
对应环境的实现
import { Storage, Metadata } from '@yolanda-qn/logger';
export default class WebStorage extends Storage {
async get(): Promise<Array<Metadata>> {
const storage = localStorage.getItem(this.key);
if (storage) {
const mdatas = JSON.parse(storage);
return mdatas.map((m: any) => new Metadata(m))
.filter((m: Metadata) => {
const r = m.validate();
if (r.valid) {
return true;
}
console.warn('[WebStorage::get] mdata validate failed, it will be dropped.', '\nmdata', m, '\nerrors', r.errors);
return false;
});
}
return [];
}
async set(value: Array<Metadata>) {
localStorage.setItem(this.key, JSON.stringify(value));
}
async clear() {
localStorage.removeItem(this.key);
}
}
枚举值
export enum LevelEnum {
info = 'info',
log = 'log',
warn = 'warn',
debug = 'debug',
error = 'error',
}
export enum RunEnvEnum {
unknown = 'unknown',
/**
* 传统浏览器环境
*/
browser = 'browser',
/**
* 混合式开发
*/
webview = 'webview',
/**
* 微信小程序(保留)
*/
miniprogram = 'miniprogram',
/**
* 快应用(保留)
*/
quickapp = 'quickapp',
}
export enum TypeEnum {
/**
* 默认未分类
*/
default = 'default',
/**
* 系统级别
*/
system = 'system',
/**
* app级别
*/
app = 'app',
/**
* http请求
*/
request = 'request',
/**
* 视图相关
*/
view = 'view',
}