Merge pull request #9342 from netbox-community/9340-sentry

Closes #9340: Enable Sentry integration
This commit is contained in:
Jeremy Stretch 2022-05-11 16:26:46 -04:00 committed by GitHub
commit 8cc94689d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 106 additions and 3 deletions

View File

@ -102,6 +102,10 @@ psycopg2-binary
# https://github.com/yaml/pyyaml # https://github.com/yaml/pyyaml
PyYAML PyYAML
# Sentry SDK
# https://github.com/getsentry/sentry-python
sentry-sdk
# Social authentication framework # Social authentication framework
# https://github.com/python-social-auth/social-core # https://github.com/python-social-auth/social-core
social-auth-core social-auth-core

View File

@ -0,0 +1,29 @@
# Error Reporting
## Sentry
NetBox v3.2.3 and later support native integration with [Sentry](https://sentry.io/) for automatic error reporting. To enable this feature, begin by creating a new project in Sentry to represent your NetBox deployment and obtain its corresponding data source name (DSN). This looks like a URL similar to the example below:
```
https://examplePublicKey@o0.ingest.sentry.io/0
```
Once you have obtained a DSN, configure Sentry in NetBox's `configuration.py` file with the following parameters:
```python
SENTRY_ENABLED = True
SENTRY_DSN = "https://YourDSNgoesHere@o0.ingest.sentry.io/0"
```
You can optionally attach one or more arbitrary tags to the outgoing error reports if desired by setting the `SENTRY_TAGS` parameter:
```python
SENTRY_TAGS = {
"custom.foo": "123",
"custom.bar": "abc",
}
```
Once the configuration has been saved, restart the NetBox service.
To test Sentry operation, try generating a 404 (page not found) error by navigating to an invalid URL, such as `https://netbox/404-error-testing`. After receiving a 404 response from the NetBox server, you should see the issue appear shortly in Sentry.

View File

@ -404,6 +404,39 @@ The file path to the location where [custom scripts](../customization/custom-scr
--- ---
## SENTRY_DSN
Default: None
Defines a Sentry data source name (DSN) for automated error reporting. `SENTRY_ENABLED` must be True for this parameter to take effect. For example:
```
SENTRY_DSN = "https://examplePublicKey@o0.ingest.sentry.io/0"
```
---
## SENTRY_ENABLED
Default: False
Set to True to enable automatic error reporting via [Sentry](https://sentry.io/). Requires `SENTRY_DSN` to be defined.
---
## SENTRY_TAGS
An optional dictionary of tags to apply to Sentry error reports. `SENTRY_ENABLED` must be True for this parameter to take effect. For example:
```
SENTRY_TAGS = {
"custom.foo": "123",
"custom.bar": "abc",
}
```
---
## SESSION_COOKIE_NAME ## SESSION_COOKIE_NAME
Default: `sessionid` Default: `sessionid`

View File

@ -11,6 +11,7 @@
* [#9278](https://github.com/netbox-community/netbox/issues/9278) - Linkify device types count under manufacturers list * [#9278](https://github.com/netbox-community/netbox/issues/9278) - Linkify device types count under manufacturers list
* [#9280](https://github.com/netbox-community/netbox/issues/9280) - Allow adopting existing components when installing a module * [#9280](https://github.com/netbox-community/netbox/issues/9280) - Allow adopting existing components when installing a module
* [#9314](https://github.com/netbox-community/netbox/issues/9314) - Add device and VM filters for FHRP group assignments * [#9314](https://github.com/netbox-community/netbox/issues/9314) - Add device and VM filters for FHRP group assignments
* [#9340](https://github.com/netbox-community/netbox/issues/9340) - Introduce support for error reporting via Sentry
### Bug Fixes ### Bug Fixes

View File

@ -123,6 +123,7 @@ nav:
- Microsoft Azure AD: 'administration/authentication/microsoft-azure-ad.md' - Microsoft Azure AD: 'administration/authentication/microsoft-azure-ad.md'
- Okta: 'administration/authentication/okta.md' - Okta: 'administration/authentication/okta.md'
- Permissions: 'administration/permissions.md' - Permissions: 'administration/permissions.md'
- Error Reporting: 'administration/error-reporting.md'
- Housekeeping: 'administration/housekeeping.md' - Housekeeping: 'administration/housekeeping.md'
- Replicating NetBox: 'administration/replicating-netbox.md' - Replicating NetBox: 'administration/replicating-netbox.md'
- NetBox Shell: 'administration/netbox-shell.md' - NetBox Shell: 'administration/netbox-shell.md'

View File

@ -8,9 +8,11 @@ import sys
import warnings import warnings
from urllib.parse import urlsplit from urllib.parse import urlsplit
import sentry_sdk
from django.contrib.messages import constants as messages from django.contrib.messages import constants as messages
from django.core.exceptions import ImproperlyConfigured, ValidationError from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.core.validators import URLValidator from django.core.validators import URLValidator
from sentry_sdk.integrations.django import DjangoIntegration
from netbox.config import PARAMS from netbox.config import PARAMS
@ -113,6 +115,9 @@ REMOTE_AUTH_GROUP_SEPARATOR = getattr(configuration, 'REMOTE_AUTH_GROUP_SEPARATO
REPORTS_ROOT = getattr(configuration, 'REPORTS_ROOT', os.path.join(BASE_DIR, 'reports')).rstrip('/') REPORTS_ROOT = getattr(configuration, 'REPORTS_ROOT', os.path.join(BASE_DIR, 'reports')).rstrip('/')
RQ_DEFAULT_TIMEOUT = getattr(configuration, 'RQ_DEFAULT_TIMEOUT', 300) RQ_DEFAULT_TIMEOUT = getattr(configuration, 'RQ_DEFAULT_TIMEOUT', 300)
SCRIPTS_ROOT = getattr(configuration, 'SCRIPTS_ROOT', os.path.join(BASE_DIR, 'scripts')).rstrip('/') SCRIPTS_ROOT = getattr(configuration, 'SCRIPTS_ROOT', os.path.join(BASE_DIR, 'scripts')).rstrip('/')
SENTRY_DSN = getattr(configuration, 'SENTRY_DSN', None)
SENTRY_ENABLED = getattr(configuration, 'SENTRY_ENABLED', False)
SENTRY_TAGS = getattr(configuration, 'SENTRY_TAGS', {})
SESSION_FILE_PATH = getattr(configuration, 'SESSION_FILE_PATH', None) SESSION_FILE_PATH = getattr(configuration, 'SESSION_FILE_PATH', None)
SESSION_COOKIE_NAME = getattr(configuration, 'SESSION_COOKIE_NAME', 'sessionid') SESSION_COOKIE_NAME = getattr(configuration, 'SESSION_COOKIE_NAME', 'sessionid')
SHORT_DATE_FORMAT = getattr(configuration, 'SHORT_DATE_FORMAT', 'Y-m-d') SHORT_DATE_FORMAT = getattr(configuration, 'SHORT_DATE_FORMAT', 'Y-m-d')
@ -428,6 +433,26 @@ EXEMPT_PATHS = (
) )
#
# Sentry
#
if SENTRY_ENABLED:
if not SENTRY_DSN:
raise ImproperlyConfigured("SENTRY_ENABLED is True but SENTRY_DSN has not been defined.")
sentry_sdk.init(
dsn=SENTRY_DSN,
release=VERSION,
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
send_default_pii=True,
http_proxy=HTTP_PROXIES.get('http') if HTTP_PROXIES else None,
https_proxy=HTTP_PROXIES.get('https') if HTTP_PROXIES else None
)
for k, v in SENTRY_TAGS.items():
sentry_sdk.set_tag(k, v)
# #
# Django social auth # Django social auth
# #

View File

@ -100,4 +100,5 @@ urlpatterns = [
path('{}'.format(settings.BASE_PATH), include(_patterns)) path('{}'.format(settings.BASE_PATH), include(_patterns))
] ]
handler404 = 'netbox.views.handler_404'
handler500 = 'netbox.views.server_error' handler500 = 'netbox.views.server_error'

View File

@ -2,7 +2,6 @@ import platform
import sys import sys
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache from django.core.cache import cache
from django.db.models import F from django.db.models import F
from django.http import HttpResponseServerError from django.http import HttpResponseServerError
@ -11,9 +10,10 @@ from django.template import loader
from django.template.exceptions import TemplateDoesNotExist from django.template.exceptions import TemplateDoesNotExist
from django.urls import reverse from django.urls import reverse
from django.views.decorators.csrf import requires_csrf_token from django.views.decorators.csrf import requires_csrf_token
from django.views.defaults import ERROR_500_TEMPLATE_NAME from django.views.defaults import ERROR_500_TEMPLATE_NAME, page_not_found
from django.views.generic import View from django.views.generic import View
from packaging import version from packaging import version
from sentry_sdk import capture_message
from circuits.models import Circuit, Provider from circuits.models import Circuit, Provider
from dcim.models import ( from dcim.models import (
@ -190,13 +190,21 @@ class StaticMediaFailureView(View):
""" """
Display a user-friendly error message with troubleshooting tips when a static media file fails to load. Display a user-friendly error message with troubleshooting tips when a static media file fails to load.
""" """
def get(self, request): def get(self, request):
return render(request, 'media_failure.html', { return render(request, 'media_failure.html', {
'filename': request.GET.get('filename') 'filename': request.GET.get('filename')
}) })
def handler_404(request, exception):
"""
Wrap Django's default 404 handler to enable Sentry reporting.
"""
capture_message("Page not found", level="error")
return page_not_found(request, exception)
@requires_csrf_token @requires_csrf_token
def server_error(request, template_name=ERROR_500_TEMPLATE_NAME): def server_error(request, template_name=ERROR_500_TEMPLATE_NAME):
""" """

View File

@ -24,6 +24,7 @@ netaddr==0.8.0
Pillow==9.1.0 Pillow==9.1.0
psycopg2-binary==2.9.3 psycopg2-binary==2.9.3
PyYAML==6.0 PyYAML==6.0
sentry-sdk==1.5.12
social-auth-app-django==5.0.0 social-auth-app-django==5.0.0
social-auth-core==4.2.0 social-auth-core==4.2.0
svgwrite==1.4.2 svgwrite==1.4.2