-
Notifications
You must be signed in to change notification settings - Fork 977
feat(semantic-conventions): update semantic conventions to v1.29.0 #5356
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
Merged
Merged
Changes from 8 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
dbbcd31
feat(semantic-conventions): update semantic conventions to v1.29.0
trentm 1f52030
markdown lint fix, add PR number
trentm 1022386
Merge branch 'main' into tm-semconv-1.29.0
trentm 3b786b1
alternative weaver config to skip attributes that accidentally don't …
trentm fddc720
style changes to semconv changelog entry
trentm 214cfd1
slight tweak to the comments on deprecated exports (include the value…
trentm f438ae3
add a note about a coming weaver improvement that we'd like to use in…
trentm d7a4760
Merge branch 'main' into tm-semconv-1.29.0
trentm 19be0f7
fix typo
trentm 7296579
typo
trentm 3463e5d
improve usage, give a working exapmle comparing two versions; break u…
trentm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| opentelemetry-specification/ | ||
| semantic-conventions/ | ||
| tmp-changelog-gen/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,377 @@ | ||
| #!/usr/bin/env node | ||
| /** | ||
| * A script to generate a meaningful changelog entry for an update in | ||
| * semantic conventions version. | ||
| * | ||
| * Usage: | ||
| * vi scripts/semconv/generate.sh # Typically update SPEC_VERSION to latest. | ||
| * ./scripts/semconv/generate.sh # Re-generate the semconv package exports. | ||
| * ./scripts/semconv/changelog-gen.sh [aVer [bVer]] | ||
| * | ||
| * where: | ||
| * - `aVer` is the base version of `@opentelemetry/semantic-conventions` to | ||
| * which to compare, e.g. "1.28.0". This defaults to the latest version | ||
| * published to npm. | ||
| * - `bVer` is the version being compared against `aVer`. This defaults to | ||
JamieDanielson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| * "local", which uses the local build in ../../semantic-conventions in this | ||
| * repo. | ||
| * | ||
| * The last command (this script) will output a text block that can be used | ||
| * in "semantic-conventions/CHANGELOG.md" (and also perhaps in the PR | ||
| * desciption). | ||
trentm marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| */ | ||
|
|
||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const globSync = require('glob').sync; | ||
| const {execSync} = require('child_process'); | ||
| const rimraf = require('rimraf'); | ||
|
|
||
| const TOP = path.resolve(__dirname, '..', '..'); | ||
| const TMP_DIR = path.join(__dirname, 'tmp-changelog-gen'); | ||
|
|
||
| /** | ||
| * Convert a string to an HTML anchor string, as Markdown does for headers. | ||
| */ | ||
| function slugify(s) { | ||
| const slug = s.trim().replace(/ /g, '-').replace(/[^\w-]/g, '') | ||
| return slug; | ||
| } | ||
|
|
||
| /** | ||
| * Given some JS `src` (typically from OTel build/esnext/... output), return | ||
| * whether the given export name `k` is marked `@deprecated`. | ||
| * | ||
| * Some of this parsing is shared with "contrib/scripts/gen-semconv-ts.js". | ||
| * | ||
| * @returns {boolean|string} `false` if not deprecated, a string deprecated | ||
| * message if deprecated and the message could be determined, otherwise | ||
| * `true` if marked deprecated. | ||
| */ | ||
| function isDeprecated(src, k) { | ||
| const re = new RegExp(`^export const ${k} = .*;$`, 'm') | ||
| const match = re.exec(src); | ||
| if (!match) { | ||
| throw new Error(`could not find the "${k}" export in semconv build/esnext/ source files`); | ||
| } | ||
|
|
||
| // Find a preceding block comment, if any. | ||
| const WHITESPACE_CHARS = [' ', '\t', '\n', '\r']; | ||
| let idx = match.index - 1; | ||
| while (idx >=1 && WHITESPACE_CHARS.includes(src[idx])) { | ||
| idx--; | ||
| } | ||
| if (src.slice(idx-1, idx+1) !== '*/') { | ||
| // There is not a block comment preceding the export. | ||
| return false; | ||
| } | ||
| idx -= 2; | ||
| while (idx >= 0) { | ||
| if (src[idx] === '/' && src[idx+1] === '*') { | ||
| // Found the start of the block comment. | ||
| const blockComment = src.slice(idx, match.index); | ||
| if (!blockComment.includes('@deprecated')) { | ||
| return false; | ||
| } | ||
| const deprecatedMsgMatch = /^\s*\*\s*@deprecated\s+(.*)$/m.exec(blockComment); | ||
| if (deprecatedMsgMatch) { | ||
| return deprecatedMsgMatch[1]; | ||
| } else { | ||
| return true; | ||
| } | ||
| } | ||
| idx--; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| function summarizeChanges({prev, curr, prevSrc, currSrc}) { | ||
| const prevNames = new Set(Object.keys(prev)); | ||
| const currNames = new Set(Object.keys(curr)); | ||
| const valChanged = (a, b) => { | ||
| if (typeof a !== typeof b) { | ||
| return true; | ||
| } else if (typeof a === 'function') { | ||
| return a.toString() !== b.toString(); | ||
| } else { | ||
| return a !== b; | ||
| } | ||
| }; | ||
| const isNewlyDeprecated = (k) => { | ||
| const isPrevDeprecated = prevNames.has(k) && isDeprecated(prevSrc, k); | ||
| const isCurrDeprecated = currNames.has(k) && isDeprecated(currSrc, k); | ||
| if (isPrevDeprecated && !isCurrDeprecated) { | ||
| throw new Error(`semconv export '${k}' was *un*-deprecated in this release!? Wassup?`); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
😄 |
||
| } | ||
| return (!isPrevDeprecated && isCurrDeprecated); | ||
| }; | ||
|
|
||
| // Determine changes. | ||
| const changes = []; | ||
| for (let k of Object.keys(curr)) { | ||
| if (!prevNames.has(k)) { | ||
| // 'ns' is the "namespace". The value here is wrong for "FEATURE_FLAG", | ||
| // "GEN_AI", etc. But good enough for the usage below. | ||
| const ns = /^(ATTR_|METRIC_|)?([^_]+)_/.exec(k)[2]; | ||
| changes.push({type: 'added', k, v: curr[k], ns}); | ||
| } else if (valChanged(curr[k], prev[k])) { | ||
| changes.push({type: 'changed', k, v: curr[k], prevV: prev[k]}); | ||
| } else { | ||
| const deprecatedResult = isNewlyDeprecated(k); | ||
| if (deprecatedResult) { | ||
| changes.push({type: 'deprecated', k, v: curr[k], deprecatedResult}); | ||
| } | ||
| } | ||
| } | ||
| for (let k of Object.keys(prev)) { | ||
| if (!currNames.has(k)) { | ||
| changes.push({change: 'removed', k, prevV: prev[k]}); | ||
| } | ||
| } | ||
|
|
||
| // Create a set of summaries, one for each change type. | ||
| let haveChanges = changes.length > 0; | ||
| const summaryFromChangeType = { | ||
| removed: [], | ||
| changed: [], | ||
| deprecated: [], | ||
| added: [], | ||
| } | ||
| const execSummaryFromChangeType = { | ||
| removed: null, | ||
| changed: null, | ||
| deprecated: null, | ||
| added: null, | ||
| }; | ||
|
|
||
| const removed = changes.filter(ch => ch.type === 'removed'); | ||
| let summary = summaryFromChangeType.removed; | ||
| if (removed.length) { | ||
| execSummaryFromChangeType.removed = `${removed.length} removed exports`; | ||
| if (summary.length) { summary.push(''); } | ||
| let last; | ||
| const longest = removed.reduce((acc, ch) => Math.max(acc, ch.k.length), 0); | ||
| removed.forEach(ch => { | ||
| if (last && ch.ns !== last.ns) { summary.push(''); } | ||
| const cindent = ' '.repeat(longest - ch.k.length + 1); | ||
|
|
||
| const prevVRepr = ch.prevV.includes('_VALUE_') ? JSON.stringify(ch.prevV) : ch.prevV; | ||
| summary.push(`${ch.k}${cindent}// ${prevVRepr}`); | ||
|
|
||
| last = ch; | ||
| }); | ||
| } | ||
|
|
||
| const changed = changes.filter(ch => ch.type === 'changed'); | ||
| summary = summaryFromChangeType.changed; | ||
| if (changed.length) { | ||
| execSummaryFromChangeType.changed = `${changed.length} exported values changed`; | ||
| if (summary.length) { summary.push(''); } | ||
| let last; | ||
| const longest = changed.reduce((acc, ch) => Math.max(acc, ch.k.length), 0); | ||
| changed.forEach(ch => { | ||
| if (last && ch.ns !== last.ns) { summary.push(''); } | ||
| const cindent = ' '.repeat(longest - ch.k.length + 1); | ||
|
|
||
| const prevVRepr = ch.k.includes('_VALUE_') ? JSON.stringify(ch.prevV) : ch.prevV; | ||
| const vRepr = ch.k.includes('_VALUE_') ? JSON.stringify(ch.v) : ch.v; | ||
| summary.push(`${ch.k}${cindent}// ${prevVRepr} -> ${vRepr}`); | ||
|
|
||
| last = ch; | ||
| }); | ||
| } | ||
|
|
||
| const deprecated = changes.filter(ch => ch.type === 'deprecated'); | ||
| summary = summaryFromChangeType.deprecated; | ||
| if (deprecated.length) { | ||
| execSummaryFromChangeType.deprecated = `${deprecated.length} newly deprecated exports`; | ||
| if (summary.length) { summary.push(''); } | ||
| let last; | ||
| const longest = deprecated.reduce((acc, ch) => Math.max(acc, ch.k.length), 0); | ||
| deprecated.forEach(ch => { | ||
| if (last && ch.ns !== last.ns) { summary.push(''); } | ||
| const cindent = ' '.repeat(longest - ch.k.length + 1); | ||
|
|
||
| if (typeof ch.deprecatedResult === 'string') { | ||
| summary.push(`${ch.k}${cindent}// ${ch.v}: ${ch.deprecatedResult}`); | ||
| } else { | ||
| summary.push(ch.k) | ||
| } | ||
|
|
||
| last = ch; | ||
| }); | ||
| } | ||
|
|
||
| const added = changes.filter(ch => ch.type === 'added'); | ||
| summary = summaryFromChangeType.added; | ||
| if (added.length) { | ||
| execSummaryFromChangeType.added = `${added.length} added exports`; | ||
| let last, lastAttr; | ||
| const longest = added.reduce((acc, ch) => Math.max(acc, ch.k.length), 0); | ||
| added.forEach(ch => { | ||
| if (last && ch.ns !== last.ns) { summary.push(''); } | ||
| let indent = ''; | ||
| if (lastAttr && ch.k.startsWith(lastAttr.k.slice('ATTR_'.length))) { | ||
| indent = ' '; | ||
| } | ||
| const cindent = ' '.repeat(longest - ch.k.length + 1); | ||
|
|
||
| const vRepr = ch.k.includes('_VALUE_') ? JSON.stringify(ch.v) : ch.v | ||
| summary.push(`${indent}${ch.k}${cindent}// ${vRepr}`); | ||
|
|
||
| last = ch; | ||
| if (ch.k.startsWith('ATTR_')) { | ||
| lastAttr = ch; | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| return { | ||
| haveChanges, | ||
| execSummaryFromChangeType, | ||
| summaryFromChangeType | ||
| }; | ||
| } | ||
|
|
||
|
|
||
| function semconvChangelogGen(aVer=undefined, bVer=undefined) { | ||
|
|
||
| console.log(`Creating tmp working dir "${TMP_DIR}"`); | ||
| rimraf.sync(TMP_DIR); | ||
| fs.mkdirSync(TMP_DIR); | ||
|
|
||
| const localDir = path.join(TOP, 'semantic-conventions'); | ||
| const pj = JSON.parse(fs.readFileSync(path.join(localDir, 'package.json'))); | ||
| const pkgInfo = JSON.parse(execSync(`npm info -j ${pj.name}`)) | ||
|
|
||
| let aDir; | ||
| if (!aVer) { | ||
| aVer = pkgInfo.version; // By default compare to latest published version. | ||
| } | ||
| aDir = path.join(TMP_DIR, aVer, 'package'); | ||
| if (!fs.existsSync(aDir)) { | ||
| console.log(`Downloading and extracting @opentelemetry/semantic-conventions@${aVer}`) | ||
| const tarballUrl = `https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-${aVer}.tgz`; | ||
| fs.mkdirSync(path.dirname(aDir)); | ||
| execSync(`curl -sf -o - ${tarballUrl} | tar xzf -`, | ||
| { cwd: path.dirname(aDir) }); | ||
| } | ||
|
|
||
| let bDir, bSemconvVer; | ||
| if (!bVer) { | ||
| bVer = 'local' // By default comparison target is the local build. | ||
| bDir = localDir; | ||
|
|
||
| // Determine target spec ver. | ||
| const generateShPath = path.join(__dirname, 'generate.sh'); | ||
| const specVerRe = /^SPEC_VERSION=(.*)$/m; | ||
| const specVerMatch = specVerRe.exec(fs.readFileSync(generateShPath)); | ||
| if (!specVerMatch) { | ||
| throw new Error(`could not determine current semconv SPEC_VERSION: ${specVerRe} did not match in ${generateShPath}`); | ||
| } | ||
| bSemconvVer = specVerMatch[1].trim(); | ||
| console.log('Target Semantic Conventions ver is:', bSemconvVer); | ||
| } else { | ||
| bSemconvVer = 'v' + bVer; | ||
| bDir = path.join(TMP_DIR, bVer, 'package'); | ||
| console.log(`Downloading and extracting @opentelemetry/semantic-conventions@${bVer}`) | ||
| const tarballUrl = `https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-${bVer}.tgz`; | ||
| fs.mkdirSync(path.dirname(bDir)); | ||
| execSync(`curl -sf -o - ${tarballUrl} | tar xzf -`, | ||
| { cwd: path.dirname(bDir) }); | ||
| } | ||
|
|
||
| console.log(`Comparing exports between versions ${aVer} and ${bVer}`) | ||
| const stableChInfo = summarizeChanges({ | ||
| // require('.../build/src/stable_*.js') from previous and current. | ||
| prev: Object.assign(...globSync(path.join(aDir, 'build/src/stable_*.js')).map(require)), | ||
| curr: Object.assign(...globSync(path.join(bDir, 'build/src/stable_*.js')).map(require)), | ||
| // Load '.../build/esnext/stable_*.js' sources to use for parsing jsdoc comments. | ||
| prevSrc: globSync(path.join(aDir, 'build/esnext/stable_*.js')) | ||
| .map(f => fs.readFileSync(f, 'utf8')) | ||
| .join('\n\n'), | ||
| currSrc: globSync(path.join(bDir, 'build/esnext/stable_*.js')) | ||
| .map(f => fs.readFileSync(f, 'utf8')) | ||
| .join('\n\n'), | ||
| }); | ||
| const unstableChInfo = summarizeChanges({ | ||
| prev: Object.assign(...globSync(path.join(aDir, 'build/src/experimental_*.js')).map(require)), | ||
| curr: Object.assign(...globSync(path.join(bDir, 'build/src/experimental_*.js')).map(require)), | ||
| prevSrc: globSync(path.join(aDir, 'build/esnext/experimental_*.js')) | ||
| .map(f => fs.readFileSync(f, 'utf8')) | ||
| .join('\n\n'), | ||
| currSrc: globSync(path.join(bDir, 'build/esnext/experimental_*.js')) | ||
| .map(f => fs.readFileSync(f, 'utf8')) | ||
| .join('\n\n'), | ||
| }); | ||
|
|
||
| // Render the "change info" into a Markdown summary for the changelog. | ||
| const changeTypes = ['removed', 'changed', 'deprecated', 'added']; | ||
| let execSummaryFromChInfo = (chInfo) => { | ||
| const parts = changeTypes | ||
| .map(chType => chInfo.execSummaryFromChangeType[chType]) | ||
| .filter(s => typeof(s) === 'string'); | ||
| if (parts.length) { | ||
| return parts.join(', '); | ||
| } else { | ||
| return 'none'; | ||
| } | ||
| } | ||
| const changelogEntry = [` | ||
| * feat: update semantic conventions to ${bSemconvVer} [#NNNN] | ||
| * Semantic Conventions ${bSemconvVer}: | ||
| [changelog](https://github.com/open-telemetry/semantic-conventions/blob/main/CHANGELOG.md#${slugify(bSemconvVer)}) | | ||
| [latest docs](https://opentelemetry.io/docs/specs/semconv/) | ||
| * \`@opentelemetry/semantic-conventions\` (stable) changes: *${execSummaryFromChInfo(stableChInfo)}* | ||
| * \`@opentelemetry/semantic-conventions/incubating\` (unstable) changes: *${execSummaryFromChInfo(unstableChInfo)}* | ||
| `]; | ||
|
|
||
| if (stableChInfo.haveChanges) { | ||
| changelogEntry.push(`#### Stable changes in ${bSemconvVer}\n`); | ||
| for (let changeType of changeTypes) { | ||
| const summary = stableChInfo.summaryFromChangeType[changeType]; | ||
| if (summary.length) { | ||
| changelogEntry.push(`<details open> | ||
| <summary>${stableChInfo.execSummaryFromChangeType[changeType]}</summary> | ||
|
|
||
| \`\`\`js | ||
| ${summary.join('\n')} | ||
| \`\`\` | ||
|
|
||
| </details> | ||
| `); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (unstableChInfo.haveChanges) { | ||
| changelogEntry.push(`#### Unstable changes in ${bSemconvVer}\n`); | ||
| for (let changeType of changeTypes) { | ||
| const summary = unstableChInfo.summaryFromChangeType[changeType]; | ||
| if (summary.length) { | ||
| changelogEntry.push(`<details> | ||
| <summary>${unstableChInfo.execSummaryFromChangeType[changeType]}</summary> | ||
|
|
||
| \`\`\`js | ||
| ${summary.join('\n')} | ||
| \`\`\` | ||
|
|
||
| </details> | ||
| `); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return changelogEntry.join('\n'); | ||
| } | ||
|
|
||
| function main() { | ||
| const [aVer, bVer] = process.argv.slice(2); | ||
| const s = semconvChangelogGen(aVer, bVer); | ||
| console.log('The following could be added to the top "Enhancement" section of "semantic-conventions/CHANGELOG.md":'); | ||
| console.log('\n- - -'); | ||
| console.log(s) | ||
| console.log('- - -'); | ||
| } | ||
|
|
||
| main(); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,11 +7,11 @@ ROOT_DIR="${SCRIPT_DIR}/../../" | |
|
|
||
| # Get latest version by running `git tag -l --sort=version:refname | tail -1` | ||
| # ... in [email protected]:open-telemetry/semantic-conventions.git | ||
| SPEC_VERSION=v1.28.0 | ||
| SPEC_VERSION=v1.29.0 | ||
| # ... in [email protected]:open-telemetry/weaver.git | ||
| GENERATOR_VERSION=v0.10.0 | ||
|
|
||
| # When running on windows and your are getting references to ";C" (like Telemetry;C) | ||
| # When running on windows and you are getting references to ";C" (like Telemetry;C) | ||
| # then this is an issue with the bash shell, so first run the following in your shell: | ||
| # export MSYS_NO_PATHCONV=1 | ||
|
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.