From d571d3a92cf356e81493631406e5670e693141b3 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Wed, 22 Jan 2025 18:04:48 -0800 Subject: [PATCH 1/4] Fix broken link to redis HMSET command (#1788) --- docs/database/redis.md | 2 +- model/database/spans.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/database/redis.md b/docs/database/redis.md index 8ef933e7a4..e0f85218a7 100644 --- a/docs/database/redis.md +++ b/docs/database/redis.md @@ -74,7 +74,7 @@ Instrumentations SHOULD document how `error.type` is populated. **[9] `db.operation.batch.size`:** Operations are only considered batches when they contain two or more operations, and so `db.operation.batch.size` SHOULD never be `1`. -**[10] `db.query.text`:** For **Redis**, the value provided for `db.query.text` SHOULD correspond to the syntax of the Redis CLI. If, for example, the [`HMSET` command](https://redis.io/commands/hmset) is invoked, `"HMSET myhash field1 'Hello' field2 'World'"` would be a suitable value for `db.query.text`. +**[10] `db.query.text`:** For **Redis**, the value provided for `db.query.text` SHOULD correspond to the syntax of the Redis CLI. If, for example, the [`HMSET` command](https://redis.io/docs/latest/commands/hmset) is invoked, `"HMSET myhash field1 'Hello' field2 'World'"` would be a suitable value for `db.query.text`. **[11] `db.query.text`:** Non-parameterized query text SHOULD NOT be collected by default unless there is sanitization that excludes sensitive data, e.g. by redacting all literal values present in the query text. See [Sanitization of `db.query.text`](../../docs/database/database-spans.md#sanitization-of-dbquerytext). diff --git a/model/database/spans.yaml b/model/database/spans.yaml index b03a9cf9a1..5fd82cef9f 100644 --- a/model/database/spans.yaml +++ b/model/database/spans.yaml @@ -403,7 +403,7 @@ groups: see [`db.operation.parameter.`](../../docs/attributes-registry/db.md)). note: > For **Redis**, the value provided for `db.query.text` SHOULD correspond to the syntax of the Redis CLI. - If, for example, the [`HMSET` command](https://redis.io/commands/hmset) is invoked, `"HMSET myhash field1 'Hello' field2 'World'"` would be a suitable value for `db.query.text`. + If, for example, the [`HMSET` command](https://redis.io/docs/latest/commands/hmset) is invoked, `"HMSET myhash field1 'Hello' field2 'World'"` would be a suitable value for `db.query.text`. - ref: network.peer.address brief: Peer address of the database node where the operation was performed. requirement_level: From 6e8cce5cb04d2f92b6de0cfcabe4774e72c3e958 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 18:06:25 -0800 Subject: [PATCH 2/4] Bump go.opentelemetry.io/build-tools/chloggen from 0.16.0 to 0.17.0 in /internal/tools (#1789) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Liudmila Molkova --- internal/tools/go.mod | 2 +- internal/tools/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/tools/go.mod b/internal/tools/go.mod index babd34a620..5682490353 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -6,7 +6,7 @@ toolchain go1.23.4 require ( github.com/client9/misspell v0.3.4 - go.opentelemetry.io/build-tools/chloggen v0.16.0 + go.opentelemetry.io/build-tools/chloggen v0.17.0 ) require ( diff --git a/internal/tools/go.sum b/internal/tools/go.sum index 3bd9909951..801a8a613c 100644 --- a/internal/tools/go.sum +++ b/internal/tools/go.sum @@ -14,8 +14,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -go.opentelemetry.io/build-tools/chloggen v0.16.0 h1:iuotHxlcK46JJtQLdwQPsC5dcAygeOL116d2akCv8M8= -go.opentelemetry.io/build-tools/chloggen v0.16.0/go.mod h1:Wk92v9Wsv36sXYi7hOg3ndeeLKmKBu0/kgB7wcaeqJg= +go.opentelemetry.io/build-tools/chloggen v0.17.0 h1:aOtA6MW67VoB1HYxcqYIlVxfiBypI/ZTxSb7SU/Jw8g= +go.opentelemetry.io/build-tools/chloggen v0.17.0/go.mod h1:Wk92v9Wsv36sXYi7hOg3ndeeLKmKBu0/kgB7wcaeqJg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From a5c879e7e0bbe32489639d373324f7b608184be9 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Wed, 22 Jan 2025 18:07:51 -0800 Subject: [PATCH 3/4] Fix PR CI check: specify forked repo (#1787) --- .github/workflows/prepare-new-pr.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/prepare-new-pr.yml b/.github/workflows/prepare-new-pr.yml index a8a00fe5eb..eccca9f12d 100644 --- a/.github/workflows/prepare-new-pr.yml +++ b/.github/workflows/prepare-new-pr.yml @@ -20,6 +20,7 @@ jobs: with: ref: ${{ github.head_ref }} path: prchangelog + repository: ${{ github.event.pull_request.head.repo.full_name }} sparse-checkout: .chloggen # we're going to run prepare-new-pr script from the main branch From bfe6e1ecde78246e5e2e02b03d5b48d26f59bfd0 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Wed, 22 Jan 2025 18:11:09 -0800 Subject: [PATCH 4/4] Add stability to `network.interface.name` and event fields, add temp policy check (#1781) --- model/device/events.yaml | 8 +++++ model/gen-ai/events.yaml | 2 ++ model/network/registry.yaml | 1 + policies/registry.rego | 19 ++++++++++ policies_test/registry_test.rego | 45 +++++++++++++++++++++--- policies_test/yaml_schema_test.rego | 9 ++--- templates/registry/markdown/stability.j2 | 4 ++- 7 files changed, 78 insertions(+), 10 deletions(-) diff --git a/model/device/events.yaml b/model/device/events.yaml index fc4a613202..494381c415 100644 --- a/model/device/events.yaml +++ b/model/device/events.yaml @@ -37,24 +37,29 @@ groups: value: 'active' brief: > The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. + stability: development - id: inactive value: 'inactive' brief: > The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. + stability: development - id: background value: 'background' brief: > The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`. + stability: development - id: foreground value: 'foreground' brief: > The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`. + stability: development - id: terminate value: 'terminate' brief: > The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. + stability: development - id: android.state stability: experimental requirement_level: @@ -72,13 +77,16 @@ groups: brief: > Any time before Activity.onResume() or, if the app has no Activity, Context.startService() has been called in the app for the first time. + stability: development - id: background value: 'background' brief: > Any time after Activity.onPause() or, if the app has no Activity, Context.stopService() has been called when the app was in the foreground state. + stability: development - id: foreground value: 'foreground' brief: > Any time after Activity.onResume() or, if the app has no Activity, Context.startService() has been called when the app was in either the created or background states. + stability: development diff --git a/model/gen-ai/events.yaml b/model/gen-ai/events.yaml index ac97d5402c..f615bb8d7f 100644 --- a/model/gen-ai/events.yaml +++ b/model/gen-ai/events.yaml @@ -111,6 +111,7 @@ groups: - id: function value: 'function' brief: Function + stability: development stability: experimental brief: > The type of the tool. @@ -275,6 +276,7 @@ groups: - id: function value: 'function' brief: Function + stability: development stability: experimental brief: > The type of the tool. diff --git a/model/network/registry.yaml b/model/network/registry.yaml index 2dc0ce39a1..542381dba5 100644 --- a/model/network/registry.yaml +++ b/model/network/registry.yaml @@ -236,6 +236,7 @@ groups: type: string brief: 'The network interface name.' examples: [ 'lo', 'eth0' ] + stability: development - id: network.connection.state type: members: diff --git a/policies/registry.rego b/policies/registry.rego index 3e145c1afa..837d34c4ce 100644 --- a/policies/registry.rego +++ b/policies/registry.rego @@ -70,6 +70,25 @@ deny contains attr_registry_violation(description, group.id, attr.id) if { description := sprintf("Attribute definition '%s' has requirement_level set to %s. Only attribute references can set requirement_level.", [attr.id, attr.requirement_level]) } +# We require attribute definitions to have stability +deny contains attr_registry_violation(description, group.id, attr.id) if { + group := input.groups[_] + attr := group.attributes[_] + not attr.stability + description := sprintf("Attribute definition '%s' does not contain stability field. All attribute definitions must include stability level.", [attr.id]) +} + +# We require span, metrics, events, resources definitions to have stability +deny contains attr_registry_violation(description, group.id, "") if { + semconv_types := {"span", "metric", "event", "resource"} + group := input.groups[_] + + semconv_types[group.type] != null + + not group.stability + description := sprintf("Semconv group '%s' does not contain stability field. All semconv definitions must include stability level.", [group.id]) +} + get_attribute_name(attr, group) := name if { full_name := concat(".", [group.prefix, attr.id]) diff --git a/policies_test/registry_test.rego b/policies_test/registry_test.rego index ce715cde3b..f0503ee837 100644 --- a/policies_test/registry_test.rego +++ b/policies_test/registry_test.rego @@ -11,20 +11,55 @@ test_registry_attribute_groups if { test_attribute_ids if { # This requires a prefix for use with opa, but weaver will fill in. - count(before_resolution.deny) > 0 with input as {"groups": [{"id": "not_registry", "prefix": "", "attributes": [{"id": "foo.bar"}]}]} + count(before_resolution.deny) > 0 with input as {"groups": [{"id": "not_registry", "prefix": "", "attributes": [{"id": "foo.bar", "stability": "rc"}]}]} count(before_resolution.deny) == 0 with input as {"groups": [ - {"id": "registry.test", "prefix": "", "attributes": [{"id": "foo.bar"}]}, - {"id": "not_registry", "prefix": "", "attributes": [{"ref": "foo.bar"}]}, + {"id": "registry.test", "prefix": "", "attributes": [{"id": "foo.bar", "stability": "rc"}]}, + {"id": "not_registry", "prefix": "", "attributes": [{"ref": "foo.bar", "stability": "rc"}]}, ]} } +test_attribute_without_stability if { + count(before_resolution.deny) > 0 with input as {"groups": [{"id": "registry.text", "attributes": [{"id": "foo.bar"}]}]} + count(before_resolution.deny) == 0 with input as {"groups": [ + {"id": "registry.test", "attributes": [{"id": "foo.bar", "stability": "alpha"}]}, + ]} +} + +test_span_without_stability if { + count(before_resolution.deny) > 0 with input as {"groups": [{"id": "span.group", "type": "span"}]} + count(before_resolution.deny) == 0 with input as {"groups": [ + {"id": "span.group", "type": "span", "stability": "alpha"}] + } +} + +test_event_without_stability if { + count(before_resolution.deny) > 0 with input as {"groups": [{"id": "event.foo", "type": "event", "name": "foo"}]} + count(before_resolution.deny) == 0 with input as {"groups": [ + {"id": "event.foo", "name": "foo", "type": "event", "stability": "alpha"}] + } +} + +test_metric_without_stability if { + count(before_resolution.deny) > 0 with input as {"groups": [{"id": "metric.foo", "type": "metric", "name": "foo"}]} + count(before_resolution.deny) == 0 with input as {"groups": [ + {"id": "metric.foo", "name": "foo", "type": "metric", "stability": "development"}] + } +} + +test_resource_without_stability if { + count(before_resolution.deny) > 0 with input as {"groups": [{"id": "resource.foo", "type": "resource", "name": "foo"}]} + count(before_resolution.deny) == 0 with input as {"groups": [ + {"id": "resource.foo", "name": "foo", "type": "resource", "stability": "stable"}] + } +} + test_attribute_refs if { count(before_resolution.deny) > 0 with input as {"groups": [{"id": "registry.foo", "attributes": [{"ref": "foo"}]}]} count(before_resolution.deny) == 0 with input as {"groups": [{"id": "not_registry", "attributes": [{"ref": "foo"}]}]} } test_attribute_requirement_levels if { - count(before_resolution.deny) > 0 with input as {"groups": [{"id": "registry.foo", "attributes": [{"id": "foo", "requirement_level": "required"}]}]} - count(before_resolution.deny) > 0 with input as {"groups": [{"id": "registry.foo", "attributes": [{"id": "foo", "requirement_level": {"recommended": "if available"}}]}]} + count(before_resolution.deny) > 0 with input as {"groups": [{"id": "registry.foo", "attributes": [{"id": "foo", "requirement_level": "required", "stability": "rc"}]}]} + count(before_resolution.deny) > 0 with input as {"groups": [{"id": "registry.foo", "attributes": [{"id": "foo", "requirement_level": {"recommended": "if available"}, "stability": "rc"}]}]} count(before_resolution.deny) == 0 with input as {"groups": [{"id": "not_registry", "attributes": [{"ref": "foo", "requirement_level": "required"}]}]} } diff --git a/policies_test/yaml_schema_test.rego b/policies_test/yaml_schema_test.rego index 81dd0f2d55..b587855f36 100644 --- a/policies_test/yaml_schema_test.rego +++ b/policies_test/yaml_schema_test.rego @@ -52,6 +52,7 @@ test_fails_on_referenced_event_name_on_event if { event := [{ "id": "event.foo", "type": "event", "name": "foo", + "stability": "rc", "attributes": [{"ref": "event.name"}]}] count(deny) == 1 with input as {"groups": event} } @@ -101,22 +102,22 @@ test_fails_on_invalid_resource_id if { } create_attribute_group(attr) = json if { - json := [{"id": "yaml_schema.test", "attributes": [{"id": attr}]}] + json := [{"id": "yaml_schema.test", "attributes": [{"id": attr, "stability": "rc"}]}] } create_metric(name) = json if { id := sprintf("metric.%s", [name]) - json := [{"id": id, "type": "metric", "metric_name": name}] + json := [{"id": id, "type": "metric", "metric_name": name, "stability": "rc"}] } create_event(name) = json if { id := sprintf("event.%s", [name]) - json := [{"id": id, "type": "event", "name": name}] + json := [{"id": id, "type": "event", "name": name, "stability": "rc"}] } create_resource(name) = json if { id := sprintf("resource.%s", [name]) - json := [{"id": id, "type": "resource", "name": name}] + json := [{"id": id, "type": "resource", "name": name, "stability": "rc"}] } invalid_names := [ diff --git a/templates/registry/markdown/stability.j2 b/templates/registry/markdown/stability.j2 index 747b5a4446..c7169eae5f 100644 --- a/templates/registry/markdown/stability.j2 +++ b/templates/registry/markdown/stability.j2 @@ -4,6 +4,8 @@ {%- elif stability == "stable" %}![Stable](https://img.shields.io/badge/-stable-lightgreen) {%- elif stability == "release_candidate" %}![Release Candidate](https://img.shields.io/badge/-rc-mediumorchid) {%- elif stability == "deprecated" %}![Deprecated](https://img.shields.io/badge/-deprecated-red) -{%- else %}![Experimental](https://img.shields.io/badge/-experimental-blue) +{%- elif stability == "experimental" %}![Experimental](https://img.shields.io/badge/-experimental-blue) +{%- elif stability == "development" %}![Experimental](https://img.shields.io/badge/-experimental-blue) +{%- else %}{{ "Unknown stability." }} {%- endif %} {%- endmacro %}