123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- """
- These settings act as the default (base) settings for the Sentry-provided
- web-server
- """
- import logging
- import os.path
- from collections import OrderedDict, namedtuple
- from datetime import timedelta
- import six
- from django.utils.translation import gettext_lazy as _
- def get_all_languages():
- results = []
- for path in os.listdir(os.path.join(MODULE_ROOT, "locale")):
- if path.startswith("."):
- continue
- if "_" in path:
- pre, post = path.split("_", 1)
- path = "{}-{}".format(pre, post.lower())
- results.append(path)
- return results
- MODULE_ROOT = os.path.dirname(__import__("sentry").__file__)
- DATA_ROOT = os.path.join(MODULE_ROOT, "data")
- BAD_RELEASE_CHARS = "\n\f\t/"
- MAX_VERSION_LENGTH = 200
- MAX_COMMIT_LENGTH = 64
- COMMIT_RANGE_DELIMITER = ".."
- SORT_OPTIONS = OrderedDict(
- (
- ("priority", _("Priority")),
- ("date", _("Last Seen")),
- ("new", _("First Seen")),
- ("freq", _("Frequency")),
- )
- )
- SEARCH_SORT_OPTIONS = OrderedDict(
- (("score", _("Score")), ("date", _("Last Seen")), ("new", _("First Seen")))
- )
- # XXX: Deprecated: use GroupStatus instead
- STATUS_UNRESOLVED = 0
- STATUS_RESOLVED = 1
- STATUS_IGNORED = 2
- STATUS_CHOICES = {
- "resolved": STATUS_RESOLVED,
- "unresolved": STATUS_UNRESOLVED,
- "ignored": STATUS_IGNORED,
- # TODO(dcramer): remove in 9.0
- "muted": STATUS_IGNORED,
- }
- # Normalize counts to the 15 minute marker. This value MUST be less than 60. A
- # value of 0 would store counts for every minute, and is the lowest level of
- # accuracy provided.
- MINUTE_NORMALIZATION = 15
- MAX_TAG_KEY_LENGTH = 32
- MAX_TAG_VALUE_LENGTH = 200
- MAX_CULPRIT_LENGTH = 200
- MAX_EMAIL_FIELD_LENGTH = 75
- ENVIRONMENT_NAME_PATTERN = r"^[^\n\r\f\/]*$"
- ENVIRONMENT_NAME_MAX_LENGTH = 64
- SENTRY_APP_SLUG_MAX_LENGTH = 64
- LOG_LEVELS = {
- logging.NOTSET: "sample",
- logging.DEBUG: "debug",
- logging.INFO: "info",
- logging.WARNING: "warning",
- logging.ERROR: "error",
- logging.FATAL: "fatal",
- }
- DEFAULT_LOG_LEVEL = "error"
- DEFAULT_LOGGER_NAME = ""
- LOG_LEVELS_MAP = {v: k for k, v in six.iteritems(LOG_LEVELS)}
- # Default alerting threshold values
- DEFAULT_ALERT_PROJECT_THRESHOLD = (500, 25) # 500%, 25 events
- DEFAULT_ALERT_GROUP_THRESHOLD = (1000, 25) # 1000%, 25 events
- # Default sort option for the group stream
- DEFAULT_SORT_OPTION = "date"
- # Setup languages for only available locales
- # _language_map = dict(settings.LANGUAGES)
- # LANGUAGES = [(k, _language_map[k]) for k in get_all_languages() if k in _language_map]
- # del _language_map
- # TODO(dcramer): We eventually want to make this user-editable
- TAG_LABELS = {
- "exc_type": "Exception Type",
- "sentry:user": "User",
- "sentry:release": "Release",
- "sentry:dist": "Distribution",
- "os": "OS",
- "url": "URL",
- "server_name": "Server",
- }
- PROTECTED_TAG_KEYS = frozenset(["environment", "release", "sentry:release"])
- # TODO(dcramer): once this is more flushed out we want this to be extendable
- SENTRY_RULES = (
- "sentry.rules.actions.notify_event.NotifyEventAction",
- "sentry.rules.actions.notify_event_service.NotifyEventServiceAction",
- "sentry.rules.conditions.every_event.EveryEventCondition",
- "sentry.rules.conditions.first_seen_event.FirstSeenEventCondition",
- "sentry.rules.conditions.regression_event.RegressionEventCondition",
- "sentry.rules.conditions.reappeared_event.ReappearedEventCondition",
- "sentry.rules.conditions.tagged_event.TaggedEventCondition",
- "sentry.rules.conditions.event_frequency.EventFrequencyCondition",
- "sentry.rules.conditions.event_frequency.EventUniqueUserFrequencyCondition",
- "sentry.rules.conditions.event_attribute.EventAttributeCondition",
- "sentry.rules.conditions.level.LevelCondition",
- )
- # Maximum length of a symbol
- MAX_SYM = 256
- # Known debug information file mimetypes
- KNOWN_DIF_FORMATS = {
- "text/x-breakpad": "breakpad",
- "application/x-mach-binary": "macho",
- "application/x-elf-binary": "elf",
- "application/x-dosexec": "pe",
- "application/x-ms-pdb": "pdb",
- "text/x-proguard+plain": "proguard",
- "application/x-sentry-bundle+zip": "sourcebundle",
- }
- NATIVE_UNKNOWN_STRING = "<unknown>"
- # Maximum number of release files that can be "skipped" (i.e., maximum paginator offset)
- # inside release files API endpoints.
- # If this number is too large, it may cause problems because of inefficient
- # LIMIT-OFFSET database queries.
- # These problems should be solved after we implement artifact bundles workflow.
- MAX_RELEASE_FILES_OFFSET = 20000
- # to go from an integration id (in _platforms.json) to the platform
- # data, such as documentation url or humanized name.
- # example: java-logback -> {"type": "framework",
- # "link": "https://docs.getsentry.com/hosted/clients/java/modules/logback/",
- # "id": "java-logback",
- # "name": "Logback"}
- INTEGRATION_ID_TO_PLATFORM_DATA = {}
- # def _load_platform_data():
- # INTEGRATION_ID_TO_PLATFORM_DATA.clear()
- # data = load_doc("_platforms")
- # if not data:
- # return
- # for platform in data["platforms"]:
- # integrations = platform.pop("integrations")
- # if integrations:
- # for integration in integrations:
- # integration_id = integration.pop("id")
- # if integration["type"] != "language":
- # integration["language"] = platform["id"]
- # INTEGRATION_ID_TO_PLATFORM_DATA[integration_id] = integration
- # _load_platform_data()
- # special cases where the marketing slug differs from the integration id
- # (in _platforms.json). missing values (for example: "java") should assume
- # the marketing slug is the same as the integration id:
- # javascript, node, python, php, ruby, go, swift, objc, java, perl, elixir
- MARKETING_SLUG_TO_INTEGRATION_ID = {
- "kotlin": "java",
- "scala": "java",
- "spring": "java",
- "android": "java-android",
- "react": "javascript-react",
- "angular": "javascript-angular",
- "angular2": "javascript-angular2",
- "ember": "javascript-ember",
- "backbone": "javascript-backbone",
- "vue": "javascript-vue",
- "express": "node-express",
- "koa": "node-koa",
- "django": "python-django",
- "flask": "python-flask",
- "sanic": "python-sanic",
- "tornado": "python-tornado",
- "celery": "python-celery",
- "rq": "python-rq",
- "bottle": "python-bottle",
- "pythonawslambda": "python-awslambda",
- "pyramid": "python-pyramid",
- "pylons": "python-pylons",
- "laravel": "php-laravel",
- "symfony": "php-symfony2",
- "rails": "ruby-rails",
- "sinatra": "ruby-sinatra",
- "dotnet": "csharp",
- }
- # to go from a marketing page slug like /for/android/ to the integration id
- # (in _platforms.json), for looking up documentation urls, etc.
- def get_integration_id_for_marketing_slug(slug):
- if slug in MARKETING_SLUG_TO_INTEGRATION_ID:
- return MARKETING_SLUG_TO_INTEGRATION_ID[slug]
- if slug in INTEGRATION_ID_TO_PLATFORM_DATA:
- return slug
- # special cases where the integration sent with the SDK differ from
- # the integration id (in _platforms.json)
- # {PLATFORM: {INTEGRATION_SENT: integration_id, ...}, ...}
- PLATFORM_INTEGRATION_TO_INTEGRATION_ID = {
- "java": {"java.util.logging": "java-logging"},
- # TODO: add more special cases...
- }
- # to go from event data to the integration id (in _platforms.json),
- # for example an event like:
- # {"platform": "java",
- # "sdk": {"name": "sentry-java",
- # "integrations": ["java.util.logging"]}} -> java-logging
- def get_integration_id_for_event(platform, sdk_name, integrations):
- if integrations:
- for integration in integrations:
- # check special cases
- if (
- platform in PLATFORM_INTEGRATION_TO_INTEGRATION_ID
- and integration in PLATFORM_INTEGRATION_TO_INTEGRATION_ID[platform]
- ):
- return PLATFORM_INTEGRATION_TO_INTEGRATION_ID[platform][integration]
- # try <platform>-<integration>, for example "java-log4j"
- integration_id = "%s-%s" % (platform, integration)
- if integration_id in INTEGRATION_ID_TO_PLATFORM_DATA:
- return integration_id
- # try sdk name, for example "sentry-java" -> "java" or "raven-java:log4j" -> "java-log4j"
- sdk_name = (
- sdk_name.lower().replace("sentry-", "").replace("raven-", "").replace(":", "-")
- )
- if sdk_name in INTEGRATION_ID_TO_PLATFORM_DATA:
- return sdk_name
- # try platform name, for example "java"
- if platform in INTEGRATION_ID_TO_PLATFORM_DATA:
- return platform
- class ObjectStatus(object):
- VISIBLE = 0
- HIDDEN = 1
- PENDING_DELETION = 2
- DELETION_IN_PROGRESS = 3
- ACTIVE = 0
- DISABLED = 1
- @classmethod
- def as_choices(cls):
- return (
- (cls.ACTIVE, "active"),
- (cls.DISABLED, "disabled"),
- (cls.PENDING_DELETION, "pending_deletion"),
- (cls.DELETION_IN_PROGRESS, "deletion_in_progress"),
- )
- class SentryAppStatus(object):
- UNPUBLISHED = 0
- PUBLISHED = 1
- INTERNAL = 2
- UNPUBLISHED_STR = "unpublished"
- PUBLISHED_STR = "published"
- INTERNAL_STR = "internal"
- @classmethod
- def as_choices(cls):
- return (
- (cls.UNPUBLISHED, cls.UNPUBLISHED_STR),
- (cls.PUBLISHED, cls.PUBLISHED_STR),
- (cls.INTERNAL, cls.INTERNAL_STR),
- )
- @classmethod
- def as_str(cls, status):
- if status == cls.UNPUBLISHED:
- return cls.UNPUBLISHED_STR
- elif status == cls.PUBLISHED:
- return cls.PUBLISHED_STR
- elif status == cls.INTERNAL:
- return cls.INTERNAL_STR
- class SentryAppInstallationStatus(object):
- PENDING = 0
- INSTALLED = 1
- PENDING_STR = "pending"
- INSTALLED_STR = "installed"
- @classmethod
- def as_choices(cls):
- return ((cls.PENDING, cls.PENDING_STR), (cls.INSTALLED, cls.INSTALLED_STR))
- @classmethod
- def as_str(cls, status):
- if status == cls.PENDING:
- return cls.PENDING_STR
- elif status == cls.INSTALLED:
- return cls.INSTALLED_STR
- StatsPeriod = namedtuple("StatsPeriod", ("segments", "interval"))
- LEGACY_RATE_LIMIT_OPTIONS = frozenset(
- ("sentry:project-rate-limit", "sentry:account-rate-limit")
- )
- # We need to limit the range of valid timestamps of an event because that
- # timestamp is used to control data retention.
- MAX_SECS_IN_FUTURE = 60
- MAX_SECS_IN_PAST = 2592000 # 30 days
- ALLOWED_FUTURE_DELTA = timedelta(seconds=MAX_SECS_IN_FUTURE)
- # DEFAULT_STORE_NORMALIZER_ARGS = dict(
- # geoip_lookup=rust_geoip,
- # stacktrace_frames_hard_limit=settings.SENTRY_STACKTRACE_FRAMES_HARD_LIMIT,
- # max_stacktrace_frames=settings.SENTRY_MAX_STACKTRACE_FRAMES,
- # max_secs_in_future=MAX_SECS_IN_FUTURE,
- # max_secs_in_past=MAX_SECS_IN_PAST,
- # enable_trimming=True,
- # )
- INTERNAL_INTEGRATION_TOKEN_COUNT_MAX = 20
- ALL_ACCESS_PROJECTS = {-1}
|