@wutiange/log-listener-plugin 1.2.3 → 1.3.0-alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/console.js +14 -15
- package/dist/console.js.map +1 -1
- package/dist/fetch.js +28 -28
- package/dist/fetch.js.map +1 -1
- package/dist/index.d.ts +2 -23
- package/dist/index.js +2 -117
- package/dist/index.js.map +1 -1
- package/dist/packages/network-logger/Logger.d.ts +28 -0
- package/dist/packages/network-logger/Logger.js +192 -0
- package/dist/packages/network-logger/Logger.js.map +1 -0
- package/dist/packages/network-logger/NetworkRequestInfo.d.ts +37 -0
- package/dist/packages/network-logger/NetworkRequestInfo.js +151 -0
- package/dist/packages/network-logger/NetworkRequestInfo.js.map +1 -0
- package/dist/packages/network-logger/constant.d.ts +2 -0
- package/dist/packages/network-logger/constant.js +6 -0
- package/dist/packages/network-logger/constant.js.map +1 -0
- package/dist/packages/network-logger/types.d.ts +14 -0
- package/dist/packages/network-logger/types.js +3 -0
- package/dist/packages/network-logger/types.js.map +1 -0
- package/dist/packages/network-logger/utils/debounce.d.ts +2 -0
- package/dist/packages/network-logger/utils/debounce.js +20 -0
- package/dist/packages/network-logger/utils/debounce.js.map +1 -0
- package/dist/packages/network-logger/utils/extractHost.d.ts +2 -0
- package/dist/packages/network-logger/utils/extractHost.js +9 -0
- package/dist/packages/network-logger/utils/extractHost.js.map +1 -0
- package/dist/packages/network-logger/utils/fromEntries.d.ts +2 -0
- package/dist/packages/network-logger/utils/fromEntries.js +8 -0
- package/dist/packages/network-logger/utils/fromEntries.js.map +1 -0
- package/dist/packages/network-logger/utils/logger.d.ts +1 -0
- package/dist/packages/network-logger/utils/logger.js +6 -0
- package/dist/packages/network-logger/utils/logger.js.map +1 -0
- package/dist/src/CompatibilityManager.d.ts +27 -0
- package/dist/src/CompatibilityManager.js +82 -0
- package/dist/src/CompatibilityManager.js.map +1 -0
- package/dist/src/__tests__/console.test.d.ts +1 -0
- package/dist/{__tests__ → src/__tests__}/console.test.js +2 -2
- package/dist/src/__tests__/console.test.js.map +1 -0
- package/dist/src/common.js.map +1 -0
- package/dist/src/console.d.ts +1 -0
- package/dist/src/console.js +20 -0
- package/dist/src/console.js.map +1 -0
- package/dist/src/fetch.d.ts +1 -0
- package/dist/src/fetch.js +48 -0
- package/dist/src/fetch.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +8 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/logPlugin.d.ts +32 -0
- package/dist/src/logPlugin.js +187 -0
- package/dist/src/logPlugin.js.map +1 -0
- package/dist/{server.d.ts → src/server.d.ts} +1 -1
- package/dist/{server.js → src/server.js} +14 -8
- package/dist/src/server.js.map +1 -0
- package/dist/src/utils.d.ts +3 -0
- package/dist/src/utils.js +38 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +13 -5
- package/packages/network-logger/Logger.ts +274 -0
- package/packages/network-logger/NetworkRequestInfo.ts +161 -0
- package/packages/network-logger/constant.ts +3 -0
- package/packages/network-logger/types.ts +36 -0
- package/packages/network-logger/utils/debounce.ts +21 -0
- package/packages/network-logger/utils/extractHost.ts +7 -0
- package/packages/network-logger/utils/fromEntries.ts +7 -0
- package/packages/network-logger/utils/logger.ts +2 -0
- package/src/CompatibilityManager.ts +71 -0
- package/src/__tests__/console.test.ts +2 -2
- package/src/common.ts +2 -3
- package/src/logPlugin.ts +229 -0
- package/src/server.ts +28 -23
- package/src/utils.ts +38 -0
- package/dist/__tests__/console.test.d.ts +0 -1
- package/dist/__tests__/console.test.js.map +0 -1
- package/dist/common.js.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/utils.d.ts +0 -1
- package/dist/utils.js +0 -14
- package/dist/utils.js.map +0 -1
- package/src/console.ts +0 -19
- package/src/fetch.ts +0 -35
- package/src/index.ts +0 -131
- /package/dist/{common.d.ts → src/common.d.ts} +0 -0
- /package/dist/{common.js → src/common.js} +0 -0
@@ -0,0 +1,161 @@
|
|
1
|
+
// @ts-ignore
|
2
|
+
import BlobFileReader from 'react-native/Libraries/Blob/FileReader';
|
3
|
+
import type {Headers, NetworkRequestInfoRow, RequestMethod} from './types';
|
4
|
+
import fromEntries from './utils/fromEntries';
|
5
|
+
|
6
|
+
export default class NetworkRequestInfo {
|
7
|
+
id = '';
|
8
|
+
type = '';
|
9
|
+
url = '';
|
10
|
+
method: RequestMethod;
|
11
|
+
status: number = -1;
|
12
|
+
dataSent = '';
|
13
|
+
responseContentType = '';
|
14
|
+
responseSize = 0;
|
15
|
+
requestHeaders: Headers = {};
|
16
|
+
responseHeaders: Headers = {};
|
17
|
+
response = '';
|
18
|
+
responseURL = '';
|
19
|
+
responseType = '';
|
20
|
+
timeout = 0;
|
21
|
+
closeReason = '';
|
22
|
+
messages = '';
|
23
|
+
serverClose: any = undefined;
|
24
|
+
serverError: any = undefined;
|
25
|
+
startTime: number = 0;
|
26
|
+
endTime: number = 0;
|
27
|
+
gqlOperation?: string;
|
28
|
+
updatedAt: number = 0;
|
29
|
+
|
30
|
+
constructor(id: string, type: string, method: RequestMethod, url: string) {
|
31
|
+
this.id = id;
|
32
|
+
this.type = type;
|
33
|
+
this.method = method;
|
34
|
+
this.url = url;
|
35
|
+
this.updatedAt = Date.now();
|
36
|
+
}
|
37
|
+
|
38
|
+
get duration() {
|
39
|
+
return this.endTime - this.startTime;
|
40
|
+
}
|
41
|
+
|
42
|
+
get curlRequest() {
|
43
|
+
let headersPart =
|
44
|
+
this.requestHeaders &&
|
45
|
+
Object.entries(this.requestHeaders)
|
46
|
+
.map(([key, value]) => `'${key}: ${this.escapeQuotes(value)}'`)
|
47
|
+
.join(' -H ');
|
48
|
+
headersPart = headersPart ? `-H ${headersPart}` : '';
|
49
|
+
|
50
|
+
const body = this.dataSent && this.escapeQuotes(this.dataSent);
|
51
|
+
|
52
|
+
const methodPart =
|
53
|
+
this.method !== 'GET' ? `-X${this.method.toUpperCase()}` : '';
|
54
|
+
const bodyPart = body ? `-d '${body}'` : '';
|
55
|
+
|
56
|
+
const parts = ['curl', methodPart, headersPart, bodyPart, `'${this.url}'`];
|
57
|
+
|
58
|
+
return parts.filter(Boolean).join(' ');
|
59
|
+
}
|
60
|
+
|
61
|
+
update(values: Partial<NetworkRequestInfo>) {
|
62
|
+
Object.assign(this, values);
|
63
|
+
if (values.dataSent) {
|
64
|
+
const data = this.parseData(values.dataSent);
|
65
|
+
this.gqlOperation = data?.operationName;
|
66
|
+
}
|
67
|
+
this.updatedAt = Date.now();
|
68
|
+
}
|
69
|
+
|
70
|
+
private escapeQuotes(value: string) {
|
71
|
+
return value.replace?.(/'/g, "\\'");
|
72
|
+
}
|
73
|
+
|
74
|
+
private parseData(data: any) {
|
75
|
+
try {
|
76
|
+
if (data?._parts?.length) {
|
77
|
+
return fromEntries(data?._parts);
|
78
|
+
}
|
79
|
+
return JSON.parse(data);
|
80
|
+
} catch (e) {
|
81
|
+
return {data};
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
private stringifyFormat(data: any) {
|
86
|
+
return JSON.stringify(this.parseData(data), null, 2);
|
87
|
+
}
|
88
|
+
|
89
|
+
public toRow(): NetworkRequestInfoRow {
|
90
|
+
return {
|
91
|
+
url: this.url,
|
92
|
+
gqlOperation: this.gqlOperation,
|
93
|
+
id: this.id,
|
94
|
+
method: this.method,
|
95
|
+
status: this.status,
|
96
|
+
duration: this.duration,
|
97
|
+
startTime: this.startTime,
|
98
|
+
};
|
99
|
+
}
|
100
|
+
|
101
|
+
getRequestBody(replaceEscaped = false) {
|
102
|
+
const body = this.stringifyFormat(this.dataSent);
|
103
|
+
|
104
|
+
if (replaceEscaped) {
|
105
|
+
return body.replace(/\\n/g, '\n').replace(/\\"/g, '"');
|
106
|
+
}
|
107
|
+
|
108
|
+
return body;
|
109
|
+
}
|
110
|
+
|
111
|
+
private async parseResponseBlob() {
|
112
|
+
const blobReader = new BlobFileReader();
|
113
|
+
blobReader.readAsText(this.response);
|
114
|
+
|
115
|
+
return await new Promise<string>((resolve, reject) => {
|
116
|
+
const handleError = () => reject(blobReader.error);
|
117
|
+
|
118
|
+
blobReader.addEventListener('load', () => {
|
119
|
+
resolve(blobReader.result);
|
120
|
+
});
|
121
|
+
blobReader.addEventListener('error', handleError);
|
122
|
+
blobReader.addEventListener('abort', handleError);
|
123
|
+
});
|
124
|
+
}
|
125
|
+
|
126
|
+
async getResponseBody() {
|
127
|
+
const body = await (this.responseType !== 'blob'
|
128
|
+
? this.response
|
129
|
+
: this.parseResponseBlob());
|
130
|
+
|
131
|
+
return this.stringifyFormat(body);
|
132
|
+
}
|
133
|
+
|
134
|
+
public copy(): NetworkRequestInfo {
|
135
|
+
const newInstance = new NetworkRequestInfo(this.id, this.type, this.method, this.url);
|
136
|
+
|
137
|
+
// 复制基本类型属性
|
138
|
+
newInstance.status = this.status;
|
139
|
+
newInstance.dataSent = this.dataSent;
|
140
|
+
newInstance.responseContentType = this.responseContentType;
|
141
|
+
newInstance.responseSize = this.responseSize;
|
142
|
+
newInstance.response = this.response;
|
143
|
+
newInstance.responseURL = this.responseURL;
|
144
|
+
newInstance.responseType = this.responseType;
|
145
|
+
newInstance.timeout = this.timeout;
|
146
|
+
newInstance.closeReason = this.closeReason;
|
147
|
+
newInstance.messages = this.messages;
|
148
|
+
newInstance.serverClose = this.serverClose;
|
149
|
+
newInstance.serverError = this.serverError;
|
150
|
+
newInstance.startTime = this.startTime;
|
151
|
+
newInstance.endTime = this.endTime;
|
152
|
+
newInstance.gqlOperation = this.gqlOperation;
|
153
|
+
newInstance.updatedAt = this.updatedAt;
|
154
|
+
|
155
|
+
// 深拷贝对象类型属性
|
156
|
+
newInstance.requestHeaders = JSON.parse(JSON.stringify(this.requestHeaders));
|
157
|
+
newInstance.responseHeaders = JSON.parse(JSON.stringify(this.responseHeaders));
|
158
|
+
|
159
|
+
return newInstance;
|
160
|
+
}
|
161
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import NetworkRequestInfo from './NetworkRequestInfo';
|
2
|
+
|
3
|
+
export type Headers = {[header: string]: string};
|
4
|
+
export type RequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
5
|
+
export type StartNetworkLoggingOptions = {
|
6
|
+
/**
|
7
|
+
* Max number of requests to keep before overwriting
|
8
|
+
* @default 500
|
9
|
+
*/
|
10
|
+
maxRequests?: number;
|
11
|
+
/** List of hosts to ignore, e.g. `services.test.com` */
|
12
|
+
ignoredHosts?: string[];
|
13
|
+
/** List of urls to ignore, e.g. `https://services.test.com/test` */
|
14
|
+
ignoredUrls?: string[];
|
15
|
+
/**
|
16
|
+
* List of url patterns to ignore, e.g. `/^GET https://test.com\/pages\/.*$/`
|
17
|
+
*
|
18
|
+
* Url to match with is in the format: `${method} ${url}`, e.g. `GET https://test.com/pages/123`
|
19
|
+
*/
|
20
|
+
ignoredPatterns?: RegExp[];
|
21
|
+
/**
|
22
|
+
* Force the network logger to start even if another program is using the network interceptor
|
23
|
+
* e.g. a dev/debuging program
|
24
|
+
*/
|
25
|
+
forceEnable?: boolean;
|
26
|
+
/**
|
27
|
+
* Refresh rate of the logger in milliseconds
|
28
|
+
* @default 50
|
29
|
+
*/
|
30
|
+
refreshRate?: number;
|
31
|
+
};
|
32
|
+
|
33
|
+
export type NetworkRequestInfoRow = Pick<
|
34
|
+
NetworkRequestInfo,
|
35
|
+
'url' | 'gqlOperation' | 'id' | 'method' | 'status' | 'duration' | 'startTime'
|
36
|
+
>;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
// https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_debounce
|
2
|
+
function debounce(func: Function, wait: number, immediate: boolean = false) {
|
3
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
4
|
+
return function () {
|
5
|
+
const args = arguments;
|
6
|
+
clearTimeout(timeout);
|
7
|
+
// @ts-ignore
|
8
|
+
if (immediate && !timeout) {
|
9
|
+
func.apply(this, args);
|
10
|
+
}
|
11
|
+
timeout = setTimeout(function () {
|
12
|
+
timeout = undefined;
|
13
|
+
// @ts-ignore
|
14
|
+
if (!immediate) {
|
15
|
+
func.apply(this, args);
|
16
|
+
}
|
17
|
+
}, wait);
|
18
|
+
};
|
19
|
+
}
|
20
|
+
|
21
|
+
export default debounce;
|
@@ -0,0 +1,71 @@
|
|
1
|
+
import NetworkRequestInfo from "../packages/network-logger/NetworkRequestInfo";
|
2
|
+
|
3
|
+
class CompatibilityManager {
|
4
|
+
private static requestInfoObj: Record<string, NetworkRequestInfo> = {}
|
5
|
+
static async interceptionToNetwork(data: NetworkRequestInfo[]) {
|
6
|
+
const tempWillSendArr: NetworkRequestInfo[] = []
|
7
|
+
if (Object.keys(CompatibilityManager.requestInfoObj).length === 0) {
|
8
|
+
CompatibilityManager.requestInfoObj = data.reduce((e, c) => {
|
9
|
+
if (c.endTime) {
|
10
|
+
const startReq = c.copy()
|
11
|
+
startReq.endTime = 0;
|
12
|
+
tempWillSendArr.push(startReq, c)
|
13
|
+
return e
|
14
|
+
}
|
15
|
+
tempWillSendArr.push(c)
|
16
|
+
return {...e, [c.id]: c}
|
17
|
+
}, {})
|
18
|
+
} else {
|
19
|
+
data.forEach(e => {
|
20
|
+
const tempObj = CompatibilityManager.requestInfoObj
|
21
|
+
if (!(e.id in tempObj)) {
|
22
|
+
if (!e.endTime) {
|
23
|
+
tempWillSendArr.push(e)
|
24
|
+
CompatibilityManager.requestInfoObj[e.id] = e
|
25
|
+
} else {
|
26
|
+
const startReq = e.copy()
|
27
|
+
startReq.endTime = 0;
|
28
|
+
tempWillSendArr.push(startReq, e)
|
29
|
+
}
|
30
|
+
return
|
31
|
+
}
|
32
|
+
if (e.id in tempObj && e.endTime) {
|
33
|
+
tempWillSendArr.push(e)
|
34
|
+
delete CompatibilityManager.requestInfoObj[e.id]
|
35
|
+
return
|
36
|
+
}
|
37
|
+
})
|
38
|
+
}
|
39
|
+
|
40
|
+
// 将要发送的数据转换成兼容的数据
|
41
|
+
return CompatibilityManager.asyncSwapSendArr(tempWillSendArr)
|
42
|
+
}
|
43
|
+
|
44
|
+
private static async asyncSwapSendArr(data: NetworkRequestInfo[]) {
|
45
|
+
const asyncTempArr = await Promise.all(data.map(async (e) => {
|
46
|
+
if (e.endTime) {
|
47
|
+
return {
|
48
|
+
headers: e.responseHeaders,
|
49
|
+
body: await e.getResponseBody(),
|
50
|
+
requestId: e.id,
|
51
|
+
statusCode: e.status,
|
52
|
+
endTime: e.endTime,
|
53
|
+
};
|
54
|
+
} else {
|
55
|
+
return {
|
56
|
+
url: e.url,
|
57
|
+
id: e.id,
|
58
|
+
method: e.method,
|
59
|
+
headers: e.requestHeaders,
|
60
|
+
body: e.getRequestBody(),
|
61
|
+
createTime: e.startTime,
|
62
|
+
};
|
63
|
+
}
|
64
|
+
}));
|
65
|
+
|
66
|
+
return asyncTempArr;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
export default CompatibilityManager
|
package/src/common.ts
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
export const [log, warn, error] = [console.log, console.warn, console.error]
|
2
|
-
|
1
|
+
export const [log, warn, error] = [console.log, console.warn, console.error];
|
3
2
|
|
4
3
|
// @ts-ignore
|
5
|
-
export const tempFetch = global.fetch as typeof fetch
|
4
|
+
export const tempFetch = global.fetch as typeof fetch;
|
package/src/logPlugin.ts
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
import Server from './server';
|
2
|
+
import Logger from '../packages/network-logger/Logger';
|
3
|
+
import NetworkRequestInfo from '../packages/network-logger/NetworkRequestInfo';
|
4
|
+
import { extractDomain } from './utils';
|
5
|
+
import CompatibilityManager from './CompatibilityManager';
|
6
|
+
|
7
|
+
class LogPlugin {
|
8
|
+
private server: Server | null = null;
|
9
|
+
private baseData: Record<string, any> = {};
|
10
|
+
private timeout: number | null = null;
|
11
|
+
private networkLogger = new Logger();
|
12
|
+
private host = '';
|
13
|
+
private isAuto = false
|
14
|
+
|
15
|
+
auto() {
|
16
|
+
if (this.host) {
|
17
|
+
this.startRecordNetwork();
|
18
|
+
this.startRecordLog();
|
19
|
+
}
|
20
|
+
this.isAuto = true
|
21
|
+
}
|
22
|
+
|
23
|
+
unAuto() {
|
24
|
+
this.stopRecordLog()
|
25
|
+
this.networkLogger.disableXHRInterception()
|
26
|
+
this.isAuto = false
|
27
|
+
}
|
28
|
+
|
29
|
+
startRecordLog() {
|
30
|
+
const common = require('./common')
|
31
|
+
console.log = (...data: any[]) => {
|
32
|
+
this.log(...data);
|
33
|
+
common.log(...data);
|
34
|
+
};
|
35
|
+
|
36
|
+
console.warn = (...data: any[]) => {
|
37
|
+
this.warn(...data);
|
38
|
+
common.warn(...data);
|
39
|
+
};
|
40
|
+
|
41
|
+
console.error = (...data: any[]) => {
|
42
|
+
this.error(...data);
|
43
|
+
common.error(...data);
|
44
|
+
};
|
45
|
+
}
|
46
|
+
|
47
|
+
stopRecordLog() {
|
48
|
+
const common = require('./common')
|
49
|
+
console.log = common.log
|
50
|
+
console.warn = common.warn
|
51
|
+
console.error = common.error
|
52
|
+
}
|
53
|
+
|
54
|
+
startRecordNetwork() {
|
55
|
+
this.networkLogger.setCallback(async (data: NetworkRequestInfo[]) => {
|
56
|
+
const sendData = await CompatibilityManager.interceptionToNetwork(data);
|
57
|
+
sendData.forEach(e => {
|
58
|
+
this.server?.network({
|
59
|
+
...this.baseData,
|
60
|
+
...e
|
61
|
+
});
|
62
|
+
})
|
63
|
+
});
|
64
|
+
|
65
|
+
this.networkLogger.enableXHRInterception({
|
66
|
+
ignoredHosts: [extractDomain(this.host)],
|
67
|
+
});
|
68
|
+
}
|
69
|
+
|
70
|
+
setBaseUrl(url: string) {
|
71
|
+
if (!url?.trim()) {
|
72
|
+
this.networkLogger.disableXHRInterception()
|
73
|
+
this.stopRecordLog()
|
74
|
+
return
|
75
|
+
}
|
76
|
+
this.host = url.includes("http") ? url : `http://${url}`;
|
77
|
+
if (this.server) {
|
78
|
+
this.server.updateUrl(url);
|
79
|
+
} else {
|
80
|
+
this.server = new Server(url);
|
81
|
+
}
|
82
|
+
if (this.isAuto) {
|
83
|
+
this.startRecordNetwork();
|
84
|
+
this.startRecordLog()
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
/**
|
89
|
+
* @deprecated 不需要手动上报,日志插件会自动收集日志
|
90
|
+
*/
|
91
|
+
setTimeout(timeout: number) {
|
92
|
+
if (typeof timeout === 'number') {
|
93
|
+
this.timeout = timeout;
|
94
|
+
this.server?.updateTimeout(this.timeout);
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* @deprecated 不需要手动上报,日志插件会自动收集日志
|
100
|
+
*/
|
101
|
+
getTimeout() {
|
102
|
+
if (typeof this.timeout === 'number') {
|
103
|
+
return this.timeout;
|
104
|
+
}
|
105
|
+
return null;
|
106
|
+
}
|
107
|
+
|
108
|
+
setBaseData(data: Record<string, any> = {}) {
|
109
|
+
this.baseData = data;
|
110
|
+
}
|
111
|
+
|
112
|
+
private _log(level: string, tag: string, ...data: any[]) {
|
113
|
+
const sendData = {
|
114
|
+
...this.baseData,
|
115
|
+
message: data,
|
116
|
+
tag,
|
117
|
+
level: level ?? 'log',
|
118
|
+
createTime: Date.now(),
|
119
|
+
};
|
120
|
+
this.server?.log(sendData);
|
121
|
+
}
|
122
|
+
|
123
|
+
tag(tag: string, ...data: any[]) {
|
124
|
+
this._log('log', tag, ...data);
|
125
|
+
}
|
126
|
+
|
127
|
+
log(...data: any[]) {
|
128
|
+
this._log('log', 'default', ...data);
|
129
|
+
}
|
130
|
+
|
131
|
+
warn(...data: any[]) {
|
132
|
+
this._log('warn', 'default', ...data);
|
133
|
+
}
|
134
|
+
|
135
|
+
error(...data: any[]) {
|
136
|
+
this._log('error', 'default', ...data);
|
137
|
+
}
|
138
|
+
|
139
|
+
/**
|
140
|
+
* @deprecated 不需要手动上报,日志插件会自动收集日志
|
141
|
+
*/
|
142
|
+
async uniqueReq(
|
143
|
+
uniqueId: string | undefined,
|
144
|
+
input: RequestInfo | URL,
|
145
|
+
init?: RequestInit
|
146
|
+
) {
|
147
|
+
let url: string | null = null;
|
148
|
+
let method = init?.method ?? 'get';
|
149
|
+
let headers = init?.headers;
|
150
|
+
let body = init?.body;
|
151
|
+
if (input instanceof Request) {
|
152
|
+
url = input.url;
|
153
|
+
method = input.method ?? 'get';
|
154
|
+
headers = (input.headers as Record<string, any>).map;
|
155
|
+
body = input.body;
|
156
|
+
} else if (input instanceof URL) {
|
157
|
+
url = input.href;
|
158
|
+
} else {
|
159
|
+
url = input;
|
160
|
+
}
|
161
|
+
return this.server?.network({
|
162
|
+
...this.baseData,
|
163
|
+
url,
|
164
|
+
id: uniqueId,
|
165
|
+
method,
|
166
|
+
headers,
|
167
|
+
body,
|
168
|
+
createTime: Date.now(),
|
169
|
+
});
|
170
|
+
}
|
171
|
+
|
172
|
+
private async _res(uniqueId?: string, id?: number, response?: Response) {
|
173
|
+
const body = await response?.text();
|
174
|
+
return this.server?.network({
|
175
|
+
...this.baseData,
|
176
|
+
headers: (response?.headers as Record<string, any>).map,
|
177
|
+
body,
|
178
|
+
requestId: uniqueId ?? Number(id),
|
179
|
+
statusCode: response?.status,
|
180
|
+
endTime: Date.now(),
|
181
|
+
});
|
182
|
+
}
|
183
|
+
|
184
|
+
/**
|
185
|
+
* @deprecated 不需要手动上报,日志插件会自动收集日志
|
186
|
+
*/
|
187
|
+
async resTimeout(uniqueId: string) {
|
188
|
+
return this.server?.network({
|
189
|
+
...this.baseData,
|
190
|
+
isTimeout: true,
|
191
|
+
requestId: uniqueId,
|
192
|
+
});
|
193
|
+
}
|
194
|
+
|
195
|
+
/**
|
196
|
+
* @deprecated 不需要手动上报,日志插件会自动收集日志
|
197
|
+
*/
|
198
|
+
async resResponseError(uniqueId: string) {
|
199
|
+
return this.server?.network({
|
200
|
+
...this.baseData,
|
201
|
+
isResponseError: true,
|
202
|
+
requestId: uniqueId,
|
203
|
+
});
|
204
|
+
}
|
205
|
+
|
206
|
+
/**
|
207
|
+
* @deprecated 不需要手动上报,日志插件会自动收集日志
|
208
|
+
*/
|
209
|
+
async uniqueRes(uniqueId: string, response?: Response) {
|
210
|
+
return this._res(uniqueId, undefined, response);
|
211
|
+
}
|
212
|
+
|
213
|
+
/**
|
214
|
+
* @deprecated 不需要手动上报,日志插件会自动收集日志
|
215
|
+
*/
|
216
|
+
async req(input: RequestInfo | URL, init?: RequestInit) {
|
217
|
+
return this.uniqueReq(undefined, input, init);
|
218
|
+
}
|
219
|
+
|
220
|
+
/**
|
221
|
+
* @deprecated 不需要手动上报,日志插件会自动收集日志
|
222
|
+
*/
|
223
|
+
async res(id: number, response?: Response) {
|
224
|
+
return this._res(undefined, id, response);
|
225
|
+
}
|
226
|
+
}
|
227
|
+
const logPlugin = new LogPlugin();
|
228
|
+
export { LogPlugin };
|
229
|
+
export default logPlugin;
|
package/src/server.ts
CHANGED
@@ -1,61 +1,66 @@
|
|
1
|
-
import { sleep
|
2
|
-
|
1
|
+
import {hasPort, sleep} from './utils';
|
2
|
+
const DEFAULT_PORT = 27751
|
3
3
|
class Server {
|
4
4
|
private baseUrl = '';
|
5
|
-
private port = 27751
|
6
5
|
private timeout: number;
|
7
6
|
|
8
|
-
|
9
7
|
constructor(url: string, timeout: number = 3000) {
|
10
|
-
this.updateUrl(url)
|
11
|
-
this.timeout = timeout
|
8
|
+
this.updateUrl(url);
|
9
|
+
this.timeout = timeout;
|
12
10
|
}
|
13
11
|
|
14
12
|
updateTimeout(timeout = 3000) {
|
15
|
-
this.timeout = timeout
|
13
|
+
this.timeout = timeout;
|
14
|
+
}
|
15
|
+
|
16
|
+
private getPort() {
|
17
|
+
if (hasPort(this.baseUrl)) {
|
18
|
+
return ''
|
19
|
+
}
|
20
|
+
return DEFAULT_PORT;
|
16
21
|
}
|
17
22
|
|
18
23
|
private async send(path: string, data: Record<string, any>) {
|
19
24
|
try {
|
20
25
|
if (!this.baseUrl) {
|
21
|
-
return null
|
26
|
+
return null;
|
22
27
|
}
|
23
|
-
const common =
|
28
|
+
const common = require('./common');
|
24
29
|
const result = await Promise.race([
|
25
|
-
common.tempFetch(`${this.baseUrl}:${this.
|
30
|
+
common.tempFetch(`${this.baseUrl}:${this.getPort()}/${path}`, {
|
26
31
|
method: 'POST',
|
27
32
|
headers: {
|
28
|
-
'Content-Type': 'application/json;charset=utf-8'
|
33
|
+
'Content-Type': 'application/json;charset=utf-8',
|
29
34
|
},
|
30
35
|
body: JSON.stringify(data, (_, val) => {
|
31
36
|
if (val instanceof Error) {
|
32
|
-
return val.toString()
|
37
|
+
return val.toString();
|
33
38
|
}
|
34
|
-
return val
|
35
|
-
})
|
39
|
+
return val;
|
40
|
+
}),
|
36
41
|
}),
|
37
|
-
sleep(this.timeout, true)
|
38
|
-
])
|
42
|
+
sleep(this.timeout, true),
|
43
|
+
]);
|
39
44
|
if (result instanceof Response) {
|
40
|
-
return result.text()
|
45
|
+
return result.text();
|
41
46
|
}
|
42
|
-
return null
|
47
|
+
return null;
|
43
48
|
} catch (error) {
|
44
|
-
return null
|
49
|
+
return null;
|
45
50
|
}
|
46
51
|
}
|
47
52
|
|
48
53
|
updateUrl(url: string) {
|
49
|
-
this.baseUrl = url
|
54
|
+
this.baseUrl = url;
|
50
55
|
}
|
51
56
|
|
52
57
|
async log(data: Record<string, any>) {
|
53
|
-
return this.send(
|
58
|
+
return this.send('log', data);
|
54
59
|
}
|
55
60
|
|
56
61
|
async network(data: Record<string, any>) {
|
57
|
-
return this.send(
|
62
|
+
return this.send('network', data);
|
58
63
|
}
|
59
64
|
}
|
60
65
|
|
61
|
-
export default Server
|
66
|
+
export default Server;
|
package/src/utils.ts
CHANGED
@@ -7,3 +7,41 @@ export function sleep(ms: number, isReject: boolean = false) {
|
|
7
7
|
}) : resolve, ms)
|
8
8
|
})
|
9
9
|
}
|
10
|
+
|
11
|
+
export function extractDomain(url: string) {
|
12
|
+
// 如果 url 是空的或不是字符串,直接返回
|
13
|
+
if (!url || typeof url !== 'string') {
|
14
|
+
return url;
|
15
|
+
}
|
16
|
+
|
17
|
+
// 使用正则表达式匹配 URL
|
18
|
+
const match = url.match(/^(https?:\/\/)?([^/:]+)/i);
|
19
|
+
|
20
|
+
// 如果没有匹配到,返回原始输入
|
21
|
+
if (!match) {
|
22
|
+
return url;
|
23
|
+
}
|
24
|
+
|
25
|
+
// 返回匹配到的域名部分
|
26
|
+
return match[2];
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
export function hasPort(url: string) {
|
31
|
+
// 如果 url 是空的或不是字符串,返回 false
|
32
|
+
if (!url || typeof url !== 'string') {
|
33
|
+
return false;
|
34
|
+
}
|
35
|
+
|
36
|
+
try {
|
37
|
+
// 使用 URL 构造函数解析 URL
|
38
|
+
const parsedUrl = new URL(url);
|
39
|
+
|
40
|
+
// 检查 port 属性是否为空
|
41
|
+
// 注意:如果使用默认端口(如 HTTP 的 80 或 HTTPS 的 443),port 会是空字符串
|
42
|
+
return parsedUrl.port !== '';
|
43
|
+
} catch (error) {
|
44
|
+
// 如果 URL 无效,捕获错误并返回 false
|
45
|
+
return false;
|
46
|
+
}
|
47
|
+
}
|
@@ -1 +0,0 @@
|
|
1
|
-
import '../console';
|