Code snippet based on a Django project for routing to a different Rollbar project based on a file path.
The squad ownership is based on a CODEOWNERS
file and is parsed using this Python library https://github.com/sbdchd/codeowners
Code snippet based on a Django project for routing to a different Rollbar project based on a file path.
The squad ownership is based on a CODEOWNERS
file and is parsed using this Python library https://github.com/sbdchd/codeowners
/basedir/documents/ @myorg/squad1 | |
/basedir/documents/otherplace @myorg/squad1 | |
/basedir/ui/ @myorg/squad3 | |
/basedir/preferences/ @myorg/squad2 |
def initialize_codeowners() -> CodeOwners: | |
with open(os.path.join(BASE_DIR, os.pardir, "CODEOWNERS")) as codeowners_file: | |
return CodeOwners(codeowners_file.read()) | |
CODEOWNERS = initialize_codeowners() | |
SQUAD_ROLLBAR_ACCESS_TOKENS = { | |
"@myorg/squad1": env.str("SQUAD1_ROLLBAR_ACCESS_TOKEN", None), | |
"@myorg/squad2": env.str("SQUAD2_ROLLBAR_ACCESS_TOKEN", None), | |
"@myorg/squad3": env.str("SQUAD3_ROLLBAR_ACCESS_TOKEN", None), | |
} | |
import rollbar | |
rollbar_orig_send_payload = rollbar.send_payload | |
def wrapped_rollbar_send_payload(payload: Dict[str, Any], access_token: str) -> None: | |
""" | |
Wraps the Rollbar payload send to modify the access token away from the default, if applicable. | |
If the given 'payload' being sent to Rollbar is an exception that has a file name, we can be | |
more specific in the Rollbar project that we send this to | |
:param payload: the entire payload being sent to Rollbar | |
:param access_token: the default Rollbar access token when Rollbar was initially configured | |
""" | |
if env.bool("ROLLBAR_SQUAD_ROUTING_DISABLED", False): | |
return rollbar_orig_send_payload(payload, access_token) | |
# Frames are the individual stack frames in reverse order from where an exception occurred. These | |
# are already reverse order meaning the first item in the list is the top-level of the stack trace (so | |
# somewhere in Django) and the last item in the list is where the exception was raised | |
exception_stackframes: Optional[List] = ( | |
payload.get("data", {}).get("body", {}).get("trace", {}).get("frames") | |
) | |
# This pathname is used for logger.error records and identifies exactly where the logger.error | |
# occurred | |
logger_call_pathname: Optional[str] = ( | |
payload.get("data", {}).get("body", {}).get("message", {}).get("record", {}).get("pathname") | |
) | |
filepaths: Optional[List[str]] = None | |
if exception_stackframes: | |
filepaths = [frame["filename"] for frame in exception_stackframes] | |
elif logger_call_pathname: | |
filepaths = [logger_call_pathname] | |
if filepaths: | |
from django.conf import settings | |
specific_owners = None | |
for path in filepaths: | |
if settings.BASE_DIR not in path: | |
# only care about files in this repo | |
continue | |
# ends up transforming /path/to/basedir -> basedir | |
code_start_path = pathlib.PurePath(settings.BASE_DIR).name | |
relative_repo_path = f"{code_start_path}{path.replace(settings.BASE_DIR, '')}" | |
specific_owners = [ | |
defined_owner[1] for defined_owner in settings.CODEOWNERS.of(relative_repo_path) | |
] | |
sent_squad_specific_rollbar = False | |
if specific_owners: | |
logger.debug(f"Sending Rollbar to {specific_owners}") | |
owner_access_tokens = [ | |
settings.SQUAD_ROLLBAR_ACCESS_TOKENS.get(owner) | |
for owner in specific_owners | |
if settings.SQUAD_ROLLBAR_ACCESS_TOKENS.get(owner) | |
] | |
if owner_access_tokens: | |
for token in owner_access_tokens: | |
rollbar_orig_send_payload(payload, token) | |
sent_squad_specific_rollbar = True | |
if not sent_squad_specific_rollbar: | |
rollbar_orig_send_payload(payload, access_token) | |
else: | |
rollbar_orig_send_payload(payload, access_token) | |
rollbar.send_payload = wrapped_rollbar_send_payload |