# Issue Platform

The Issue Platform allows developers to create new issue types from arbitrary data sources. If you have data about something that you want to track via an issue, you can build it on the issue platform. For example, building profiling issues on the issue platform allowed us to turn things like “JSON decoding on the main thread” into their own issue types.

To use the Issue Platform you need to:

1. [Write a Detector](https://docs.sentry.io/.md#writing-a-detector)
2. [Register an Issue Type](https://docs.sentry.io/.md#register-an-issue-type)
3. [Send Payloads to the Issue Platform](https://docs.sentry.io/.md#send-payloads-to-the-issue-platform)
4. [Release](https://docs.sentry.io/.md#releasing-your-issue-type)

## [Writing a Detector](https://docs.sentry.io/.md#writing-a-detector)

The first step to introducing a new issue type to Sentry is to determine what type of issue you want to detect. It can be from any data stream, as long as you can produce an [Occurrence](https://docs.sentry.io/.md#issue-occurrence-schema) representing the issue.

Writing a detector is the hardest part of creating a new issue type. Refer to [this guide](https://docs.sentry.io/backend/issue-platform-detectors.md) for tips on how to write one.

## [Register an Issue Type](https://docs.sentry.io/.md#register-an-issue-type)

To register a new issue type you need to subclass [`GroupType`](https://github.com/getsentry/sentry/blob/ef76b0765f6c057af12b1cd0dc2de6b42a938c02/src/sentry/issues/grouptype.py#L98-L108)

When registering the class, set the following required attributes on the class:

* `type_id`: A unique integer to identify your issue type.
* `slug`: A unique slug to identify your issue type. Used to search by issue type in the issue stream
* `description`: A human-readable description of your issue type.
* `category`: The overall category that your issue type belongs to. You can [register a category](https://docs.sentry.io/.md#register-a-category) if the existing ones don't make sense for your issue type.

You may also set these optional attributes:

* `released`: Whether this issue type has been released to all customers. See [Releasing your issue type](https://docs.sentry.io/.md#releasing-your-issue-type)

* `noise_config`: A `NoiseConfig` that allows you to set policy on how many times a fingerprint must occur in a period of time before an issue is created. NoiseConfig has two attributes:

  * `ignore_limit`: How many occurrences need to occur before we create a new issue
  * `expiry_time`: The period of time the occurrences must occur in before we reset the count

* `enable_auto_resolve`: Whether this issue type can be resolved automatically after a number of days with no events. The auto\_resolve window is configurable in each project's settings. By default this attribute is set to true.

* `enable_escalation_detection`: Whether this issue type can escalate using the [Escalating Issues Algorithm](https://docs.sentry.io/product/issues/states-triage/escalating-issues.md). By default this attribute is set to true.

Here's an example issue type:

```python
@dataclass(frozen=True)
class ProfileFileIOGroupType(GroupType):
    type_id = 2001
    slug = "profile_file_io_main_thread"
    description = "File I/O on Main Thread"
    category = GroupCategory.PROFILE.value
```

and here's one with `noise_config` configured

```python
@dataclass(frozen=True)
class ProfileFileIOGroupType(GroupType):
    type_id = 2001
    slug = "profile_file_io_main_thread"
    description = "File I/O on Main Thread"
    category = GroupCategory.PROFILE.value
    noise_config = NoiseConfig(5, timedelta(days=2))
```

### [Register a Category](https://docs.sentry.io/.md#register-a-category)

You might also want to register a new category related to your issue type as well. This allows you to group related issue types together. To do so, add your category to [this enum](https://github.com/getsentry/sentry/blob/97f4174c28041357aa190f27012dc33c1c7bafc7/src/sentry/issues/grouptype.py#L17-L22)

## [Send Payloads to the Issue Platform](https://docs.sentry.io/.md#send-payloads-to-the-issue-platform)

If operating within the Sentry codebase, you can call [sentry.issues.produce\_occurrence\_to\_kafka](https://github.com/getsentry/sentry/blob/master/src/sentry/issues/producer.py#L41-L46) with the following optional parameters:

* `payload_type`: [PayloadType](https://docs.sentry.io/.md#payload-type)

* one of the following, per `payload_type`

  * `occurrence`: [IssueOccurrence](https://github.com/getsentry/sentry/blob/d262bbd9d8d3a2747d5251bee35c016c13ca050a/src/sentry/issues/issue_occurrence.py#L58)
  * `status_change`: [StatusChange](https://github.com/getsentry/sentry/blob/7fd40bc33607e727ea2fac0183bd04f4ad298ba3/src/sentry/issues/status_change_message.py#L15)

* `event_data`: Dict\[str, Any]

If operating from an external service then pass a json payload that matches the [Issue Occurrence Schema](https://docs.sentry.io/.md#issue-occurrence-schema) to the `ingest-occurrences` topic on the [issue occurrences Kafka cluster](https://github.com/getsentry/getsentry/blob/97039335a29517a7e48149148cdd7a30a60971e7/getsentry/conf/settings/prod.py#L567-L571)

### [Payload Type](https://docs.sentry.io/.md#payload-type)

Determines the type of payload sent to the issue platform. By default, `payload_type` is set to `OCCURRENCE`.

The [PayloadType](https://github.com/getsentry/sentry/blob/2e5a39ff3dd4afbd33f2ff7d2ba161285107afe4/src/sentry/issues/producer.py#L23) enum has two types:

* `OCCURRENCE`: for sending an occurrence
* `STATUS_CHANGE`: for sending a status update

### [Issue Occurrence Schema](https://docs.sentry.io/.md#issue-occurrence-schema)

[Schema](https://github.com/getsentry/sentry/blob/ccfb37212102945df5f35e8f55fe38891b70036b/src/sentry/issues/issue_occurrence.py#L23-L36)

Required:

* `id`: str. A user generated uuid in string format representing a unique id for this occurrence. Generally it's a good idea to generate this separately to your event id.
* `project_id`: int. Id of the project this occurred in
* `fingerprint`: Sequence\[str]. Unique identifier for the root cause of this problem. Used for aggregating occurrences together into groups. We only make use of the first fingerprint for the moment - if you have a use case for additional fingerprints let the issue platform team know.
* `issue_title`: str. A short description of the problem. This will be used as the title of the issue and also used in notifications.
* `subtitle`: str: Extra detail about the issue, displayed below the `issue_title`
* `culprit`: str: Where the problem occurred. This could be an api path, a function path, etc. [![issue properties](https://docs.sentry.io/_next/image/?url=%2Fmdx-images%2FissueProperties-ARGRMZMI.jpg%23561x84\&w=1200\&q=75)](https://docs.sentry.io/mdx-images/issueProperties-ARGRMZMI.jpg)
* `evidence_data`: Mapping\[str, Any]. An arbitrary map of data. The issue platform doesn't make use of this data directly, it just make it available for use on the frontend and in notifications. This can be used to customize the issue details ui, notifications and so on.
* `evidence_display`: Sequence\[[IssueEvidence](https://docs.sentry.io/.md#issue-evidence-schema)]. A sequence of `IssueEvidence` entries. These are used to display generic information about your issue in the issue details ui and in various notifications. Even if you are customizing the ui and email, it's recommended to include this so that we can display information correctly on all our other integrations. Typically, these will be displayed in a table when space allows. For space limited integrations we'll display one row that is labelled `important` if available.
* `type`: int: The type of issue you are creating. Maps to `type_id` in your registered `GroupType`.
* `detection_time`: float. A timestamp representing when the issue was detected.
* `level`: str. Info\Warning\Error

One of:

* `event_id`: str. The event id of an existing event, typically this would be an error or transaction id.
* `event`: [Event](https://docs.sentry.io/.md#event-schema)

Optional:

* `resource_id`: str | None. An identifier used to link to an external system to load data. For example, this could be an id that we use to build a link to a specific product page.

### [Issue Evidence Schema](https://docs.sentry.io/.md#issue-evidence-schema)

[Schema](https://github.com/getsentry/sentry/blob/ccfb37212102945df5f35e8f55fe38891b70036b/src/sentry/issues/issue_occurrence.py#L17-L20)

* `name`: str.
* `value`: str
* `important`: bool. Whether this entry contains important data to display to the user. One entry should be marked as important, and it will be displayed in space constrained integrations.

The most current version of this schema is documented here:

### [Event Schema](https://docs.sentry.io/.md#event-schema)

[Schema](https://github.com/getsentry/sentry/blob/ccfb37212102945df5f35e8f55fe38891b70036b/src/sentry/issues/json_schemas.py#L3)

The event schema should match the [Sentry event schema](https://docs.sentry.io/sdk/data-model/event-payloads.md). Any fields/interfaces defined here can be passed along with your event. It's best to fill in as many of these as makes sense for your issue type.

There's a minimum set of fields which should be included:

* `environment`
* `event_id`
* `platform`
* `project_id`
* `received`
* `tags` - Should be an empty dict if no tags
* `timestamp`

Caveats

* Attachments will not work. If you have a need for this please contact the issues team.

### [Status Change Schema](https://docs.sentry.io/.md#status-change-schema)

If `payload_type` is set to `STATUS_CHANGE`, providing a `StatusChangeMessage` will update the status of an issue.

The `StatusChangeMessage` schema is as follows:

* `fingerprint`: unique identifier for the occurrence

* `project_id`: int.

* `new_status`: int. Uses [GroupStatus](https://docs.sentry.io/.md) enum. We currently support the following:

  * `UNRESOLVED`
  * `RESOLVED`
  * `IGNORED`

* `new_substatus`: int | None. Uses [GroupSubStatus](https://docs.sentry.io/.md) enum. We do not support the `NEW` substatus.

When providing the `new_status` and `new_substatus`, refer to the supported issue states and transitions [here](https://docs.sentry.io/.md).

## [Releasing your issue type](https://docs.sentry.io/.md#releasing-your-issue-type)

The issue platform provides functionality to help release your new issue type in a controlled way. There are 3 feature flags that are used to release an issue type:

* Ingest - This controls whether we'll accept or drop issues of this type in our consumer
* Post processing - This controls whether we'll pass the issue along to post processing. If disabled, then issues will be created but no notifications will be sent. This can be helpful for testing out what issues look like before release. *Note:* Any issues created this way will not send new issue notifications after the flag is enabled, since they already exist. In the future, if there is demand we might provide a way to remove all test versions of a new issue type.
* UI - This controls whether the issue type will appear in the issue list and elsewhere in the ui.

These flags are all controlled via flagpole and set via options automator. To get the base values for all of these for easy pasting into flagpole, run `sentry createissueflag --slug=<your_group_slug> --owner=<your_team_name>`. The results of this can be directly pasted into flagpole.yml.

Once your issue type is fully released, and you want it to go out to self-hosted and single tenant you can set `released = True` on your GroupType. This allows it to be released everywhere, and removes the feature flags and options. Generally we recommend doing this after your issue type has been in GA for long enough to verify that it's working as intended.
