mirror of
https://github.com/getsentry/sentry-for-ai.git
synced 2026-09-14 14:28:22 +08:00
4714a99345
* feat(sentry-instrument): add generated semantics lookup tree Embed stable Sentry semantic convention attributes as domain-split reference files and list them from the instrument skill. Co-Authored-By: Evan Purkhiser <evan.purkhiser@sentry.io> * style: apply prek fixes * fix(sentry-instrument): lead semantics files with domain descriptions Replace generation notes at the top of each domain file with a short description of what that domain covers. Co-Authored-By: David Cramer <david@sentry.io> * style: apply prek fixes --------- Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: Evan Purkhiser <evan.purkhiser@sentry.io> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: David Cramer <david@sentry.io>
165 lines
7.3 KiB
Python
165 lines
7.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate semantic-convention attribute lookup files for skill references.
|
|
|
|
Source: https://getsentry.github.io/sentry-conventions/api/attributes.json
|
|
Writes stable-only domain files under src/references/semantics/.
|
|
Re-run when conventions change. Generated markdown is checked in on purpose.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import urllib.request
|
|
from collections import defaultdict
|
|
from pathlib import Path
|
|
|
|
SOURCE_URL = "https://getsentry.github.io/sentry-conventions/api/attributes.json"
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
OUT_DIR = REPO_ROOT / "src" / "references" / "semantics"
|
|
|
|
# One-line domain intros shown at the top of each file. Keep these about the
|
|
# domain, not about how the file was generated.
|
|
DOMAIN_BLURBS: dict[str, str] = {
|
|
"angular": "Attributes from Angular framework instrumentation.",
|
|
"app": "Application identity and lifecycle attributes for mobile and desktop apps.",
|
|
"art": "Android Runtime (ART) profiling and runtime attributes.",
|
|
"aws": "AWS service, region, and request attributes for cloud instrumentation.",
|
|
"browser": "Browser environment and web-vital attributes on client spans.",
|
|
"cache": "Cache read/write attributes — key, hit/miss, item size.",
|
|
"client": "Client address and port for the side that initiated a connection.",
|
|
"cloud": "Generic cloud provider attributes shared across AWS, GCP, and others.",
|
|
"cloudflare": "Cloudflare Workers, bindings, and edge platform attributes.",
|
|
"code": "Source location attributes — function, file, line, namespace.",
|
|
"culture": "Locale and cultural preference attributes.",
|
|
"db": "Database query attributes — system, operation, statement summary, and collection.",
|
|
"device": "Device hardware and form-factor attributes for mobile and desktop.",
|
|
"error": "Error classification attributes attached to failures.",
|
|
"event": "Event identity attributes for discrete application events.",
|
|
"exception": "Exception type, message, and stack details on error spans.",
|
|
"faas": "Function-as-a-service / serverless invocation attributes.",
|
|
"file": "File path and I/O operation attributes.",
|
|
"flag": "Feature-flag evaluation attributes.",
|
|
"gcp": "Google Cloud Platform service and resource attributes.",
|
|
"gen_ai": "LLM and agent attributes — model, tokens, cost, tools, and conversation id.",
|
|
"general": "Uncategorized stable attributes that do not belong to a named domain.",
|
|
"graphql": "GraphQL operation name, type, and document attributes.",
|
|
"grpc": "gRPC method, status, and service attributes.",
|
|
"http": "HTTP client and server attributes — method, route, status, timing, and headers.",
|
|
"jsonrpc": "JSON-RPC method and request identity attributes.",
|
|
"jvm": "JVM runtime and memory attributes.",
|
|
"koa": "Koa framework middleware and request attributes.",
|
|
"logger": "Logger name and logging-context attributes.",
|
|
"mcp": "Model Context Protocol attributes for MCP client/server spans.",
|
|
"mdc": "Mapped diagnostic context (MDC) attributes from logging frameworks.",
|
|
"messaging": "Message queue / pubsub attributes — destination, operation, and message id.",
|
|
"middleware": "Middleware layer name and ordering attributes.",
|
|
"navigation": "Client-side navigation and route-change attributes.",
|
|
"nel": "Network Error Logging (NEL) report attributes.",
|
|
"network": "Network transport attributes — protocol, connection type, carrier.",
|
|
"os": "Operating system name, version, and type attributes.",
|
|
"otel": "OpenTelemetry bridge attributes carried into Sentry.",
|
|
"params": "Request or route parameter attributes.",
|
|
"process": "Process identity and runtime attributes (pid, executable, command).",
|
|
"react": "React component and rendering attributes.",
|
|
"remix": "Remix framework route and loader attributes.",
|
|
"resource": "Browser resource-load attributes (script, css, image, etc.).",
|
|
"rpc": "Generic RPC system attributes outside gRPC-specific keys.",
|
|
"score": "Score and rating attributes (for example web-vital grades).",
|
|
"sentry": "Sentry SDK and product attributes (sample rates, origins, mechanism).",
|
|
"server": "Server address and port for the receiving side of a connection.",
|
|
"service": "Service name and version attributes for the instrumented unit.",
|
|
"session": "Session identity attributes for user sessions.",
|
|
"state": "Application or request state attributes.",
|
|
"thread": "Thread id and name attributes.",
|
|
"timber": "Timber logging framework attributes.",
|
|
"trpc": "tRPC procedure and path attributes.",
|
|
"ui": "UI component and rendering attributes for client interfaces.",
|
|
"url": "URL components — full, path, query, fragment, template.",
|
|
"user": "End-user identity attributes (id, email, username, geo).",
|
|
"user_agent": "User-agent string and parsed client attributes.",
|
|
"vercel": "Vercel platform and deployment attributes.",
|
|
}
|
|
|
|
|
|
def fetch_attributes() -> list[dict]:
|
|
with urllib.request.urlopen(SOURCE_URL, timeout=60) as resp:
|
|
return json.load(resp)
|
|
|
|
|
|
def domain_blurb(cat: str) -> str:
|
|
if cat in DOMAIN_BLURBS:
|
|
return DOMAIN_BLURBS[cat]
|
|
label = cat.replace("_", " ")
|
|
return f"Stable `{cat}.*` attributes for {label} instrumentation."
|
|
|
|
|
|
def domain_title(cat: str) -> str:
|
|
# Prefer readable titles for multi-word / known acronyms.
|
|
special = {
|
|
"gen_ai": "Gen AI",
|
|
"user_agent": "User agent",
|
|
"jsonrpc": "JSON-RPC",
|
|
"grpc": "gRPC",
|
|
"graphql": "GraphQL",
|
|
"trpc": "tRPC",
|
|
"mcp": "MCP",
|
|
"jvm": "JVM",
|
|
"aws": "AWS",
|
|
"gcp": "GCP",
|
|
"http": "HTTP",
|
|
"db": "Database",
|
|
"os": "OS",
|
|
"ui": "UI",
|
|
"faas": "FaaS",
|
|
"otel": "OpenTelemetry",
|
|
"nel": "NEL",
|
|
"mdc": "MDC",
|
|
"art": "ART",
|
|
}
|
|
if cat in special:
|
|
return f"{special[cat]} attributes"
|
|
return f"{cat.replace('_', ' ').capitalize()} attributes"
|
|
|
|
|
|
def main() -> None:
|
|
attrs = fetch_attributes()
|
|
stable = [a for a in attrs if not a.get("deprecated")]
|
|
by_cat: dict[str, list[dict]] = defaultdict(list)
|
|
for a in stable:
|
|
cat = a.get("category") or "general"
|
|
by_cat[cat].append(a)
|
|
|
|
for cat in by_cat:
|
|
by_cat[cat].sort(key=lambda a: a["key"])
|
|
|
|
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
for old in OUT_DIR.glob("*.md"):
|
|
old.unlink()
|
|
|
|
unknown = sorted(set(by_cat) - set(DOMAIN_BLURBS))
|
|
if unknown:
|
|
print(f"warning: domains missing custom blurbs (using fallback): {', '.join(unknown)}")
|
|
|
|
for cat, items in sorted(by_cat.items()):
|
|
lines = [
|
|
f"# {domain_title(cat)}",
|
|
"",
|
|
domain_blurb(cat),
|
|
"",
|
|
"| Key | Type | Brief |",
|
|
"| --- | --- | --- |",
|
|
]
|
|
for a in items:
|
|
key = a["key"].replace("|", "\\|")
|
|
typ = str(a.get("type", "")).replace("|", "\\|")
|
|
brief = str(a.get("brief", "")).replace("|", "\\|").replace("\n", " ")
|
|
lines.append(f"| `{key}` | `{typ}` | {brief} |")
|
|
lines.append("")
|
|
(OUT_DIR / f"{cat}.md").write_text("\n".join(lines), encoding="utf-8")
|
|
|
|
print(f"wrote {len(by_cat)} domain files ({len(stable)} stable attrs) -> {OUT_DIR.relative_to(REPO_ROOT)}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|