diff --git a/javascript/sentry-conventions/src/attributes.ts b/javascript/sentry-conventions/src/attributes.ts index 71820f4c..6df18f5f 100644 --- a/javascript/sentry-conventions/src/attributes.ts +++ b/javascript/sentry-conventions/src/attributes.ts @@ -3151,6 +3151,27 @@ export const DB_STATEMENT = 'db.statement'; */ export type DB_STATEMENT_TYPE = string; +// Path: model/attributes/db/db__stored_procedure__name.json + +/** + * The name of a stored procedure being called. `db.stored_procedure.name` + * + * Attribute Value Type: `string` {@link DB_STORED_PROCEDURE_NAME_TYPE} + * + * Contains PII: maybe + * + * Attribute defined in OTEL: Yes + * Visibility: public + * + * @example "GetUserById" + */ +export const DB_STORED_PROCEDURE_NAME = 'db.stored_procedure.name'; + +/** + * Type for {@link DB_STORED_PROCEDURE_NAME} db.stored_procedure.name + */ +export type DB_STORED_PROCEDURE_NAME_TYPE = string; + // Path: model/attributes/db/db__system.json /** @@ -13375,6 +13396,7 @@ export const ATTRIBUTE_TYPE: Record = { [DB_REDIS_PARAMETERS]: 'string[]', [DB_SQL_BINDINGS]: 'string[]', [DB_STATEMENT]: 'string', + [DB_STORED_PROCEDURE_NAME]: 'string', [DB_SYSTEM]: 'string', [DB_SYSTEM_NAME]: 'string', [DB_USER]: 'string', @@ -13979,6 +14001,7 @@ export type AttributeName = | typeof DB_REDIS_PARAMETERS | typeof DB_SQL_BINDINGS | typeof DB_STATEMENT + | typeof DB_STORED_PROCEDURE_NAME | typeof DB_SYSTEM | typeof DB_SYSTEM_NAME | typeof DB_USER @@ -16429,6 +16452,17 @@ export const ATTRIBUTE_METADATA: Record = { aliases: [DB_QUERY_TEXT], changelog: [{ version: '0.4.0', prs: [199] }, { version: '0.1.0', prs: [61, 127] }, { version: '0.0.0' }], }, + [DB_STORED_PROCEDURE_NAME]: { + brief: 'The name of a stored procedure being called.', + type: 'string', + pii: { + isPii: 'maybe', + }, + isInOtel: true, + visibility: 'public', + example: 'GetUserById', + changelog: [{ version: 'next', prs: [398] }], + }, [DB_SYSTEM]: { brief: 'An identifier for the database management system (DBMS) product being used. See [OpenTelemetry docs](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-spans.md#notes-and-well-known-identifiers-for-dbsystem) for a list of well-known identifiers.', @@ -22509,6 +22543,7 @@ export type Attributes = { [DB_REDIS_PARAMETERS]?: DB_REDIS_PARAMETERS_TYPE; [DB_SQL_BINDINGS]?: DB_SQL_BINDINGS_TYPE; [DB_STATEMENT]?: DB_STATEMENT_TYPE; + [DB_STORED_PROCEDURE_NAME]?: DB_STORED_PROCEDURE_NAME_TYPE; [DB_SYSTEM]?: DB_SYSTEM_TYPE; [DB_SYSTEM_NAME]?: DB_SYSTEM_NAME_TYPE; [DB_USER]?: DB_USER_TYPE; diff --git a/model/attributes/db/db__stored_procedure__name.json b/model/attributes/db/db__stored_procedure__name.json new file mode 100644 index 00000000..d26e2515 --- /dev/null +++ b/model/attributes/db/db__stored_procedure__name.json @@ -0,0 +1,17 @@ +{ + "key": "db.stored_procedure.name", + "brief": "The name of a stored procedure being called.", + "type": "string", + "pii": { + "key": "maybe" + }, + "is_in_otel": true, + "example": "GetUserById", + "visibility": "public", + "changelog": [ + { + "version": "next", + "prs": [398] + } + ] +} diff --git a/python/src/sentry_conventions/attributes.py b/python/src/sentry_conventions/attributes.py index 9ad8cf4e..b814c444 100644 --- a/python/src/sentry_conventions/attributes.py +++ b/python/src/sentry_conventions/attributes.py @@ -2024,6 +2024,19 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): Example: "SELECT * FROM users" """ + # Path: model/attributes/db/db__stored_procedure__name.json + DB_STORED_PROCEDURE_NAME: Literal["db.stored_procedure.name"] = ( + "db.stored_procedure.name" + ) + """The name of a stored procedure being called. + + Type: str + Contains PII: maybe + Defined in OTEL: Yes + Visibility: public + Example: "GetUserById" + """ + # Path: model/attributes/db/db__system.json DB_SYSTEM: Literal["db.system"] = "db.system" """An identifier for the database management system (DBMS) product being used. See [OpenTelemetry docs](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-spans.md#notes-and-well-known-identifiers-for-dbsystem) for a list of well-known identifiers. @@ -9794,6 +9807,17 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): ChangelogEntry(version="0.0.0"), ], ), + "db.stored_procedure.name": AttributeMetadata( + brief="The name of a stored procedure being called.", + type=AttributeType.STRING, + pii=PiiInfo(isPii=IsPii.MAYBE), + is_in_otel=True, + visibility=Visibility.PUBLIC, + example="GetUserById", + changelog=[ + ChangelogEntry(version="next", prs=[398]), + ], + ), "db.system": AttributeMetadata( brief="An identifier for the database management system (DBMS) product being used. See [OpenTelemetry docs](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-spans.md#notes-and-well-known-identifiers-for-dbsystem) for a list of well-known identifiers.", type=AttributeType.STRING, @@ -16125,6 +16149,7 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): "db.redis.parameters": List[str], "db.sql.bindings": List[str], "db.statement": str, + "db.stored_procedure.name": str, "db.system": str, "db.system.name": str, "db.user": str, diff --git a/test/name.test.ts b/test/name.test.ts index 4177dd8a..c1c513a4 100644 --- a/test/name.test.ts +++ b/test/name.test.ts @@ -6,8 +6,10 @@ import { describe, expect, it } from 'vitest'; import schema from '../schemas/name.schema.json'; import type { NameJson } from '../scripts/types'; +import { attributeKeyToFileName } from '../scripts/utils'; const namesFolder = path.resolve(__dirname, '../model/name'); +const attributesFolder = path.resolve(__dirname, '../model/attributes'); describe('Name JSON', async () => { const filesIterator = fs.promises.glob(`${namesFolder}/*.json`); @@ -42,6 +44,35 @@ describe('Name JSON', async () => { expect(lastNameTemplate, "the last template shouldn't reference any attributes").not.toContain('{{'); } }); + + it('only references existing attributes', async () => { + const placeholder = /\{\{([^}]+)\}\}/g; + const missing: string[] = []; + + for (const operation of content.operations) { + for (const tmpl of operation.templates) { + for (const match of tmpl.matchAll(placeholder)) { + const key = match[1] as string; + const fileName = attributeKeyToFileName(key); + const namespace = key.includes('.') ? (key.split('.')[0] as string) : undefined; + const filePath = namespace + ? path.join(attributesFolder, namespace, fileName) + : path.join(attributesFolder, fileName); + + const exists = await fs.promises + .access(filePath, fs.constants.F_OK) + .then(() => true) + .catch(() => false); + + if (!exists) { + missing.push(key); + } + } + } + } + + expect(missing, `template attributes without definitions: ${missing.join(', ')}`).toEqual([]); + }); }); } });