Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions packages/sdk-core/src/BacktraceCoreClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '.';
import { SdkOptions } from './builder/SdkOptions';
import { BacktraceConfiguration } from './model/configuration/BacktraceConfiguration';
import { AttributeType } from './model/data/BacktraceData';
import { AttributeType, BacktraceData } from './model/data/BacktraceData';
import { BacktraceReportSubmission } from './model/http/BacktraceReportSubmission';
import { BacktraceRequestHandler } from './model/http/BacktraceRequestHandler';
import { BacktraceReport } from './model/report/BacktraceReport';
Expand Down Expand Up @@ -154,9 +154,21 @@ export abstract class BacktraceCoreClient {
skipFrames: this.skipFrameOnMessage(data),
});

const backtraceData = this.generateSubmissionData(report);
if (!backtraceData) {
return;
}

await this._reportSubmission.send(backtraceData, this.generateSubmissionAttachments(report, reportAttachments));
}

private generateSubmissionData(report: BacktraceReport): BacktraceData | undefined {
const { annotations, attributes } = this._attributeProvider.get();
const backtraceData = this._dataBuilder.build(report, attributes, annotations);
await this._reportSubmission.send(backtraceData, this.generateSubmissionAttachments(report, reportAttachments));
if (!this.options.beforeSend) {
return backtraceData;
}
return this.options.beforeSend(backtraceData);
}

private generateSubmissionAttachments(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BacktraceAttachment } from '../attachment';
import { BacktraceData } from '../data/BacktraceData';
import { BacktraceDatabaseConfiguration } from './BacktraceDatabaseConfiguration';

export interface BacktraceMetricsOptions {
Expand Down Expand Up @@ -56,6 +57,13 @@ export interface BacktraceConfiguration {
timeout?: number;
ignoreSslCertificate?: boolean;

/**
* Triggers an event every time an exception in the managed environment occurs, which allows you to skip the report (by returning a null value)
* or to modify data that library collected before sending the report. You can use the BeforeSend event to extend attributes or JSON object
* data based on data the application has at the time of exception.
*/
beforeSend?: (data: BacktraceData) => BacktraceData | undefined;

/**
* Limits the number of reports the client will send per minute. If set to '0', there is no limit.
* If set to a value greater than '0' and the value is reached, the client will not send any reports until the next minute.
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk-core/tests/client/attributesTests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('Attributes tests', () => {
const scopedAttributeGetFunction = jest
.fn()
.mockReturnValue({ [providerAttributeKey]: providerAttributeValue });
const fakeClient = BacktraceTestClient.buildFakeClient([
const fakeClient = BacktraceTestClient.buildFakeClient({}, [
{
type: 'scoped',
get: scopedAttributeGetFunction,
Expand All @@ -66,7 +66,7 @@ describe('Attributes tests', () => {
const scopedAttributeGetFunction = jest
.fn()
.mockReturnValue({ [providerAttributeKey]: providerAttributeValue });
const fakeClient = BacktraceTestClient.buildFakeClient([
const fakeClient = BacktraceTestClient.buildFakeClient({}, [
{
type: 'dynamic',
get: scopedAttributeGetFunction,
Expand Down
50 changes: 50 additions & 0 deletions packages/sdk-core/tests/client/clientCallbacksTests.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { BacktraceReportSubmissionResult } from '../../src';
import { BacktraceData } from '../../src/model/data/BacktraceData';
import { BacktraceTestClient } from '../mocks/BacktraceTestClient';

describe('Client callbacks tests', () => {
describe('Submission data modification tests', () => {
it('Should invoke the before send event', async () => {
let triggered = false;
const client = BacktraceTestClient.buildFakeClient({
beforeSend: (data) => {
triggered = true;
return data;
},
});

await client.send(new Error());
expect(triggered).toBeTruthy();
});

it('Should allow to modify the report attribute', async () => {
const attributeName = 'test';
const expectedAttributeVaue = 'invoked';
const client = BacktraceTestClient.buildFakeClient({
beforeSend: (data) => {
data.attributes[attributeName] = expectedAttributeVaue;
return data;
},
});
jest.spyOn(client.requestHandler, 'postError').mockImplementationOnce((_: string, data: BacktraceData) => {
expect(data.attributes[attributeName]).toEqual(expectedAttributeVaue);
return Promise.resolve(BacktraceReportSubmissionResult.Ok({}));
});

client.addAttribute({ [attributeName]: 'not-invoked' });

await client.send(new Error());
});

it('Should skip sending events if the user decide not to send it', async () => {
const client = BacktraceTestClient.buildFakeClient({
beforeSend: () => {
return undefined;
},
});

await client.send(new Error());
expect(client.requestHandler.postError).not.toHaveBeenCalled();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you not have to spy on this to see if it was called?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's alerady in wrapped by using spy in the test backtrace client implementation

});
});
});
4 changes: 2 additions & 2 deletions packages/sdk-core/tests/client/clientTests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('Client tests', () => {
},
};

const client = BacktraceTestClient.buildFakeClient([], [inMemoryAttachment]);
const client = BacktraceTestClient.buildFakeClient({}, [], [inMemoryAttachment]);

expect(client.attachments).toBeDefined();
expect(client.attachments.length).toEqual(1);
Expand Down Expand Up @@ -90,7 +90,7 @@ describe('Client tests', () => {
return new Uint8Array(0);
},
};
const client = BacktraceTestClient.buildFakeClient([], [clientAttachment]);
const client = BacktraceTestClient.buildFakeClient({}, [], [clientAttachment]);

await client.send(new Error(''), {}, [reportAttachment]);

Expand Down
17 changes: 12 additions & 5 deletions packages/sdk-core/tests/mocks/BacktraceTestClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
BacktraceAttachment,
BacktraceAttributeProvider,
BacktraceConfiguration,
BacktraceCoreClient,
BacktraceReportSubmissionResult,
BacktraceRequestHandler,
Expand All @@ -13,18 +14,22 @@ export const APPLICATION_VERSION = '5.4.3';
export class BacktraceTestClient extends BacktraceCoreClient {
public readonly requestHandler: BacktraceRequestHandler;
constructor(
options: Partial<BacktraceConfiguration>,
handler: BacktraceRequestHandler,
attributeProviders: BacktraceAttributeProvider[] = [],
attachments: BacktraceAttachment[] = [],
) {
super(
{
url: TEST_SUBMISSION_URL,
token: TOKEN,
attachments,
metrics: {
enable: false,
...{
url: TEST_SUBMISSION_URL,
token: TOKEN,
attachments,
metrics: {
enable: false,
},
},
...(options ?? {}),
},
{
agent: 'test',
Expand All @@ -39,6 +44,7 @@ export class BacktraceTestClient extends BacktraceCoreClient {
}

public static buildFakeClient(
options: Partial<BacktraceConfiguration> = {},
attributeProviders: BacktraceAttributeProvider[] = [],
attachments: BacktraceAttachment[] = [],
) {
Expand All @@ -52,6 +58,7 @@ export class BacktraceTestClient extends BacktraceCoreClient {
},
});
return new BacktraceTestClient(
options,
{
post: jest.fn().mockResolvedValue(Promise.resolve(BacktraceReportSubmissionResult.Ok('Ok'))),
postError: jest.fn().mockResolvedValue(Promise.resolve()),
Expand Down