From 4f6bd1232711c86f617fa7789d87e915d2e10023 Mon Sep 17 00:00:00 2001 From: Thomas Hunter II Date: Thu, 23 Oct 2025 15:17:21 -0700 Subject: [PATCH 1/2] collect tags --- packages/dd-trace/src/process-tags/index.js | 26 +++++++++++++++++++++ packages/dd-trace/src/proxy.js | 2 ++ 2 files changed, 28 insertions(+) create mode 100644 packages/dd-trace/src/process-tags/index.js diff --git a/packages/dd-trace/src/process-tags/index.js b/packages/dd-trace/src/process-tags/index.js new file mode 100644 index 00000000000..919763212de --- /dev/null +++ b/packages/dd-trace/src/process-tags/index.js @@ -0,0 +1,26 @@ +'use strict' + +const path = require('node:path') +const pkg = require('../pkg') + +const CURRENT_WORKING_DIRECTORY = process.cwd() +const ENTRYPOINT_PATH = require.main?.filename || '' + +module.exports = function processTags () { + return { + // last segment of the current working directory, e.g. /foo/bar/baz/ -> baz + 'entrypoint.workdir': path.basename(CURRENT_WORKING_DIRECTORY), + + // the entrypoint script filename without the extension, e.g. /foo/bar/baz/banana.js -> banana + 'entrypoint.name': path.basename(ENTRYPOINT_PATH, path.extname(ENTRYPOINT_PATH)), + + // always script for JavaScript applications + 'entrypoint.type': 'script', + + // the immediate parent directory name of the entrypoint script, e.g. /foo/bar/baz/banana.js -> baz + 'entrypoint.basedir': path.basename(path.dirname(ENTRYPOINT_PATH)), + + // the .name field from the application's package.json + 'package.json.name': pkg.name + } +} diff --git a/packages/dd-trace/src/proxy.js b/packages/dd-trace/src/proxy.js index 13651fa5697..add01f8d6a6 100644 --- a/packages/dd-trace/src/proxy.js +++ b/packages/dd-trace/src/proxy.js @@ -18,6 +18,7 @@ const { removeBaggageItem, removeAllBaggageItems } = require('./baggage') +const getProcessTags = require('./process-tags') class LazyModule { constructor (provider) { @@ -78,6 +79,7 @@ class Tracer extends NoopProxy { this.getAllBaggageItems = getAllBaggageItems this.removeBaggageItem = removeBaggageItem this.removeAllBaggageItems = removeAllBaggageItems + this.processTags = getProcessTags() // these requires must work with esm bundler this._modules = { From 79d07acf7f8cfea6ee7711196ba9b2a74c95b360 Mon Sep 17 00:00:00 2001 From: Thomas Hunter II Date: Mon, 27 Oct 2025 13:59:03 -0400 Subject: [PATCH 2/2] serializer --- packages/dd-trace/src/process-tags/index.js | 60 +++++++++++++++++---- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/packages/dd-trace/src/process-tags/index.js b/packages/dd-trace/src/process-tags/index.js index 919763212de..d6e023c3e61 100644 --- a/packages/dd-trace/src/process-tags/index.js +++ b/packages/dd-trace/src/process-tags/index.js @@ -2,25 +2,67 @@ const path = require('node:path') const pkg = require('../pkg') +const { tags } = require('../config_defaults') const CURRENT_WORKING_DIRECTORY = process.cwd() const ENTRYPOINT_PATH = require.main?.filename || '' +console.log('ENTRYPOINT_PATH:', ENTRYPOINT_PATH) +console.log('CURRENT_WORKING_DIRECTORY:', CURRENT_WORKING_DIRECTORY) -module.exports = function processTags () { - return { - // last segment of the current working directory, e.g. /foo/bar/baz/ -> baz - 'entrypoint.workdir': path.basename(CURRENT_WORKING_DIRECTORY), +// if we don't have a value we should send nothing at all +// e.g. undefined which is dropped upon JSON serialization + +// $ cd /foo/bar && node baz/banana.js +// entrypoint.workdir = bar +// entrypoint.name = banana +// entrypoint.type = script +// entrypoint.basedir = baz +// package.json.name = + +module.exports = function getProcessTags () { + // this list is sorted alphabetically for consistent serialization + const tags = [ + // the immediate parent directory name of the entrypoint script, e.g. /foo/bar/baz/banana.js -> baz + ['entrypoint.basedir', ENTRYPOINT_PATH === '' ? undefined : path.basename(path.dirname(ENTRYPOINT_PATH))], // the entrypoint script filename without the extension, e.g. /foo/bar/baz/banana.js -> banana - 'entrypoint.name': path.basename(ENTRYPOINT_PATH, path.extname(ENTRYPOINT_PATH)), + ['entrypoint.name', path.basename(ENTRYPOINT_PATH, path.extname(ENTRYPOINT_PATH)) || undefined], // always script for JavaScript applications - 'entrypoint.type': 'script', + ['entrypoint.type', 'script'], - // the immediate parent directory name of the entrypoint script, e.g. /foo/bar/baz/banana.js -> baz - 'entrypoint.basedir': path.basename(path.dirname(ENTRYPOINT_PATH)), + // last segment of the current working directory, e.g. /foo/bar/baz/ -> baz + ['entrypoint.workdir', path.basename(CURRENT_WORKING_DIRECTORY) || undefined], // the .name field from the application's package.json - 'package.json.name': pkg.name + ['package.json.name', pkg.name || undefined] + ] + + const serialized = serialize(tags) + + return { + tags, + serialized } } + +function serialize(tags) { + const intermediary = [] + for (let [name, value] of tags) { + if (value === undefined) continue + intermediary.push(`${name}:${sanitize(value)}`) + } + return intermediary.join(',') +} + +/** + * Sanitize a process tag value + * + * @param {string} value + * @returns {string} + */ +function sanitize(value) { + return String(value) + .toLowerCase() + .replaceAll(/[^a-zA-Z0-9/_.-]/g, '_') +} \ No newline at end of file