otel-semantic-conventions
OpenTelemetry semantic convention lookup and naming guidance. Use when selecting released semantic convention groups, attributes, or span naming rules, when checking semantic convention compliance, or checking which semantic-conventions version a language SDK's semconv package ex
Install
npx skills add https://github.com/ollygarden/opentelemetry-agent-skills/tree/main/skills/otel-semantic-conventions
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install ollygarden-opentelemetry-agent-skills@llmmart
git clone https://github.com/ollygarden/opentelemetry-agent-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole ollygarden/opentelemetry-agent-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
OpenTelemetry Semantic Conventions
Use this skill when you need released semantic convention guidance for naming, attributes, or compliance checks.
Workflow
- Start with released semantic conventions, not model memory.
- do not load the full semantic convention spec into context
- use the bundled lookup script to query only the needed released group or attribute
- for local verification against a checked-out upstream repo, set
OTEL_SEMCONV_REPO=/path/to/semantic-conventions
- Choose the closest released group before inventing custom keys.
- identify the boundary type such as
http,db,messaging,rpc, ornetwork - pick one primary group first, then add related groups only when they add needed context
- for
gen_ai.*, OpenAI, or MCP conventions, use the dedicated OpenTelemetry GenAI semantic conventions repository; the core repository keeps only deprecated GenAI-era stubs after v1.42.0 - see
references/semconv-selection.md - to target a version a language's semconv package actually exposes (works offline, dated), see
references/sdk-semconv-packages.md
- Query only the released guidance you need.
- list groups:
./scripts/query-otel-semantic-conventions.sh --groups - inspect one group:
./scripts/query-otel-semantic-conventions.sh http - inspect one kind:
./scripts/query-otel-semantic-conventions.sh http spans - inspect one exact attribute or entry:
./scripts/query-otel-semantic-conventions.sh http http.request.method - see
references/otel-semantic-conventions.md - after changing the parser, run
OTEL_SEMCONV_REPO=/path/to/semantic-conventions bash ./scripts/test-query-otel-semantic-conventions.sh
- Apply the released naming and attribute rules directly.
- use required and recommended attributes before optional ones
- derive semconv-governed span names directly from the released naming rule
- do not prepend or append protocol labels, hostnames, product names, business hints, or other custom prose to semconv-governed span names
- if the released naming rule does not provide a low-cardinality target, use the simpler fallback allowed by that convention
- if no released key exists, use a stable custom namespace and keep values bounded
- Return the result with exact source context.
- include the group name, released version, and source URL from the script output
- call out any concrete compatibility limitation if the implementation cannot fully match the released guidance
Files (opentelemetry-agent-skills)
-
evals
-
evals.json 1.2 KB
{ "skill": "otel-semantic-conventions", "cases": [ { "id": "offline-sdk-semconv-package-versions", "prompt": "No web lookups please, just your knowledge and skills. We run services in Go (go.opentelemetry.io/otel v1.47.0), Java, JavaScript, and Python, and want every service to emit the same semantic-conventions version. Which semconv version does each language's semconv package expose, and which version should we standardize on?", "files": [], "expectations": [ "Says the newest Go package in otel v1.47.0 is go.opentelemetry.io/otel/semconv/v1.43.0 and that there is no v1.44.0 package.", "Says @opentelemetry/semantic-conventions 1.43.0 exposes semconv 1.43.0.", "Says Java opentelemetry-semconv 1.44.0 and Python opentelemetry-semantic-conventions 0.66b1 expose semconv 1.44.0.", "Recommends 1.43.0, the lowest version all four packages expose, as the shared version.", "Frames the versions as verified on the recorded date rather than as currently latest, and suggests re-checking the package registries before pinning.", "Does not perform any web search, web fetch, or network command." ] } ] }
-
-
references
-
otel-semantic-conventions.md 2 KB
--- title: OpenTelemetry Semantic Conventions read_when: Choosing released semantic convention attributes for instrumentation --- Do not load the full semantic convention spec into context. Query only the needed released group with `./scripts/query-otel-semantic-conventions.sh`. Use: - list groups: `./scripts/query-otel-semantic-conventions.sh --groups` - group lookup: `./scripts/query-otel-semantic-conventions.sh http` - kind lookup: `./scripts/query-otel-semantic-conventions.sh http spans` - exact entry: `./scripts/query-otel-semantic-conventions.sh http http.request.method` - local checkout mode: `OTEL_SEMCONV_REPO=/path/to/semantic-conventions ./scripts/query-otel-semantic-conventions.sh http` Rules: - use `--groups` first if you do not already know the right group - start with one group - use the one-argument form first to discover the current released attribute ids and available kinds - pass a listed kind as the second argument to list the released entries of that kind - pass an exact entry id as the second argument to return its upstream definition block - the script resolves the latest released semantic conventions version and reads released YAML model files under `model/<group>/` from that tag - definition/2 registry attributes, signal definitions, and refinements introduced in v1.44 are parsed by their schema entry keys; messaging provider files are included under their signal kind even when their filenames do not contain `spans`, `metrics`, or `events` - deprecated model files and directories are excluded from lookup results - the core semantic-conventions repository added `model/manifest.yaml` in v1.43.0; use it as release metadata, not as a convention group - `gen_ai.*`, OpenAI, and MCP conventions moved to the dedicated OpenTelemetry GenAI semantic conventions repository in v1.42.0; do not treat deprecated stubs under the core repository as current guidance Common groups: `http`, `db`, `messaging`, `rpc`, `network`, `url`, `server`, `error`, `user-agent`, `service`, `cloud`, `k8s`, `process`, `otel`, `log`, `exceptions` -
sdk-semconv-packages.md 2.3 KB
# SDK semantic-convention packages Which semantic-conventions release each language's semconv package exposes. Packages trail the spec, so pick the version your SDK can emit, not the newest spec release. ## Verified 2026-10-15 Offline, cite this date, never call a value currently latest, and confirm it against the evidence before deploying. Online, re-check the package registry first. Latest spec release: the `otel-sdk-versions` index if it lists semantic-conventions, else the GitHub releases. | Language | Package and version | Newest semconv exposed | |---|---|---| | Go | `go.opentelemetry.io/otel` v1.47.0, packages `go.opentelemetry.io/otel/semconv/vX` | `v1.43.0` (added in v1.45.0; no `v1.44.0` package) | | Java | `io.opentelemetry.semconv:opentelemetry-semconv` 1.44.0 (`-incubating` 1.44.0-alpha) | 1.44.0 | | JavaScript | `@opentelemetry/semantic-conventions` 1.43.0 | 1.43.0 | | Python | `opentelemetry-semantic-conventions` 0.66b1 | 1.44.0 | | Ruby | `opentelemetry-semantic_conventions` 1.44.0 | 1.44.0 | | PHP | `open-telemetry/sem-conv` 1.44.0 | 1.44.0 | | C++ | `opentelemetry-cpp` v1.29.0 headers | 1.44.0 | | Rust | `opentelemetry-semantic-conventions` 0.33.1 | 1.42.0 | | .NET | `OpenTelemetry.SemanticConventions`: only the unlisted 1.0.0-rc9.9 on NuGet; unreleased dotnet-contrib source tracks 1.44.0 | - (no current release) | Evidence, at each release tag or in the published artifact: - Go: `semconv/` directories at tag `v1.47.0`; CHANGELOG `1.45.0` adds `semconv/v1.43.0`. - Java: the jar's `SchemaUrls` highest constant is `schemas/1.44.0`. - JavaScript: package `VERSION = '1.43.0'`; its CHANGELOG `1.43.0` cites Semantic Conventions v1.43.0. - Python: the wheel's `opentelemetry/semconv/schemas.py` highest member is `V1_44_0`. - Ruby: the gem's `semantic_conventions/version.rb` `SPEC_VERSION = '1.44.0'`. - PHP: `Version.php` at tag `1.44.0` defines `VERSION_1_44_0`. - C++: `api/include/opentelemetry/semconv/schema_url.h` at `v1.29.0`. - Rust: the crate's `SCHEMA_URL` is `schemas/1.42.0`. - .NET: NuGet registration (`listed: false`); dotnet-contrib `src/OpenTelemetry.SemanticConventions/CHANGELOG.md` Unreleased (#5121). For services in several languages, the shared version is the lowest "Newest semconv exposed" value among the languages in use (1.43.0 for Go plus JavaScript, 1.42.0 with Rust). .NET has no value, so it cannot join a shared version. -
semconv-selection.md 2.2 KB
# Semantic Convention Selection Pick the closest released semantic convention group before inventing custom keys. ## Common Starting Groups - `http` for HTTP client and server operations - `db` for database operations - `messaging` for queues, streams, and pub-sub - `rpc` for remote procedure calls - `network` for transport-level details - `url` for URL components - `server` for server endpoint metadata - `error` for error classification - `user-agent` for client user-agent details - `service` and `cloud` for service and cloud resource metadata - `k8s` and `process` for Kubernetes and process entities or metrics - `otel`, `log`, and `exceptions` for OpenTelemetry SDK telemetry, log records, and exception telemetry ## Selection Rules 1. Start with one primary group that matches the boundary. 2. Add related groups only when they add needed context. 3. Prefer required and recommended attributes before optional ones. 4. If no released key exists, use a stable custom namespace and keep values bounded. 5. For `gen_ai.*`, OpenAI, or MCP conventions, use the dedicated OpenTelemetry GenAI semantic conventions repository; do not use deprecated GenAI-era stubs from the core repository as current guidance. ## Lookup Workflow Use the bundled script instead of loading large spec files: 1. `./scripts/query-otel-semantic-conventions.sh --groups` 2. `./scripts/query-otel-semantic-conventions.sh <group>` 3. `./scripts/query-otel-semantic-conventions.sh <group> <kind-or-entry-id>` Use the one-argument form first. Pass a listed kind to enumerate its entries, or pass an exact entry id to return its released upstream definition. To verify against a local upstream checkout, set `OTEL_SEMCONV_REPO=/path/to/semantic-conventions`. ## Typical Group Pairings - HTTP server: `http`, then maybe `url`, `server`, `network`, `user-agent`, `error` - HTTP client: `http`, then maybe `url`, `server`, `network`, `error` - Database: `db`, then maybe `server`, `error` - Messaging: `messaging`, then maybe `network`, `server`, `error` - RPC: `rpc`, then maybe `server`, `network`, `error` If a domain is not listed by `./scripts/query-otel-semantic-conventions.sh --groups`, treat it as not available in the currently released semantic conventions and use a stable custom namespace.
-
-
scripts
-
query-otel-semantic-conventions.sh 17.7 KB
#!/usr/bin/env bash set -euo pipefail readonly RELEASE_API_URL="https://api.github.com/repos/open-telemetry/semantic-conventions/releases/latest" readonly SEMCONV_REPO="${OTEL_SEMCONV_REPO:-}" readonly SEMCONV_TAG="${OTEL_SEMCONV_TAG:-}" blob_url() { local tag="$1" local path="$2" local line="$3" printf 'https://github.com/open-telemetry/semantic-conventions/blob/%s/%s#L%s' "$tag" "$path" "$line" } group_url() { local tag="$1" local group="$2" printf 'https://github.com/open-telemetry/semantic-conventions/tree/%s/model/%s' "$tag" "$group" } usage() { cat <<'EOF' >&2 Usage: ./scripts/query-otel-semantic-conventions.sh --groups ./scripts/query-otel-semantic-conventions.sh <group> ./scripts/query-otel-semantic-conventions.sh <group> <kind> ./scripts/query-otel-semantic-conventions.sh <group> <id> Examples: ./scripts/query-otel-semantic-conventions.sh --groups ./scripts/query-otel-semantic-conventions.sh http ./scripts/query-otel-semantic-conventions.sh http spans ./scripts/query-otel-semantic-conventions.sh http span.http.client ./scripts/query-otel-semantic-conventions.sh http http.request.method EOF } require_bin() { command -v "$1" >/dev/null 2>&1 || { echo "missing dependency: $1" >&2 exit 1 } } normalize_group() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -d '.' } is_supported_kind() { case "$1" in common|entities|events|logs|metrics|registry|spans) return 0 ;; *) return 1 ;; esac } validate_release_tag() { local tag="$1" if [[ ! "$tag" =~ ^v[0-9]+(\.[0-9]+)*$ ]]; then echo "not a stable semantic conventions release tag: ${tag}" >&2 return 1 fi } fetch_latest_tag() { if [[ -n "$SEMCONV_TAG" ]]; then validate_release_tag "$SEMCONV_TAG" || return 1 printf '%s\n' "$SEMCONV_TAG" return 0 fi if [[ -n "$SEMCONV_REPO" ]]; then local tag tag="$( git -C "$SEMCONV_REPO" tag --list 'v[0-9]*' --sort=-version:refname | grep -E '^v[0-9]+(\.[0-9]+)*$' | sed -n '1p' || true )" if [[ -z "$tag" ]]; then echo "failed to find a stable semantic conventions release tag in ${SEMCONV_REPO}" >&2 return 1 fi validate_release_tag "$tag" || return 1 printf '%s\n' "$tag" return 0 fi local tag tag="$(curl -fsSL "$RELEASE_API_URL" | jq -er '.tag_name')" validate_release_tag "$tag" || return 1 printf '%s\n' "$tag" } fetch_model_paths() { local tag="$1" if [[ -n "$SEMCONV_REPO" ]]; then if ! git -C "$SEMCONV_REPO" ls-tree -r --name-only "$tag" model 2>/dev/null; then echo "failed to read semantic convention model tree from ${SEMCONV_REPO} at ${tag}" >&2 return 1 fi return 0 fi local url="https://api.github.com/repos/open-telemetry/semantic-conventions/git/trees/${tag}?recursive=1" if ! curl -fsSL "$url" 2>/dev/null | jq -r '.tree[] | select(.type == "blob") | .path'; then echo "failed to fetch semantic convention model tree from ${url}" >&2 return 1 fi } fetch_group_file() { local tag="$1" local path="$2" if [[ -n "$SEMCONV_REPO" ]]; then if ! git -C "$SEMCONV_REPO" show "${tag}:${path}" 2>/dev/null; then echo "failed to read semantic convention file ${path} from ${SEMCONV_REPO} at ${tag}" >&2 return 1 fi return 0 fi local url="https://raw.githubusercontent.com/open-telemetry/semantic-conventions/${tag}/${path}" if ! curl -fsSL "$url" 2>/dev/null; then echo "failed to fetch semantic convention file from ${url}" >&2 return 1 fi } model_records() { local model_paths="$1" awk ' function kind_for_file(file) { if (index(file, "registry")) return "registry" if (index(file, "spans")) return "spans" if (index(file, "events")) return "events" if (index(file, "metrics")) return "metrics" if (index(file, "entities")) return "entities" if (index(file, "apphub")) return "entities" if (index(file, "common")) return "common" if (index(file, "logs")) return "logs" return "" } $0 ~ "^model/[^/]+/.+\\.ya?ml$" { path = $0 if (path ~ /\/deprecated\//) next count = split(path, parts, "/") file = tolower(parts[count]) if (index(file, "deprecated")) next kind = kind_for_file(file) if (kind != "") { printf "%s\t%s\t%s\t%s\n", parts[2], kind, path, parts[count] } else if (count == 3 && parts[1] == "model" && parts[2] == "messaging") { # v1.44 definition/2 provider files can contain both span definitions # and cross-signal attribute groups, despite neutral filenames. printf "%s\tspans\t%s\t%s\n", parts[2], path, parts[count] printf "%s\tcommon\t%s\t%s\n", parts[2], path, parts[count] } } ' <<<"$model_paths" } list_available_groups() { local records="$1" awk -F '\t' '{ print $1 }' <<<"$records" | sort -u } group_records() { local records="$1" local normalized_group="$2" awk -F '\t' -v group="$normalized_group" ' function comparable(value) { gsub(/_/, "-", value) return value } $1 == group || comparable($1) == comparable(group) ' <<<"$records" } list_group_kinds() { local records="$1" awk -F '\t' ' { key = $2 if (files[key] == "") { files[key] = $4 } else { files[key] = files[key] ", " $4 } } END { for (key in files) { printf "%s\t%s\n", key, files[key] } } ' <<<"$records" | sort -t $'\t' -k1,1 } find_kind_files() { local records="$1" local requested_kind="$2" awk -F '\t' -v kind="$requested_kind" '$2 == kind { printf "%s\t%s\n", $3, $4 }' <<<"$records" } find_registry_path() { local records="$1" awk -F '\t' '$2 == "registry" { print $3; exit }' <<<"$records" } is_definition_v2() { local content="$1" [[ "$content" == file_format:\ definition/2* || "$content" == *$'\nfile_format: definition/2'* ]] } print_available_groups() { local version="$1" local groups="$2" printf 'version: %s\n' "$version" printf 'groups:\n' sed 's/^/- /' <<<"$groups" } print_kinds_section() { local kinds="$1" printf 'kinds:\n' awk -F '\t' '{ printf "- %s (%s)\n", $1, $2 }' <<<"$kinds" } extract_entries() { local content="$1" local id_prefix="$2" local field_prefix="$3" local width="$4" awk \ -v id_prefix="$id_prefix" \ -v field_prefix="$field_prefix" \ -v width="$width" ' function trim(value) { sub(/^[[:space:]]+/, "", value) sub(/[[:space:]]+$/, "", value) return value } function squish(value) { gsub(/[[:space:]]+/, " ", value) return trim(value) } function unquote(value) { value = trim(value) if (length(value) >= 2) { if ((substr(value, 1, 1) == "\"" && substr(value, length(value), 1) == "\"") || (substr(value, 1, 1) == "'"'"'" && substr(value, length(value), 1) == "'"'"'")) { value = substr(value, 2, length(value) - 2) } } return value } function indentation(value) { match(value, /[^ ]/) return RSTART == 0 ? length(value) : RSTART - 1 } function emit_record() { local_brief = squish(brief) local_stability = stability == "" ? "-" : stability if (id != "") { printf "%-*s %-12s %s\n", width, id, local_stability, local_brief } id = "" stability = "" brief = "" collecting_brief = 0 } index($0, id_prefix) == 1 { emit_record() id = $0 sub("^" id_prefix, "", id) next } id == "" { next } collecting_brief && $0 !~ /^[[:space:]]*$/ && indentation($0) < length(field_prefix) { collecting_brief = 0 next } collecting_brief && $0 ~ ("^" field_prefix "[A-Za-z_][A-Za-z0-9_]*:") { collecting_brief = 0 } collecting_brief { line = $0 sub(/^[[:space:]]+/, "", line) brief = brief " " line next } index($0, field_prefix "stability: ") == 1 { stability = $0 sub("^" field_prefix "stability: ", "", stability) sub(/[[:space:]]+#.*/, "", stability) stability = unquote(stability) next } index($0, field_prefix "brief:") == 1 { line = $0 sub("^" field_prefix "brief:[[:space:]]*", "", line) if (line == "" || line == ">" || line == "|" || line == ">-" || line == "|-" || line == ">+" || line == "|+") { collecting_brief = 1 next } brief = brief " " unquote(line) next } END { emit_record() } ' <<<"$content" } extract_v2_entries() { local content="$1" local requested_kind="$2" local width="$3" awk -v requested_kind="$requested_kind" -v width="$width" ' function trim(value) { sub(/^[[:space:]]+/, "", value) sub(/[[:space:]]+$/, "", value) return value } function squish(value) { gsub(/[[:space:]]+/, " ", value) return trim(value) } function section_kind(value) { if (value == "attributes") return "registry" if (value == "spans" || value == "span_refinements") return "spans" if (value == "events" || value == "event_refinements") return "events" if (value == "metrics" || value == "metric_refinements") return "metrics" if (value == "entities" || value == "entity_refinements") return "entities" if (value == "logs" || value == "log_refinements") return "logs" if (value == "attribute_groups") return "common" return "" } function emit() { if (id != "") { printf "%-*s %-12s %s\n", width, id, (stability == "" ? "-" : stability), squish(brief) } id = stability = brief = "" collecting_brief = 0 } /^[A-Za-z_][A-Za-z0-9_]*:$/ { emit() section = $0 sub(/:$/, "", section) active = section_kind(section) == requested_kind next } active && /^ - (id|key|name|type): / { emit() id = $0 sub(/^ - (id|key|name|type): /, "", id) next } active && id != "" && /^ stability: / { stability = $0 sub(/^ stability: /, "", stability) sub(/[[:space:]]+#.*/, "", stability) next } active && id != "" && /^ brief:/ { line = $0 sub(/^ brief:[[:space:]]*/, "", line) if (line == "" || line ~ /^[>|][-+]?$/) collecting_brief = 1 else brief = line next } collecting_brief { if ($0 ~ /^ /) { line = $0 sub(/^ /, "", line) brief = brief " " line } else { collecting_brief = 0 } } END { emit() } ' <<<"$content" } extract_exact_v2_entry() { local content="$1" local entry_id="$2" local tag="$3" local path="$4" awk -v entry_id="$entry_id" -v tag="$tag" -v path="$path" ' /^ - (id|key|name|type): / { if (found) exit candidate = $0 sub(/^ - (id|key|name|type): /, "", candidate) if (candidate == entry_id) { found = 1 start_line = NR print "source: https://github.com/open-telemetry/semantic-conventions/blob/" tag "/" path "#L" start_line } } found { if (NR > start_line && $0 ~ /^[A-Za-z_][A-Za-z0-9_]*:$/) exit print } END { if (!found) exit 1 } ' <<<"$content" } extract_exact_entry() { local content="$1" local id_prefix="$2" local entry_id="$3" local tag="$4" local path="$5" awk -v id_prefix="$id_prefix" -v entry_id="$entry_id" -v tag="$tag" -v path="$path" ' BEGIN { entry_indent = match(id_prefix, /[^ ]/) - 1 } index($0, id_prefix) == 1 { if (found) { exit } if ($0 == id_prefix entry_id) { found = 1 start_line = NR print "source: https://github.com/open-telemetry/semantic-conventions/blob/" tag "/" path "#L" start_line } } found { if (NR > start_line && $0 !~ /^[[:space:]]*$/) { current_indent = match($0, /[^ ]/) - 1 if (current_indent <= entry_indent) { exit } } print } END { if (!found) { exit 1 } } ' <<<"$content" } print_group_summary() { local requested_group="$1" local version="$2" local kinds="$3" local source_url="$4" local registry_entries="${5:-}" printf 'group: %s\n' "$requested_group" printf 'version: %s\n' "$version" printf 'source: %s\n' "$source_url" print_kinds_section "$kinds" printf '\n' if [[ -n "$registry_entries" ]]; then printf '%s' "$registry_entries" else printf 'note: no registry file available for this group in the latest release\n' fi } print_kind_listing() { local requested_group="$1" local version="$2" local kinds="$3" local source_url="$4" local requested_kind="$5" local kind_entries="$6" printf 'group: %s\n' "$requested_group" printf 'version: %s\n' "$version" printf 'source: %s\n' "$source_url" print_kinds_section "$kinds" printf '\nkind: %s\n\n%s' "$requested_kind" "$kind_entries" } main() { require_bin awk if [[ -n "$SEMCONV_REPO" ]]; then require_bin git else require_bin curl require_bin jq fi case "${1:-}" in ""|-h|--help) usage [[ $# -gt 0 ]] && return 0 return 1 ;; esac local tag version model_paths records groups tag="$(fetch_latest_tag)" version="${tag#v}" model_paths="$(fetch_model_paths "$tag")" records="$(model_records "$model_paths")" case "${1:-}" in --groups) [[ $# -eq 1 ]] || { usage; return 1; } groups="$(list_available_groups "$records")" print_available_groups "$version" "$groups" return 0 ;; esac [[ $# -le 2 ]] || { usage; return 1; } local requested_group="$1" local second_arg="${2:-}" local normalized_group resolved_group group_records_output kinds registry_path registry_content registry_entries source_url local requested_kind kind_files file_path file_content kind_entries matched_entry normalized_group="$(normalize_group "$requested_group")" group_records_output="$(group_records "$records" "$normalized_group")" [[ -n "$group_records_output" ]] || { echo "no supported semantic convention files found for group '${requested_group}'" >&2 return 1 } resolved_group="$(awk -F '\t' 'NR == 1 { print $1 }' <<<"$group_records_output")" kinds="$(list_group_kinds "$group_records_output")" registry_path="$(find_registry_path "$group_records_output")" source_url="$(group_url "$tag" "$resolved_group")" if [[ -z "$second_arg" ]]; then if [[ -n "$registry_path" ]]; then registry_content="$(fetch_group_file "$tag" "$registry_path")" if is_definition_v2 "$registry_content"; then registry_entries="$(extract_v2_entries "$registry_content" registry 32)" else registry_entries="$(extract_entries "$registry_content" " - id: " " " 32)" fi else registry_entries="" fi print_group_summary "$resolved_group" "$version" "$kinds" "$source_url" "$registry_entries" return 0 fi if is_supported_kind "$second_arg"; then requested_kind="$second_arg" kind_files="$(find_kind_files "$group_records_output" "$requested_kind")" [[ -n "$kind_files" ]] || { echo "semantic convention kind '${requested_kind}' is not available for group '${requested_group}'" >&2 return 1 } if [[ "$requested_kind" == "registry" ]]; then [[ -n "$registry_path" ]] || { echo "semantic convention kind 'registry' is not available for group '${requested_group}'" >&2 return 1 } registry_content="$(fetch_group_file "$tag" "$registry_path")" if is_definition_v2 "$registry_content"; then registry_entries="$(extract_v2_entries "$registry_content" registry 32)" else registry_entries="$(extract_entries "$registry_content" " - id: " " " 32)" fi print_kind_listing "$resolved_group" "$version" "$kinds" "$source_url" "$requested_kind" "$registry_entries" return 0 fi kind_entries="" while IFS=$'\t' read -r file_path _; do [[ -n "$file_path" ]] || continue file_content="$(fetch_group_file "$tag" "$file_path")" if is_definition_v2 "$file_content"; then kind_entries+="$(extract_v2_entries "$file_content" "$requested_kind" 36)"$'\n' else kind_entries+="$(extract_entries "$file_content" " - id: " " " 36)"$'\n' fi done <<<"$kind_files" print_kind_listing "$resolved_group" "$version" "$kinds" "$source_url" "$requested_kind" "$kind_entries" return 0 fi if [[ -n "$registry_path" ]]; then registry_content="$(fetch_group_file "$tag" "$registry_path")" if is_definition_v2 "$registry_content" && matched_entry="$(extract_exact_v2_entry "$registry_content" "$second_arg" "$tag" "$registry_path")"; then printf '%s\n' "$matched_entry" return 0 fi if matched_entry="$(extract_exact_entry "$registry_content" " - id: " "$second_arg" "$tag" "$registry_path")"; then printf '%s\n' "$matched_entry" return 0 fi fi while IFS=$'\t' read -r requested_kind _; do [[ -n "$requested_kind" ]] || continue [[ "$requested_kind" == "registry" ]] && continue kind_files="$(find_kind_files "$group_records_output" "$requested_kind")" while IFS=$'\t' read -r file_path _; do [[ -n "$file_path" ]] || continue file_content="$(fetch_group_file "$tag" "$file_path")" if is_definition_v2 "$file_content" && matched_entry="$(extract_exact_v2_entry "$file_content" "$second_arg" "$tag" "$file_path")"; then printf '%s\n' "$matched_entry" return 0 fi if matched_entry="$(extract_exact_entry "$file_content" " - id: " "$second_arg" "$tag" "$file_path")"; then printf '%s\n' "$matched_entry" return 0 fi done <<<"$kind_files" done <<<"$kinds" echo "semantic convention entry not found: ${second_arg}" >&2 return 1 } main "$@" -
test-query-otel-semantic-conventions.sh 1.8 KB
#!/usr/bin/env bash set -euo pipefail script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) repo=${OTEL_SEMCONV_REPO:-} if [[ -z "$repo" ]]; then printf 'OTEL_SEMCONV_REPO must point to a semantic-conventions checkout\n' >&2 exit 2 fi query=(env OTEL_SEMCONV_REPO="$repo" OTEL_SEMCONV_TAG=v1.44.0 "$script_dir/query-otel-semantic-conventions.sh") messaging_spans=$("${query[@]}" messaging spans) grep -q '^span[.]messaging[.]aws[.]sqs[.]send[.]producer' <<<"$messaging_spans" messaging_common=$("${query[@]}" messaging common) grep -q '^messaging[.]kafka[.]attributes[.]common' <<<"$messaging_common" grep -q '^messaging[.]rabbitmq[.]attributes[.]destination' <<<"$messaging_common" exact_entry=$("${query[@]}" messaging span.messaging.aws.sqs.send.producer) grep -q '^source: .*semantic-conventions/blob/v1[.]44[.]0/model/messaging/aws[.]yaml#L' <<<"$exact_entry" client_registry=$("${query[@]}" client registry) grep -q '^client[.]address' <<<"$client_registry" client_exact=$("${query[@]}" client client.address) grep -q '^source: .*semantic-conventions/blob/v1[.]44[.]0/model/client/registry[.]yaml#L' <<<"$client_exact" hardware_metrics=$("${query[@]}" hardware metrics) grep -q '^hw[.]battery[.]charge ' <<<"$hardware_metrics" hardware_exact=$("${query[@]}" hardware hw.battery.charge) grep -q '^source: .*semantic-conventions/blob/v1[.]44[.]0/model/hardware/battery-metrics[.]yaml#L' <<<"$hardware_exact" legacy_http=$(env OTEL_SEMCONV_REPO="$repo" OTEL_SEMCONV_TAG=v1.43.0 "$script_dir/query-otel-semantic-conventions.sh" http spans) grep -q '^span[.]http[.]client' <<<"$legacy_http" legacy_messaging=$(env OTEL_SEMCONV_REPO="$repo" OTEL_SEMCONV_TAG=v1.43.0 "$script_dir/query-otel-semantic-conventions.sh" messaging spans) grep -q '^messaging[.]kafka' <<<"$legacy_messaging"
-
-
SKILL.md 2.7 KB
--- name: otel-semantic-conventions description: OpenTelemetry semantic convention lookup and naming guidance. Use when selecting released semantic convention groups, attributes, or span naming rules, when checking semantic convention compliance, or checking which semantic-conventions version a language SDK's semconv package exposes. --- # OpenTelemetry Semantic Conventions Use this skill when you need released semantic convention guidance for naming, attributes, or compliance checks. ## Workflow 1. Start with released semantic conventions, not model memory. - do not load the full semantic convention spec into context - use the bundled lookup script to query only the needed released group or attribute - for local verification against a checked-out upstream repo, set `OTEL_SEMCONV_REPO=/path/to/semantic-conventions` 2. Choose the closest released group before inventing custom keys. - identify the boundary type such as `http`, `db`, `messaging`, `rpc`, or `network` - pick one primary group first, then add related groups only when they add needed context - for `gen_ai.*`, OpenAI, or MCP conventions, use the dedicated OpenTelemetry GenAI semantic conventions repository; the core repository keeps only deprecated GenAI-era stubs after v1.42.0 - see `references/semconv-selection.md` - to target a version a language's semconv package actually exposes (works offline, dated), see `references/sdk-semconv-packages.md` 3. Query only the released guidance you need. - list groups: `./scripts/query-otel-semantic-conventions.sh --groups` - inspect one group: `./scripts/query-otel-semantic-conventions.sh http` - inspect one kind: `./scripts/query-otel-semantic-conventions.sh http spans` - inspect one exact attribute or entry: `./scripts/query-otel-semantic-conventions.sh http http.request.method` - see `references/otel-semantic-conventions.md` - after changing the parser, run `OTEL_SEMCONV_REPO=/path/to/semantic-conventions bash ./scripts/test-query-otel-semantic-conventions.sh` 4. Apply the released naming and attribute rules directly. - use required and recommended attributes before optional ones - derive semconv-governed span names directly from the released naming rule - do not prepend or append protocol labels, hostnames, product names, business hints, or other custom prose to semconv-governed span names - if the released naming rule does not provide a low-cardinality target, use the simpler fallback allowed by that convention - if no released key exists, use a stable custom namespace and keep values bounded 5. Return the result with exact source context. - include the group name, released version, and source URL from the script output - call out any concrete compatibility limitation if the implementation cannot fully match the released guidance
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.