Skip to main content

backend-conventions

Sentry backend conventions for logging, tracing/spans, span/tag attribute naming, metrics tags, and the options system. Use when adding or editing Python in src/ that logs (logger.info/exception), records metrics (metrics.incr/timing with tags), instruments spans/transactions, calls sentry_sdk.set_tag/set_attribute or set_span_tag/set_span_data, or reads registered options with options.get(). Trigger on "add logging", "log an error", "add a metric", "add a span", "instrument tracing", "set an attribute", "add a tag", "read an option", "LOG005", "LOG011", or metrics tag cardinality questions.

소스 정보

저장소
getsentry/sentry
최근 소스 활동
2026년 9월 23일 08:41
감지된 SKILL.md 언어
영어
스타
45,528
포크
4,915

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
backend-conventions
description
Sentry backend conventions for logging, tracing/spans, span/tag attribute naming, metrics tags, and the options system. Use when adding or editing Python in src/ that logs (logger.info/exception), records metrics (metrics.incr/timing with tags), instruments spans/transactions, calls sentry_sdk.set_tag/set_attribute or set_span_tag/set_span_data, or reads registered options with options.get(). Trigger on "add logging", "log an error", "add a metric", "add a span", "instrument tracing", "set an attribute", "add a tag", "read an option", "LOG005", "LOG011", or metrics tag cardinality questions.
# Backend Conventions: Logging, Tracing, Metrics, Options ## Options System Sentry uses a centralized options system where all options are registered in `src/sentry/options/defaults.py` with required default values. ```python # CORRECT: options.get() without default - registered default is used from sentry import options batch_size = options.get("deletions.group-hash-metadata.batch-size") # WRONG: Redundant default value batch_size = options.get("deletions.group-hash-metadata.batch-size", 1000) ``` **Important**: Never add a default value to `options.get()` calls. All options are registered via `register()` in `defaults.py` which requires a default value. The options system always returns the registered default if no value is set, making a second default parameter redundant and potentially inconsistent. ## Logging Pattern ```python import logging from sentry import analytics from sentry.analytics.events.feature_used import FeatureUsedEvent # does not exist, only for demonstration purposes logger = logging.getLogger(__name__) # Structured logging logger.info( "user.action.complete", extra={ "user_id": user.id, "action": "login", "ip_address": request.META.get("REMOTE_ADDR"), } ) # IMPORTANT: LOG005 use exception() within an exception handler # WRONG: Calling logger.error() when capturing exception try: risky_operation() except ValidationError as e: logger.error("error.invalid_payload") # RIGHT: Use logger.exception() with a message when capturing an exception try: risky_operation() except ValidationError: logger.exception("error.invalid_payload") # IMPORTANT: Avoid LOG011 - Never pre-format log messages with f-strings or .format() # WRONG: Pre-formatting evaluates before logger call, even if logging is disabled logger.info(f"User {user.id} completed {action}") logger.info("User {} completed {}".format(user.id, action)) # RIGHT: Use logger's %-formatting for lazy evaluation logger.info("%s.user.action.complete", PREFIX) # ALSO RIGHT: Use structured logging with extra parameters only logger.info( "user.action.complete", extra={"user_id": user.id} ) # Analytics event analytics.record( FeatureUsedEvent( user_id=user.id, organization_id=org.id, feature="new-dashboard", ) ) ``` ## Span / Tag Attribute Names Before inventing a key for `sentry_sdk.set_tag`/`set_attribute`, `set_span_tag`, or `set_span_data`, check whether OTel or Sentry already has a standard name for it in `sentry_conventions.attributes.ATTRIBUTE_NAMES`. Reusing a convention name keeps the attribute queryable and consistent with what other producers (SDKs, Relay) already emit for the same concept — a bespoke name fragments the same data across two keys. ```python from sentry_conventions.attributes import ATTRIBUTE_NAMES # WRONG: inventing a name for a concept the conventions already cover sentry_sdk.set_attribute("request_user_agent", user_agent) # RIGHT: use the existing convention name sentry_sdk.set_attribute(ATTRIBUTE_NAMES.USER_AGENT_ORIGINAL, user_agent) ``` `ATTRIBUTE_NAMES` is generated from the OTel semantic conventions plus Sentry's own model (`.venv/lib/python*/site-packages/sentry_conventions/attributes.py`); grep it for candidate keywords before adding a new one. Only fall back to a custom key when the concept genuinely isn't covered, and prefer a namespaced, descriptive name over a generic one. A key kept behind a `_test`/POC suffix while a feature is unreleased is a separate, deliberate case — that's about hiding the field, not about picking its name. ## Metrics Tags Every distinct tag-value combination is a separate time series, so keep tags **low-cardinality, meaningful, and minimal**: - Add a tag only if you'll actually filter or group by it. Fewer is better. - Tag values must be bounded/enumerable (e.g. `status`, `platform`, `reason`) — never unbounded identifiers (IDs, emails, URLs, free text). The middleware (`src/sentry/metrics/middleware.py`) enforces this by denylisting tag keys that **end in `_id`** or that are exactly **`event`/`project`/`group`**. Such tags **will not work**: they're silently stripped by default, and raise `BadMetricTags` when `SENTRY_METRICS_DISALLOW_BAD_TAGS` is on (e.g. CI) — so a metric that looks fine locally can fail elsewhere. ```python metrics.incr("my.metric", tags={"project_id": project.id}) # WRONG: stripped / raises metrics.incr("my.metric", tags={"platform": project.platform}) # RIGHT: bounded values ``` A few keys are allowlisted despite the rule (see `_NOT_BAD_TAGS`); don't expand it to work around the constraint — pick a low-cardinality tag instead.
GitHub에서 보기