Skip to content

Commit

Permalink
feat(opentelemetry-js): add content-length attributes to HTTP spans
Browse files Browse the repository at this point in the history
Signed-off-by: Carlo Pearson <cpearson@newrelic.com>
  • Loading branch information
Carlo Pearson authored and nijotz committed Oct 26, 2020
1 parent fba5038 commit 97c8799
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 26 deletions.
33 changes: 19 additions & 14 deletions packages/opentelemetry-plugin-http/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,33 +218,38 @@ export const setSpanWithError = (
};

/**
*
* @param headers
* @param Attributes
* Adds attributes for content-length and content-encoding HTTP headers
* @param { OutgoingHttpHeaders | IncomingHttpHeaders } headers http headers
* @param { Attributes } Attributes span attributes
* @param { boolean } isRequest set true for setting request content-header
*/
export const setRequestContentLengthAttributes = (
export const setContentLengthAttributes = (
headers: OutgoingHttpHeaders | IncomingHttpHeaders,
attributes: Attributes
attributes: Attributes,
isRequest: boolean
) => {
let isCompressed = false
let isCompressed = false;

if (headers['content-length'] === undefined)
return;

if (headers['content-encoding'] && headers['content-encoding'] !== 'identity') {
isCompressed = true
}
};

if (isCompressed) {
if (headers as OutgoingHttpHeaders) {
if (isRequest) {
attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH] = headers['content-length']
} else {
attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH] = headers['content-length']
}
};
} else {
if (headers as OutgoingHttpHeaders) {
if (isRequest) {
attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED] = headers['content-length']
} else {
attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED] = headers['content-length']
}
}
};
};
};

/**
Expand Down Expand Up @@ -396,7 +401,7 @@ export const getOutgoingRequestAttributesOnResponse = (
[HttpAttribute.HTTP_HOST]: `${options.hostname}:${remotePort}`,
};

// Place content-length func here?
setContentLengthAttributes(headers, attributes, false)

if (statusCode) {
attributes[HttpAttribute.HTTP_STATUS_CODE] = statusCode;
Expand Down Expand Up @@ -458,7 +463,7 @@ export const getIncomingRequestAttributes = (
attributes[HttpAttribute.HTTP_USER_AGENT] = userAgent;
}

// Place content-length func here?
setContentLengthAttributes(headers, attributes, true)

const httpKindAttributes = getAttributesFromHttpKind(httpVersion);
return Object.assign(attributes, httpKindAttributes);
Expand Down
118 changes: 108 additions & 10 deletions packages/opentelemetry-plugin-http/test/functionals/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,16 +310,114 @@ describe('Utility', () => {
});
});

describe('setRequestContentLengthAttributes', () => {
it('should set attributes', () => {
const attributes: Attributes = {}
let headers: http.OutgoingHttpHeaders = {
'content-length': 1200
}
describe('setContentLengthAttributes', () => {
it('should set response content-length uncompressed attribute with no content-encoding header', () => {
const attributes: Attributes = {};

let headers: http.IncomingHttpHeaders = {};

headers["content-length"] = '1200';

utils.setContentLengthAttributes(headers, attributes, false);

assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED], '1200');
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH], undefined);
});

it('should set response content-length uncompressed attribute with "identity" content-encoding header', () => {
const attributes: Attributes = {};

let headers: http.IncomingHttpHeaders = {};

headers["content-length"] = '1200';
headers["content-encoding"] = 'identity';

utils.setContentLengthAttributes(headers, attributes, false);

assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED], '1200');
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH], undefined);
});

it('should set response content-length compressed attribute with "gzip" content-encoding header', () => {
const attributes: Attributes = {};

let headers: http.IncomingHttpHeaders = {};

headers["content-length"] = '1200';
headers["content-encoding"] = 'gzip';

utils.setContentLengthAttributes(headers, attributes, false);

assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH], '1200');
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH], undefined);
});

it('should set request content-length uncompressed attribute with no content-encoding header', () => {
const attributes: Attributes = {};

let headers: http.OutgoingHttpHeaders = {};

headers["content-length"] = '1200';

utils.setRequestContentLengthAttributes(headers, attributes)
utils.setContentLengthAttributes(headers, attributes, true);

assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED], 1200)
})
})
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED], '1200');
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH], undefined);
});

it('should set request content-length uncompressed attribute with "identity" content-encoding header', () => {
const attributes: Attributes = {};

let headers: http.OutgoingHttpHeaders = {};

headers["content-length"] = '1200';
headers["content-encoding"] = 'identity';

utils.setContentLengthAttributes(headers, attributes, true);

assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED], '1200');
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH], undefined);
});

it('should set request content-length compressed attribute with "gzip" content-encoding header', () => {
const attributes: Attributes = {};

let headers: http.OutgoingHttpHeaders = {};

headers["content-length"] = '1200';
headers["content-encoding"] = 'gzip';

utils.setContentLengthAttributes(headers, attributes, true);

assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH], '1200');
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH], undefined);
});

it('should set no attributes with no content-length header', () => {
const attributes: Attributes = {};

let headers: http.OutgoingHttpHeaders = {};

headers["content-encoding"] = 'gzip';

utils.setContentLengthAttributes(headers, attributes, true);

assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED], undefined);
assert.strictEqual(attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH], undefined);
});
});
});
33 changes: 33 additions & 0 deletions packages/opentelemetry-plugin-http/test/utils/assertSpan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,24 @@ export const assertSpan = (
);
}
}

if (span.kind === SpanKind.CLIENT) {
if (validations.resHeaders['content-length']) {
const contentLength = validations.resHeaders['content-length']

if (validations.resHeaders['content-encoding'] && validations.resHeaders['content-encoding'] != 'identity') {
assert.strictEqual(
span.attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH],
contentLength
);
} else {
assert.strictEqual(
span.attributes[HttpAttribute.HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED],
contentLength
);
}
}

assert.strictEqual(
span.attributes[GeneralAttribute.NET_PEER_NAME],
validations.hostname,
Expand All @@ -105,6 +122,22 @@ export const assertSpan = (
);
}
if (span.kind === SpanKind.SERVER) {
if (validations.reqHeaders && validations.reqHeaders['content-length']) {
const contentLength = validations.reqHeaders['content-length']

if (validations.reqHeaders['content-encoding'] && validations.reqHeaders['content-encoding'] != 'identity') {
assert.strictEqual(
span.attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH],
contentLength
);
} else {
assert.strictEqual(
span.attributes[HttpAttribute.HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED],
contentLength
);
}
}

if (validations.serverName) {
assert.strictEqual(
span.attributes[HttpAttribute.HTTP_SERVER_NAME],
Expand Down
4 changes: 2 additions & 2 deletions packages/opentelemetry-semantic-conventions/src/trace/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export const HttpAttribute = {
HTTP_CLIENT_IP: 'http.client_ip',
HTTP_SCHEME: 'http.scheme',
HTTP_RESPONSE_CONTENT_LENGTH: 'http.response_content_length',
HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED: 'http.request_content_length_uncompressed',
HTTP_REQUEST_CONTENT_LENGTH: 'http.response_content_length',
HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED: 'http.response_content_length_uncompressed',
HTTP_REQUEST_CONTENT_LENGTH: 'http.request_content_length',
HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED: 'http.request_content_length_uncompressed',

// NOT ON OFFICIAL SPEC
Expand Down

0 comments on commit 97c8799

Please sign in to comment.