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
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ Please see our [Upgrade Guide](./UPGRADING.md) for specific steps.

### Compatibility with OTel packages

The SDK is built on top of OpenTelemetry and, as such, it is possible to use it alongside other OTel libraries.
The SDK is built on top of OpenTelemetry and, as such, it is possible to use it alongside other OTel libraries.
**Important: New projects should use OpenTelemetry 2.x.**
OpenTelemetry 1.x support is limited to 1.x versions of the SDK, which are deprecated.

Expand Down Expand Up @@ -605,7 +605,6 @@ module.exports = {
__dirname,
'./node_modules/@opentelemetry/semantic-conventions/build/src/index-incubating.js'
),
uuid: path.resolve(__dirname, './node_modules/uuid/dist/index.js'),
},
},
};
Expand Down
14 changes: 0 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@
"@opentelemetry/semantic-conventions": "1.38.0",
"@opentelemetry/web-common": "0.208.0",
"hoist-non-react-statics": "3.3.2",
"uuid": "13.0.0",
"web-vitals": "5.1.0"
},
"devDependencies": {
Expand Down
4 changes: 1 addition & 3 deletions src/processors/EmbraceNetworkSpanProcessor/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ interface NetworkSpan extends ReadableSpan {
attributes: NetworkSpanAttributes;
}

const SCHEME_RE = /.+:\/\/.+/;

export const isNetworkSpan = (
span: ReadableSpan | NetworkSpan,
): span is NetworkSpan => {
Expand All @@ -43,7 +41,7 @@ export const isNetworkSpan = (
const url =
span.attributes[ATTR_URL_FULL] ?? span.attributes[SEMATTRS_HTTP_URL];

return !!(url && typeof url === 'string' && SCHEME_RE.exec(url));
return typeof url === 'string' && url.includes('://');
}

return false;
Expand Down
11 changes: 11 additions & 0 deletions src/utils/generateUUID.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,15 @@ describe('generateUUID', () => {
const uuid2 = generateUUID();
expect(uuid1).to.not.equal(uuid2);
});

it('should only contain valid hex characters', () => {
const validHex = /^[0-9A-F]+$/;
for (let i = 0; i < 100; i++) {
const uuid = generateUUID();
expect(uuid).to.match(
validHex,
`UUID ${uuid} contains invalid characters`,
);
}
});
});
17 changes: 15 additions & 2 deletions src/utils/generateUUID.ts
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd be concerned about replacing the uuid library with our own implementation without more extensive testing around the values we're getting out being similarly random. Could you also speak to where the performance gains are relative to https://github.com/uuidjs/uuid/blob/main/src/v4.ts ?

Copy link
Copy Markdown
Member Author

@overbalance overbalance Jan 6, 2026

Choose a reason for hiding this comment

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

I benchmarked more thoroughly and the performance is negligible:

  Browser Benchmark (Chromium)

  | Implementation         | ops/sec | ns/op | vs uuid |
  |------------------------|---------|-------|---------|
  | uuid library           | 925K    | 1,081 | 1.00x   |
  | Math.random            | 8.7M    | 115   | 9.42x   |
  | crypto.getRandomValues | 1.1M    | 930   | 1.16x   |

Absolute impact per 1,000 spans:
  - uuid library: 1.1ms
  - Math.random: 0.1ms
  - crypto.getRandomValues: 0.9ms

What we do gain:

  1. Removing uuid means one less third-party lib
  2. crypto is more secure than Math.random and slightly faster than uuid npm package

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

do we know why this ends up faster than the uuid package? It is also using crypto.getRandomValues: https://github.com/uuidjs/uuid/blob/main/src/rng-browser.ts#L18

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Surprisingly it's the string manipulation actions to change case and add/remove hyphens.

Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import { v4 as uuid } from 'uuid';
const UUID_BYTES = 16;
const BUFFER = new Uint8Array(UUID_BYTES);

export const generateUUID = () => uuid().replace(/-/g, '').toUpperCase();
// Pre-computed uppercase hex lookup - faster than toString(16) in browsers
const HEX: string[] = Array.from({ length: 256 }, (_, i) =>
i.toString(16).padStart(2, '0').toUpperCase(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

would we need the i + 0x100 piece that is being done in https://github.com/uuidjs/uuid/blob/main/src/stringify.ts#L10 as well? Or is that handled by padStart?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correct, padStart gives the same 2 digit guarantee

);

export const generateUUID = (): string => {
crypto.getRandomValues(BUFFER);
let hex = '';
for (let i = 0; i < UUID_BYTES; i++) {
hex += HEX[BUFFER[i]];
}
return hex;
};
1 change: 0 additions & 1 deletion tests/integration/platforms/webpack-4/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ module.exports = {
__dirname,
'./node_modules/@opentelemetry/semantic-conventions/build/src/index-incubating.js',
),
uuid: path.resolve(__dirname, './node_modules/uuid/dist/index.js'),
},
},
devServer: {
Expand Down
2 changes: 1 addition & 1 deletion tests/performance/biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"linter": {
"rules": {
"correctness": {
// functions defined in html are not detected as used
// functions defined in html are not detected as in use
"noUnusedVariables": {
"level": "off"
}
Expand Down
2 changes: 1 addition & 1 deletion tests/performance/config/thresholds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const TOTAL_TASK_DURATION_THRESHOLD_IN_MS = getFromEnv(
);
const TOTAL_HEAP_SIZE_THRESHOLD_IN_MB = getFromEnv(
'TOTAL_HEAP_SIZE_THRESHOLD_IN_MB',
15,
16,
);
const TOTAL_BLOCKING_TIME_THRESHOLD_IN_MS = getFromEnv(
'TOTAL_BLOCKING_TIME_THRESHOLD_IN_MS',
Expand Down
6 changes: 4 additions & 2 deletions tests/performance/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"compilerOptions": {
"allowImportingTsExtensions": true,
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "Node",
"moduleResolution": "bundler",
"esModuleInterop": true,
"resolveJsonModule": true,
"strict": true,
"outDir": "dist"
"outDir": "dist",
"noEmit": true
}
}
Loading