-
Notifications
You must be signed in to change notification settings - Fork 517
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into ivana/populate-tox
- Loading branch information
Showing
7 changed files
with
408 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
name: "Automation: Notify issues for release" | ||
on: | ||
release: | ||
types: | ||
- published | ||
workflow_dispatch: | ||
inputs: | ||
version: | ||
description: Which version to notify issues for | ||
required: false | ||
|
||
# This workflow is triggered when a release is published | ||
jobs: | ||
release-comment-issues: | ||
runs-on: ubuntu-20.04 | ||
name: Notify issues | ||
steps: | ||
- name: Get version | ||
id: get_version | ||
run: echo "version=${{ github.event.inputs.version || github.event.release.tag_name }}" >> $GITHUB_OUTPUT | ||
|
||
- name: Comment on linked issues that are mentioned in release | ||
if: | | ||
steps.get_version.outputs.version != '' | ||
&& !contains(steps.get_version.outputs.version, 'a') | ||
&& !contains(steps.get_version.outputs.version, 'b') | ||
&& !contains(steps.get_version.outputs.version, 'rc') | ||
uses: getsentry/release-comment-issues-gh-action@v1 | ||
with: | ||
github_token: ${{ secrets.GITHUB_TOKEN }} | ||
version: ${{ steps.get_version.outputs.version }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
from sentry_sdk.flag_utils import flag_error_processor | ||
|
||
import sentry_sdk | ||
from sentry_sdk.integrations import Integration | ||
|
||
|
||
class FeatureFlagsIntegration(Integration): | ||
""" | ||
Sentry integration for capturing feature flags on error events. To manually buffer flag data, | ||
call `integrations.featureflags.add_feature_flag`. We recommend you do this on each flag | ||
evaluation. | ||
See the [feature flag documentation](https://develop.sentry.dev/sdk/expected-features/#feature-flags) | ||
for more information. | ||
@example | ||
``` | ||
import sentry_sdk | ||
from sentry_sdk.integrations.featureflags import FeatureFlagsIntegration, add_feature_flag | ||
sentry_sdk.init(dsn="my_dsn", integrations=[FeatureFlagsIntegration()]); | ||
add_feature_flag('my-flag', true); | ||
sentry_sdk.capture_exception(Exception('broke')); // 'my-flag' should be captured on this Sentry event. | ||
``` | ||
""" | ||
|
||
identifier = "featureflags" | ||
|
||
@staticmethod | ||
def setup_once(): | ||
# type: () -> None | ||
scope = sentry_sdk.get_current_scope() | ||
scope.add_error_processor(flag_error_processor) | ||
|
||
|
||
def add_feature_flag(flag, result): | ||
# type: (str, bool) -> None | ||
""" | ||
Records a flag and its value to be sent on subsequent error events by FeatureFlagsIntegration. | ||
We recommend you do this on flag evaluations. Flags are buffered per Sentry scope. | ||
""" | ||
flags = sentry_sdk.get_current_scope().flags | ||
flags.set(flag, result) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import concurrent.futures as cf | ||
import sys | ||
|
||
import pytest | ||
|
||
import sentry_sdk | ||
from sentry_sdk.integrations.featureflags import ( | ||
FeatureFlagsIntegration, | ||
add_feature_flag, | ||
) | ||
|
||
|
||
def test_featureflags_integration(sentry_init, capture_events, uninstall_integration): | ||
uninstall_integration(FeatureFlagsIntegration.identifier) | ||
sentry_init(integrations=[FeatureFlagsIntegration()]) | ||
|
||
add_feature_flag("hello", False) | ||
add_feature_flag("world", True) | ||
add_feature_flag("other", False) | ||
|
||
events = capture_events() | ||
sentry_sdk.capture_exception(Exception("something wrong!")) | ||
|
||
assert len(events) == 1 | ||
assert events[0]["contexts"]["flags"] == { | ||
"values": [ | ||
{"flag": "hello", "result": False}, | ||
{"flag": "world", "result": True}, | ||
{"flag": "other", "result": False}, | ||
] | ||
} | ||
|
||
|
||
def test_featureflags_integration_threaded( | ||
sentry_init, capture_events, uninstall_integration | ||
): | ||
uninstall_integration(FeatureFlagsIntegration.identifier) | ||
sentry_init(integrations=[FeatureFlagsIntegration()]) | ||
events = capture_events() | ||
|
||
# Capture an eval before we split isolation scopes. | ||
add_feature_flag("hello", False) | ||
|
||
def task(flag_key): | ||
# Creates a new isolation scope for the thread. | ||
# This means the evaluations in each task are captured separately. | ||
with sentry_sdk.isolation_scope(): | ||
add_feature_flag(flag_key, False) | ||
# use a tag to identify to identify events later on | ||
sentry_sdk.set_tag("task_id", flag_key) | ||
sentry_sdk.capture_exception(Exception("something wrong!")) | ||
|
||
# Run tasks in separate threads | ||
with cf.ThreadPoolExecutor(max_workers=2) as pool: | ||
pool.map(task, ["world", "other"]) | ||
|
||
# Capture error in original scope | ||
sentry_sdk.set_tag("task_id", "0") | ||
sentry_sdk.capture_exception(Exception("something wrong!")) | ||
|
||
assert len(events) == 3 | ||
events.sort(key=lambda e: e["tags"]["task_id"]) | ||
|
||
assert events[0]["contexts"]["flags"] == { | ||
"values": [ | ||
{"flag": "hello", "result": False}, | ||
] | ||
} | ||
assert events[1]["contexts"]["flags"] == { | ||
"values": [ | ||
{"flag": "hello", "result": False}, | ||
{"flag": "other", "result": False}, | ||
] | ||
} | ||
assert events[2]["contexts"]["flags"] == { | ||
"values": [ | ||
{"flag": "hello", "result": False}, | ||
{"flag": "world", "result": False}, | ||
] | ||
} | ||
|
||
|
||
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher") | ||
def test_featureflags_integration_asyncio( | ||
sentry_init, capture_events, uninstall_integration | ||
): | ||
asyncio = pytest.importorskip("asyncio") | ||
|
||
uninstall_integration(FeatureFlagsIntegration.identifier) | ||
sentry_init(integrations=[FeatureFlagsIntegration()]) | ||
events = capture_events() | ||
|
||
# Capture an eval before we split isolation scopes. | ||
add_feature_flag("hello", False) | ||
|
||
async def task(flag_key): | ||
# Creates a new isolation scope for the thread. | ||
# This means the evaluations in each task are captured separately. | ||
with sentry_sdk.isolation_scope(): | ||
add_feature_flag(flag_key, False) | ||
# use a tag to identify to identify events later on | ||
sentry_sdk.set_tag("task_id", flag_key) | ||
sentry_sdk.capture_exception(Exception("something wrong!")) | ||
|
||
async def runner(): | ||
return asyncio.gather(task("world"), task("other")) | ||
|
||
asyncio.run(runner()) | ||
|
||
# Capture error in original scope | ||
sentry_sdk.set_tag("task_id", "0") | ||
sentry_sdk.capture_exception(Exception("something wrong!")) | ||
|
||
assert len(events) == 3 | ||
events.sort(key=lambda e: e["tags"]["task_id"]) | ||
|
||
assert events[0]["contexts"]["flags"] == { | ||
"values": [ | ||
{"flag": "hello", "result": False}, | ||
] | ||
} | ||
assert events[1]["contexts"]["flags"] == { | ||
"values": [ | ||
{"flag": "hello", "result": False}, | ||
{"flag": "other", "result": False}, | ||
] | ||
} | ||
assert events[2]["contexts"]["flags"] == { | ||
"values": [ | ||
{"flag": "hello", "result": False}, | ||
{"flag": "world", "result": False}, | ||
] | ||
} |
Oops, something went wrong.