@kush_hemant/react-api-monitor 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +16 -0
- package/src/core/init.js +7 -0
- package/src/core/sender.js +20 -0
- package/src/index.js +1 -0
- package/src/network/auto.js +0 -0
- package/src/network/fetchMonitor.js +54 -0
- package/src/network/xhrMonitor.js +50 -0
- package/src/utils/metadata.js +7 -0
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kush_hemant/react-api-monitor",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Automatic API monitoring SDK for React apps",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"react",
|
|
9
|
+
"monitoring",
|
|
10
|
+
"api",
|
|
11
|
+
"logging",
|
|
12
|
+
"observability"
|
|
13
|
+
],
|
|
14
|
+
"author": "Hemant Kushwah",
|
|
15
|
+
"license": "MIT"
|
|
16
|
+
}
|
package/src/core/init.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
let endpoint = "";
|
|
2
|
+
|
|
3
|
+
export function configureSender(url) {
|
|
4
|
+
endpoint = url;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function sendLog(data) {
|
|
8
|
+
if (!endpoint) return;
|
|
9
|
+
|
|
10
|
+
navigator.sendBeacon?.(
|
|
11
|
+
endpoint,
|
|
12
|
+
JSON.stringify(data)
|
|
13
|
+
) ||
|
|
14
|
+
fetch(endpoint, {
|
|
15
|
+
method: "POST",
|
|
16
|
+
headers: { "Content-Type": "application/json" },
|
|
17
|
+
body: JSON.stringify(data),
|
|
18
|
+
keepalive: true,
|
|
19
|
+
}).catch(() => {});
|
|
20
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { initMonitoring } from "./core/init";
|
|
File without changes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { sendLog } from "../core/sender";
|
|
2
|
+
import { getMetadata } from "../utils/metadata";
|
|
3
|
+
|
|
4
|
+
export function monitorFetch() {
|
|
5
|
+
const originalFetch = window.fetch;
|
|
6
|
+
|
|
7
|
+
window.fetch = async (input, init = {}) => {
|
|
8
|
+
const start = Date.now();
|
|
9
|
+
|
|
10
|
+
let requestBody = init.body || null;
|
|
11
|
+
let method = init.method || "GET";
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const response = await originalFetch(input, init);
|
|
15
|
+
|
|
16
|
+
// Clone response to read body safely
|
|
17
|
+
const clone = response.clone();
|
|
18
|
+
let responseBody = null;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
responseBody = await clone.text();
|
|
22
|
+
} catch {}
|
|
23
|
+
|
|
24
|
+
sendLog({
|
|
25
|
+
type: "api_call",
|
|
26
|
+
transport: "fetch",
|
|
27
|
+
url: typeof input === "string" ? input : input.url,
|
|
28
|
+
method,
|
|
29
|
+
statusCode: response.status,
|
|
30
|
+
requestHeaders: init.headers,
|
|
31
|
+
requestBody,
|
|
32
|
+
responseHeaders: Object.fromEntries(
|
|
33
|
+
response.headers.entries()
|
|
34
|
+
),
|
|
35
|
+
responseBody,
|
|
36
|
+
duration: Date.now() - start,
|
|
37
|
+
...getMetadata(),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return response;
|
|
41
|
+
} catch (err) {
|
|
42
|
+
sendLog({
|
|
43
|
+
type: "api_error",
|
|
44
|
+
transport: "fetch",
|
|
45
|
+
url: input,
|
|
46
|
+
method,
|
|
47
|
+
error: err.message,
|
|
48
|
+
...getMetadata(),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { sendLog } from "../core/sender";
|
|
2
|
+
import { getMetadata } from "../utils/metadata";
|
|
3
|
+
|
|
4
|
+
export function monitorXHR() {
|
|
5
|
+
const originalOpen = XMLHttpRequest.prototype.open;
|
|
6
|
+
const originalSend = XMLHttpRequest.prototype.send;
|
|
7
|
+
const originalSetHeader =
|
|
8
|
+
XMLHttpRequest.prototype.setRequestHeader;
|
|
9
|
+
|
|
10
|
+
XMLHttpRequest.prototype.open = function (
|
|
11
|
+
method,
|
|
12
|
+
url,
|
|
13
|
+
...rest
|
|
14
|
+
) {
|
|
15
|
+
this._method = method;
|
|
16
|
+
this._url = url;
|
|
17
|
+
this._headers = {};
|
|
18
|
+
return originalOpen.call(this, method, url, ...rest);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
XMLHttpRequest.prototype.setRequestHeader = function (
|
|
22
|
+
key,
|
|
23
|
+
value
|
|
24
|
+
) {
|
|
25
|
+
this._headers[key] = value;
|
|
26
|
+
return originalSetHeader.call(this, key, value);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
XMLHttpRequest.prototype.send = function (body) {
|
|
30
|
+
const start = Date.now();
|
|
31
|
+
|
|
32
|
+
this.addEventListener("loadend", () => {
|
|
33
|
+
sendLog({
|
|
34
|
+
type: "api_call",
|
|
35
|
+
transport: "xhr",
|
|
36
|
+
url: this._url,
|
|
37
|
+
method: this._method,
|
|
38
|
+
statusCode: this.status,
|
|
39
|
+
requestHeaders: this._headers,
|
|
40
|
+
requestBody: body,
|
|
41
|
+
responseHeaders: this.getAllResponseHeaders(),
|
|
42
|
+
responseBody: this.responseText,
|
|
43
|
+
duration: Date.now() - start,
|
|
44
|
+
...getMetadata(),
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return originalSend.call(this, body);
|
|
49
|
+
};
|
|
50
|
+
}
|