Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion packages/datadog-plugin-fetch/test/index.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict'

const util = require('node:util')

const { expect } = require('chai')
const { describe, it, beforeEach, afterEach } = require('mocha')

Expand Down Expand Up @@ -226,7 +228,7 @@ describe('Plugin', function () {
.assertSomeTraces(traces => {
expect(traces[0][0].meta).to.have.property(ERROR_TYPE, error.name)
expect(traces[0][0].meta).to.have.property(ERROR_MESSAGE, error.message || error.code)
expect(traces[0][0].meta).to.have.property(ERROR_STACK, error.stack)
expect(traces[0][0].meta).to.have.property(ERROR_STACK, util.inspect(error, { depth: 0 }))
Copy link
Member

Choose a reason for hiding this comment

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

What if error is not an actual error object?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See https://github.com/DataDog/dd-trace-js/pull/6776/files#diff-5490d33b84fdf38d10fd4f4460c01af269e82e9a95d9bda16aef99b9353102b7R89-R97

We check for it having a message property or if it is an instance of error to determine if we add the tags.
The object will be serialized as a whole, if it contains a stack property. If it would be a object with a message and a stack property, that would be serialized instead of only showing the stack property. That in itself seems beneficial for users one way or the other. If it does not have a stack property, that is kept as is.

Copy link
Member

Choose a reason for hiding this comment

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

If it's not an error we should properly extract the existing stack as it was done before, and only use util.inspect for errors since it special cases them to get the stack with additional metadata.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I discussed it with error tracking and I am going to handle it as separate properties for now.
They said we could have a look how it would be on staging, while it will likely break a couple of existing pretty printing.

So I am marking it as draft for now.

expect(traces[0][0].meta).to.have.property('component', 'fetch')
})
.then(done)
Expand Down
12 changes: 5 additions & 7 deletions packages/datadog-plugin-http/src/client.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict'

const { URL } = require('url')

const ClientPlugin = require('../../dd-trace/src/plugins/client')
const { storage } = require('../../datadog-core')
const tags = require('../../../ext/tags')
Expand All @@ -8,8 +10,8 @@ const formats = require('../../../ext/formats')
const HTTP_HEADERS = formats.HTTP_HEADERS
const urlFilter = require('../../dd-trace/src/plugins/util/urlfilter')
const log = require('../../dd-trace/src/log')
const { CLIENT_PORT_KEY, COMPONENT, ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
const { URL } = require('url')
const { CLIENT_PORT_KEY, COMPONENT } = require('../../dd-trace/src/constants')
const { addErrorTagsToSpan } = require('../../dd-trace/src/util')

const HTTP_STATUS_CODE = tags.HTTP_STATUS_CODE
const HTTP_REQUEST_HEADERS = tags.HTTP_REQUEST_HEADERS
Expand Down Expand Up @@ -116,11 +118,7 @@ class HttpClientPlugin extends ClientPlugin {
error ({ span, error, args, customRequestTimeout }) {
if (!span) return
if (error) {
span.addTags({
[ERROR_TYPE]: error.name,
[ERROR_MESSAGE]: error.message || error.code,
[ERROR_STACK]: error.stack
})
addErrorTagsToSpan(span, error)
} else {
// conditions for no error:
// 1. not using a custom agent instance with custom timeout specified
Expand Down
15 changes: 9 additions & 6 deletions packages/datadog-plugin-http/test/client.spec.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
'use strict'

const fs = require('node:fs')
const path = require('node:path')
const { inspect } = require('node:util')

const { expect } = require('chai')
const { satisfies } = require('semver')

const { withNamingSchema, withPeerService } = require('../../dd-trace/test/setup/mocha')
const agent = require('../../dd-trace/test/plugins/agent')
const fs = require('fs')
const path = require('path')
const tags = require('../../../ext/tags')
const { expect } = require('chai')
const { storage } = require('../../datadog-core')
const key = fs.readFileSync(path.join(__dirname, './ssl/test.key'))
const cert = fs.readFileSync(path.join(__dirname, './ssl/test.crt'))
const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
const { rawExpectedSchema } = require('./naming')
const { satisfies } = require('semver')

const HTTP_REQUEST_HEADERS = tags.HTTP_REQUEST_HEADERS
const HTTP_RESPONSE_HEADERS = tags.HTTP_RESPONSE_HEADERS
Expand Down Expand Up @@ -552,7 +555,7 @@ describe('Plugin', () => {
.assertSomeTraces(traces => {
expect(traces[0][0].meta).to.have.property(ERROR_TYPE, error.name)
expect(traces[0][0].meta).to.have.property(ERROR_MESSAGE, error.message || error.code)
expect(traces[0][0].meta).to.have.property(ERROR_STACK, error.stack)
expect(traces[0][0].meta).to.have.property(ERROR_STACK, inspect(error, { depth: 0 }))
expect(traces[0][0].meta).to.have.property('component', 'http')
})
.then(done)
Expand Down Expand Up @@ -625,7 +628,7 @@ describe('Plugin', () => {
expect(traces[0][0]).to.have.property('error', 1)
expect(traces[0][0].meta).to.have.property(ERROR_MESSAGE, error.message)
expect(traces[0][0].meta).to.have.property(ERROR_TYPE, error.name)
expect(traces[0][0].meta).to.have.property(ERROR_STACK, error.stack)
expect(traces[0][0].meta).to.have.property(ERROR_STACK, inspect(error, { depth: 0 }))
expect(traces[0][0].meta).to.not.have.property('http.status_code')
expect(traces[0][0].meta).to.have.property('component', 'http')
})
Expand Down
7 changes: 5 additions & 2 deletions packages/datadog-plugin-undici/test/index.spec.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
'use strict'

const { inspect } = require('node:util')

const { expect } = require('chai')

const { withNamingSchema, withVersions } = require('../../dd-trace/test/setup/mocha')
const agent = require('../../dd-trace/test/plugins/agent')
const tags = require('../../../ext/tags')
const { expect } = require('chai')
const { rawExpectedSchema } = require('./naming')
const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
const { NODE_MAJOR } = require('../../../version')
Expand Down Expand Up @@ -204,7 +207,7 @@ describe('Plugin', () => {
.assertSomeTraces(traces => {
expect(traces[0][0].meta).to.have.property(ERROR_TYPE, error.name)
expect(traces[0][0].meta).to.have.property(ERROR_MESSAGE, error.message || error.code)
expect(traces[0][0].meta).to.have.property(ERROR_STACK, error.stack)
expect(traces[0][0].meta).to.have.property(ERROR_STACK, inspect(error, { depth: 0 }))
expect(traces[0][0].meta).to.have.property('component', 'undici')
})
.then(done)
Expand Down
13 changes: 10 additions & 3 deletions packages/dd-trace/src/format.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,16 @@ function extractError (formattedSpan, error) {
// AggregateError only has a code and no message.
// TODO(BridgeAR)[31.03.2025]: An AggregateError can have a message. Should
// the code just generally be added, if available?
addTag(formattedSpan.meta, formattedSpan.metrics, ERROR_MESSAGE, error.message || error.code)
addTag(formattedSpan.meta, formattedSpan.metrics, ERROR_TYPE, error.name)
addTag(formattedSpan.meta, formattedSpan.metrics, ERROR_STACK, error.stack)
const message = error.message || error.code
if (message != null) {
formattedSpan.meta[ERROR_MESSAGE] = message
}
if (error.name != null) {
formattedSpan.meta[ERROR_TYPE] = error.name
}
if (error.stack != null) {
formattedSpan.meta[ERROR_STACK] = error.stack
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions packages/dd-trace/src/lambda/runtime/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

class ExtendedError extends Error {
constructor (reason) {
const { stackTraceLimit } = Error
Error.stackTraceLimit = 0
super(reason)
Error.stackTraceLimit = stackTraceLimit
Object.setPrototypeOf(this, new.target.prototype)
}
}
Expand Down
4 changes: 3 additions & 1 deletion packages/dd-trace/src/llmobs/span_processor.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict'

const { inspect } = require('node:util')

const {
SPAN_KIND,
MODEL_NAME,
Expand Down Expand Up @@ -140,7 +142,7 @@ class LLMObsSpanProcessor {
if (error) {
meta[ERROR_MESSAGE] = spanTags[ERROR_MESSAGE] || error.message || error.code
meta[ERROR_TYPE] = spanTags[ERROR_TYPE] || error.name
meta[ERROR_STACK] = spanTags[ERROR_STACK] || error.stack
meta[ERROR_STACK] = spanTags[ERROR_STACK] || (error.stack ? inspect(error, { depth: 0 }) : error.stack)
}

const metrics = mlObsTags[METRICS] || {}
Expand Down
12 changes: 5 additions & 7 deletions packages/dd-trace/src/opentelemetry/span.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ const { timeInputToHrTime } = require('@opentelemetry/core')

const tracer = require('../../')
const DatadogSpan = require('../opentracing/span')
const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK, IGNORE_OTEL_ERROR } = require('../constants')
const { ERROR_MESSAGE, IGNORE_OTEL_ERROR } = require('../constants')
const { SERVICE_NAME, RESOURCE_NAME } = require('../../../../ext/tags')
const kinds = require('../../../../ext/kinds')

const { addErrorTagsToSpan } = require('../util')

const SpanContext = require('./span_context')
const id = require('../id')

Expand Down Expand Up @@ -290,12 +292,8 @@ class Span {
}

recordException (exception, timeInput) {
this._ddSpan.addTags({
[ERROR_TYPE]: exception.name,
[ERROR_MESSAGE]: exception.message,
[ERROR_STACK]: exception.stack,
[IGNORE_OTEL_ERROR]: this._ddSpan.context()._tags[IGNORE_OTEL_ERROR] ?? true
})
addErrorTagsToSpan(this._ddSpan, exception)
this._ddSpan.setTag(IGNORE_OTEL_ERROR, this._ddSpan.context()._tags[IGNORE_OTEL_ERROR] ?? true)
const attributes = {}
if (exception.message) attributes['exception.message'] = exception.message
if (exception.type) attributes['exception.type'] = exception.type
Expand Down
11 changes: 3 additions & 8 deletions packages/dd-trace/src/plugins/util/web.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ const tags = require('../../../../../ext/tags')
const types = require('../../../../../ext/types')
const kinds = require('../../../../../ext/kinds')
const urlFilter = require('./urlfilter')
const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../constants')
const { ERROR_MESSAGE } = require('../../constants')
const { createInferredProxySpan, finishInferredProxySpan } = require('./inferred_proxy')
const TracingPlugin = require('../tracing')
const { addErrorTagsToSpan } = require('../../util')

let extractIp

Expand Down Expand Up @@ -216,13 +217,7 @@ const web = {
const span = context.middleware.pop()

if (span) {
if (error) {
span.addTags({
[ERROR_TYPE]: error.name,
[ERROR_MESSAGE]: error.message,
[ERROR_STACK]: error.stack
})
}
addErrorTagsToSpan(span, error)

span.finish()
}
Expand Down
19 changes: 4 additions & 15 deletions packages/dd-trace/src/tracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
const Tracer = require('./opentracing/tracer')
const tags = require('../../../ext/tags')
const Scope = require('./scope')
const { isError } = require('./util')
const { setStartupLogConfig } = require('./startup-log')
const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
const { DataStreamsCheckpointer, DataStreamsManager, DataStreamsProcessor } = require('./datastreams')
const { flushStartupLogs } = require('../../datadog-instrumentations/src/helpers/check-require-cache')
const log = require('./log/writer')
const { addErrorTagsToSpan } = require('./util')

const SPAN_TYPE = tags.SPAN_TYPE
const RESOURCE_NAME = tags.RESOURCE_NAME
Expand Down Expand Up @@ -66,7 +65,7 @@ class DatadogTracer extends Tracer {
try {
if (fn.length > 1) {
return this.scope().activate(span, () => fn(span, err => {
addError(span, err)
addErrorTagsToSpan(span, err)
span.finish()
}))
}
Expand All @@ -80,7 +79,7 @@ class DatadogTracer extends Tracer {
return value
},
err => {
addError(span, err)
addErrorTagsToSpan(span, err)
span.finish()
throw err
}
Expand All @@ -90,7 +89,7 @@ class DatadogTracer extends Tracer {

return result
} catch (e) {
addError(span, e)
addErrorTagsToSpan(span, e)
span.finish()
throw e
}
Expand Down Expand Up @@ -145,16 +144,6 @@ class DatadogTracer extends Tracer {
}
}

function addError (span, error) {
if (isError(error)) {
span.addTags({
[ERROR_TYPE]: error.name,
[ERROR_MESSAGE]: error.message,
[ERROR_STACK]: error.stack
})
}
}

function addTags (span, options) {
const tags = {}

Expand Down
14 changes: 14 additions & 0 deletions packages/dd-trace/src/util.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
'use strict'

const { inspect } = require('util')
const path = require('path')

const { ERROR_STACK, ERROR_MESSAGE, ERROR_TYPE } = require('./constants')

function isTrue (str) {
str = String(str).toLowerCase()
return str === 'true' || str === '1'
Expand Down Expand Up @@ -83,7 +86,18 @@ function normalizePluginEnvName (envPluginName, makeLowercase = false) {
return makeLowercase ? envPluginName.toLowerCase() : envPluginName
}

function addErrorTagsToSpan (span, error) {
if (isError(error)) {
span.addTags({
[ERROR_TYPE]: error.name,
[ERROR_MESSAGE]: error.message || error.code,
[ERROR_STACK]: error.stack ? inspect(error, { depth: 0 }) : error.stack
})
}
}

module.exports = {
addErrorTagsToSpan,
isTrue,
isFalse,
isError,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict'

const { inspect } = require('node:util')

const chai = require('chai')
const { describe, it, beforeEach } = require('mocha')
const semifies = require('semifies')
Expand Down Expand Up @@ -239,7 +241,7 @@ describe('integrations', () => {
error,
errorType: error.type || error.name,
errorMessage: error.message,
errorStack: error.stack
errorStack: inspect(error, { depth: 0 })
})

expect(llmobsSpans[0]).to.deepEqualWithMockValues(expected)
Expand Down Expand Up @@ -292,7 +294,7 @@ describe('integrations', () => {
error,
errorType: error.type || error.name,
errorMessage: error.message,
errorStack: error.stack
errorStack: inspect(error, { depth: 0 })
})

expect(llmobsSpans[0]).to.deepEqualWithMockValues(expected)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict'

const { inspect } = require('node:util')

const chai = require('chai')
const { describe, it, beforeEach } = require('mocha')
const semifies = require('semifies')
Expand Down Expand Up @@ -407,7 +409,7 @@ describe('integrations', () => {
error,
errorType: 'Error',
errorMessage: error.message,
errorStack: error.stack
errorStack: inspect(error, { depth: 0 })
})

expect(llmobsSpans[0]).to.deepEqualWithMockValues(expected)
Expand Down Expand Up @@ -456,7 +458,7 @@ describe('integrations', () => {
error,
errorType: 'Error',
errorMessage: error.message,
errorStack: error.stack
errorStack: inspect(error, { depth: 0 })
})

expect(llmobsSpans[0]).to.deepEqualWithMockValues(expected)
Expand Down
Loading