diff --git a/integration-tests/esbuild.spec.js b/integration-tests/esbuild.spec.js index 378dda5baa2..c7a912b8dcb 100755 --- a/integration-tests/esbuild.spec.js +++ b/integration-tests/esbuild.spec.js @@ -8,24 +8,28 @@ const path = require('path') const CWD = process.cwd() const TEST_DIR = path.join(__dirname, 'esbuild') -// eslint-disable-next-line no-console -console.log(`cd ${TEST_DIR}`) -process.chdir(TEST_DIR) +describe('esbuild', () => { + it('works', () => { + // eslint-disable-next-line no-console + console.log(`cd ${TEST_DIR}`) + process.chdir(TEST_DIR) -// eslint-disable-next-line no-console -console.log('npm run build') -chproc.execSync('npm run build') + // eslint-disable-next-line no-console + console.log('npm run build') + chproc.execSync('npm run build') -// eslint-disable-next-line no-console -console.log('npm run built') -try { - chproc.execSync('npm run built', { - timeout: 1000 * 30 + // eslint-disable-next-line no-console + console.log('npm run built') + try { + chproc.execSync('npm run built', { + timeout: 1000 * 30 + }) + } catch (err) { + // eslint-disable-next-line no-console + console.error(err) + process.exit(1) + } finally { + process.chdir(CWD) + } }) -} catch (err) { - // eslint-disable-next-line no-console - console.error(err) - process.exit(1) -} finally { - process.chdir(CWD) -} +}) diff --git a/packages/dd-trace/src/config.js b/packages/dd-trace/src/config.js index 93efce8c7c2..93a9a1f68ce 100644 --- a/packages/dd-trace/src/config.js +++ b/packages/dd-trace/src/config.js @@ -9,6 +9,7 @@ const coalesce = require('koalas') const tagger = require('./tagger') const { isTrue, isFalse } = require('./util') const uuid = require('crypto-randomuuid') +const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('./plugins/util/tags') const fromEntries = Object.fromEntries || (entries => entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {})) @@ -408,6 +409,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?) true ) + const DD_TRACE_GIT_METADATA_ENABLED = coalesce( + process.env.DD_TRACE_GIT_METADATA_ENABLED, + true + ) + const ingestion = options.ingestion || {} const dogstatsd = coalesce(options.dogstatsd, {}) const sampler = { @@ -522,6 +528,19 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?) this.isGitUploadEnabled = this.isCiVisibility && (this.isIntelligentTestRunnerEnabled && !isFalse(DD_CIVISIBILITY_GIT_UPLOAD_ENABLED)) + this.gitMetadataEnabled = isTrue(DD_TRACE_GIT_METADATA_ENABLED) + + if (this.gitMetadataEnabled) { + this.repositoryUrl = coalesce( + process.env.DD_GIT_REPOSITORY_URL, + this.tags[GIT_REPOSITORY_URL] + ) + this.commitSHA = coalesce( + process.env.DD_GIT_COMMIT_SHA, + this.tags[GIT_COMMIT_SHA] + ) + } + this.stats = { enabled: isTrue(DD_TRACE_STATS_COMPUTATION_ENABLED) } diff --git a/packages/dd-trace/src/constants.js b/packages/dd-trace/src/constants.js index 6811af6a89c..0d220b36837 100644 --- a/packages/dd-trace/src/constants.js +++ b/packages/dd-trace/src/constants.js @@ -25,5 +25,7 @@ module.exports = { ERROR_MESSAGE: 'error.message', ERROR_STACK: 'error.stack', COMPONENT: 'component', - CLIENT_PORT_KEY: 'network.destination.port' + CLIENT_PORT_KEY: 'network.destination.port', + SCI_REPOSITORY_URL: '_dd.git.repository_url', + SCI_COMMIT_SHA: '_dd.git.commit.sha' } diff --git a/packages/dd-trace/src/git_metadata_tagger.js b/packages/dd-trace/src/git_metadata_tagger.js new file mode 100644 index 00000000000..dd3db945940 --- /dev/null +++ b/packages/dd-trace/src/git_metadata_tagger.js @@ -0,0 +1,17 @@ +const { SCI_COMMIT_SHA, SCI_REPOSITORY_URL } = require('./constants') + +class GitMetadataTagger { + constructor (config) { + this._config = config + } + + tagGitMetadata (spanContext) { + if (this._config.gitMetadataEnabled) { + // These tags are added only to the local root span + spanContext._trace.tags[SCI_COMMIT_SHA] = this._config.commitSHA + spanContext._trace.tags[SCI_REPOSITORY_URL] = this._config.repositoryUrl + } + } +} + +module.exports = GitMetadataTagger diff --git a/packages/dd-trace/src/span_processor.js b/packages/dd-trace/src/span_processor.js index 884d87698a2..aea348b11fb 100644 --- a/packages/dd-trace/src/span_processor.js +++ b/packages/dd-trace/src/span_processor.js @@ -3,6 +3,7 @@ const log = require('./log') const format = require('./format') const SpanSampler = require('./span_sampler') +const GitMetadataTagger = require('./git_metadata_tagger') const { SpanStatsProcessor } = require('./span_stats') @@ -18,6 +19,7 @@ class SpanProcessor { this._stats = new SpanStatsProcessor(config) this._spanSampler = new SpanSampler(config.sampler) + this._gitMetadataTagger = new GitMetadataTagger(config) } process (span) { @@ -32,6 +34,7 @@ class SpanProcessor { if (started.length === finished.length || finished.length >= flushMinSpans) { this._prioritySampler.sample(spanContext) this._spanSampler.sample(spanContext) + this._gitMetadataTagger.tagGitMetadata(spanContext) for (const span of started) { if (span._duration !== undefined) { diff --git a/packages/dd-trace/test/git_metadata_tagger.spec.js b/packages/dd-trace/test/git_metadata_tagger.spec.js new file mode 100644 index 00000000000..1d679d7403e --- /dev/null +++ b/packages/dd-trace/test/git_metadata_tagger.spec.js @@ -0,0 +1,58 @@ +'use strict' + +require('./setup/tap') + +const agent = require('./plugins/agent') +const { SCI_COMMIT_SHA, SCI_REPOSITORY_URL } = require('../src/constants') + +const DUMMY_GIT_SHA = '13851f2b092e97acebab1b73f6c0e7818e795b50' +const DUMMY_REPOSITORY_URL = 'git@github.com:DataDog/sci_git_example.git' + +const oldEnv = process.env + +describe('git metadata tagging', () => { + let tracer + + beforeEach(() => { + process.env = { + ...oldEnv, + DD_GIT_COMMIT_SHA: DUMMY_GIT_SHA, + DD_TAGS: `git.repository_url:${DUMMY_REPOSITORY_URL}` + } + tracer = require('../') + return agent.load() + }) + + afterEach(() => { + agent.close() + }) + + afterEach(() => { + process.env = oldEnv + }) + + it('should include git metadata when using DD_GIT_* tags and DD_TAGS', async () => { + const span = tracer.startSpan('hello', { + tags: { + 'resource.name': '/hello/:name' + } + }) + + const childSpan = tracer.startSpan('world', { + childOf: span + }) + + childSpan.finish() + span.finish() + + return agent.use((payload) => { + const firstSpan = payload[0][0] + expect(firstSpan.meta[SCI_COMMIT_SHA]).to.equal(DUMMY_GIT_SHA) + expect(firstSpan.meta[SCI_REPOSITORY_URL]).to.equal(DUMMY_REPOSITORY_URL) + + const secondSpan = payload[0][1] + expect(secondSpan.meta[SCI_COMMIT_SHA]).not.to.exist + expect(secondSpan.meta[SCI_REPOSITORY_URL]).not.to.exist + }) + }) +})