|
@@ -66,7 +66,8 @@ commit_message_base_messages = [
|
|
|
|
|
|
base_paths_by_file_type = {"js": ["components/", "views/"], "py": ["flask/", "routes/"]}
|
|
|
|
|
|
-rate_by_release_num = [1.0, 0.99, 0.9]
|
|
|
+rate_by_release_num = [0.9, 0.95, 0.85]
|
|
|
+agg_rate_by_release_num = [0.995, 0.998, 0.95]
|
|
|
|
|
|
org_users = [
|
|
|
("scefali", "Stephen Cefali"),
|
|
@@ -77,6 +78,30 @@ org_users = [
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
+contexts_by_mobile_platform = {
|
|
|
+ "apple-ios": {
|
|
|
+ "device": [
|
|
|
+ ["iPad13,1", "iOS"],
|
|
|
+ ["iPad13,2", "iOS"],
|
|
|
+ ["iPhone13,1", "iOS"],
|
|
|
+ ["iPhone11", "iOS"],
|
|
|
+ ],
|
|
|
+ "os": [["iOS", "14.5"], ["iOS", "13.3"], ["iOS", "14.6"], ["iOS", "12"]],
|
|
|
+ },
|
|
|
+ "android": {
|
|
|
+ "device": [
|
|
|
+ ["Pixel 4", "Pixel"],
|
|
|
+ ["Pixel 5", "Pixel"],
|
|
|
+ ["Pixel 3a", "Pixel"],
|
|
|
+ ["SM-A125U", "SM-A125U"],
|
|
|
+ ["SM-G973U", "SM-G973U"],
|
|
|
+ ],
|
|
|
+ "os": [["Android", "10"], ["Android", "9"], ["Android", "8"]],
|
|
|
+ },
|
|
|
+}
|
|
|
+
|
|
|
+mobile_platforms = ["apple-ios", "android", "react-native"]
|
|
|
+
|
|
|
|
|
|
def get_data_file_path(file_name):
|
|
|
return os.path.join(os.path.dirname(__file__), "data", file_name)
|
|
@@ -271,6 +296,22 @@ def gen_base_context():
|
|
|
return random.choice(contexts)
|
|
|
|
|
|
|
|
|
+def gen_mobile_context(platform):
|
|
|
+ """
|
|
|
+ Generates context for mobile events
|
|
|
+ """
|
|
|
+ if platform == "react-native":
|
|
|
+ platform = random.choice(["apple-ios", "android"])
|
|
|
+ contexts = contexts_by_mobile_platform[platform]
|
|
|
+ device = random.choice(contexts["device"])
|
|
|
+ os = random.choice(contexts["os"])
|
|
|
+ context = {
|
|
|
+ "device": {"model": device[0], "family": device[1], "type": "device"},
|
|
|
+ "os": {"name": os[0], "version": os[1], "type": "os"},
|
|
|
+ }
|
|
|
+ return context
|
|
|
+
|
|
|
+
|
|
|
def get_release_from_time(org_id, timestamp):
|
|
|
"""
|
|
|
Returns the most release before a specific time
|
|
@@ -466,20 +507,20 @@ def fix_measurements(event_json):
|
|
|
measurements.update(measurement_markers)
|
|
|
|
|
|
|
|
|
-def update_context(event, trace=None):
|
|
|
+def update_context(event, trace=None, platform=None):
|
|
|
+ mobile = platform in mobile_platforms
|
|
|
context = event["contexts"]
|
|
|
# delete device since we aren't mocking it (yet)
|
|
|
if "device" in context:
|
|
|
del context["device"]
|
|
|
# generate random browser and os
|
|
|
- context.update(**gen_base_context())
|
|
|
+ base_context = gen_mobile_context(platform) if mobile else gen_base_context()
|
|
|
+ context.update(**base_context)
|
|
|
+
|
|
|
# add our trace info
|
|
|
base_trace = context.get("trace", {})
|
|
|
if not trace:
|
|
|
- trace = {
|
|
|
- "trace_id": uuid4().hex,
|
|
|
- "span_id": uuid4().hex[:16],
|
|
|
- }
|
|
|
+ trace = {"trace_id": uuid4().hex, "span_id": uuid4().hex[:16]}
|
|
|
base_trace.update(**trace)
|
|
|
context["trace"] = base_trace
|
|
|
|
|
@@ -615,6 +656,8 @@ class DataPopulation:
|
|
|
"components/Form.js",
|
|
|
"flask/app.py",
|
|
|
"purchase.py",
|
|
|
+ "checkout.swift",
|
|
|
+ "shop.java",
|
|
|
],
|
|
|
["js", "py"],
|
|
|
)
|
|
@@ -678,7 +721,7 @@ class DataPopulation:
|
|
|
alert_rule = create_alert_rule(
|
|
|
org,
|
|
|
[project],
|
|
|
- "High Error Rate",
|
|
|
+ f"High Error Rate - {project.name} ",
|
|
|
"level:error",
|
|
|
"count()",
|
|
|
10,
|
|
@@ -1053,7 +1096,61 @@ class DataPopulation:
|
|
|
|
|
|
self.log_info("populate_connected_event_scenario_2.finished")
|
|
|
|
|
|
- def populate_generic_error(self, project: Project, file_path, dist_number, starting_release=0):
|
|
|
+ def populate_connected_event_scenario_3(self, ios_project: Project):
|
|
|
+
|
|
|
+ ios_error = get_event_from_file("scen3/handled.json")
|
|
|
+ ios_transaction = get_event_from_file("scen3/ios_transaction.json")
|
|
|
+
|
|
|
+ self.log_info("populate_connected_event_scenario_3.start")
|
|
|
+
|
|
|
+ for (timestamp, day) in self.iter_timestamps(4):
|
|
|
+ transaction_user = self.generate_user()
|
|
|
+ trace_id = uuid4().hex
|
|
|
+ release = get_release_from_time(ios_project.organization_id, timestamp)
|
|
|
+ release_sha = release.version
|
|
|
+
|
|
|
+ old_span_id = ios_transaction["contexts"]["trace"]["span_id"]
|
|
|
+ root_span_id = uuid4().hex[:16]
|
|
|
+ duration = self.gen_frontend_duration(day)
|
|
|
+
|
|
|
+ trace = {
|
|
|
+ "trace_id": trace_id,
|
|
|
+ "span_id": root_span_id,
|
|
|
+ }
|
|
|
+
|
|
|
+ # iOS transaction
|
|
|
+ local_event = copy.deepcopy(ios_transaction)
|
|
|
+ local_event.update(
|
|
|
+ project=ios_project,
|
|
|
+ platform=ios_project.platform,
|
|
|
+ event_id=uuid4().hex,
|
|
|
+ user=transaction_user,
|
|
|
+ release=release_sha,
|
|
|
+ timestamp=timestamp,
|
|
|
+ start_timestamp=timestamp - timedelta(duration),
|
|
|
+ )
|
|
|
+ update_context(local_event, trace, platform=ios_project.platform)
|
|
|
+ self.fix_transaction_event(local_event, old_span_id)
|
|
|
+ self.safe_send_event(local_event)
|
|
|
+
|
|
|
+ # iOS Error
|
|
|
+ local_event = copy.deepcopy(ios_error)
|
|
|
+ local_event.update(
|
|
|
+ project=ios_project,
|
|
|
+ platform=ios_project.platform,
|
|
|
+ timestamp=timestamp,
|
|
|
+ user=transaction_user,
|
|
|
+ release=release_sha,
|
|
|
+ )
|
|
|
+ update_context(local_event, trace, platform=ios_project.platform)
|
|
|
+ self.fix_error_event(local_event)
|
|
|
+ self.safe_send_event(local_event)
|
|
|
+
|
|
|
+ self.log_info("populate_connected_event_scenario_3.finished")
|
|
|
+
|
|
|
+ def populate_generic_error(
|
|
|
+ self, project: Project, file_path, dist_number, mobile=False, starting_release=0
|
|
|
+ ):
|
|
|
"""
|
|
|
This function populates a single error
|
|
|
Occurrance times and durations are randomized
|
|
@@ -1075,13 +1172,18 @@ class DataPopulation:
|
|
|
user=transaction_user,
|
|
|
release=release_sha,
|
|
|
)
|
|
|
- update_context(local_event)
|
|
|
+ update_context(local_event, platform=project.platform)
|
|
|
self.fix_error_event(local_event)
|
|
|
self.safe_send_event(local_event)
|
|
|
self.log_info("populate_generic_error.finished")
|
|
|
|
|
|
def populate_generic_transaction(
|
|
|
- self, project: Project, file_path, dist_number, starting_release=0
|
|
|
+ self,
|
|
|
+ project: Project,
|
|
|
+ file_path,
|
|
|
+ dist_number,
|
|
|
+ mobile,
|
|
|
+ starting_release=0,
|
|
|
):
|
|
|
"""
|
|
|
This function populates a single transaction
|
|
@@ -1110,7 +1212,7 @@ class DataPopulation:
|
|
|
start_timestamp=timestamp - timedelta(seconds=duration),
|
|
|
)
|
|
|
|
|
|
- update_context(local_event)
|
|
|
+ update_context(local_event, platform=project.platform)
|
|
|
|
|
|
self.fix_transaction_event(local_event, old_span_id)
|
|
|
self.safe_send_event(local_event)
|
|
@@ -1158,7 +1260,7 @@ class DataPopulation:
|
|
|
release_num = int(version.split(".")[-1])
|
|
|
threshold = rate_by_release_num[release_num]
|
|
|
outcome = random.random()
|
|
|
- if outcome > threshold:
|
|
|
+ if outcome <= threshold:
|
|
|
if error_file:
|
|
|
local_event = copy.deepcopy(error)
|
|
|
local_event.update(
|
|
@@ -1218,7 +1320,8 @@ class DataPopulation:
|
|
|
item_headers = json.dumps({"type": "sessions"})
|
|
|
|
|
|
agg = []
|
|
|
- threshold = 0.004
|
|
|
+ release_num = int(version.split(".")[-1])
|
|
|
+ threshold = agg_rate_by_release_num[release_num]
|
|
|
|
|
|
if self.quick:
|
|
|
num_users = int(random.uniform(100, 200))
|
|
@@ -1290,13 +1393,15 @@ class DataPopulation:
|
|
|
self.populate_generic_error(react_project, "errors/react/func_undefined.json", 3)
|
|
|
self.populate_generic_error(python_project, "errors/python/cert_error.json", 5)
|
|
|
self.populate_generic_error(
|
|
|
- python_project, "errors/python/concat_str_none.json", 4, starting_release=2
|
|
|
+ python_project, "errors/python/concat_str_none.json", 4, starting_release=1
|
|
|
)
|
|
|
self.assign_issues()
|
|
|
|
|
|
def handle_mobile_scenario(
|
|
|
self, ios_project: Project, android_project: Project, react_native_project: Project
|
|
|
):
|
|
|
+ with sentry_sdk.start_span(op="handle_mobile_scenario", description="pre_event_setup"):
|
|
|
+ self.generate_alerts(android_project)
|
|
|
if not self.get_config_var("DISABLE_SESSIONS"):
|
|
|
with sentry_sdk.start_span(
|
|
|
op="handle_react_python_scenario", description="populate_sessions"
|
|
@@ -1304,28 +1409,31 @@ class DataPopulation:
|
|
|
self.populate_sessions(ios_project, 6, True)
|
|
|
self.populate_sessions(android_project, 8, True)
|
|
|
self.populate_sessions(react_native_project, 9, True)
|
|
|
-
|
|
|
+ with sentry_sdk.start_span(op="handle_mobile_scenario", description="populate_connected"):
|
|
|
+ self.populate_connected_event_scenario_3(ios_project)
|
|
|
with sentry_sdk.start_span(op="handle_mobile_scenario", description="populate_errors"):
|
|
|
- self.populate_generic_error(ios_project, "errors/ios/exc_bad_access.json", 3)
|
|
|
self.populate_generic_error(
|
|
|
- ios_project, "errors/ios/handled.json", 5, starting_release=1
|
|
|
- )
|
|
|
- self.populate_generic_transaction(
|
|
|
- ios_project, "transactions/ios/ios_transaction.json", 4
|
|
|
+ ios_project, "errors/ios/exc_bad_access.json", 3, mobile=True
|
|
|
)
|
|
|
+
|
|
|
self.populate_generic_error(
|
|
|
- android_project, "errors/android/out_of_bounds.json", 2, starting_release=1
|
|
|
+ android_project,
|
|
|
+ "errors/android/out_of_bounds.json",
|
|
|
+ 2,
|
|
|
+ mobile=True,
|
|
|
+ starting_release=2,
|
|
|
)
|
|
|
self.populate_generic_error(
|
|
|
- android_project, "errors/android/app_not_responding.json", 3
|
|
|
+ android_project, "errors/android/app_not_responding.json", 3, mobile=True
|
|
|
)
|
|
|
self.populate_generic_error(
|
|
|
- react_native_project, "errors/react_native/out_of_memory.json", 5
|
|
|
+ react_native_project, "errors/react_native/out_of_memory.json", 5, mobile=True
|
|
|
)
|
|
|
self.populate_generic_error(
|
|
|
react_native_project,
|
|
|
"errors/react_native/promise_rejection.json",
|
|
|
3,
|
|
|
- starting_release=1,
|
|
|
+ mobile=True,
|
|
|
+ starting_release=2,
|
|
|
)
|
|
|
self.assign_issues()
|