feat(tracker-axios): 3.4.0 capture headers
This commit is contained in:
parent
d6914cc3c8
commit
f44f2273a7
4 changed files with 62 additions and 26 deletions
|
|
@ -21,22 +21,25 @@ const tracker = new Tracker({
|
|||
});
|
||||
tracker.start();
|
||||
|
||||
tracker.use(trackerAxios());
|
||||
tracker.use(trackerAxios({ /* options here*/ }));
|
||||
```
|
||||
Options:
|
||||
|
||||
```ts
|
||||
{
|
||||
instance: AxiosInstance; // default: axios
|
||||
failuresOnly: boolean; // default: true
|
||||
failuresOnly: boolean; // default: false
|
||||
captureWhen: (AxiosRequestConfig) => boolean; // default: () => true
|
||||
sessionTokenHeader: string; // default: undefined
|
||||
ingoreHeaders: Array<string> | boolean, // default [ 'Cookie', 'Set-Cookie', 'Authorization' ]
|
||||
}
|
||||
```
|
||||
By default plugin connects to the static `axios` instance, but you can specify one with the `instance` option.
|
||||
|
||||
Set `failuresOnly` option to `false` if you want to record every single request regardless of the status code. By default only failed requests are captured, when the axios' promise is rejected. You can also [regulate](https://github.com/axios/axios#request-config) this axios behaviour with the `validateStatus` option.
|
||||
Set `failuresOnly` option to `true` if you want to record only failed requests, when the axios' promise is rejected. You can also [regulate](https://github.com/axios/axios#request-config) axios failing behaviour with the `validateStatus` option.
|
||||
|
||||
`captureWhen` parameter allows you to set a filter on what should be captured. The function will be called with the axios config object and expected to return `true` or `false`.
|
||||
|
||||
In case you use [OpenReplay integrations (sentry, bugsnag or others)](https://docs.openreplay.com/integrations), you can use `sessionTokenHeader` option to specify the header name. This header will be appended automatically to the each axios request and will contain OpenReplay session identificator value.
|
||||
|
||||
You can define list of headers that you don't want to capture with the `ingoreHeaders` options. Set its value to `false` if you want to catch them all (`true` if opposite). By default plugin ignores the list of headers that might be sensetive such as `[ 'Cookie', 'Set-Cookie', 'Authorization' ]`.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-axios",
|
||||
"description": "Tracker plugin for axios requests recording",
|
||||
"version": "3.0.1",
|
||||
"version": "3.4.0",
|
||||
"keywords": [
|
||||
"axios",
|
||||
"logging",
|
||||
|
|
|
|||
|
|
@ -9,16 +9,16 @@ export interface Options {
|
|||
instance: AxiosInstance;
|
||||
failuresOnly: boolean;
|
||||
captureWhen: (AxiosRequestConfig) => boolean;
|
||||
//ingoreHeaders: Array<string> | boolean;
|
||||
ingoreHeaders: Array<string> | boolean;
|
||||
}
|
||||
|
||||
export default function(opts: Partial<Options> = {}) {
|
||||
const options: Options = Object.assign(
|
||||
{
|
||||
instance: axios,
|
||||
failuresOnly: true,
|
||||
failuresOnly: false,
|
||||
captureWhen: () => true,
|
||||
//ingoreHeaders: [ 'Cookie', 'Set-Cookie', 'Authorization' ],
|
||||
ingoreHeaders: [ 'Cookie', 'Set-Cookie', 'Authorization' ],
|
||||
},
|
||||
opts,
|
||||
);
|
||||
|
|
@ -27,48 +27,80 @@ export default function(opts: Partial<Options> = {}) {
|
|||
return;
|
||||
}
|
||||
|
||||
const sendFetchMessage = (response: AxiosResponse) => {
|
||||
const ihOpt = options.ingoreHeaders
|
||||
const isHIgnoring = Array.isArray(ihOpt)
|
||||
? name => ihOpt.includes(name)
|
||||
: () => ihOpt
|
||||
|
||||
const sendFetchMessage = (res: AxiosResponse) => {
|
||||
// @ts-ignore
|
||||
const startTime: number = response.config.__openreplayStartTs;
|
||||
const startTime: number = res.config.__openreplayStartTs;
|
||||
const duration = performance.now() - startTime;
|
||||
if (typeof startTime !== 'number') {
|
||||
return;
|
||||
}
|
||||
|
||||
let requestData: string = '';
|
||||
if (typeof response.config.data === 'string') {
|
||||
requestData = response.config.data;
|
||||
let reqBody: string = '';
|
||||
if (typeof res.config.data === 'string') {
|
||||
reqBody = res.config.data;
|
||||
} else {
|
||||
try {
|
||||
requestData = JSON.stringify(response.config.data) || '';
|
||||
reqBody = JSON.stringify(res.config.data) || '';
|
||||
} catch (e) {} // TODO: app debug
|
||||
}
|
||||
let resBody: string = '';
|
||||
if (typeof res.data === 'string') {
|
||||
resBody = res.data;
|
||||
} else {
|
||||
try {
|
||||
resBody = JSON.stringify(res.data) || '';
|
||||
} catch (e) {}
|
||||
}
|
||||
let responseData: string = '';
|
||||
if (typeof response.data === 'string') {
|
||||
responseData = response.data;
|
||||
} else {
|
||||
try {
|
||||
responseData = JSON.stringify(response.data) || '';
|
||||
} catch (e) {}
|
||||
|
||||
const reqHs: Record<string, string> = {}
|
||||
const resHs: Record<string, string> = {}
|
||||
// TODO: type safe axios headers
|
||||
if (ihOpt !== true) {
|
||||
function writeReqHeader([n, v]: [string, string]) {
|
||||
if (!isHIgnoring(n)) { reqHs[n] = v }
|
||||
}
|
||||
if (res.config.headers instanceof Headers) {
|
||||
res.config.headers.forEach((v, n) => writeReqHeader([n, v]))
|
||||
} else if (Array.isArray(res.config.headers)) {
|
||||
res.config.headers.forEach(writeReqHeader);
|
||||
} else if (typeof res.config.headers === 'object') {
|
||||
Object.entries(res.config.headers as Record<string, string>).forEach(writeReqHeader)
|
||||
}
|
||||
|
||||
// TODO: type safe axios headers
|
||||
if (typeof res.headers === 'object') {
|
||||
Object.entries(res.headers as Record<string, string>).forEach(([v, n]) => { if (!isHIgnoring(n)) resHs[n] = v })
|
||||
}
|
||||
}
|
||||
|
||||
// Why can't axios propogate the final request URL somewhere?
|
||||
const fullURL = buildFullPath(response.config.baseURL, options.instance.getUri(response.config));
|
||||
const fullURL = buildFullPath(res.config.baseURL, options.instance.getUri(res.config));
|
||||
|
||||
app.send(
|
||||
Messages.Fetch(
|
||||
typeof response.config.method === 'string' ? response.config.method.toUpperCase() : 'GET',
|
||||
typeof res.config.method === 'string' ? res.config.method.toUpperCase() : 'GET',
|
||||
fullURL,
|
||||
requestData,
|
||||
responseData,
|
||||
response.status,
|
||||
JSON.stringify({
|
||||
headers: reqHs,
|
||||
body: reqBody,
|
||||
}),
|
||||
JSON.stringify({
|
||||
headers: resHs,
|
||||
body: resBody,
|
||||
}),
|
||||
res.status,
|
||||
startTime + performance.timing.navigationStart,
|
||||
duration,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// TODO: why app.safe doesn't work here?
|
||||
options.instance.interceptors.request.use(function (config) {
|
||||
if (options.sessionTokenHeader) {
|
||||
const sessionToken = app.getSessionToken();
|
||||
|
|
@ -80,7 +112,7 @@ export default function(opts: Partial<Options> = {}) {
|
|||
config.headers.append(options.sessionTokenHeader, sessionToken);
|
||||
} else if (Array.isArray(config.headers)) {
|
||||
config.headers.push([options.sessionTokenHeader, sessionToken]);
|
||||
} else {
|
||||
} else if (typeof config.headers === 'object') {
|
||||
config.headers[options.sessionTokenHeader] = sessionToken;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"module": "es6",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"outDir": "./lib"
|
||||
"outDir": "./lib",
|
||||
"lib": ["es6", "dom", "es2017"] // is all necessary?
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue