Skip to content

Commit

Permalink
feat(instrumentation-fetch): Add applyCustomAttributesOnSpan option (#…
Browse files Browse the repository at this point in the history
…2071)

Co-authored-by: Valentin Marchaud <contact@vmarchaud.fr>
  • Loading branch information
niekert and vmarchaud committed Apr 12, 2021
1 parent 90a4b4d commit 5dbe53a
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 1 deletion.
8 changes: 8 additions & 0 deletions packages/opentelemetry-instrumentation-fetch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ fetch('http://localhost:8090/fetch.js');

See [examples/tracer-web/fetch](https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/tracer-web) for a short example.

### Fetch Instrumentation options

Fetch instrumentation plugin has few options available to choose from. You can set the following:

| Options | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------------------------- |
| [`applyCustomAttributesOnSpan`](https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L47) | `HttpCustomAttributeFunction` | Function for adding custom attributes |

## Useful links

- For more information on OpenTelemetry, visit: <https://opentelemetry.io/>
Expand Down
35 changes: 35 additions & 0 deletions packages/opentelemetry-instrumentation-fetch/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
isWrapped,
InstrumentationBase,
InstrumentationConfig,
safeExecuteInTheMiddle,
} from '@opentelemetry/instrumentation';
import * as core from '@opentelemetry/core';
import * as web from '@opentelemetry/web';
Expand All @@ -43,6 +44,14 @@ const getUrlNormalizingAnchor = () => {
return a;
};

export interface FetchCustomAttributeFunction {
(
span: api.Span,
request: Request | RequestInit,
result: Response | FetchError
): void;
}

/**
* FetchPlugin Config
*/
Expand All @@ -61,6 +70,8 @@ export interface FetchInstrumentationConfig extends InstrumentationConfig {
* also not be traced.
*/
ignoreUrls?: Array<string | RegExp>;
/** Function for adding custom attributes on the span */
applyCustomAttributesOnSpan?: FetchCustomAttributeFunction;
}

/**
Expand Down Expand Up @@ -311,6 +322,7 @@ export class FetchInstrumentation extends InstrumentationBase<
response: Response
) {
try {
plugin._applyAttributesAfterFetch(span, options, response);
if (response.status >= 200 && response.status < 400) {
plugin._endSpan(span, spanData, response);
} else {
Expand All @@ -331,6 +343,7 @@ export class FetchInstrumentation extends InstrumentationBase<
error: FetchError
) {
try {
plugin._applyAttributesAfterFetch(span, options, error);
plugin._endSpan(span, spanData, {
status: error.status || 0,
statusText: error.message,
Expand Down Expand Up @@ -360,6 +373,28 @@ export class FetchInstrumentation extends InstrumentationBase<
};
}

private _applyAttributesAfterFetch(
span: api.Span,
request: Request | RequestInit,
result: Response | FetchError
) {
const applyCustomAttributesOnSpan = this._getConfig()
.applyCustomAttributesOnSpan;
if (applyCustomAttributesOnSpan) {
safeExecuteInTheMiddle(
() => applyCustomAttributesOnSpan(span, request, result),
error => {
if (!error) {
return;
}

api.diag.error('applyCustomAttributesOnSpan', error);
},
true
);
}
}

/**
* Prepares a span data - needed later for matching appropriate network
* resources
Expand Down
74 changes: 73 additions & 1 deletion packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ import {
} from '@opentelemetry/web';
import * as assert from 'assert';
import * as sinon from 'sinon';
import { FetchInstrumentation, FetchInstrumentationConfig } from '../src';
import {
FetchInstrumentation,
FetchInstrumentationConfig,
FetchCustomAttributeFunction,
} from '../src';
import { AttributeNames } from '../src/enums/AttributeNames';
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';

Expand All @@ -57,6 +61,7 @@ const getData = (url: string, method?: string) =>
},
});

const CUSTOM_ATTRIBUTE_KEY = 'span kind';
const defaultResource = {
connectEnd: 15,
connectStart: 13,
Expand Down Expand Up @@ -576,6 +581,73 @@ describe('fetch', () => {
});
});

describe('applyCustomAttributesOnSpan option', () => {
const noop = () => {};
const prepare = (
url: string,
applyCustomAttributesOnSpan: FetchCustomAttributeFunction,
cb: VoidFunction = noop
) => {
const propagateTraceHeaderCorsUrls = [url];

prepareData(cb, url, {
propagateTraceHeaderCorsUrls,
applyCustomAttributesOnSpan,
});
};

afterEach(() => {
clearData();
});

it('applies attributes when the request is succesful', done => {
prepare(
url,
span => {
span.setAttribute(CUSTOM_ATTRIBUTE_KEY, 'custom value');
},
() => {
const span: tracing.ReadableSpan = exportSpy.args[1][0][0];
const attributes = span.attributes;

assert.ok(attributes[CUSTOM_ATTRIBUTE_KEY] === 'custom value');
done();
}
);
});

it('applies custom attributes when the request fails', done => {
prepare(
badUrl,
span => {
span.setAttribute(CUSTOM_ATTRIBUTE_KEY, 'custom value');
},
() => {
const span: tracing.ReadableSpan = exportSpy.args[1][0][0];
const attributes = span.attributes;

assert.ok(attributes[CUSTOM_ATTRIBUTE_KEY] === 'custom value');
done();
}
);
});

it('has request and response objects in callback arguments', done => {
const applyCustomAttributes: FetchCustomAttributeFunction = (
span,
request,
response
) => {
assert.ok(request.method === 'GET');
assert.ok(response.status === 200);

done();
};

prepare(url, applyCustomAttributes);
});
});

describe('when url is ignored', () => {
beforeEach(done => {
const propagateTraceHeaderCorsUrls = url;
Expand Down

0 comments on commit 5dbe53a

Please sign in to comment.