Skip to content
This repository has been archived by the owner on Nov 10, 2022. It is now read-only.

Commit

Permalink
Merge branch 'main' into cl
Browse files Browse the repository at this point in the history
  • Loading branch information
obecny authored May 17, 2021
2 parents 5c3d2ce + 28fabc4 commit dd0dbc0
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 143 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ Because the npm installer and node module resolution algorithm could potentially
- `HttpBaggage` renamed to `HttpBaggagePropagator`
- [#45](https://github.com/open-telemetry/opentelemetry-js-api/pull/45) `Span#context` renamed to `Span#spanContext`
- [#47](https://github.com/open-telemetry/opentelemetry-js-api/pull/47) `getSpan`/`setSpan`/`getSpanContext`/`setSpanContext` moved to `trace` namespace
- [#55](https://github.com/open-telemetry/opentelemetry-js-api/pull/55) `getBaggage`/`setBaggage`/`createBaggage` moved to `propagation` namespace

## Useful links

Expand Down
7 changes: 7 additions & 0 deletions src/api/propagation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
registerGlobal,
unregisterGlobal,
} from '../internal/global-utils';
import { getBaggage, createBaggage, setBaggage } from '../baggage/index';

const API_NAME = 'propagation';

Expand Down Expand Up @@ -100,6 +101,12 @@ export class PropagationAPI {
unregisterGlobal(API_NAME);
}

public createBaggage = createBaggage;

public getBaggage = getBaggage;

public setBaggage = setBaggage;

private _getGlobalPropagator(): TextMapPropagator {
return getGlobal(API_NAME) || NOOP_TEXT_MAP_PROPAGATOR;
}
Expand Down
6 changes: 6 additions & 0 deletions src/context/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ import { Context } from './types';

/** Get a key to uniquely identify a context value */
export function createContextKey(description: string) {
// The specification states that for the same input, multiple calls should
// return different keys. Due to the nature of the JS dependency management
// system, this creates problems where multiple versions of some package
// could hold different keys for the same property.
//
// Therefore, we use Symbol.for which returns the same key for the same input.
return Symbol.for(description);
}

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

export * from './baggage';
export { baggageEntryMetadataFromString } from './baggage';
export * from './common/Exception';
export * from './common/Time';
export * from './diag';
Expand Down
42 changes: 41 additions & 1 deletion src/trace/NoopTracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
* limitations under the License.
*/

import { getSpanContext } from '../trace/context-utils';
import { context } from '../';
import { Context } from '../context/types';
import { getSpanContext, setSpan } from '../trace/context-utils';
import { NonRecordingSpan } from './NonRecordingSpan';
import { Span } from './span';
import { isSpanContextValid } from './spancontext-utils';
Expand Down Expand Up @@ -45,6 +46,45 @@ export class NoopTracer implements Tracer {
return new NonRecordingSpan();
}
}

startActiveSpan<F extends (span: Span) => ReturnType<F>>(
name: string,
arg2: F | SpanOptions,
arg3?: F | Context,
arg4?: F
): ReturnType<F> | undefined {
let fn: F | undefined,
options: SpanOptions | undefined,
activeContext: Context | undefined;
if (arguments.length === 2 && typeof arg2 === 'function') {
fn = arg2;
} else if (
arguments.length === 3 &&
typeof arg2 === 'object' &&
typeof arg3 === 'function'
) {
options = arg2;
fn = arg3;
} else if (
arguments.length === 4 &&
typeof arg2 === 'object' &&
typeof arg3 === 'object' &&
typeof arg4 === 'function'
) {
options = arg2;
activeContext = arg3;
fn = arg4;
}

const parentContext = activeContext ?? context.active();
const span = this.startSpan(name, options, parentContext);
const contextWithSpanSet = setSpan(parentContext, span);

if (fn) {
return context.with(contextWithSpanSet, fn, undefined, span);
}
return;
}
}

function isSpanContext(spanContext: any): spanContext is SpanContext {
Expand Down
10 changes: 10 additions & 0 deletions src/trace/ProxyTracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ export class ProxyTracer implements Tracer {
return this._getTracer().startSpan(name, options, context);
}

startActiveSpan<F extends (span: Span) => unknown>(
_name: string,
_options: F | SpanOptions,
_context?: F | Context,
_fn?: F
): ReturnType<F> {
const tracer = this._getTracer();
return Reflect.apply(tracer.startActiveSpan, tracer, arguments);
}

/**
* Try to get a tracer from the proxy tracer provider.
* If the proxy tracer provider has no delegate, return a noop tracer.
Expand Down
38 changes: 0 additions & 38 deletions src/trace/context-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,6 @@ import { NonRecordingSpan } from './NonRecordingSpan';
*/
const SPAN_KEY = createContextKey('OpenTelemetry Context Key SPAN');

/**
* Shared key for indicating if instrumentation should be suppressed beyond
* this current scope.
*/
const SUPPRESS_INSTRUMENTATION_KEY = createContextKey(
'OpenTelemetry Context Key SUPPRESS_INSTRUMENTATION'
);

/**
* Return the span if one exists
*
Expand Down Expand Up @@ -74,33 +66,3 @@ export function setSpanContext(
export function getSpanContext(context: Context): SpanContext | undefined {
return getSpan(context)?.spanContext();
}

/**
* Sets value on context to indicate that instrumentation should
* be suppressed beyond this current scope.
*
* @param context context to set the suppress instrumentation value on.
*/
export function suppressInstrumentation(context: Context): Context {
return context.setValue(SUPPRESS_INSTRUMENTATION_KEY, true);
}

/**
* Sets value on context to indicate that instrumentation should
* no-longer be suppressed beyond this current scope.
*
* @param context context to set the suppress instrumentation value on.
*/
export function unsuppressInstrumentation(context: Context): Context {
return context.setValue(SUPPRESS_INSTRUMENTATION_KEY, false);
}

/**
* Return current suppress instrumentation value for the given context,
* if it exists.
*
* @param context context check for the suppress instrumentation value.
*/
export function isInstrumentationSuppressed(context: Context): boolean {
return Boolean(context.getValue(SUPPRESS_INSTRUMENTATION_KEY));
}
59 changes: 59 additions & 0 deletions src/trace/tracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,63 @@ export interface Tracer {
* span.end();
*/
startSpan(name: string, options?: SpanOptions, context?: Context): Span;

/**
* Starts a new {@link Span} and calls the given function passing it the
* created span as first argument.
* Additionally the new span gets set in context and this context is activated
* for the duration of the function call.
*
* @param name The name of the span
* @param [options] SpanOptions used for span creation
* @param [context] Context to use to extract parent
* @param fn function called in the context of the span and receives the newly created span as an argument
* @returns return value of fn
* @example
* const something = tracer.startActiveSpan('op', span => {
* try {
* do some work
* span.setStatus({code: SpanStatusCode.OK});
* return something;
* } catch (err) {
* span.setStatus({
* code: SpanStatusCode.ERROR,
* message: err.message,
* });
* throw err;
* } finally {
* span.end();
* }
* });
* @example
* const span = tracer.startActiveSpan('op', span => {
* try {
* do some work
* return span;
* } catch (err) {
* span.setStatus({
* code: SpanStatusCode.ERROR,
* message: err.message,
* });
* throw err;
* }
* });
* do some more work
* span.end();
*/
startActiveSpan<F extends (span: Span) => unknown>(
name: string,
fn: F
): ReturnType<F>;
startActiveSpan<F extends (span: Span) => unknown>(
name: string,
options: SpanOptions,
fn: F
): ReturnType<F>;
startActiveSpan<F extends (span: Span) => unknown>(
name: string,
options: SpanOptions,
context: Context,
fn: F
): ReturnType<F>;
}
28 changes: 14 additions & 14 deletions test/baggage/Baggage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,22 @@

import * as assert from 'assert';
import {
createBaggage,
setBaggage,
getBaggage,
ROOT_CONTEXT,
propagation,
baggageEntryMetadataFromString,
} from '../../src';

describe('Baggage', () => {
describe('create', () => {
it('should create an empty bag', () => {
const bag = createBaggage();
const bag = propagation.createBaggage();

assert.deepStrictEqual(bag.getAllEntries(), []);
});

it('should create a bag with entries', () => {
const meta = baggageEntryMetadataFromString('opaque string');
const bag = createBaggage({
const bag = propagation.createBaggage({
key1: { value: 'value1' },
key2: { value: 'value2', metadata: meta },
});
Expand All @@ -47,7 +45,9 @@ describe('Baggage', () => {

describe('get', () => {
it('should not allow modification of returned entries', () => {
const bag = createBaggage().setEntry('key', { value: 'value' });
const bag = propagation
.createBaggage()
.setEntry('key', { value: 'value' });

const entry = bag.getEntry('key');
assert.ok(entry);
Expand All @@ -59,7 +59,7 @@ describe('Baggage', () => {

describe('set', () => {
it('should create a new bag when an entry is added', () => {
const bag = createBaggage();
const bag = propagation.createBaggage();

const bag2 = bag.setEntry('key', { value: 'value' });

Expand All @@ -73,7 +73,7 @@ describe('Baggage', () => {

describe('remove', () => {
it('should create a new bag when an entry is removed', () => {
const bag = createBaggage({
const bag = propagation.createBaggage({
key: { value: 'value' },
});

Expand All @@ -87,7 +87,7 @@ describe('Baggage', () => {
});

it('should create an empty bag multiple keys are removed', () => {
const bag = createBaggage({
const bag = propagation.createBaggage({
key: { value: 'value' },
key1: { value: 'value1' },
key2: { value: 'value2' },
Expand All @@ -107,7 +107,7 @@ describe('Baggage', () => {
});

it('should create an empty bag when it cleared', () => {
const bag = createBaggage({
const bag = propagation.createBaggage({
key: { value: 'value' },
key1: { value: 'value1' },
});
Expand All @@ -125,11 +125,11 @@ describe('Baggage', () => {

describe('context', () => {
it('should set and get a baggage from a context', () => {
const bag = createBaggage();
const bag = propagation.createBaggage();

const ctx = setBaggage(ROOT_CONTEXT, bag);
const ctx = propagation.setBaggage(ROOT_CONTEXT, bag);

assert.strictEqual(bag, getBaggage(ctx));
assert.strictEqual(bag, propagation.getBaggage(ctx));
});
});

Expand All @@ -148,7 +148,7 @@ describe('Baggage', () => {
});

it('should retain metadata', () => {
const bag = createBaggage({
const bag = propagation.createBaggage({
key: {
value: 'value',
metadata: baggageEntryMetadataFromString('meta'),
Expand Down
29 changes: 27 additions & 2 deletions test/noop-implementations/noop-tracer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@

import * as assert from 'assert';
import {
context,
NoopTracer,
Span,
SpanContext,
SpanKind,
TraceFlags,
context,
trace,
TraceFlags,
} from '../../src';
import { NonRecordingSpan } from '../../src/trace/NonRecordingSpan';

Expand Down Expand Up @@ -56,4 +57,28 @@ describe('NoopTracer', () => {
assert(span.spanContext().spanId === parent.spanId);
assert(span.spanContext().traceFlags === parent.traceFlags);
});

it('should accept 2 to 4 args and start an active span', () => {
const tracer = new NoopTracer();
const name = 'span-name';
const fn = (span: Span) => {
try {
return 1;
} finally {
span.end();
}
};
const opts = { attributes: { foo: 'bar' } };
const ctx = context.active();

const a = tracer.startActiveSpan(name, fn);
assert.strictEqual(a, 1);

const b = tracer.startActiveSpan(name, opts, fn);

assert.strictEqual(b, 1);

const c = tracer.startActiveSpan(name, opts, ctx, fn);
assert.strictEqual(c, 1);
});
});
Loading

0 comments on commit dd0dbc0

Please sign in to comment.