# Contributing Running this repo requires the usage of [volta](https://volta.sh/). See instructions on installing volta on their documentation [here](https://docs.volta.sh/guide/getting-started). The repo requires Node v22 or higher to run. ## Setup To install required dependencies, run `yarn install`. ```bash yarn install ``` ## Process Before attributes are sent from SDKs, or attribute values or definitions change, the attributes MUST be defined or updated in this repo. If the convention you need doesn't exist yet, open a PR there to propose it. Only after the convention has been merged, ship it in an SDK. This ensures all SDKs use consistent naming and semantics. The merge process for sentry-conventions PRs: 1. Open a PR with the proposed convention change ([Adding an Attribute](#adding-a-new-attribute)). 2. Get an approval from at least one code owner. 3. Wait for at least 3 business days after the first approval to give other code owners a chance to review. This grace period exists because attribute names, once shipped in an SDK release, are effectively permanent. If a bad name gets adopted by even one SDK, fixing it requires a deprecation cycle across the SDK(s) that shipped it and the Sentry backend. There is no urgency exception. If a name feels wrong, raise it during review, not after. 4. Merge your PR (alternatively, code owners may merge it after review) ## Adding a new attribute > [!IMPORTANT] > > ### OTel Alignment > > Before proposing a new attribute, check the [OpenTelemetry semantic conventions registry](https://opentelemetry.io/docs/specs/semconv/registry/attributes/). > > If OTel already defines the attribute: > > - Use the OTel name and type. Set `is_in_otel: true`. > - Do not create a Sentry-specific synonym!. Diverging from OTel for the same concept creates more confusion and work than value. > > If OTel doesn't define it, or the concept is Sentry-specific, set `is_in_otel: false`. > > When in doubt, prefer OTel alignment. Sentry conventions should only extend OTel, not diverge from it. Run `yarn run create:attribute` to create a new attribute. This will prompt you to enter information about the attribute. There are two modes: - Interactive mode: This will prompt you to enter information about the attribute. - Non-interactive mode: This will use the information provided to create the attribute. You'll need to explicitly specify all the needed information when running the command. Provide example values with the `examples` field as a non-empty JSON array. For an array-valued attribute, each example is itself an array. The legacy `example` field remains supported for existing definitions, but new and updated attributes should use `examples`. ```bash # Interactive mode yarn run create:attribute # Non-interactive mode yarn run create:attribute --key http.route --description "The route pattern of the request" --type string --apply_scrubbing never --is_in_otel true --visibility public --examples '["/users/:id","/teams/:id"]' --alias "url.template" ``` After you've created an attribute, the script will ask if you'd like to generate the docs. This will run `yarn run generate`. If you want to skip this step, you can run `yarn run generate` manually afterwards. If you need help, run `yarn run create:attribute --help` to see the available options. ### Adding an attribute transformation Most deprecated attributes only need a direct rename via `deprecation.replacement` and a `_status` of `backfill` or `normalize`. Add an attribute transformation only when the replacement value must be derived or reshaped from one or more source attributes. Attribute transformations are descriptive documents in `model/attribute_transformations/`. They define the transformation contract for downstream consumers such as Relay; they do not contain executable transformation code. Relay owns the implementation. When adding an attribute transformation: 1. Create a JSON document in `model/attribute_transformations/` using `schemas/attribute_transformation.schema.json`. 2. Use a stable, descriptive `id`, for example `namespace_old_attribute_to_new_attribute`. The file name MUST match the id. 3. List the source attributes in `inputs` and replacement attributes in `outputs`. 4. Describe the transformation in `actions`, including how existing replacement values should be handled. 5. Add examples showing input attributes and expected output attributes. 6. On every source attribute, set: - `deprecation.replacement` to the replacement attribute, - `deprecation._status` to `transform`, - `deprecation.transformation` to the transformation id. 7. Run `yarn run generate` so generated metadata includes the transformation reference. 8. Run the relevant tests, or `yarn test` for the full suite. After the change is released, update downstream consumers that apply conventions at ingest time, especially Relay. ## Adding a new convention for span names Span name conventions are organized loosely by type of span operation. To create a convention for a new type of span operation: 1. Create a new file in the `models/name` directory. Ideally the file name should match a folder in the `models/attributes` directory (e.g., `ui.json`). 2. Fill in the contents of the file with the necessary information. You can find the schema for the document in `schemas/name.schema.json`. - The `"brief"` field should be a short description of what kind of information the `name` field contains for this kind of span operation. - The `"is_in_otel"` field describes whether the [OpenTelemetry Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/) describe how the `name` field should be constructed for this kind of span operation. If there are no OTel conventions for this kind of operation, set this field to `false`. - The `"op"` field contains a list of all known Sentry span operation names that the convention is applicable to. For example, in Sentry `"db"`, and `"db.query"` spans can construct their names using the `"db"` name conventions. - The `"templates"` field contains a list of string templates for constructing the `name` field from known span attributes. Strings in curly braces are replaced with the value of the corresponding attribute. For example, the template `"{{db.system}}"` becomes `"postgres"` for a span with the attribute `"db.system"` set to the string `"postgres"`. The top template should be the preferred version, with subsequent templates being fallbacks. The final template should be a static string without any curly braces. - The `"examples"` field contains a list of example span names. Please add a few examples that correspond to the available templates. Remember to run `yarn run generate` after editing or creating a `name` convention to recreate the documentation and auto-generated code. ## Code Generation After you edit an attribute or add a new one, run `yarn run generate` to generate and format the code, which are generated from the json files stored in the `model` directory. Docs are generated on every PR merge. ## Releasing and Updating Downstream Repos For detailed instructions on releasing new versions and updating downstream repos (Relay, Snuba, Sentry), see the [Sentry Conventions engineering practice guide](https://develop.sentry.dev/engineering-practices/sentry-conventions/) on the develop docs. ## Policies ### Attributes Here's a list of policies that any newly added attributes MUST follow. Most of these are automatically enforced by the test suite. - The attribute MUST be namespaced. Example: `nextjs.function_id`, not `function_id`. - Use dots as separators for namespaces and logical grouoing, not underscores (`http.request.method`, not `http_request_method`) - Use `snake_case` for multi-word names (`browser.web_vital.ttfb.request_time`, not `browser.webVital.ttfb.request-time`) - Exception: For names where the separating delimiter is already established in the ecosystem, do not convert them to snake_case. For example, http headers like `user-agent` SHOULD keep the separating `-` to retain integrity of the value. Other examples are parameter names (URL, Routing, DB query parameters, etc). When in doubt, check the OTel semantic conventions, since they follow the same approach (see [request headers](https://opentelemetry.io/docs/specs/semconv/registry/attributes/http/#http-request-header) for example). - The `apply_scrubbing` field in the attribute definition MUST be `manual` or `auto` (if the attribute can contain sensitive data). It SHOULD be `never` only if scrubbing the attribute value for PII would potentially break product features. For example, `sentry.replay_id` should have `apply_scrubbing` set to `never`. - When an attribute is added that deprecates an old one: - The old one should be marked as deprecated, and it MUST point to the new one using the `deprecation.replacement` field. - For both the new and the old attribute, and any existing aliases of the old attribute, the new and old names MUST be added to the `aliases` list. - The deprecation status of the old one SHOULD be set to `backfill` for at least 90 days, and then set to `normalize`. - If the value cannot be copied directly to the replacement attribute, use `_status: "transform"` and reference an attribute transformation with `deprecation.transformation`. - Prefer keeping names stable. Renames require deprecation cycles across all SDKs that adopted the attribute! ### Span operations Span ops live in `model/op/` and are shipped to SDKs as generated constants, so they can't just be removed. - Deprecate an op instead of deleting it, by adding a `deprecation` object to its field in `model/op/.json`. - Point at the successor with `deprecation.replacement` only if there is a direct, 1:1 replacement. It MUST be an existing, non-deprecated op. - Add a `deprecation.note` if the replacement alone doesn't explain the change. If there is no direct replacement, use the note to recommend what to use instead (e.g. "Use `ui.mount` or `ui.update` instead, depending on the operation."). - If the op is listed in more than one category, all of its definitions MUST declare the same `deprecation`, because they share a single generated constant. - Run `yarn run generate` afterwards. Deprecated ops keep their constant, marked with a JSDoc `@deprecated` tag in JavaScript and `#[deprecated]` in Rust. ## Testing This repo uses [Vitest](https://vitest.dev/) for testing. To run the tests, run `yarn test`. The tests enforce logical correctness as well as policies that the model should follow. ```bash yarn test ``` ## Linting This repo uses [oxlint](https://oxc.rs/docs/guide/usage/linter.html) and [oxfmt](https://oxc.rs/docs/guide/usage/formatter.html) along with other platform-specific tools for linting and formatting. To run the linting, run `yarn lint`. ```bash yarn lint ``` This includes TypeScript type checking, which you can also run on its own: ```bash yarn lint:types ```