Skip to content

Commit cba3155

Browse files
authored
feat(serverless): tag Vercel runtime spans (#9660)
* feat(serverless): tag Vercel runtime spans * refactor(serverless): collect platform span tags
1 parent cd42868 commit cba3155

4 files changed

Lines changed: 112 additions & 1 deletion

File tree

packages/dd-trace/src/config/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const { isTrue } = require('../util')
1515
const telemetry = require('../telemetry')
1616
const telemetryMetrics = require('../telemetry/metrics')
1717
const {
18+
getPlatformTags,
1819
IS_SERVERLESS,
1920
getIsGCPFunction,
2021
getIsAzureFunction,
@@ -597,6 +598,9 @@ class Config extends ConfigBase {
597598
this.tags.version = this.version
598599
}
599600
this.tags['runtime-id'] = RUNTIME_ID
601+
for (const [name, value] of Object.entries(getPlatformTags())) {
602+
this.tags[name] ??= value
603+
}
600604

601605
if (IS_SERVERLESS) {
602606
setAndTrack(this, 'telemetry.DD_INSTRUMENTATION_TELEMETRY_ENABLED', false)

packages/dd-trace/src/serverless.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,36 @@ function isInServerlessEnvironment () {
4242
return inAWSLambda || isGCPFunction || isAzureFunction
4343
}
4444

45+
/**
46+
* Gets tags describing the platform where the tracer is running.
47+
*
48+
* @returns {Record<string, string>}
49+
*/
50+
function getPlatformTags () {
51+
return getVercelTags()
52+
}
53+
54+
/**
55+
* @returns {Record<string, string>}
56+
*/
57+
function getVercelTags () {
58+
if (getEnvironmentVariable('VERCEL') !== '1') return {}
59+
60+
const tags = {
61+
'vercel.project_id': getEnvironmentVariable('VERCEL_PROJECT_ID'),
62+
'vercel.environment': getEnvironmentVariable('VERCEL_ENV'),
63+
'vercel.region': getEnvironmentVariable('VERCEL_REGION'),
64+
}
65+
66+
for (const [name, value] of Object.entries(tags)) {
67+
if (!value) delete tags[name]
68+
}
69+
70+
return tags
71+
}
72+
4573
module.exports = {
74+
getPlatformTags,
4675
getIsGCPFunction,
4776
getIsAzureFunction,
4877
enableGCPPubSubPushSubscription,

packages/dd-trace/test/plugins/agent.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ const TRACKED_NON_PREFIX_ENV_NAMES = new Set([
6161
'FUNCTIONS_WORKER_RUNTIME',
6262
'GCP_PROJECT',
6363
'K_SERVICE',
64+
'VERCEL',
65+
'VERCEL_ENV',
66+
'VERCEL_PROJECT_ID',
67+
'VERCEL_REGION',
6468
'WEBSITE_SKU',
6569
// lambda RITM target path (computed once at module load)
6670
'LAMBDA_TASK_ROOT',

packages/dd-trace/test/serverless.spec.js

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ const { describe, it, afterEach } = require('mocha')
66

77
require('./setup/core')
88

9-
const { enableGCPPubSubPushSubscription } = require('../src/serverless')
9+
const { getPlatformTags, enableGCPPubSubPushSubscription } = require('../src/serverless')
10+
const agent = require('./plugins/agent')
1011

1112
describe('enableGCPPubSubPushSubscription', () => {
1213
const originalKService = process.env.K_SERVICE
@@ -36,3 +37,76 @@ describe('enableGCPPubSubPushSubscription', () => {
3637
assert.strictEqual(enableGCPPubSubPushSubscription(), false)
3738
})
3839
})
40+
41+
describe('Vercel span metadata', () => {
42+
const environment = process.env
43+
44+
afterEach(async () => {
45+
process.env = environment
46+
await agent.close()
47+
})
48+
49+
it('does not add tags outside Vercel', async () => {
50+
process.env = {
51+
...environment,
52+
VERCEL_DEPLOYMENT_ID: 'dpl_123',
53+
VERCEL_ENV: 'preview',
54+
VERCEL_PROJECT_ID: 'prj_123',
55+
VERCEL_REGION: 'iad1',
56+
VERCEL_TARGET_ENV: 'staging',
57+
}
58+
delete process.env.VERCEL
59+
60+
const tracer = await agent.load([], [], { service: 'vercel-metadata-test' })
61+
tracer.startSpan('non-vercel-span').finish()
62+
63+
await agent.assertSomeTraces(traces => {
64+
const { meta } = traces[0][0]
65+
assert.strictEqual(meta['vercel.project_id'], undefined)
66+
assert.strictEqual(meta['vercel.environment'], undefined)
67+
assert.strictEqual(meta['vercel.region'], undefined)
68+
})
69+
})
70+
71+
it('adds present Vercel metadata to encoded spans', async () => {
72+
process.env = {
73+
...environment,
74+
VERCEL: '1',
75+
VERCEL_DEPLOYMENT_ID: 'dpl_123',
76+
VERCEL_ENV: 'preview',
77+
VERCEL_PROJECT_ID: 'prj_123',
78+
VERCEL_REGION: 'iad1',
79+
VERCEL_TARGET_ENV: 'staging',
80+
}
81+
82+
const tracer = await agent.load([], [], {
83+
service: 'vercel-metadata-test',
84+
tags: { 'vercel.region': 'custom-region' },
85+
})
86+
tracer.startSpan('vercel-span').finish()
87+
88+
await agent.assertSomeTraces(traces => {
89+
assert.deepStrictEqual(Object.fromEntries(
90+
Object.entries(traces[0][0].meta).filter(([name]) => name.startsWith('vercel.'))
91+
), {
92+
'vercel.project_id': 'prj_123',
93+
'vercel.environment': 'preview',
94+
'vercel.region': 'custom-region',
95+
})
96+
})
97+
})
98+
99+
it('discovers only present Vercel metadata as platform tags', () => {
100+
process.env = {
101+
...environment,
102+
VERCEL: '1',
103+
VERCEL_ENV: 'preview',
104+
VERCEL_PROJECT_ID: 'prj_123',
105+
}
106+
107+
assert.deepStrictEqual(getPlatformTags(), {
108+
'vercel.project_id': 'prj_123',
109+
'vercel.environment': 'preview',
110+
})
111+
})
112+
})

0 commit comments

Comments
 (0)