From 5d581face34b2f95945fb51d58fd13570ddcfd2e Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Thu, 9 Jul 2026 14:48:24 +0200 Subject: [PATCH 1/3] feat(attribute): Add `koa.type` --- .../sentry-conventions/src/attributes.ts | 35 +++++++++++++++++++ model/attributes/koa/koa__type.json | 18 ++++++++++ python/src/sentry_conventions/attributes.py | 25 +++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 model/attributes/koa/koa__type.json diff --git a/javascript/sentry-conventions/src/attributes.ts b/javascript/sentry-conventions/src/attributes.ts index 933c1e6f..2bc8b332 100644 --- a/javascript/sentry-conventions/src/attributes.ts +++ b/javascript/sentry-conventions/src/attributes.ts @@ -8259,6 +8259,27 @@ export const JVM_THREAD_STATE = 'jvm.thread.state'; */ export type JVM_THREAD_STATE_TYPE = string; +// Path: model/attributes/koa/koa__type.json + +/** + * The type of the Koa layer that handled the request. `koa.type` + * + * Attribute Value Type: `string` {@link KOA_TYPE_TYPE} + * + * Apply Scrubbing: manual + * + * Attribute defined in OTEL: No + * Visibility: public + * + * @example "router" + */ +export const KOA_TYPE = 'koa.type'; + +/** + * Type for {@link KOA_TYPE} koa.type + */ +export type KOA_TYPE_TYPE = string; + // Path: model/attributes/lcp.json /** @@ -15264,6 +15285,7 @@ export const ATTRIBUTE_TYPE: Record = { 'jvm.memory.type': 'string', 'jvm.thread.daemon': 'boolean', 'jvm.thread.state': 'string', + 'koa.type': 'string', lcp: 'double', 'lcp.element': 'string', 'lcp.id': 'string', @@ -15941,6 +15963,7 @@ export type AttributeName = | typeof JVM_MEMORY_TYPE | typeof JVM_THREAD_DAEMON | typeof JVM_THREAD_STATE + | typeof KOA_TYPE | typeof LCP | typeof LCP_ELEMENT | typeof LCP_ID @@ -21343,6 +21366,17 @@ export const ATTRIBUTE_METADATA: Record = { example: 'blocked', changelog: [{ version: '0.1.0', prs: [127] }, { version: '0.0.0' }], }, + 'koa.type': { + brief: 'The type of the Koa layer that handled the request.', + type: 'string', + applyScrubbing: { + key: 'manual', + }, + isInOtel: false, + visibility: 'public', + example: 'router', + changelog: [{ version: 'next', prs: [471], description: 'Added koa.type attribute' }], + }, lcp: { brief: 'The value of the recorded Largest Contentful Paint (LCP) web vital', type: 'double', @@ -25559,6 +25593,7 @@ export type Attributes = { [JVM_MEMORY_TYPE]?: JVM_MEMORY_TYPE_TYPE; [JVM_THREAD_DAEMON]?: JVM_THREAD_DAEMON_TYPE; [JVM_THREAD_STATE]?: JVM_THREAD_STATE_TYPE; + [KOA_TYPE]?: KOA_TYPE_TYPE; [LCP]?: LCP_TYPE; [LCP_ELEMENT]?: LCP_ELEMENT_TYPE; [LCP_ID]?: LCP_ID_TYPE; diff --git a/model/attributes/koa/koa__type.json b/model/attributes/koa/koa__type.json new file mode 100644 index 00000000..9c0a5d45 --- /dev/null +++ b/model/attributes/koa/koa__type.json @@ -0,0 +1,18 @@ +{ + "key": "koa.type", + "brief": "The type of the Koa layer that handled the request.", + "type": "string", + "apply_scrubbing": { + "key": "manual" + }, + "is_in_otel": false, + "example": "router", + "visibility": "public", + "changelog": [ + { + "version": "next", + "prs": [471], + "description": "Added koa.type attribute" + } + ] +} diff --git a/python/src/sentry_conventions/attributes.py b/python/src/sentry_conventions/attributes.py index 4eda9e50..67929923 100644 --- a/python/src/sentry_conventions/attributes.py +++ b/python/src/sentry_conventions/attributes.py @@ -4947,6 +4947,17 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): Example: "blocked" """ + # Path: model/attributes/koa/koa__type.json + KOA_TYPE: Literal["koa.type"] = "koa.type" + """The type of the Koa layer that handled the request. + + Type: str + Apply Scrubbing: manual + Defined in OTEL: No + Visibility: public + Example: "router" + """ + # Path: model/attributes/lcp/lcp__element.json LCP_ELEMENT: Literal["lcp.element"] = "lcp.element" """The dom element responsible for the largest contentful paint. @@ -14074,6 +14085,19 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): ChangelogEntry(version="0.0.0"), ], ), + "koa.type": AttributeMetadata( + brief="The type of the Koa layer that handled the request.", + type=AttributeType.STRING, + apply_scrubbing=ApplyScrubbingInfo(key=ApplyScrubbing.MANUAL), + is_in_otel=False, + visibility=Visibility.PUBLIC, + example="router", + changelog=[ + ChangelogEntry( + version="next", prs=[471], description="Added koa.type attribute" + ), + ], + ), "lcp.element": AttributeMetadata( brief="The dom element responsible for the largest contentful paint.", type=AttributeType.STRING, @@ -18452,6 +18476,7 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): "jvm.memory.type": str, "jvm.thread.daemon": bool, "jvm.thread.state": str, + "koa.type": str, "lcp.element": str, "lcp.id": str, "lcp.loadTime": int, From 3ecf17e57d91a63555ca4e0050f59a3cc6901162 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Mon, 13 Jul 2026 10:34:08 +0200 Subject: [PATCH 2/3] add koa.name --- .../sentry-conventions/src/attributes.ts | 40 +++++++++++++++++++ model/attributes/koa/koa__name.json | 22 ++++++++++ python/src/sentry_conventions/attributes.py | 32 +++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 model/attributes/koa/koa__name.json diff --git a/javascript/sentry-conventions/src/attributes.ts b/javascript/sentry-conventions/src/attributes.ts index 2bc8b332..5a79cc14 100644 --- a/javascript/sentry-conventions/src/attributes.ts +++ b/javascript/sentry-conventions/src/attributes.ts @@ -8259,6 +8259,28 @@ export const JVM_THREAD_STATE = 'jvm.thread.state'; */ export type JVM_THREAD_STATE_TYPE = string; +// Path: model/attributes/koa/koa__name.json + +/** + * The name of the Koa middleware or matched route that handled the request. `koa.name` + * + * Attribute Value Type: `string` {@link KOA_NAME_TYPE} + * + * Apply Scrubbing: manual + * + * Attribute defined in OTEL: No + * Visibility: public + * + * @deprecated - No single replacement. SDKs should use `http.route` for router layers and `code.function.name` for middleware layers instead. + * @example "/users/:id" + */ +export const KOA_NAME = 'koa.name'; + +/** + * Type for {@link KOA_NAME} koa.name + */ +export type KOA_NAME_TYPE = string; + // Path: model/attributes/koa/koa__type.json /** @@ -15285,6 +15307,7 @@ export const ATTRIBUTE_TYPE: Record = { 'jvm.memory.type': 'string', 'jvm.thread.daemon': 'boolean', 'jvm.thread.state': 'string', + 'koa.name': 'string', 'koa.type': 'string', lcp: 'double', 'lcp.element': 'string', @@ -15963,6 +15986,7 @@ export type AttributeName = | typeof JVM_MEMORY_TYPE | typeof JVM_THREAD_DAEMON | typeof JVM_THREAD_STATE + | typeof KOA_NAME | typeof KOA_TYPE | typeof LCP | typeof LCP_ELEMENT @@ -21366,6 +21390,21 @@ export const ATTRIBUTE_METADATA: Record = { example: 'blocked', changelog: [{ version: '0.1.0', prs: [127] }, { version: '0.0.0' }], }, + 'koa.name': { + brief: 'The name of the Koa middleware or matched route that handled the request.', + type: 'string', + applyScrubbing: { + key: 'manual', + }, + isInOtel: false, + visibility: 'public', + example: '/users/:id', + deprecation: { + reason: + 'No single replacement. SDKs should use `http.route` for router layers and `code.function.name` for middleware layers instead.', + }, + changelog: [{ version: 'next', prs: [490], description: 'Added koa.name attribute as deprecated' }], + }, 'koa.type': { brief: 'The type of the Koa layer that handled the request.', type: 'string', @@ -25593,6 +25632,7 @@ export type Attributes = { [JVM_MEMORY_TYPE]?: JVM_MEMORY_TYPE_TYPE; [JVM_THREAD_DAEMON]?: JVM_THREAD_DAEMON_TYPE; [JVM_THREAD_STATE]?: JVM_THREAD_STATE_TYPE; + [KOA_NAME]?: KOA_NAME_TYPE; [KOA_TYPE]?: KOA_TYPE_TYPE; [LCP]?: LCP_TYPE; [LCP_ELEMENT]?: LCP_ELEMENT_TYPE; diff --git a/model/attributes/koa/koa__name.json b/model/attributes/koa/koa__name.json new file mode 100644 index 00000000..068c34c2 --- /dev/null +++ b/model/attributes/koa/koa__name.json @@ -0,0 +1,22 @@ +{ + "key": "koa.name", + "brief": "The name of the Koa middleware or matched route that handled the request.", + "type": "string", + "apply_scrubbing": { + "key": "manual" + }, + "is_in_otel": false, + "example": "/users/:id", + "visibility": "public", + "deprecation": { + "_status": null, + "reason": "No single replacement. SDKs should use http.route for router layers and code.function.name for middleware layers instead." + }, + "changelog": [ + { + "version": "next", + "prs": [490], + "description": "Added koa.name attribute as deprecated" + } + ] +} diff --git a/python/src/sentry_conventions/attributes.py b/python/src/sentry_conventions/attributes.py index 67929923..d391a121 100644 --- a/python/src/sentry_conventions/attributes.py +++ b/python/src/sentry_conventions/attributes.py @@ -211,6 +211,7 @@ class _AttributeNamesMeta(type): "HTTP_URL", "HTTP_USER_AGENT", "INP", + "KOA_NAME", "LCP_ELEMENT", "LCP_ID", "LCP_LOADTIME", @@ -4947,6 +4948,18 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): Example: "blocked" """ + # Path: model/attributes/koa/koa__name.json + KOA_NAME: Literal["koa.name"] = "koa.name" + """The name of the Koa middleware or matched route that handled the request. + + Type: str + Apply Scrubbing: manual + Defined in OTEL: No + Visibility: public + DEPRECATED: No replacement at this time - No single replacement. SDKs should use http.route for router layers and code.function.name for middleware layers instead. + Example: "/users/:id" + """ + # Path: model/attributes/koa/koa__type.json KOA_TYPE: Literal["koa.type"] = "koa.type" """The type of the Koa layer that handled the request. @@ -14085,6 +14098,24 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): ChangelogEntry(version="0.0.0"), ], ), + "koa.name": AttributeMetadata( + brief="The name of the Koa middleware or matched route that handled the request.", + type=AttributeType.STRING, + apply_scrubbing=ApplyScrubbingInfo(key=ApplyScrubbing.MANUAL), + is_in_otel=False, + visibility=Visibility.PUBLIC, + example="/users/:id", + deprecation=DeprecationInfo( + reason="No single replacement. SDKs should use http.route for router layers and code.function.name for middleware layers instead." + ), + changelog=[ + ChangelogEntry( + version="next", + prs=[490], + description="Added koa.name attribute as deprecated", + ), + ], + ), "koa.type": AttributeMetadata( brief="The type of the Koa layer that handled the request.", type=AttributeType.STRING, @@ -18476,6 +18507,7 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): "jvm.memory.type": str, "jvm.thread.daemon": bool, "jvm.thread.state": str, + "koa.name": str, "koa.type": str, "lcp.element": str, "lcp.id": str, From 6a0cc4ec9e7d5605cf08b748cfb5b911b2a9cce9 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Mon, 13 Jul 2026 10:39:32 +0200 Subject: [PATCH 3/3] format and lint --- javascript/sentry-conventions/src/attributes.ts | 4 ++-- scripts/generate_attributes.ts | 2 +- scripts/gzip_folder.ts | 3 +-- test/attributes.test.ts | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/javascript/sentry-conventions/src/attributes.ts b/javascript/sentry-conventions/src/attributes.ts index 436903f8..45221a11 100644 --- a/javascript/sentry-conventions/src/attributes.ts +++ b/javascript/sentry-conventions/src/attributes.ts @@ -9124,7 +9124,7 @@ export type JVM_THREAD_STATE_TYPE = string; * Attribute defined in OTEL: No * Visibility: public * - * @deprecated - No single replacement. SDKs should use `http.route` for router layers and `code.function.name` for middleware layers instead. + * @deprecated - No single replacement. SDKs should use http.route for router layers and code.function.name for middleware layers instead. * @example "/users/:id" */ export const KOA_NAME = 'koa.name'; @@ -23131,7 +23131,7 @@ export const ATTRIBUTE_METADATA: Record = { example: '/users/:id', deprecation: { reason: - 'No single replacement. SDKs should use `http.route` for router layers and `code.function.name` for middleware layers instead.', + 'No single replacement. SDKs should use http.route for router layers and code.function.name for middleware layers instead.', }, changelog: [{ version: 'next', prs: [490], description: 'Added koa.name attribute as deprecated' }], }, diff --git a/scripts/generate_attributes.ts b/scripts/generate_attributes.ts index c3a8f704..83e6f5a1 100644 --- a/scripts/generate_attributes.ts +++ b/scripts/generate_attributes.ts @@ -110,7 +110,7 @@ function writeToJs(attributesDir: string, attributeFiles: string[]) { let individualConstants = ''; // Generate individual attribute constants with documentation AND build the explicit type map - for (const { file, key, constantName, attributeJson, isDeprecated } of allAttributes) { + for (const { file, key, constantName, attributeJson, _isDeprecated } of allAttributes) { const { brief, type, apply_scrubbing, is_in_otel, example, has_dynamic_suffix, deprecation, alias } = attributeJson; const visibility = getVisibility(attributeJson); diff --git a/scripts/gzip_folder.ts b/scripts/gzip_folder.ts index 22eeb61e..c925a362 100644 --- a/scripts/gzip_folder.ts +++ b/scripts/gzip_folder.ts @@ -1,5 +1,4 @@ -import { createReadStream, createWriteStream } from 'node:fs'; -import { join } from 'node:path'; +import { createWriteStream } from 'node:fs'; import { pipeline } from 'node:stream'; import { promisify } from 'node:util'; import { createGzip } from 'node:zlib'; diff --git a/test/attributes.test.ts b/test/attributes.test.ts index e10fc692..9594a3f1 100644 --- a/test/attributes.test.ts +++ b/test/attributes.test.ts @@ -237,7 +237,7 @@ describe('alias group consistency', async () => { const failedGroups: Array<{ group: string[]; missingAliases: Array<{ key: string; missing: string[] }> }> = []; // Validate each group - for (const [canonicalKey, group] of aliasGroups) { + for (const [_canonicalKey, group] of aliasGroups) { const groupArray = Array.from(group).sort(); const missingAliases: Array<{ key: string; missing: string[] }> = [];