diff --git a/javascript/sentry-conventions/src/attributes.ts b/javascript/sentry-conventions/src/attributes.ts index 6a5bf0d0b..08a9a1a30 100644 --- a/javascript/sentry-conventions/src/attributes.ts +++ b/javascript/sentry-conventions/src/attributes.ts @@ -1155,7 +1155,7 @@ export type APP_NAME_TYPE = string; * * Aliases: {@link APP_VITALS_START_COLD_VALUE} `app.vitals.start.cold.value` * - * @deprecated Use {@link APP_VITALS_START_COLD_VALUE} (app.vitals.start.cold.value) instead - Replaced by app.vitals.start.cold.value to align with the app.vitals.* namespace for mobile performance attributes + * @deprecated Use {@link APP_VITALS_START_VALUE} (app.vitals.start.value) instead - Replaced by app.vitals.start.value plus app.vitals.start.type * @example 1234.56 */ export const APP_START_COLD = 'app_start_cold'; @@ -1226,7 +1226,7 @@ export type APP_START_TYPE_TYPE = string; * * Aliases: {@link APP_VITALS_START_WARM_VALUE} `app.vitals.start.warm.value` * - * @deprecated Use {@link APP_VITALS_START_WARM_VALUE} (app.vitals.start.warm.value) instead - Replaced by app.vitals.start.warm.value to align with the app.vitals.* namespace for mobile performance attributes + * @deprecated Use {@link APP_VITALS_START_VALUE} (app.vitals.start.value) instead - Replaced by app.vitals.start.value plus app.vitals.start.type * @example 1234.56 */ export const APP_START_WARM = 'app_start_warm'; @@ -1457,6 +1457,7 @@ export type APP_VITALS_STALL_PERCENTAGE_TYPE = number; * * Aliases: {@link APP_START_COLD} `app_start_cold` * + * @deprecated Use {@link APP_VITALS_START_VALUE} (app.vitals.start.value) instead - Replaced by app.vitals.start.value plus app.vitals.start.type. Cold and warm are not aliases of the unified value because they are mutually exclusive type-specific names. * @example 1234.56 */ export const APP_VITALS_START_COLD_VALUE = 'app.vitals.start.cold.value'; @@ -1552,6 +1553,27 @@ export const APP_VITALS_START_TYPE = 'app.vitals.start.type'; */ export type APP_VITALS_START_TYPE_TYPE = string; +// Path: model/attributes/app/app__vitals__start__value.json + +/** + * The duration of an app start in milliseconds. Use with app.vitals.start.type to distinguish cold vs warm starts. `app.vitals.start.value` + * + * Attribute Value Type: `number` {@link APP_VITALS_START_VALUE_TYPE} + * + * Apply Scrubbing: manual + * + * Attribute defined in OTEL: No + * Visibility: public + * + * @example 1234.56 + */ +export const APP_VITALS_START_VALUE = 'app.vitals.start.value'; + +/** + * Type for {@link APP_VITALS_START_VALUE} app.vitals.start.value + */ +export type APP_VITALS_START_VALUE_TYPE = number; + // Path: model/attributes/app/app__vitals__start__warm__value.json /** @@ -1566,6 +1588,7 @@ export type APP_VITALS_START_TYPE_TYPE = string; * * Aliases: {@link APP_START_WARM} `app_start_warm` * + * @deprecated Use {@link APP_VITALS_START_VALUE} (app.vitals.start.value) instead - Replaced by app.vitals.start.value plus app.vitals.start.type. Cold and warm are not aliases of the unified value because they are mutually exclusive type-specific names. * @example 1234.56 */ export const APP_VITALS_START_WARM_VALUE = 'app.vitals.start.warm.value'; @@ -17769,6 +17792,7 @@ export const ATTRIBUTE_TYPE: Record = { 'app.vitals.start.reason': 'string', 'app.vitals.start.screen': 'string', 'app.vitals.start.type': 'string', + 'app.vitals.start.value': 'double', 'app.vitals.start.warm.value': 'double', 'app.vitals.ttfd.value': 'double', 'app.vitals.ttid.value': 'double', @@ -18564,6 +18588,7 @@ export type AttributeName = | typeof APP_VITALS_START_REASON | typeof APP_VITALS_START_SCREEN | typeof APP_VITALS_START_TYPE + | typeof APP_VITALS_START_VALUE | typeof APP_VITALS_START_WARM_VALUE | typeof APP_VITALS_TTFD_VALUE | typeof APP_VITALS_TTID_VALUE @@ -20162,7 +20187,7 @@ export const ATTRIBUTE_METADATA: Record = { app_start_cold: { brief: 'The duration of a cold app start in milliseconds', type: 'double', - keys: ['app.vitals.start.cold.value', 'app_start_cold'], + keys: ['app_start_cold'], applyScrubbing: { key: 'manual', }, @@ -20170,13 +20195,18 @@ export const ATTRIBUTE_METADATA: Record = { visibility: 'public', example: 1234.56, deprecation: { - replacement: 'app.vitals.start.cold.value', - reason: - 'Replaced by app.vitals.start.cold.value to align with the app.vitals.* namespace for mobile performance attributes', - status: 'backfill', + replacement: 'app.vitals.start.value', + reason: 'Replaced by app.vitals.start.value plus app.vitals.start.type', + status: 'transform', + transformation: 'app_vitals_start_cold_warm_to_value', }, aliases: ['app.vitals.start.cold.value'], changelog: [ + { + version: 'next', + prs: [576], + description: 'Retargeted deprecation replacement to app.vitals.start.value via transform', + }, { version: '0.5.0', prs: [323], description: 'Added and deprecated in favor of app.vitals.start.cold.value' }, ], }, @@ -20219,7 +20249,7 @@ export const ATTRIBUTE_METADATA: Record = { app_start_warm: { brief: 'The duration of a warm app start in milliseconds', type: 'double', - keys: ['app.vitals.start.warm.value', 'app_start_warm'], + keys: ['app_start_warm'], applyScrubbing: { key: 'manual', }, @@ -20227,13 +20257,18 @@ export const ATTRIBUTE_METADATA: Record = { visibility: 'public', example: 1234.56, deprecation: { - replacement: 'app.vitals.start.warm.value', - reason: - 'Replaced by app.vitals.start.warm.value to align with the app.vitals.* namespace for mobile performance attributes', - status: 'backfill', + replacement: 'app.vitals.start.value', + reason: 'Replaced by app.vitals.start.value plus app.vitals.start.type', + status: 'transform', + transformation: 'app_vitals_start_cold_warm_to_value', }, aliases: ['app.vitals.start.warm.value'], changelog: [ + { + version: 'next', + prs: [576], + description: 'Retargeted deprecation replacement to app.vitals.start.value via transform', + }, { version: '0.5.0', prs: [323], description: 'Added and deprecated in favor of app.vitals.start.warm.value' }, ], }, @@ -20373,15 +20408,29 @@ export const ATTRIBUTE_METADATA: Record = { 'app.vitals.start.cold.value': { brief: 'The duration of a cold app start in milliseconds', type: 'double', - keys: ['app.vitals.start.cold.value', 'app_start_cold'], + keys: ['app.vitals.start.cold.value'], applyScrubbing: { key: 'manual', }, isInOtel: false, visibility: 'public', example: 1234.56, + deprecation: { + replacement: 'app.vitals.start.value', + reason: + 'Replaced by app.vitals.start.value plus app.vitals.start.type. Cold and warm are not aliases of the unified value because they are mutually exclusive type-specific names.', + status: 'transform', + transformation: 'app_vitals_start_cold_warm_to_value', + }, aliases: ['app_start_cold'], - changelog: [{ version: '0.5.0', prs: [313], description: 'Added app.vitals.start.cold.value attribute' }], + changelog: [ + { + version: 'next', + prs: [576], + description: 'Deprecated in favor of app.vitals.start.value plus app.vitals.start.type via transform', + }, + { version: '0.5.0', prs: [313], description: 'Added app.vitals.start.cold.value attribute' }, + ], }, 'app.vitals.start.prewarmed': { brief: 'Whether the app start was prewarmed.', @@ -20433,18 +20482,51 @@ export const ATTRIBUTE_METADATA: Record = { aliases: ['app_start_type'], changelog: [{ version: '0.5.0', prs: [313], description: 'Added app.vitals.start.type attribute' }], }, + 'app.vitals.start.value': { + brief: + 'The duration of an app start in milliseconds. Use with app.vitals.start.type to distinguish cold vs warm starts.', + type: 'double', + keys: ['app.vitals.start.value'], + applyScrubbing: { + key: 'manual', + }, + isInOtel: false, + visibility: 'public', + example: 1234.56, + changelog: [ + { version: 'next', prs: [576], description: 'Added app.vitals.start.value as the unified app start duration' }, + ], + additionalContext: [ + 'Send this together with app.vitals.start.type (`cold` or `warm`). This replaces app.vitals.start.cold.value and app.vitals.start.warm.value.', + 'Not aliased to the cold/warm attributes: those names are type-specific, not 1:1 copies of this key. Ingest derives this attribute (and type) from the older names via the app_vitals_start_cold_warm_to_value transformation.', + ], + }, 'app.vitals.start.warm.value': { brief: 'The duration of a warm app start in milliseconds', type: 'double', - keys: ['app.vitals.start.warm.value', 'app_start_warm'], + keys: ['app.vitals.start.warm.value'], applyScrubbing: { key: 'manual', }, isInOtel: false, visibility: 'public', example: 1234.56, + deprecation: { + replacement: 'app.vitals.start.value', + reason: + 'Replaced by app.vitals.start.value plus app.vitals.start.type. Cold and warm are not aliases of the unified value because they are mutually exclusive type-specific names.', + status: 'transform', + transformation: 'app_vitals_start_cold_warm_to_value', + }, aliases: ['app_start_warm'], - changelog: [{ version: '0.5.0', prs: [313], description: 'Added app.vitals.start.warm.value attribute' }], + changelog: [ + { + version: 'next', + prs: [576], + description: 'Deprecated in favor of app.vitals.start.value plus app.vitals.start.type via transform', + }, + { version: '0.5.0', prs: [313], description: 'Added app.vitals.start.warm.value attribute' }, + ], }, 'app.vitals.ttfd.value': { brief: 'The duration of time to full display in milliseconds', @@ -31788,10 +31870,10 @@ export const ATTRIBUTE_SEARCH_METADATA: Record deprecationChain: ['app.vitals.stall.percentage', 'stall_percentage'], }, 'app.vitals.start.cold.value': { - canonicalName: 'app.vitals.start.cold.value', + canonicalName: 'app.vitals.start.value', type: 'double', brief: 'The duration of a cold app start in milliseconds', - deprecationChain: ['app.vitals.start.cold.value', 'app_start_cold'], + deprecationChain: ['app.vitals.start.cold.value'], }, 'app.vitals.start.prewarmed': { canonicalName: 'app.vitals.start.prewarmed', @@ -31818,11 +31900,18 @@ export const ATTRIBUTE_SEARCH_METADATA: Record brief: 'The type of app start, for example `cold` or `warm`', deprecationChain: ['app.vitals.start.type', 'app_start_type'], }, + 'app.vitals.start.value': { + canonicalName: 'app.vitals.start.value', + type: 'double', + brief: + 'The duration of an app start in milliseconds. Use with app.vitals.start.type to distinguish cold vs warm starts.', + deprecationChain: ['app.vitals.start.value'], + }, 'app.vitals.start.warm.value': { - canonicalName: 'app.vitals.start.warm.value', + canonicalName: 'app.vitals.start.value', type: 'double', brief: 'The duration of a warm app start in milliseconds', - deprecationChain: ['app.vitals.start.warm.value', 'app_start_warm'], + deprecationChain: ['app.vitals.start.warm.value'], }, 'app.vitals.ttfd.value': { canonicalName: 'app.vitals.ttfd.value', @@ -31837,10 +31926,10 @@ export const ATTRIBUTE_SEARCH_METADATA: Record deprecationChain: ['app.vitals.ttid.value', 'time_to_initial_display'], }, app_start_cold: { - canonicalName: 'app.vitals.start.cold.value', + canonicalName: 'app.vitals.start.value', type: 'double', brief: 'The duration of a cold app start in milliseconds', - deprecationChain: ['app.vitals.start.cold.value', 'app_start_cold'], + deprecationChain: ['app_start_cold'], }, app_start_type: { canonicalName: 'app.vitals.start.type', @@ -31849,10 +31938,10 @@ export const ATTRIBUTE_SEARCH_METADATA: Record deprecationChain: ['app.vitals.start.type', 'app_start_type'], }, app_start_warm: { - canonicalName: 'app.vitals.start.warm.value', + canonicalName: 'app.vitals.start.value', type: 'double', brief: 'The duration of a warm app start in milliseconds', - deprecationChain: ['app.vitals.start.warm.value', 'app_start_warm'], + deprecationChain: ['app_start_warm'], }, 'art.gc.blocking_count': { canonicalName: 'art.gc.blocking_count', @@ -36414,6 +36503,7 @@ export type Attributes = { [APP_VITALS_START_REASON]?: APP_VITALS_START_REASON_TYPE; [APP_VITALS_START_SCREEN]?: APP_VITALS_START_SCREEN_TYPE; [APP_VITALS_START_TYPE]?: APP_VITALS_START_TYPE_TYPE; + [APP_VITALS_START_VALUE]?: APP_VITALS_START_VALUE_TYPE; [APP_VITALS_START_WARM_VALUE]?: APP_VITALS_START_WARM_VALUE_TYPE; [APP_VITALS_TTFD_VALUE]?: APP_VITALS_TTFD_VALUE_TYPE; [APP_VITALS_TTID_VALUE]?: APP_VITALS_TTID_VALUE_TYPE; diff --git a/model/attribute_transformations/app_vitals_start_cold_warm_to_value.json b/model/attribute_transformations/app_vitals_start_cold_warm_to_value.json new file mode 100644 index 000000000..a1f5b2772 --- /dev/null +++ b/model/attribute_transformations/app_vitals_start_cold_warm_to_value.json @@ -0,0 +1,82 @@ +{ + "id": "app_vitals_start_cold_warm_to_value", + "brief": "Derive unified app.vitals.start.value and app.vitals.start.type from the type-specific cold and warm duration attributes. Cold and warm are mutually exclusive, so they are not 1:1 aliases of the unified key.", + "inputs": [ + { + "attribute": "app.vitals.start.cold.value", + "brief": "Deprecated cold app start duration." + }, + { + "attribute": "app.vitals.start.warm.value", + "brief": "Deprecated warm app start duration." + }, + { + "attribute": "app_start_cold", + "brief": "Legacy cold app start duration." + }, + { + "attribute": "app_start_warm", + "brief": "Legacy warm app start duration." + } + ], + "outputs": [ + { + "attribute": "app.vitals.start.value", + "brief": "Unified app start duration in milliseconds." + }, + { + "attribute": "app.vitals.start.type", + "brief": "App start type, cold or warm." + } + ], + "actions": [ + "If app.vitals.start.value is already present, keep it and do not overwrite it.", + "Prefer app.vitals.start.cold.value over app_start_cold, and app.vitals.start.warm.value over app_start_warm, when both a namespaced and a legacy name are present.", + "If a cold duration is present and app.vitals.start.value is missing, copy that duration to app.vitals.start.value and set app.vitals.start.type to \"cold\" when type is missing.", + "Otherwise, if a warm duration is present and app.vitals.start.value is missing, copy that duration to app.vitals.start.value and set app.vitals.start.type to \"warm\" when type is missing.", + "Do not copy a source duration that exceeds 180000 milliseconds.", + "Leave the source cold and warm attributes in place. Do not treat cold and warm as interchangeable copies of the unified key." + ], + "examples": [ + { + "name": "cold namespaced duration", + "input": { + "app.vitals.start.cold.value": 1234.0 + }, + "output": { + "app.vitals.start.value": 1234.0, + "app.vitals.start.type": "cold" + } + }, + { + "name": "warm namespaced duration", + "input": { + "app.vitals.start.warm.value": 567.0 + }, + "output": { + "app.vitals.start.value": 567.0, + "app.vitals.start.type": "warm" + } + }, + { + "name": "legacy cold duration", + "input": { + "app_start_cold": 1234.0 + }, + "output": { + "app.vitals.start.value": 1234.0, + "app.vitals.start.type": "cold" + } + }, + { + "name": "legacy warm duration", + "input": { + "app_start_warm": 567.0 + }, + "output": { + "app.vitals.start.value": 567.0, + "app.vitals.start.type": "warm" + } + } + ] +} diff --git a/model/attributes/app/app__vitals__start__cold__value.json b/model/attributes/app/app__vitals__start__cold__value.json index 4614c8ec1..bb13b2626 100644 --- a/model/attributes/app/app__vitals__start__cold__value.json +++ b/model/attributes/app/app__vitals__start__cold__value.json @@ -8,8 +8,19 @@ "is_in_otel": false, "example": 1234.56, "alias": ["app_start_cold"], + "deprecation": { + "replacement": "app.vitals.start.value", + "reason": "Replaced by app.vitals.start.value plus app.vitals.start.type. Cold and warm are not aliases of the unified value because they are mutually exclusive type-specific names.", + "_status": "transform", + "transformation": "app_vitals_start_cold_warm_to_value" + }, "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [576], + "description": "Deprecated in favor of app.vitals.start.value plus app.vitals.start.type via transform" + }, { "version": "0.5.0", "prs": [313], diff --git a/model/attributes/app/app__vitals__start__value.json b/model/attributes/app/app__vitals__start__value.json new file mode 100644 index 000000000..94710f00d --- /dev/null +++ b/model/attributes/app/app__vitals__start__value.json @@ -0,0 +1,22 @@ +{ + "key": "app.vitals.start.value", + "brief": "The duration of an app start in milliseconds. Use with app.vitals.start.type to distinguish cold vs warm starts.", + "type": "double", + "apply_scrubbing": { + "key": "manual" + }, + "is_in_otel": false, + "example": 1234.56, + "visibility": "public", + "additional_context": [ + "Send this together with app.vitals.start.type (`cold` or `warm`). This replaces app.vitals.start.cold.value and app.vitals.start.warm.value.", + "Not aliased to the cold/warm attributes: those names are type-specific, not 1:1 copies of this key. Ingest derives this attribute (and type) from the older names via the app_vitals_start_cold_warm_to_value transformation." + ], + "changelog": [ + { + "version": "next", + "prs": [576], + "description": "Added app.vitals.start.value as the unified app start duration" + } + ] +} diff --git a/model/attributes/app/app__vitals__start__warm__value.json b/model/attributes/app/app__vitals__start__warm__value.json index 824f023a2..5f662a28e 100644 --- a/model/attributes/app/app__vitals__start__warm__value.json +++ b/model/attributes/app/app__vitals__start__warm__value.json @@ -8,8 +8,19 @@ "is_in_otel": false, "example": 1234.56, "alias": ["app_start_warm"], + "deprecation": { + "replacement": "app.vitals.start.value", + "reason": "Replaced by app.vitals.start.value plus app.vitals.start.type. Cold and warm are not aliases of the unified value because they are mutually exclusive type-specific names.", + "_status": "transform", + "transformation": "app_vitals_start_cold_warm_to_value" + }, "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [576], + "description": "Deprecated in favor of app.vitals.start.value plus app.vitals.start.type via transform" + }, { "version": "0.5.0", "prs": [313], diff --git a/model/attributes/app_start_cold.json b/model/attributes/app_start_cold.json index 0381aebe2..e1f2d010f 100644 --- a/model/attributes/app_start_cold.json +++ b/model/attributes/app_start_cold.json @@ -9,12 +9,18 @@ "example": 1234.56, "alias": ["app.vitals.start.cold.value"], "deprecation": { - "replacement": "app.vitals.start.cold.value", - "reason": "Replaced by app.vitals.start.cold.value to align with the app.vitals.* namespace for mobile performance attributes", - "_status": "backfill" + "replacement": "app.vitals.start.value", + "reason": "Replaced by app.vitals.start.value plus app.vitals.start.type", + "_status": "transform", + "transformation": "app_vitals_start_cold_warm_to_value" }, "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [576], + "description": "Retargeted deprecation replacement to app.vitals.start.value via transform" + }, { "version": "0.5.0", "prs": [323], diff --git a/model/attributes/app_start_warm.json b/model/attributes/app_start_warm.json index a73587cac..070da7626 100644 --- a/model/attributes/app_start_warm.json +++ b/model/attributes/app_start_warm.json @@ -9,12 +9,18 @@ "example": 1234.56, "alias": ["app.vitals.start.warm.value"], "deprecation": { - "replacement": "app.vitals.start.warm.value", - "reason": "Replaced by app.vitals.start.warm.value to align with the app.vitals.* namespace for mobile performance attributes", - "_status": "backfill" + "replacement": "app.vitals.start.value", + "reason": "Replaced by app.vitals.start.value plus app.vitals.start.type", + "_status": "transform", + "transformation": "app_vitals_start_cold_warm_to_value" }, "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [576], + "description": "Retargeted deprecation replacement to app.vitals.start.value via transform" + }, { "version": "0.5.0", "prs": [323], diff --git a/model/measurements/app_start_cold.json b/model/measurements/app_start_cold.json index 9b73fba0f..07fa90051 100644 --- a/model/measurements/app_start_cold.json +++ b/model/measurements/app_start_cold.json @@ -1,8 +1,8 @@ { "key": "app_start_cold", "full_name": "App Start Cold", - "brief": "The time it takes for the app to start from a cold state", + "brief": "The time it takes for the app to start from a cold state. Corresponds to app.vitals.start.value when app.vitals.start.type is cold.", "unit": "millisecond", "platform": "mobile", - "attribute": "app.vitals.start.cold.value" + "attribute": "app.vitals.start.value" } diff --git a/model/measurements/app_start_warm.json b/model/measurements/app_start_warm.json index b62779c24..d38e6a613 100644 --- a/model/measurements/app_start_warm.json +++ b/model/measurements/app_start_warm.json @@ -1,8 +1,8 @@ { "key": "app_start_warm", "full_name": "App Start Warm", - "brief": "The time it takes for the app to start from a warm state", + "brief": "The time it takes for the app to start from a warm state. Corresponds to app.vitals.start.value when app.vitals.start.type is warm.", "unit": "millisecond", "platform": "mobile", - "attribute": "app.vitals.start.warm.value" + "attribute": "app.vitals.start.value" } diff --git a/python/src/sentry_conventions/attributes.py b/python/src/sentry_conventions/attributes.py index e78a4b14d..795a5236a 100644 --- a/python/src/sentry_conventions/attributes.py +++ b/python/src/sentry_conventions/attributes.py @@ -197,6 +197,8 @@ class _AttributeNamesMeta(type): "APP_APP_NAME", "APP_APP_START_TIME", "APP_APP_VERSION", + "APP_VITALS_START_COLD_VALUE", + "APP_VITALS_START_WARM_VALUE", "APP_START_COLD", "APP_START_TYPE", "APP_START_WARM", @@ -1151,6 +1153,7 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): Defined in OTEL: No Visibility: public Aliases: app_start_cold + DEPRECATED: Use app.vitals.start.value instead - Replaced by app.vitals.start.value plus app.vitals.start.type. Cold and warm are not aliases of the unified value because they are mutually exclusive type-specific names. Example: 1234.56 """ @@ -1205,6 +1208,17 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): Example: "cold" """ + # Path: model/attributes/app/app__vitals__start__value.json + APP_VITALS_START_VALUE: Literal["app.vitals.start.value"] = "app.vitals.start.value" + """The duration of an app start in milliseconds. Use with app.vitals.start.type to distinguish cold vs warm starts. + + Type: float + Apply Scrubbing: manual + Defined in OTEL: No + Visibility: public + Example: 1234.56 + """ + # Path: model/attributes/app/app__vitals__start__warm__value.json APP_VITALS_START_WARM_VALUE: Literal["app.vitals.start.warm.value"] = ( "app.vitals.start.warm.value" @@ -1216,6 +1230,7 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): Defined in OTEL: No Visibility: public Aliases: app_start_warm + DEPRECATED: Use app.vitals.start.value instead - Replaced by app.vitals.start.value plus app.vitals.start.type. Cold and warm are not aliases of the unified value because they are mutually exclusive type-specific names. Example: 1234.56 """ @@ -1252,7 +1267,7 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): Defined in OTEL: No Visibility: public Aliases: app.vitals.start.cold.value - DEPRECATED: Use app.vitals.start.cold.value instead - Replaced by app.vitals.start.cold.value to align with the app.vitals.* namespace for mobile performance attributes + DEPRECATED: Use app.vitals.start.value instead - Replaced by app.vitals.start.value plus app.vitals.start.type Example: 1234.56 """ @@ -1278,7 +1293,7 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): Defined in OTEL: No Visibility: public Aliases: app.vitals.start.warm.value - DEPRECATED: Use app.vitals.start.warm.value instead - Replaced by app.vitals.start.warm.value to align with the app.vitals.* namespace for mobile performance attributes + DEPRECATED: Use app.vitals.start.value instead - Replaced by app.vitals.start.value plus app.vitals.start.type Example: 1234.56 """ @@ -11411,16 +11426,24 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): "app.vitals.start.cold.value": AttributeMetadata( brief="The duration of a cold app start in milliseconds", type=AttributeType.DOUBLE, - keys=( - "app.vitals.start.cold.value", - "app_start_cold", - ), + keys=("app.vitals.start.cold.value",), apply_scrubbing=ApplyScrubbingInfo(key=ApplyScrubbing.MANUAL), is_in_otel=False, visibility=Visibility.PUBLIC, example=1234.56, + deprecation=DeprecationInfo( + replacement="app.vitals.start.value", + reason="Replaced by app.vitals.start.value plus app.vitals.start.type. Cold and warm are not aliases of the unified value because they are mutually exclusive type-specific names.", + status=DeprecationStatus.TRANSFORM, + transformation="app_vitals_start_cold_warm_to_value", + ), aliases=["app_start_cold"], changelog=[ + ChangelogEntry( + version="next", + prs=[576], + description="Deprecated in favor of app.vitals.start.value plus app.vitals.start.type via transform", + ), ChangelogEntry( version="0.5.0", prs=[313], @@ -11496,19 +11519,47 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): ), ], ), + "app.vitals.start.value": AttributeMetadata( + brief="The duration of an app start in milliseconds. Use with app.vitals.start.type to distinguish cold vs warm starts.", + type=AttributeType.DOUBLE, + keys=("app.vitals.start.value",), + apply_scrubbing=ApplyScrubbingInfo(key=ApplyScrubbing.MANUAL), + is_in_otel=False, + visibility=Visibility.PUBLIC, + example=1234.56, + changelog=[ + ChangelogEntry( + version="next", + prs=[576], + description="Added app.vitals.start.value as the unified app start duration", + ), + ], + additional_context=[ + "Send this together with app.vitals.start.type (`cold` or `warm`). This replaces app.vitals.start.cold.value and app.vitals.start.warm.value.", + "Not aliased to the cold/warm attributes: those names are type-specific, not 1:1 copies of this key. Ingest derives this attribute (and type) from the older names via the app_vitals_start_cold_warm_to_value transformation.", + ], + ), "app.vitals.start.warm.value": AttributeMetadata( brief="The duration of a warm app start in milliseconds", type=AttributeType.DOUBLE, - keys=( - "app.vitals.start.warm.value", - "app_start_warm", - ), + keys=("app.vitals.start.warm.value",), apply_scrubbing=ApplyScrubbingInfo(key=ApplyScrubbing.MANUAL), is_in_otel=False, visibility=Visibility.PUBLIC, example=1234.56, + deprecation=DeprecationInfo( + replacement="app.vitals.start.value", + reason="Replaced by app.vitals.start.value plus app.vitals.start.type. Cold and warm are not aliases of the unified value because they are mutually exclusive type-specific names.", + status=DeprecationStatus.TRANSFORM, + transformation="app_vitals_start_cold_warm_to_value", + ), aliases=["app_start_warm"], changelog=[ + ChangelogEntry( + version="next", + prs=[576], + description="Deprecated in favor of app.vitals.start.value plus app.vitals.start.type via transform", + ), ChangelogEntry( version="0.5.0", prs=[313], @@ -11559,21 +11610,24 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): "app_start_cold": AttributeMetadata( brief="The duration of a cold app start in milliseconds", type=AttributeType.DOUBLE, - keys=( - "app.vitals.start.cold.value", - "app_start_cold", - ), + keys=("app_start_cold",), apply_scrubbing=ApplyScrubbingInfo(key=ApplyScrubbing.MANUAL), is_in_otel=False, visibility=Visibility.PUBLIC, example=1234.56, deprecation=DeprecationInfo( - replacement="app.vitals.start.cold.value", - reason="Replaced by app.vitals.start.cold.value to align with the app.vitals.* namespace for mobile performance attributes", - status=DeprecationStatus.BACKFILL, + replacement="app.vitals.start.value", + reason="Replaced by app.vitals.start.value plus app.vitals.start.type", + status=DeprecationStatus.TRANSFORM, + transformation="app_vitals_start_cold_warm_to_value", ), aliases=["app.vitals.start.cold.value"], changelog=[ + ChangelogEntry( + version="next", + prs=[576], + description="Retargeted deprecation replacement to app.vitals.start.value via transform", + ), ChangelogEntry( version="0.5.0", prs=[323], @@ -11611,21 +11665,24 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): "app_start_warm": AttributeMetadata( brief="The duration of a warm app start in milliseconds", type=AttributeType.DOUBLE, - keys=( - "app.vitals.start.warm.value", - "app_start_warm", - ), + keys=("app_start_warm",), apply_scrubbing=ApplyScrubbingInfo(key=ApplyScrubbing.MANUAL), is_in_otel=False, visibility=Visibility.PUBLIC, example=1234.56, deprecation=DeprecationInfo( - replacement="app.vitals.start.warm.value", - reason="Replaced by app.vitals.start.warm.value to align with the app.vitals.* namespace for mobile performance attributes", - status=DeprecationStatus.BACKFILL, + replacement="app.vitals.start.value", + reason="Replaced by app.vitals.start.value plus app.vitals.start.type", + status=DeprecationStatus.TRANSFORM, + transformation="app_vitals_start_cold_warm_to_value", ), aliases=["app.vitals.start.warm.value"], changelog=[ + ChangelogEntry( + version="next", + prs=[576], + description="Retargeted deprecation replacement to app.vitals.start.value via transform", + ), ChangelogEntry( version="0.5.0", prs=[323], @@ -24267,6 +24324,7 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): "app.vitals.start.reason": str, "app.vitals.start.screen": str, "app.vitals.start.type": str, + "app.vitals.start.value": float, "app.vitals.start.warm.value": float, "app.vitals.ttfd.value": float, "app.vitals.ttid.value": float,