diff --git a/CHANGELOG.md b/CHANGELOG.md index 66f4e5d119..bd1372e254 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. ### :rocket: (Enhancement) +* perf(opentelemetry-core): improve hexToBase64 performance [#3178](https://github.com/open-telemetry/opentelemetry-js/pull/3178) * feat(sdk-trace-base): move Sampler declaration into sdk-trace-base [#3088](https://github.com/open-telemetry/opentelemetry-js/pull/3088) @legendecas * fix(grpc-instrumentation): added grpc attributes in instrumentation [#3127](https://github.com/open-telemetry/opentelemetry-js/pull/3127) @andrewzenkov * feat: support latest `@opentelemetry/api` [#3177](https://github.com/open-telemetry/opentelemetry-js/pull/3177) @dyladan diff --git a/packages/opentelemetry-core/src/platform/node/hex-to-base64.ts b/packages/opentelemetry-core/src/platform/node/hex-to-base64.ts index 9330aaa91f..66d4ad0fe9 100644 --- a/packages/opentelemetry-core/src/platform/node/hex-to-base64.ts +++ b/packages/opentelemetry-core/src/platform/node/hex-to-base64.ts @@ -13,14 +13,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +function intValue(charCode: number): number { + // 0-9 + if (charCode >= 48 && charCode <= 57) { + return charCode - 48; + } + + // a-f + if (charCode >= 97 && charCode <= 102) { + return charCode - 87; + } + + // A-F + return charCode - 55; +} + +const buf8 = Buffer.alloc(8); +const buf16 = Buffer.alloc(16); + export function hexToBase64(hexStr: string): string { - const hexStrLen = hexStr.length; - let hexAsciiCharsStr = ''; - for (let i = 0; i < hexStrLen; i += 2) { - const hexPair = hexStr.substring(i, i + 2); - const hexVal = parseInt(hexPair, 16); - hexAsciiCharsStr += String.fromCharCode(hexVal); + let buf; + if (hexStr.length === 16) { + buf = buf8; + } else if (hexStr.length === 32) { + buf = buf16; + } else { + buf = Buffer.alloc(hexStr.length / 2); + } + let offset = 0; + + for (let i = 0; i < hexStr.length; i += 2) { + const hi = intValue(hexStr.charCodeAt(i)); + const lo = intValue(hexStr.charCodeAt(i + 1)); + buf.writeUInt8((hi << 4) | lo, offset++); } - return Buffer.from(hexAsciiCharsStr, 'ascii').toString('base64'); + return buf.toString('base64'); } diff --git a/packages/opentelemetry-core/test/platform/hex-to-base64.test.ts b/packages/opentelemetry-core/test/platform/hex-to-base64.test.ts index 7f78ded3ef..d73409fc09 100644 --- a/packages/opentelemetry-core/test/platform/hex-to-base64.test.ts +++ b/packages/opentelemetry-core/test/platform/hex-to-base64.test.ts @@ -20,8 +20,12 @@ import { hexToBase64 } from '../../src/platform'; describe('hexToBase64', () => { it('convert hex to base64', () => { const id1 = '7deb739e02e44ef2'; - const id2 = '46cef837b919a16ff26e608c8cf42c80'; + const id2 = '12abc034d567e89ff26e608c8cf42c80'; + const id3 = id2.toUpperCase(); assert.strictEqual(hexToBase64(id1), 'fetzngLkTvI='); - assert.strictEqual(hexToBase64(id2), 'Rs74N7kZoW/ybmCMjPQsgA=='); + assert.strictEqual(hexToBase64(id2), 'EqvANNVn6J/ybmCMjPQsgA=='); + assert.strictEqual(hexToBase64(id3), 'EqvANNVn6J/ybmCMjPQsgA=='); + // Don't use the preallocated path + assert.strictEqual(hexToBase64(id2.repeat(2)), 'EqvANNVn6J/ybmCMjPQsgBKrwDTVZ+if8m5gjIz0LIA='); }); });