Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Added otel compliant spans to external http spans #2169

Merged
merged 3 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion lib/spans/span-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class SpanEvent {
* category of the segment.
*
* @param {TraceSegment} segment - The segment to turn into a span event.
* @param {?string} [parentId=null] - The ID of the segment's parent.
* @param {?string} [parentId] - The ID of the segment's parent.
* @param isRoot
* @returns {SpanEvent} The constructed event.
*/
Expand All @@ -106,6 +106,12 @@ class SpanEvent {

let span = null
if (HttpSpanEvent.testSegment(segment)) {
// Get external host from the segment name
const nameParams = segment.name.split('/')
const external = nameParams.indexOf('External')
if (external > -1) {
attributes.host = nameParams[external + 1]
}
span = new HttpSpanEvent(attributes, customAttributes)
} else if (DatastoreSpanEvent.testSegment(segment)) {
span = new DatastoreSpanEvent(attributes, customAttributes)
Expand Down Expand Up @@ -194,8 +200,14 @@ class HttpSpanEvent extends SpanEvent {
attributes.url = null
}

if (attributes.host) {
this.addAttribute('server.address', attributes.host)
attributes.host = null
}

if (attributes.procedure) {
this.addAttribute('http.method', attributes.procedure)
this.addAttribute('http.request.method', attributes.procedure)
attributes.procedure = null
}
}
Expand Down
16 changes: 14 additions & 2 deletions lib/spans/streaming-span-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class StreamingSpanEvent {
*
* @param {string} key Name of the attribute to be stored.
* @param {string|boolean|number} value Value of the attribute to be stored.
* @param {boolean} [truncateExempt=false] Set to true if attribute should not be truncated.
* @param {boolean} [truncateExempt] Set to true if attribute should not be truncated.
*/
addCustomAttribute(key, value, truncateExempt = false) {
const shouldKeep = this._checkFilter(key)
Expand All @@ -79,7 +79,7 @@ class StreamingSpanEvent {
*
* @param {string} key Name of the attribute to be stored.
* @param {string|boolean|number} value Value of the attribute to be stored.
* @param {boolean} [truncateExempt=false] Set to true if attribute should not be truncated.
* @param {boolean} [truncateExempt] Set to true if attribute should not be truncated.
*/
addAgentAttribute(key, value, truncateExempt = false) {
const shouldKeep = this._checkFilter(key)
Expand Down Expand Up @@ -128,6 +128,12 @@ class StreamingSpanEvent {

let span = null
if (StreamingHttpSpanEvent.isHttpSegment(segment)) {
// Get external host from the segment name
const nameParams = segment.name.split('/')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems heavy handed. what i would do is abstract away the assigning of the attributes for http externals, and just add another one there for host. the reason i suggest abstracting is because we have multiple libraries that instrument libraries as http externals. in fact looking into this i think we were doing it wrong in grpc. I can show you a diff of what I'm suggesting

const external = nameParams.indexOf('External')
if (external > -1) {
agentAttributes.host = nameParams[external + 1]
}
span = new StreamingHttpSpanEvent(traceId, agentAttributes, customAttributes)
} else if (StreamingDatastoreSpanEvent.isDatastoreSegment(segment)) {
span = new StreamingDatastoreSpanEvent(traceId, agentAttributes, customAttributes)
Expand Down Expand Up @@ -197,8 +203,14 @@ class StreamingHttpSpanEvent extends StreamingSpanEvent {
agentAttributes.url = null
}

if (agentAttributes.host) {
this.addAgentAttribute('server.address', agentAttributes.host)
agentAttributes.host = null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed the nullifying of these properties isn't doing what we expect. I will file another ticket to deal with that

}

if (agentAttributes.procedure) {
this.addAgentAttribute('http.method', agentAttributes.procedure)
this.addAgentAttribute('http.request.method', agentAttributes.procedure)
agentAttributes.procedure = null
}
}
Expand Down
4 changes: 4 additions & 0 deletions test/unit/spans/span-event.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ tap.test('fromSegment()', (t) => {

// Should have (most) http properties.
t.equal(attributes['http.url'], 'https://example.com/')
t.equal(attributes['server.address'], 'example.com')
t.ok(attributes['http.method'])
t.ok(attributes['http.request.method'])
t.equal(attributes['http.statusCode'], 200)
t.equal(attributes['http.statusText'], 'OK')

Expand Down Expand Up @@ -251,7 +253,9 @@ tap.test('fromSegment()', (t) => {
// Should have not http properties.
const hasOwnAttribute = Object.hasOwnProperty.bind(attributes)
t.notOk(hasOwnAttribute('http.url'))
t.notOk(hasOwnAttribute('server.address'))
t.notOk(hasOwnAttribute('http.method'))
t.notOk(hasOwnAttribute('http.request.method'))

// Should have (most) datastore properties.
t.ok(attributes['db.instance'])
Expand Down
4 changes: 4 additions & 0 deletions test/unit/spans/streaming-span-event.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ tap.test('fromSegment()', (t) => {

// Should have (most) http properties.
t.same(agentAttributes['http.url'], { [STRING_TYPE]: 'https://example.com/' })
t.same(agentAttributes['server.address'], { [STRING_TYPE]: 'example.com' })
t.ok(agentAttributes['http.method'])
t.ok(agentAttributes['http.request.method'])
t.same(agentAttributes['http.statusCode'], { [INT_TYPE]: 200 })
t.same(agentAttributes['http.statusText'], { [STRING_TYPE]: 'OK' })

Expand Down Expand Up @@ -246,7 +248,9 @@ tap.test('fromSegment()', (t) => {
// Should have not http properties.
const hasOwnAttribute = Object.hasOwnProperty.bind(agentAttributes)
t.notOk(hasOwnAttribute('http.url'))
t.notOk(hasOwnAttribute('server.address'))
t.notOk(hasOwnAttribute('http.method'))
t.notOk(hasOwnAttribute('http.request.method'))

// Should have (most) datastore properties.
t.ok(agentAttributes['db.instance'])
Expand Down
Loading