diff --git a/packages/opentelemetry-instrumentation/src/utils.ts b/packages/opentelemetry-instrumentation/src/utils.ts index d4406e3a85e..8f1c98c1fa2 100644 --- a/packages/opentelemetry-instrumentation/src/utils.ts +++ b/packages/opentelemetry-instrumentation/src/utils.ts @@ -43,6 +43,32 @@ export function safeExecuteInTheMiddle( } } +/** + * Async function to execute patched function and being able to catch errors + * @param execute - function to be executed + * @param onFinish - callback to run when execute finishes + */ +export async function safeExecuteInTheMiddleAsync( + execute: () => T, + onFinish: (e: Error | undefined, result: T | undefined) => void, + preventThrowingError?: boolean +): Promise { + let error: Error | undefined; + let result: T | undefined; + try { + result = await execute(); + } catch (e) { + error = e; + } finally { + onFinish(error, result); + if (error && !preventThrowingError) { + // eslint-disable-next-line no-unsafe-finally + throw error; + } + // eslint-disable-next-line no-unsafe-finally + return result as T; + } +} /** * Checks if certain function has been already wrapped * @param func diff --git a/packages/opentelemetry-instrumentation/test/common/utils.test.ts b/packages/opentelemetry-instrumentation/test/common/utils.test.ts index 805490ea155..cfc10fb38f3 100644 --- a/packages/opentelemetry-instrumentation/test/common/utils.test.ts +++ b/packages/opentelemetry-instrumentation/test/common/utils.test.ts @@ -15,7 +15,11 @@ */ import * as assert from 'assert'; -import { isWrapped, safeExecuteInTheMiddle } from '../../src'; +import { + isWrapped, + safeExecuteInTheMiddle, + safeExecuteInTheMiddleAsync, +} from '../../src'; describe('isWrapped', () => { describe('when function is wrapped', () => { @@ -45,13 +49,12 @@ describe('isWrapped', () => { describe('safeExecuteInTheMiddle', () => { it('should not throw error', () => { - const error = new Error('test'); safeExecuteInTheMiddle( () => { - throw error; + return 'foo'; }, err => { - assert.deepStrictEqual(error, err); + assert.deepStrictEqual(err, undefined); }, true ); @@ -84,3 +87,47 @@ describe('safeExecuteInTheMiddle', () => { assert.deepStrictEqual(result, 1); }); }); + +describe('safeExecuteInTheMiddleAsync', () => { + it('should not throw error', () => { + safeExecuteInTheMiddleAsync( + async () => { + await setTimeout(() => {}, 1); + return 'foo'; + }, + err => { + assert.deepStrictEqual(err, undefined); + }, + true + ); + }); + it('should throw error', () => { + const error = new Error('test'); + try { + safeExecuteInTheMiddleAsync( + async () => { + await setTimeout(() => {}, 1); + throw error; + }, + err => { + assert.deepStrictEqual(error, err); + } + ); + } catch (err) { + assert.deepStrictEqual(error, err); + } + }); + it('should return result', async () => { + const result = await safeExecuteInTheMiddleAsync( + async () => { + await setTimeout(() => {}, 1); + return 1; + }, + (err, result) => { + assert.deepStrictEqual(err, undefined); + assert.deepStrictEqual(result, 1); + } + ); + assert.deepStrictEqual(result, 1); + }); +});