How to customize event in before_send

Hi there,

We’re switching from the Raven-powered sentry client to the unified (python) SDK. We have a lot of sensitive fields that we scrubbed/replaced with masks in the past, and others that we popped completely from the event when they were uninformative for our use case.

Previously, we subclasseed raven.contrib.django.client.DjangoClient to accomplish this.

I’ve seen both

and

and while they’re helpful, they don’t cover all our needs. We’d also like to recreate our own version of the raven.processors.SanitizePasswordsProcessor that we used previously.

Is there any way I can directly modify the event object? Is there a event schema somewhere I can reference?

Thanks!!

Seve

Hi @sbisogni, if you’re only looking to replicate the behavior of raven’s processor, it’s possible to copy that processor’s code into your app and explicitly use it in before_send. Instantiate the processor and call process(event) in your before_send: https://github.com/getsentry/raven-python/blob/8e7de70c5f099600480e08bdc708041dc581929e/raven/processors.py#L24

An overview of the event schema is available at https://docs.sentry.io/development/sdk-dev/attributes/

1 Like

Thank you @untitaker !

The event schema is very helpful and if we keep raven I’ll definitely follow your advice calling process(event)

Are you aware of a way to remove a top level event field populated by an interface? Ex: "user". I’ve tried event.pop("user", None) in before_send to no avail.

Also, to remove a tag?
Where event.setdefault("tags", {})[<tag_key>] = <tag_value> works perfectly for adding a tag, event["tags"].pop(<tag_key>, None) doesn’t seem to work for removal.
We want to remove a few tags such as runtime and trace.

Let me know if these follow-up questions belong in another post - I’m happy to create one.

Thank you again for your help, here.

Those tags are generated by Sentry from other event data, for runtime you would need to remove event.contexts.runtime while for trace you would need to remove event.contexts.trace. For tags set by the SDK, your approach should work fine.

I don’t understand why removing user that way shouldn’t work… try adding debug=True to your init() call to look at crashing invocations of before_send.

1 Like

Hey @untitaker, thanks again!

Was able to log the event inside the before_send function and it looks like user is probably something generated post-before_send similar to the runtime and trace tags you mentioned

event.pop("server-name") is working, for example, but user doesn’t seem to be present yet at the time of before_send.

In any case, I think we’re totally good to go with leaving the user since we can pop off the other top-level fields we needed to. Thanks again!!

If you’re curious, here is the event as I’m seeing at the beginning of before_send (sorry for long text)
{ 'level': 'error', 'exception': { 'values': [{ 'module': 'exceptions', 'type': 'AccountAlreadyConnectedToTxnHistoryImport', 'value': 'The Account is already connected to import Transactions.', 'stacktrace': { 'frames': [{ 'filename': '<ipython-input-6-a9dacff1e604>', 'abs_path': '/app/central_banking/<ipython-input-6-a9dacff1e604>', 'function': '<module>', 'module': '__main__', 'lineno': 2, 'pre_context': ['try:'], 'context_line': ' acc.connect_plaid_site({}, str(uuid.uuid4()), "LUL")', 'post_context': ['except Exception as e:', ' capture_exception(e)', ' '], 'vars': { 'pprint': "<module 'pprint' from '/usr/local/lib/python3.7/pprint.py'>", 'uuid': "<module 'uuid' from '/usr/local/lib/python3.7/uuid.py'>", 'clients': "<module 'clients' from '/app/central_banking/clients/__init__.py'>", 'datatypes': "<module 'datatypes' from '/app/central_banking/datatypes/__init__.py'>", 'exceptions': "<module 'exceptions' from '/app/central_banking/exceptions/__init__.py'>", 'repositories': "<module 'repositories' from '/app/central_banking/repositories/__init__.py'>", 'services': "<module 'services' from '/app/central_banking/services/__init__.py'>", 'Group': "<class 'django.contrib.auth.models.Group'>", 'Permission': "<class 'django.contrib.auth.models.Permission'>", 'User': "<class 'django.contrib.auth.models.User'>", 'ContentType': "<class 'django.contrib.contenttypes.models.ContentType'>", 'Account': "<class 'repositories.account.models.Account'>", 'AccountAuditRecord': "<class 'repositories.account.models.AccountAuditRecord'>", 'AccountProductAssociation': "<class 'repositories.account.models.AccountProductAssociation'>", 'HistoricalAccountBalance': "<class 'repositories.account.models.HistoricalAccountBalance'>", 'Institution': "<class 'repositories.institution.models.Institution'>", 'NotificationLog': "<class 'repositories.notification.models.NotificationLog'>" }, 'in_app': True }, { 'filename': 'services/account.py', 'abs_path': '/app/central_banking/services/account.py', 'function': 'connect_plaid_site', 'module': 'services.account', 'lineno': 274, 'pre_context': [' ctx: Context,', ' business_id: BusinessId,', ' public_token: PlaidPublicToken,', ' ) -> typing.Iterable[AccountSummary]:', ' """Connect all accounts under a given online banking login."""'], 'context_line': ' raise AccountAlreadyConnectedToTxnHistoryImport', 'post_context': [' site_id = self._site_repo.create_site(ctx, Account.Origin.PLAID)', ' return self._plaid_service.connect_plaid_site(', ' ctx, business_id, public_token, site_id', ' )', ''], 'vars': { 'self': '<services.account.AccountService object at 0x7f519eadab38>', 'ctx': {}, 'business_id': "'4c3f5d5c-f657-4032-8200-25292c91f0b8'", 'public_token': "'LUL'" }, 'in_app': True }] } }] }, 'event_id': '0be150aab1f341a7b08c35d0e0d64891', 'timestamp': '2019-08-19T17:41:11.247484Z', 'breadcrumbs': [{ 'type': 'subprocess', 'category': 'subprocess', 'data': {}, 'timestamp': '2019-08-19T17:26:48.763319Z' }, { 'type': 'subprocess', 'category': 'subprocess', 'data': {}, 'timestamp': '2019-08-19T17:26:48.765539Z' }, { 'type': 'subprocess', 'category': 'subprocess', 'data': {}, 'timestamp': '2019-08-19T17:26:49.630888Z' }, { 'type': 'http', 'category': 'httplib', 'data': { 'url': 'https://sentry.io/api/235106/store/', 'method': 'POST', 'httplib_response': '<http.client.HTTPResponse object at 0x7f519f0351d0>', 'status_code': 200, 'reason': 'OK' }, 'timestamp': '2019-08-19T17:29:29.987822Z' }, { 'type': 'http', 'category': 'httplib', 'data': { 'url': 'https://sentry.io/api/235106/store/', 'method': 'POST', 'httplib_response': '<http.client.HTTPResponse object at 0x7f519e4a2080>', 'status_code': 200, 'reason': 'OK' }, 'timestamp': '2019-08-19T17:39:55.290403Z' }, { 'type': 'http', 'category': 'httplib', 'data': { 'url': 'https://sentry.io/api/235106/store/', 'method': 'POST', 'httplib_response': '<http.client.HTTPResponse object at 0x7f519e4d1b38>', 'status_code': 200, 'reason': 'OK' }, 'timestamp': '2019-08-19T17:41:00.213008Z' }], 'contexts': { 'runtime': { 'name': 'CPython', 'version': '3.7.3', 'build': '3.7.3 (default, Mar 27 2019, 23:48:15) \n[GCC 8.2.0]' } }, 'modules': { 'wheel': '0.33.1', 'wcwidth': '0.1.7', 'wave-messages': '16.4.0', 'virtualenv': '16.7.3', 'virtualenv-clone': '0.5.3', 'uwsgi': '2.0.18', 'urllib3': '1.25.3', 'ua-parser': '0.8.0', 'traitlets': '4.3.2', 'titlecase': '0.12.0', 'sqlparse': '0.3.0', 'six': '1.12.0', 'setuptools': '40.8.0', 'sentry-sdk': '0.10.2', 's3transfer': '0.2.1', 'rsa': '3.4.2', 'requests': '2.22.0', 'redis': '3.3.7', 'raven': '6.10.0', 'pyyaml': '3.13', 'pytz': '2019.2', 'python-wave-message-bus': '9.0.0', 'python-wave-common': '0.3.0', 'python-dateutil': '2.8.0', 'pygments': '2.4.2', 'pycparser': '2.19', 'pyasn1': '0.4.5', 'ptyprocess': '0.6.0', 'psycopg2': '2.8.3', 'psutil': '5.6.3', 'protobuf': '3.8.0', 'prompt-toolkit': '2.0.9', 'plaid-python': '3.3.0', 'pipenv': '2018.11.26', 'pip': '19.2.2', 'pika': '1.1.0', 'pickleshare': '0.7.5', 'pexpect': '4.7.0', 'parso': '0.5.1', 'pan-sanitizer': '1.1.0', 'next-accounting-utils': '29.0.0', 'newrelic': '5.0.2.126', 'msgpack-python': '0.5.6', 'metrics-client': '2.1.1', 'marshmallow': '2.20.1', 'jmespath': '0.9.4', 'jedi': '0.15.1', 'ipython': '7.7.0', 'ipython-genutils': '0.2.0', 'ipdb': '0.12.2', 'idna': '2.8', 'hiredis': '1.0.0', 'enum34': '1.1.6', 'docutils': '0.14', 'djangorestframework': '3.10.2', 'django': '2.2.4', 'django-wave-logging': '1.4.0', 'django-wave-common': '4.0.0', 'django-watchman': '0.17.0', 'django-redis': '4.10.0', 'django-jsonview': '1.2.0', 'django-fernet-fields': '0.6', 'django-extensions': '2.2.1', 'django-cache-url': '3.0.0', 'dj-database-url': '0.5.0', 'decorator': '4.4.0', 'ddtrace': '0.27.1', 'datadog': '0.29.3', 'cryptography': '2.7', 'contextlib2': '0.5.5', 'colorama': '0.3.9', 'chunnel': '3.3.0', 'chardet': '3.0.4', 'cffi': '1.12.3', 'certifi': '2019.6.16', 'botocore': '1.12.208', 'boto3': '1.9.208', 'backcall': '0.1.0', 'babel': '2.7.0', 'awscli': '1.16.157', 'asn1crypto': '0.24.0', 'arrow': '0.14.5' }, 'extra': { 'sys.argv': ['manage.py', 'shell_plus'] }, 'release': 'RXRUPPORKVM', 'environment': 'convox-proteus', 'server_name': '7d3341ab43de', 'sdk': { 'name': 'sentry.python', 'version': '0.10.2', 'packages': [{ 'name': 'pypi:sentry-sdk', 'version': '0.10.2' }], 'integrations': ['argv', 'atexit', 'dedupe', 'django', 'excepthook', 'logging', 'modules', 'stdlib', 'threading'] }, 'platform': 'python', '_meta': { 'exception': { 'values': { '0': { 'stacktrace': { 'frames': { '0': { 'vars': { '': { 'len': 17 } } } } } } } } } }