Skip to content

Commit

Permalink
feat(instrumentation): add util to execute span customization hook in…
Browse files Browse the repository at this point in the history
… base class (open-telemetry#4663)

* feat(instrumentation): hoist span event hook execution to base class

* test: add test for new hook runner

* chore: changelog

* fix: use event name from arguments

* fix: remove unused import

* fix: make diag message structual

* make the private function start with underscore

* chore: rename insetrumentation event to span customization hook

* chore: update changelog

* chore: lint fix

* Update experimental/packages/opentelemetry-instrumentation/src/instrumentation.ts

Co-authored-by: Marc Pichler <[email protected]>

* chore: move CHANGELOG to experimental

* fix: changelog

---------

Co-authored-by: Marc Pichler <[email protected]>
  • Loading branch information
2 people authored and Zirak committed Sep 14, 2024
1 parent 9de0bc2 commit d70a5a5
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 2 deletions.
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/

### :rocket: (Enhancement)

* feat(instrumentation): generic config type in instrumentation base [#4659](https://github.com/open-telemetry/opentelemetry-js/pull/4659) @blumamir
* feat: support node 22 [#4666](https://github.com/open-telemetry/opentelemetry-js/pull/4666) @dyladan
* feat(sdk-trace-node): support `xray` Propagator via `OTEL_PROPAGATORS` environment variable [#4602](https://github.com/open-telemetry/opentelemetry-js/pull/4602) @anuraags

Expand Down
2 changes: 2 additions & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ All notable changes to experimental packages in this project will be documented

### :rocket: (Enhancement)

* feat(instrumentation): add util to execute span customization hook in base class [#4663](https://github.com/open-telemetry/opentelemetry-js/pull/4663) @blumamir
* feat(instrumentation): generic config type in instrumentation base [#4659](https://github.com/open-telemetry/opentelemetry-js/pull/4659) @blumamir
* feat: support node 22 [#4666](https://github.com/open-telemetry/opentelemetry-js/pull/4666) @dyladan
* feat(propagator-aws-xray-lambda): add AWS Xray Lambda propagator [4554](https://github.com/open-telemetry/opentelemetry-js/pull/4554)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ import {
trace,
Tracer,
TracerProvider,
Span,
} from '@opentelemetry/api';
import { Logger, LoggerProvider, logs } from '@opentelemetry/api-logs';
import * as shimmer from 'shimmer';
import {
InstrumentationModuleDefinition,
Instrumentation,
InstrumentationConfig,
SpanCustomizationHook,
} from './types';

/**
Expand Down Expand Up @@ -178,4 +180,33 @@ export abstract class InstrumentationAbstract<
| InstrumentationModuleDefinition
| InstrumentationModuleDefinition[]
| void;

/**
* Execute span customization hook, if configured, and log any errors.
* Any semantics of the trigger and info are defined by the specific instrumentation.
* @param hookHandler The optional hook handler which the user has configured via instrumentation config
* @param triggerName The name of the trigger for executing the hook for logging purposes
* @param span The span to which the hook should be applied
* @param info The info object to be passed to the hook, with useful data the hook may use
*/
protected _runSpanCustomizationHook<SpanCustomizationInfoType>(
hookHandler: SpanCustomizationHook<SpanCustomizationInfoType> | undefined,
triggerName: string,
span: Span,
info: SpanCustomizationInfoType
) {
if (!hookHandler) {
return;
}

try {
hookHandler(span, info);
} catch (e) {
this._diag.error(
`Error running span customization hook due to exception in handler`,
{ triggerName },
e
);
}
}
}
23 changes: 22 additions & 1 deletion experimental/packages/opentelemetry-instrumentation/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import { TracerProvider, MeterProvider } from '@opentelemetry/api';
import { TracerProvider, MeterProvider, Span } from '@opentelemetry/api';
import { LoggerProvider } from '@opentelemetry/api-logs';

/** Interface Instrumentation to apply patch. */
Expand Down Expand Up @@ -135,3 +135,24 @@ export interface InstrumentationModuleDefinition {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
unpatch?: (moduleExports: any, moduleVersion?: string) => void;
}

/**
* SpanCustomizationHook is a common way for instrumentations to expose extension points
* where users can add custom behavior to a span based on info object passed to the hook at different times of the span lifecycle.
* This is an advanced feature, commonly used to add additional or non-spec-compliant attributes to the span,
* capture payloads, modify the span in some way, or carry some other side effect.
*
* The hook is registered with the instrumentation specific config by implementing an handler function with this signature,
* and if the hook is present, it will be called with the span and the event information
* when the event is emitted.
*
* When and under what conditions the hook is called and what data is passed
* in the info argument, is specific to each instrumentation and life-cycle event
* and should be documented where it is used.
*
* Instrumentation may define multiple hooks, for different spans, or different span life-cycle events.
*/
export type SpanCustomizationHook<SpanCustomizationInfoType> = (
span: Span,
info: SpanCustomizationInfoType
) => void;
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
InstrumentationBase,
InstrumentationConfig,
InstrumentationModuleDefinition,
SpanCustomizationHook,
} from '../../src';

import { MeterProvider } from '@opentelemetry/sdk-metrics';
Expand All @@ -36,6 +37,12 @@ class TestInstrumentation extends InstrumentationBase {
override enable() {}
override disable() {}
init() {}

// the runInstrumentationEventHook, so we have to invoke it from the class for testing
testRunHook(hookHandler?: SpanCustomizationHook<any>) {
const span = this.tracer.startSpan('test');
this._runSpanCustomizationHook(hookHandler, 'test', span, {});
}
}

describe('BaseInstrumentation', () => {
Expand Down Expand Up @@ -182,5 +189,30 @@ describe('BaseInstrumentation', () => {

assert.deepStrictEqual(instrumentation.getModuleDefinitions(), []);
});

describe('runInstrumentationEventHook', () => {
it('should call the hook', () => {
const instrumentation = new TestInstrumentation({});
let called = false;
const hook = () => {
called = true;
};
instrumentation.testRunHook(hook);
assert.strictEqual(called, true);
});

it('empty hook should work', () => {
const instrumentation = new TestInstrumentation({});
instrumentation.testRunHook(undefined);
});

it('exception in hook should not crash', () => {
const instrumentation = new TestInstrumentation({});
const hook = () => {
throw new Error('test');
};
instrumentation.testRunHook(hook);
});
});
});
});

0 comments on commit d70a5a5

Please sign in to comment.