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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@

- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott

## 7.41.0

- feat: Ensure we use the same default `environment` everywhere (#7327)
- feat(profiling): Add JS self profiling in the browser (#7273)
- feat(vue): Allow to set `routeLabel: 'path'` to opt-out of using name (#7326)
- fix(profiling): Guard from throwing if profiler constructor throws (#7328)
- fix(react): Use namespace import for react router v6 (#7330)
- fix(remix): Correctly parse `X-Forwarded-For` Http header (#7329)

Work in this release contributed by @OliverJAsh. Thank you for your contribution!

## 7.40.0

- feat(nextjs): Automatically resolve source of errors in dev mode (#7294)
Expand Down
5 changes: 5 additions & 0 deletions packages/browser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@ export { Replay } from '@sentry/replay';
// __ROLLUP_EXCLUDE_OFFLINE_FROM_BUNDLES_BEGIN__
export { makeBrowserOfflineTransport } from './transports/offline';
// __ROLLUP_EXCLUDE_OFFLINE_FROM_BUNDLES_END__

// __ROLLUP_EXCLUDE_BROWSER_PROFILING_FROM_BUNDLES_BEGIN__
export { onProfilingStartRouteTransaction } from './profiling/hubextensions';
export { BrowserProfilingIntegration } from './profiling/integration';
// __ROLLUP_EXCLUDE_BROWSER_PROFILING_FROM_BUNDLES_END__
72 changes: 72 additions & 0 deletions packages/browser/src/profiling/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import type { Event } from '@sentry/types';

/**
* Creates a cache that evicts keys in fifo order
* @param size {Number}
*/
export function makeProfilingCache<Key extends string, Value extends Event>(
size: number,
): {
get: (key: Key) => Value | undefined;
add: (key: Key, value: Value) => void;
delete: (key: Key) => boolean;
clear: () => void;
size: () => number;
} {
// Maintain a fifo queue of keys, we cannot rely on Object.keys as the browser may not support it.
let evictionOrder: Key[] = [];
let cache: Record<string, Value> = {};

return {
add(key: Key, value: Value) {
while (evictionOrder.length >= size) {
// shift is O(n) but this is small size and only happens if we are
// exceeding the cache size so it should be fine.
const evictCandidate = evictionOrder.shift();

if (evictCandidate !== undefined) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete cache[evictCandidate];
}
}

// in case we have a collision, delete the old key.
if (cache[key]) {
this.delete(key);
}

evictionOrder.push(key);
cache[key] = value;
},
clear() {
cache = {};
evictionOrder = [];
},
get(key: Key): Value | undefined {
return cache[key];
},
size() {
return evictionOrder.length;
},
// Delete cache key and return true if it existed, false otherwise.
delete(key: Key): boolean {
if (!cache[key]) {
return false;
}

// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete cache[key];

for (let i = 0; i < evictionOrder.length; i++) {
if (evictionOrder[i] === key) {
evictionOrder.splice(i, 1);
break;
}
}

return true;
},
};
}

export const PROFILING_EVENT_CACHE = makeProfilingCache<string, Event>(20);
Loading