Sentry Conventions

How to add, release, and deploy semantic convention attributes across sentry-conventions, Relay, Snuba, and Sentry.

Sentry Semantic Conventions is the single source of truth for attribute names, types, PII classification, and deprecation status across all of Sentry's systems. Changes to conventions flow through a defined pipeline before they take effect in production.

For full contribution details (setup, policies, testing), see the CONTRIBUTING.md in the repo.

Any questions? Ask in #discuss-conventions on Slack.

Convention changes go through four stages:

  1. Define: Add or modify attributes in sentry-conventions
  2. Release: Publish a new version to npm and PyPI
  3. Update downstream repos: Bump the dependency in Relay, Snuba, and Sentry
  4. Register (if needed): Make new attributes queryable or add ingestion logic in Sentry

Copied
yarn create:attribute

This walks you through creating the attribute JSON file in model/attributes/. You can also use non-interactive mode:

Copied
yarn create:attribute \
  --key my.attribute.name \
  --description "What this attribute represents" \
  --type string \
  --apply_scrubbing manual \
  --is_in_otel false \
  --visibility public \
  --examples '["example_1","example_2"]'

  1. Modify the existing attribute JSON: Add a deprecation block with _status, replacement, and reason.
  2. Create the replacement attribute if it doesn't already exist.
  3. Ensure symmetric alias entries: Every member of an alias group must list every other member. The test suite enforces this.

  • Set apply_scrubbing appropriately:
    • "manual" (default): the attribute may contain sensitive data; scrubbing is left to the user's data scrubbing settings.
    • "auto": the attribute is expected to contain sensitive data in normal use; scrubbing is applied automatically.
    • "never": the attribute is not expected to contain sensitive data, and scrubbing it would break product features.
  • Set visibility to
    • "public" if the attribute should be visible to sentry users (i.e. most of the time).
    • "private" if the attribute should not be visible in the UI (but will be returned by the debug endpoint).
  • Add a changelog entry with "version": "next".
  • Run yarn generate to regenerate the JS and Python code.
  • Run yarn test to verify all tests pass (including alias symmetry, name template validation, etc.).

PRs require a 3 business day grace period after the first approval before merging. This exists because attribute names, once shipped in an SDK release, are effectively permanent. See CONTRIBUTING.md for details.

  1. Trigger the Release workflow on GitHub Actions with the new version number. Almost always a minor bump (e.g. 0.12.0 → 0.13.0).
  2. Craft creates a release/x.y.z branch and opens an issue on getsentry/publish.
  3. Add the accepted label on the publish issue to approve.
  4. CI publishes to npm, PyPI, and GitHub Releases.
  5. Wait ~20 minutes for the internal PyPI mirror (pypi.devinfra.sentry.io) to sync before updating Sentry and Snuba.

Convention changes don't take effect in production until the downstream repos are updated and deployed.

Snuba uses the PyPI package.

  1. Run the bump-version workflow with package sentry-conventions and the new version. This creates a PR updating pyproject.toml and the lockfile.
  2. Review and merge the PR once approved by a code owner.
  3. Deploy Snuba.

Sentry uses the PyPI package and may require additional registration for new attributes.

  1. Run the bump-version workflow with package sentry-conventions and the new version. This creates a PR updating pyproject.toml and uv.lock.
  2. Review and merge the PR. Self-approval is permitted for simple bumps.
  3. If the new attribute needs special adjustments in the Sentry UI (see below), add it to:
  4. If the new attribute needs to be extracted or transformed from incoming data (e.g. derived server-side, or a deprecation backfill requiring type conversion), add ingestion/normalization logic in the spans consumers.
When does an attribute need Sentry code adjustments? (Steps 3 and 4)

Most new attributes don't need steps 3-4. They're sent by SDKs and flow through as-is. Deprecation backfills with backfill or normalize status are handled automatically by Relay using the conventions metadata. Step 3 is only required when the attribute needs special adjustments in the Sentry UI.

The SPAN_ATTRIBUTE_DEFINITIONS needs an entry when:

  1. The attribute is prefixed with sentry.*. To avoid divergence between Explore and the trace waterfall, add a public alias for the attribute (e.g. the attribute without the sentry.* prefix)
  2. The public alias differs from the internal name (e.g., public alias: span.duration -> internal name: sentry.duration_ms)
  3. The attribute needs a special search type that is not a primitive, like for example currency, byte, millisecond, percentage.
  4. The attribute has a validator or normalizer (e.g., validate_span_id, validate_event_id) or value normalization (e.g., normalize_event_id_strict) only runs through an explicit definition
  5. The attribute has a processor (post-processing transforms on query results require an explicit definition)
  6. The attribute is private (private=True restricts access to callers with the attribute in their fields_acl; this flag only works through an explicit definition)
  7. The attribute is a secondary alias (secondary_alias=True marks compatibility aliases that shouldn't be preferred in reverse lookups)
  8. The attribute has context (context=AttributeContext(brief=...) provides human-readable descriptions exposed through the API)

If none of these apply, no entry is required.

The SPAN_EAP_COLUMN_MAP needs an entry when the queried field in clickhouse differs from the attribute name.

Relay uses sentry-conventions as a git submodule. The build script reads the JSON model files and generates Rust code at compile time.

  1. Make sure you set up Relay and checked out its submodules:
    Copied
    git submodule update --init --recursive
    
  2. Update the submodule to the release tag:
    Copied
    # If the submodule is not initialized yet:
    git submodule update --init relay-conventions/sentry-conventions
    
    cd relay-conventions/sentry-conventions
    git fetch --tags
    git checkout <version>
    cd ../..
    git add relay-conventions/sentry-conventions
    
  3. If the release deprecates attributes, check for Rust compilation errors. clippy treats deprecated constant usage as errors. Migrate to the new constant names. Not every newly added deprecation results in a compilation error. This is fine and requires no changes.
  4. Add a CHANGELOG.md entry. If the release contains no user-observable changes, you can skip this step. But most changes are user-facing (e.g. adding an attribute with a manual or never scrubbing policy, adding/changing a name or description inference rule, etc.).
  5. Open + merge PR at getsentry/relay.

Sentry uses the @sentry/conventions package in the frontend, which just needs to be bumped:

  1. Bump the package version:
    Copied
    pnpm install -w @sentry/conventions@^<version>
    
  2. Commit, open a PR, and merge it once you got approval.

Importantly, 0.x NPM packages are not bumped to the latest minor version, despite the ^ semver operator. Therefore, we need to explicitly bump the conventions package to the latest version.

Was this helpful?
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").