Skip to content

Commit b84b04e

Browse files
committed
react-native: add and use factory for FileBreadcrumbsStorage and pass size limitations to AlternatingFileWriter
1 parent 9dd2260 commit b84b04e

File tree

5 files changed

+409
-20
lines changed

5 files changed

+409
-20
lines changed

packages/react-native/src/BacktraceClient.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ import {
1010
} from '@backtrace/sdk-core';
1111
import { NativeModules, Platform } from 'react-native';
1212
import { type BacktraceConfiguration } from './BacktraceConfiguration';
13+
import { ReactNativeRequestHandler } from './ReactNativeRequestHandler';
14+
import { ReactStackTraceConverter } from './ReactStackTraceConverter';
1315
import { FileBreadcrumbsStorage } from './breadcrumbs/FileBreadcrumbsStorage';
1416
import { BacktraceClientBuilder } from './builder/BacktraceClientBuilder';
1517
import type { BacktraceClientSetup } from './builder/BacktraceClientSetup';
1618
import { version } from './common/platformHelper';
1719
import { CrashReporter } from './crashReporter/CrashReporter';
1820
import { generateUnhandledExceptionHandler } from './handlers';
1921
import { type ExceptionHandler } from './handlers/ExceptionHandler';
20-
import { ReactNativeRequestHandler } from './ReactNativeRequestHandler';
21-
import { ReactStackTraceConverter } from './ReactStackTraceConverter';
2222
import { type FileSystem } from './storage/FileSystem';
2323

2424
export class BacktraceClient extends BacktraceCoreClient<BacktraceConfiguration> {
@@ -55,13 +55,7 @@ export class BacktraceClient extends BacktraceCoreClient<BacktraceConfiguration>
5555

5656
const breadcrumbsManager = this.modules.get(BreadcrumbsManager);
5757
if (breadcrumbsManager && this.sessionFiles) {
58-
breadcrumbsManager.setStorage(
59-
FileBreadcrumbsStorage.create(
60-
fileSystem,
61-
this.sessionFiles,
62-
clientSetup.options.breadcrumbs?.maximumBreadcrumbs ?? 100,
63-
),
64-
);
58+
breadcrumbsManager.setStorage(FileBreadcrumbsStorage.factory(fileSystem, this.sessionFiles));
6559
}
6660

6761
this.attributeManager.attributeEvents.on(

packages/react-native/src/attachment/BacktraceFileAttachment.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { type BacktraceFileAttachment as CoreBacktraceFileAttachment } from '@ba
22
import { Platform } from 'react-native';
33
import { type FileSystem } from '../storage/';
44
import { type FileLocation } from '../types/FileLocation';
5-
export class BacktraceFileAttachment implements CoreBacktraceFileAttachment {
5+
export class BacktraceFileAttachment implements CoreBacktraceFileAttachment<FileLocation> {
66
public readonly name: string;
77
public readonly mimeType: string;
88

@@ -18,7 +18,7 @@ export class BacktraceFileAttachment implements CoreBacktraceFileAttachment {
1818
this._uploadUri = Platform.OS === 'android' ? `file://${this.filePath}` : this.filePath;
1919
}
2020

21-
public get(): FileLocation | string | undefined {
21+
public get(): FileLocation | undefined {
2222
const exists = this._fileSystemProvider.existsSync(this.filePath);
2323

2424
if (!exists) {

packages/react-native/src/breadcrumbs/FileBreadcrumbsStorage.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import {
22
BreadcrumbLogLevel,
33
BreadcrumbType,
4-
jsonEscaper,
54
SessionFiles,
65
TimeHelper,
6+
jsonEscaper,
77
type BacktraceAttachment,
88
type Breadcrumb,
99
type BreadcrumbsStorage,
10+
type BreadcrumbsStorageFactory,
11+
type BreadcrumbsStorageLimits,
1012
type RawBreadcrumb,
1113
} from '@backtrace/sdk-core';
1214
import { BacktraceFileAttachment } from '..';
1315
import { type FileSystem } from '../storage';
16+
import type { FileLocation } from '../types/FileLocation';
1417
import { AlternatingFileWriter } from './AlternatingFileWriter';
1518

1619
const FILE_PREFIX = 'bt-breadcrumbs';
@@ -27,23 +30,26 @@ export class FileBreadcrumbsStorage implements BreadcrumbsStorage {
2730
private readonly _fileSystem: FileSystem,
2831
private readonly _mainFile: string,
2932
private readonly _fallbackFile: string,
30-
maximumBreadcrumbs: number,
33+
private readonly _limits: BreadcrumbsStorageLimits,
3134
) {
3235
this._writer = new AlternatingFileWriter(
36+
_fileSystem,
3337
_mainFile,
3438
_fallbackFile,
35-
Math.floor(maximumBreadcrumbs / 2),
36-
_fileSystem,
39+
Math.floor((this._limits.maximumBreadcrumbs ?? 100) / 2),
40+
this._limits.maximumTotalBreadcrumbsSize,
3741
);
3842
}
3943

40-
public static create(fileSystem: FileSystem, session: SessionFiles, maximumBreadcrumbs: number) {
41-
const file1 = session.getFileName(this.getFileName(0));
42-
const file2 = session.getFileName(this.getFileName(1));
43-
return new FileBreadcrumbsStorage(fileSystem, file1, file2, maximumBreadcrumbs);
44+
public static factory(fileSystem: FileSystem, session: SessionFiles): BreadcrumbsStorageFactory {
45+
return ({ limits }) => {
46+
const file1 = session.getFileName(this.getFileName(0));
47+
const file2 = session.getFileName(this.getFileName(1));
48+
return new FileBreadcrumbsStorage(fileSystem, file1, file2, limits);
49+
};
4450
}
4551

46-
public getAttachments(): BacktraceAttachment<unknown>[] {
52+
public getAttachments(): [BacktraceAttachment<FileLocation>, BacktraceAttachment<FileLocation>] {
4753
return [
4854
new BacktraceFileAttachment(this._fileSystem, this._mainFile, 'bt-breadcrumbs-0'),
4955
new BacktraceFileAttachment(this._fileSystem, this._fallbackFile, 'bt-breadcrumbs-1'),
@@ -73,6 +79,14 @@ export class FileBreadcrumbsStorage implements BreadcrumbsStorage {
7379
};
7480

7581
const breadcrumbJson = JSON.stringify(breadcrumb, jsonEscaper());
82+
const jsonLength = breadcrumbJson.length + 1; // newline
83+
const sizeLimit = this._limits.maximumTotalBreadcrumbsSize;
84+
if (sizeLimit !== undefined) {
85+
if (jsonLength > sizeLimit) {
86+
return id;
87+
}
88+
}
89+
7690
this._writer.writeLine(breadcrumbJson);
7791

7892
return id;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { MockedFileSystem, mockFileSystem } from '@backtrace/sdk-core/tests/_mocks/fileSystem';
2+
import { randomUUID } from 'crypto';
3+
import path from 'path';
4+
import { StreamWriter } from '../../src';
5+
import { FileSystem } from '../../src/storage/FileSystem';
6+
7+
function mockStreamWriter(files: Record<string, string>): StreamWriter {
8+
const streams = new Map<string, string>();
9+
return {
10+
create(source) {
11+
const id = randomUUID();
12+
const fullPath = path.resolve(source);
13+
streams.set(id, fullPath);
14+
files[fullPath] = '';
15+
return id;
16+
},
17+
append(key, content) {
18+
const source = streams.get(key);
19+
if (!source) {
20+
return Promise.resolve(false);
21+
}
22+
files[source] += content;
23+
return Promise.resolve(true);
24+
},
25+
close(key) {
26+
const source = streams.get(key);
27+
if (!source) {
28+
return false;
29+
}
30+
31+
streams.delete(key);
32+
return true;
33+
},
34+
};
35+
}
36+
37+
export function mockReactFileSystem(files?: Record<string, string>): MockedFileSystem<FileSystem> {
38+
const fs = mockFileSystem(files);
39+
40+
return {
41+
...fs,
42+
43+
copy: jest.fn().mockImplementation((sourceFile: string, destinationFile: string) => {
44+
const src = fs.files[path.resolve(sourceFile)];
45+
if (!src) {
46+
return Promise.resolve(false);
47+
}
48+
49+
fs.files[path.resolve(destinationFile)] = src;
50+
return Promise.resolve(true);
51+
}),
52+
53+
copySync: jest.fn().mockImplementation((sourceFile: string, destinationFile: string) => {
54+
const src = fs.files[path.resolve(sourceFile)];
55+
if (!src) {
56+
return false;
57+
}
58+
59+
fs.files[path.resolve(destinationFile)] = src;
60+
return true;
61+
}),
62+
63+
applicationDirectory: jest.fn().mockReturnValue(path.resolve('.')),
64+
streamWriter: mockStreamWriter(fs.files),
65+
};
66+
}

0 commit comments

Comments
 (0)