Skip to content

Commit

Permalink
Merge branch 'main' into event-payload
Browse files Browse the repository at this point in the history
  • Loading branch information
martinkuba authored Mar 30, 2024
2 parents 712493e + f3aedb7 commit 5c5678d
Show file tree
Hide file tree
Showing 9 changed files with 565 additions and 200 deletions.
4 changes: 4 additions & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ and AnyValueMap types [#4575](https://github.com/open-telemetry/opentelemetry-js

### :rocket: (Enhancement)

* feat(opentelemetry-instrumentation-xhr): optionally ignore network events [#4571](https://github.com/open-telemetry/opentelemetry-js/pull/4571/) @mustafahaddara
* refactor(instr-http): use exported strings for semconv. [#4573](https://github.com/open-telemetry/opentelemetry-js/pull/4573/) @JamieDanielson
* perf(instrumentation-http): remove obvious temp allocations [#4576](https://github.com/open-telemetry/opentelemetry-js/pull/4576) @Samuron
* feat(sdk-node): add `HostDetector` as default resource detector
* feat(api-events): added data field to the Event interface [4575](https://github.com/open-telemetry/opentelemetry-js/pull/4575)

Expand All @@ -38,6 +40,8 @@ and AnyValueMap types [#4575](https://github.com/open-telemetry/opentelemetry-js

### :books: (Refine Doc)

* docs(instr-http): document semantic conventions and attributes in use. [#4587](https://github.com/open-telemetry/opentelemetry-js/pull/4587/) @JamieDanielson

### :house: (Internal)

## 0.49.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,39 @@ The following options are deprecated:
| Options | Type | Description |
| ------- | ---- | ----------- |
| `ignoreIncomingPaths` | `IgnoreMatcher[]` | Http instrumentation will not trace all incoming requests that match paths |
| `ignoreOutgoingUrls` | `IgnoreMatcher[]` | Http instrumentation will not trace all outgoing requests that match URLs |

## Semantic Conventions

This package uses `@opentelemetry/semantic-conventions` version `1.22+`, which implements Semantic Convention [Version 1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md)

Attributes collected:

| Attribute | Short Description | Notes |
| ------------------------------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------------- |
| `ip_tcp` | Transport protocol used | Key: `NETTRANSPORTVALUES_IP_TCP` |
| `ip_udp` | Transport protocol used | Key: `NETTRANSPORTVALUES_IP_UDP` |
| `http.client_ip` | The IP address of the original client behind all proxies, if known | Key: `SEMATTRS_HTTP_CLIENT_IP` |
| `http.flavor` | Kind of HTTP protocol used | Key: `SEMATTRS_HTTP_FLAVOR` |
| `http.host` | The value of the HTTP host header | Key: `SEMATTRS_HTTP_HOST` |
| `http.method` | HTTP request method | Key: `SEMATTRS_HTTP_METHOD` |
| `http.request_content_length` | The size of the request payload body in bytes | Key: `SEMATTRS_HTTP_REQUEST_CONTENT_LENGTH` |
| `http.request_content_length_uncompressed` | The size of the uncompressed request payload body after transport decoding | Key: `SEMATTRS_HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED` |
| `http.response_content_length` | The size of the response payload body in bytes | Key: `SEMATTRS_HTTP_RESPONSE_CONTENT_LENGTH` |
| `http.response_content_length_uncompressed` | The size of the uncompressed response payload body after transport decoding | Key: `SEMATTRS_HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED` |
| `http.route` | The matched route (path template). | Key: `SEMATTRS_HTTP_ROUTE` |
| `http.scheme` | The URI scheme identifying the used protocol | Key: `SEMATTRS_HTTP_SCHEME` |
| `http.server_name` | The primary server name of the matched virtual host | Key: `SEMATTRS_HTTP_SERVER_NAME` |
| `http.status_code` | HTTP response status code | Key: `SEMATTRS_HTTP_STATUS_CODE` |
| `http.target` | The full request target as passed in a HTTP request line or equivalent | Key: `SEMATTRS_HTTP_TARGET` |
| `http.url` | Full HTTP request URL in the form `scheme://host[:port]/path?query[#fragment]` | Key: `SEMATTRS_HTTP_URL` |
| `http.user_agent` | Value of the HTTP User-Agent header sent by the client | Key: `SEMATTRS_HTTP_USER_AGENT` |
| `net.host.ip` | Like net.peer.ip but for the host IP. Useful in case of a multi-IP host | Key: `SEMATTRS_NET_HOST_IP` |
| `net.host.name` | Local hostname or similar | Key: `SEMATTRS_NET_HOST_NAME` |
| `net.host.port` | Like net.peer.port but for the host port | Key: `SEMATTRS_NET_HOST_PORT` |
| `net.peer.ip.` | Remote address of the peer (dotted decimal for IPv4 or RFC5952 for IPv6) | Key: `SEMATTRS_NET_PEER_IP` |
| `net.peer.name` | Remote hostname or similar | Key: `SEMATTRS_NET_PEER_NAME` |
| `net.peer.port` | Remote port number | Key: `SEMATTRS_NET_PEER_PORT` |
| `net.transport` | Transport protocol used | Key: `SEMATTRS_NET_TRANSPORT` |

## Useful links

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,8 @@ export const isIgnored = (
export const setSpanWithError = (span: Span, error: Err): void => {
const message = error.message;

span.setAttributes({
[AttributeNames.HTTP_ERROR_NAME]: error.name,
[AttributeNames.HTTP_ERROR_MESSAGE]: message,
});

span.setAttribute(AttributeNames.HTTP_ERROR_NAME, error.name);
span.setAttribute(AttributeNames.HTTP_ERROR_MESSAGE, message);
span.setStatus({ code: SpanStatusCode.ERROR, message });
span.recordException(error);
};
Expand Down Expand Up @@ -371,7 +368,7 @@ export const getOutgoingRequestAttributes = (
[SEMATTRS_HTTP_METHOD]: method,
[SEMATTRS_HTTP_TARGET]: requestOptions.path || '/',
[SEMATTRS_NET_PEER_NAME]: hostname,
[SEMATTRS_HTTP_HOST]: requestOptions.headers?.host ?? `${hostname}:${port}`,
[SEMATTRS_HTTP_HOST]: headers.host ?? `${hostname}:${port}`,
};

if (userAgent !== undefined) {
Expand Down Expand Up @@ -399,8 +396,10 @@ export const getOutgoingRequestMetricAttributes = (
* Returns attributes related to the kind of HTTP protocol used
* @param {string} [kind] Kind of HTTP protocol used: "1.0", "1.1", "2", "SPDY" or "QUIC".
*/
export const getAttributesFromHttpKind = (kind?: string): SpanAttributes => {
const attributes: SpanAttributes = {};
export const setAttributesFromHttpKind = (
kind: string | undefined,
attributes: SpanAttributes
): void => {
if (kind) {
attributes[SEMATTRS_HTTP_FLAVOR] = kind;
if (kind.toUpperCase() !== 'QUIC') {
Expand All @@ -409,7 +408,6 @@ export const getAttributesFromHttpKind = (kind?: string): SpanAttributes => {
attributes[SEMATTRS_NET_TRANSPORT] = NETTRANSPORTVALUES_IP_UDP;
}
}
return attributes;
};

/**
Expand All @@ -436,8 +434,8 @@ export const getOutgoingRequestAttributesOnResponse = (
).toUpperCase();
}

const httpKindAttributes = getAttributesFromHttpKind(httpVersion);
return Object.assign(attributes, httpKindAttributes);
setAttributesFromHttpKind(httpVersion, attributes);
return attributes;
};

/**
Expand Down Expand Up @@ -509,9 +507,8 @@ export const getIncomingRequestAttributes = (
attributes[SEMATTRS_HTTP_USER_AGENT] = userAgent;
}
setRequestContentLengthAttribute(request, attributes);

const httpKindAttributes = getAttributesFromHttpKind(httpVersion);
return Object.assign(attributes, httpKindAttributes, options.hookAttributes);
setAttributesFromHttpKind(httpVersion, attributes);
return Object.assign(attributes, options.hookAttributes);
};

/**
Expand Down Expand Up @@ -584,24 +581,24 @@ export const getIncomingRequestMetricAttributesOnResponse = (
};

export function headerCapture(type: 'request' | 'response', headers: string[]) {
const normalizedHeaders = new Map(
headers.map(header => [
header.toLowerCase(),
header.toLowerCase().replace(/-/g, '_'),
])
);
const normalizedHeaders = new Map<string, string>();
for (let i = 0, len = headers.length; i < len; i++) {
const capturedHeader = headers[i].toLowerCase();
normalizedHeaders.set(capturedHeader, capturedHeader.replace(/-/g, '_'));
}

return (
span: Span,
getHeader: (key: string) => undefined | string | string[] | number
) => {
for (const [capturedHeader, normalizedHeader] of normalizedHeaders) {
for (const capturedHeader of normalizedHeaders.keys()) {
const value = getHeader(capturedHeader);

if (value === undefined) {
continue;
}

const normalizedHeader = normalizedHeaders.get(capturedHeader);
const key = `http.${type}.header.${normalizedHeader}`;

if (typeof value === 'string') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ req.send();

```

### XHR Instrumentation options

XHR 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/experimental/packages/opentelemetry-instrumentation-xml-http-request/src/xhr.ts#L76) | `XHRCustomAttributeFunction` | Function for adding custom attributes |
| [`ignoreNetworkEvents`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-xml-http-request/src/xhr.ts#L78) | `boolean` | Disable network events being added as span events (network events are added by default) |

## Example Screenshots

![Screenshot of the running example](images/main.jpg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export interface XMLHttpRequestInstrumentationConfig
ignoreUrls?: Array<string | RegExp>;
/** Function for adding custom attributes on the span */
applyCustomAttributesOnSpan?: XHRCustomAttributeFunction;
/** Ignore adding network events as span events */
ignoreNetworkEvents?: boolean;
}

/**
Expand Down Expand Up @@ -140,7 +142,9 @@ export class XMLHttpRequestInstrumentation extends InstrumentationBase<XMLHttpRe
const childSpan = this.tracer.startSpan('CORS Preflight', {
startTime: corsPreFlightRequest[PTN.FETCH_START],
});
addSpanNetworkEvents(childSpan, corsPreFlightRequest);
if (!this._getConfig().ignoreNetworkEvents) {
addSpanNetworkEvents(childSpan, corsPreFlightRequest);
}
childSpan.end(corsPreFlightRequest[PTN.RESPONSE_END]);
});
}
Expand Down Expand Up @@ -292,7 +296,9 @@ export class XMLHttpRequestInstrumentation extends InstrumentationBase<XMLHttpRe
this._addChildSpan(span, corsPreFlightRequest);
this._markResourceAsUsed(corsPreFlightRequest);
}
addSpanNetworkEvents(span, mainRequest);
if (!this._getConfig().ignoreNetworkEvents) {
addSpanNetworkEvents(span, mainRequest);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,20 @@ describe('xhr', () => {
);
});
});

describe('when network events are ignored', () => {
beforeEach(done => {
clearData();
prepareData(done, url, {
ignoreNetworkEvents: true,
});
});
it('should NOT add network events', () => {
const span: tracing.ReadableSpan = exportSpy.args[1][0][0];
const events = span.events;
assert.strictEqual(events.length, 3, 'number of events is wrong');
});
});
});

describe('when request is NOT successful', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@opentelemetry/sdk-trace-base": "1.22.0",
"axios": "1.5.1",
"body-parser": "1.19.0",
"express": "4.17.3"
"express": "4.19.2"
},
"devDependencies": {
"typescript": "4.4.4"
Expand Down
Loading

0 comments on commit 5c5678d

Please sign in to comment.