From 43d5e0dff8ae2c5b50dfa7e52fd7628766a312d4 Mon Sep 17 00:00:00 2001 From: Nev Wylie <54870357+MSNev@users.noreply.github.com> Date: Wed, 7 Aug 2024 09:33:48 -0700 Subject: [PATCH 1/8] feat: Add support for event body fields --- .gitignore | 3 + crates/weaver_forge/data/exception.yaml | 54 + crates/weaver_forge/data/mobile-events.yaml | 140 +- crates/weaver_forge/data/trace-exception.yaml | 16 + .../semconv_jq_fn/semconv_attributes.json | 2 +- .../semconv_jq_fn/semconv_events.json | 1 + .../semconv_grouped_attributes.json | 2 +- ...ouped_attributes_without_experimental.json | 2 +- .../test/attribute_group/exception.md | 79 + .../expected_output/test/attribute_groups.md | 83 + .../expected_output/test/event/device_app.md | 16 + .../expected_output/test/event/lifecycle.md | 57 - .../expected_output/test/event/other.md | 92 + .../expected_output/test/events.md | 96 +- .../expected_output/test/registry.md | 5 +- .../whitespace_control/registry.md | 5 +- crates/weaver_forge/src/registry.rs | 8 + .../semconv_jq_fn/semconv_events.json | 1 + .../templates/semconv_jq_fn/weaver.yaml | 9 + crates/weaver_forge/templates/test/event.md | 6 +- crates/weaver_forge/templates/test/events.md | 4 +- .../weaver_forge/templates/test/weaver.yaml | 22 +- .../weaver_resolved_schema/src/attribute.rs | 2 +- crates/weaver_resolved_schema/src/body.rs | 82 + crates/weaver_resolved_schema/src/error.rs | 15 +- crates/weaver_resolved_schema/src/lib.rs | 3 +- crates/weaver_resolved_schema/src/registry.rs | 5 + crates/weaver_resolved_schema/src/signal.rs | 29 +- .../expected-attribute-catalog.json | 2037 ++++++++++++++++- .../expected-events.json | 221 ++ .../expected-registry.json | 1590 ++++++++++++- .../observed-events.json | 219 ++ .../registry/browser-event.yaml | 54 + .../registry/client-exception-event.yaml | 39 + .../registry/log-event.yaml | 7 + .../registry/mobile-events.yaml | 138 +- .../registry/ping-event.yaml | 5 + .../registry/referenced-attributes.yaml | 32 + .../registry/referenced-client.yaml | 28 + .../registry/referenced-exception.yaml | 55 + .../registry/referenced-gen_ai.yaml | 148 ++ .../registry/referenced-network.yaml | 235 ++ .../registry/referenced-rpc.yaml | 265 +++ .../registry/referenced-server.yaml | 28 + .../registry/trace-exception.yaml | 16 + .../registry/trace-gen-ai.yaml | 73 + .../registry/trace-rpc.yaml | 131 ++ crates/weaver_resolver/src/attribute.rs | 11 +- crates/weaver_resolver/src/body.rs | 50 + crates/weaver_resolver/src/lib.rs | 12 + crates/weaver_resolver/src/registry.rs | 33 + crates/weaver_semconv/data/event.yaml | 149 ++ crates/weaver_semconv/src/body.rs | 244 ++ crates/weaver_semconv/src/group.rs | 31 +- crates/weaver_semconv/src/lib.rs | 2 + crates/weaver_semconv/src/registry.rs | 2 + 56 files changed, 6366 insertions(+), 328 deletions(-) create mode 100644 crates/weaver_forge/data/exception.yaml create mode 100644 crates/weaver_forge/data/trace-exception.yaml create mode 100644 crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json create mode 100644 crates/weaver_forge/expected_output/test/attribute_group/exception.md create mode 100644 crates/weaver_forge/expected_output/test/event/device_app.md delete mode 100644 crates/weaver_forge/expected_output/test/event/lifecycle.md create mode 100644 crates/weaver_forge/expected_output/test/event/other.md create mode 100644 crates/weaver_forge/templates/semconv_jq_fn/semconv_events.json create mode 100644 crates/weaver_resolved_schema/src/body.rs create mode 100644 crates/weaver_resolver/data/registry-test-4-events/expected-events.json create mode 100644 crates/weaver_resolver/data/registry-test-4-events/observed-events.json create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/log-event.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/ping-event.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-attributes.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-client.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-exception.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-gen_ai.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-network.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-rpc.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-server.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/trace-exception.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/trace-gen-ai.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/trace-rpc.yaml create mode 100644 crates/weaver_resolver/src/body.rs create mode 100644 crates/weaver_semconv/data/event.yaml create mode 100644 crates/weaver_semconv/src/body.rs diff --git a/.gitignore b/.gitignore index 18f2c1c9..a5dffafe 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ just.zsh .vscode/ .devcontainer/ +# Visual Studio +.vs/ + # Emacs *~ \#*\# diff --git a/crates/weaver_forge/data/exception.yaml b/crates/weaver_forge/data/exception.yaml new file mode 100644 index 00000000..70dea3d5 --- /dev/null +++ b/crates/weaver_forge/data/exception.yaml @@ -0,0 +1,54 @@ +groups: + - id: registry.exception + type: attribute_group + prefix: exception + brief: > + This document defines the shared attributes used to + report a single exception associated with a span or log. + attributes: + - id: type + type: string + stability: stable + brief: > + The type of the exception (its fully-qualified class name, if applicable). + The dynamic type of the exception should be preferred over the static type + in languages that support it. + examples: ["java.net.ConnectException", "OSError"] + - id: message + type: string + stability: stable + brief: The exception message. + examples: ["Division by zero", "Can't convert 'int' object to str implicitly"] + - id: stacktrace + type: string + stability: stable + brief: > + A stacktrace as a string in the natural representation for the language runtime. + The representation is to be determined and documented by each language SIG. + examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n + at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n + at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n + at com.example.GenerateTrace.main(GenerateTrace.java:5)' + - id: escaped + type: boolean + stability: stable + brief: > + SHOULD be set to true if the exception event is recorded at a point where + it is known that the exception is escaping the scope of the span. + note: |- + An exception is considered to have escaped (or left) the scope of a span, + if that span is ended while the exception is still logically "in flight". + This may be actually "in flight" in some languages (e.g. if the exception + is passed to a Context manager's `__exit__` method in Python) but will + usually be caught at the point of recording the exception in most languages. + + It is usually not possible to determine at the point where an exception is thrown + whether it will escape the scope of a span. + However, it is trivial to know that an exception + will escape, if one checks for an active exception just before ending the span, + as done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception). + + It follows that an exception may still escape the scope of the span + even if the `exception.escaped` attribute was not set or set to false, + since the event might have been recorded at a time where it was not + clear whether the exception will escape. diff --git a/crates/weaver_forge/data/mobile-events.yaml b/crates/weaver_forge/data/mobile-events.yaml index 9f0af378..b1b219d5 100644 --- a/crates/weaver_forge/data/mobile-events.yaml +++ b/crates/weaver_forge/data/mobile-events.yaml @@ -1,74 +1,74 @@ groups: - - id: ios.lifecycle.events + - id: device.app.lifecycle + stability: experimental type: event - prefix: ios name: device.app.lifecycle brief: > - This event represents an occurrence of a lifecycle transition on the iOS platform. - attributes: - - id: state - stability: experimental - requirement_level: "required" - note: > - The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), - and from which the `OS terminology` column values are derived. - brief: > - This attribute represents the state the application has transitioned into at the occurrence of the event. - type: - allow_custom_values: false - members: - - id: active - value: 'active' - brief: > - The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. - - id: inactive - value: 'inactive' - brief: > - The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. - - id: background - value: 'background' - brief: > - The app is now in the background. - This value is associated with UIKit notification `applicationDidEnterBackground`. - - id: foreground - value: 'foreground' - brief: > - The app is now in the foreground. - This value is associated with UIKit notification `applicationWillEnterForeground`. - - id: terminate - value: 'terminate' - brief: > - The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. - - id: android.lifecycle.events - type: event - prefix: android - name: device.app.lifecycle - brief: > - This event represents an occurrence of a lifecycle transition on the Android platform. - attributes: - - id: state - stability: experimental - requirement_level: required - brief: > - This attribute represents the state the application has transitioned into at the occurrence of the event. - note: > - The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), - and from which the `OS identifiers` are derived. - type: - allow_custom_values: false - members: - - id: created - value: 'created' - 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. - - 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. - - 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. \ No newline at end of file + This event represents an occurrence of a lifecycle transition on Android or iOS platform. + note: > + This event identifies the fields that are common to all lifecycle events for android and iOS using + the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are + mutually exclusive. + body: + fields: + - id: ios.state + stability: experimental + requirement_level: + conditionally_required: if and only if `os.name` is `ios` + note: > + The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), + and from which the `OS terminology` column values are derived. + brief: > + This attribute represents the state the application has transitioned into at the occurrence of the event. + type: + allow_custom_values: false + members: + - id: active + value: 'active' + brief: > + The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. + - id: inactive + value: 'inactive' + brief: > + The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. + - id: background + value: 'background' + brief: > + The app is now in the background. + This value is associated with UIKit notification `applicationDidEnterBackground`. + - id: foreground + value: 'foreground' + brief: > + The app is now in the foreground. + This value is associated with UIKit notification `applicationWillEnterForeground`. + - id: terminate + value: 'terminate' + brief: > + The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. + - id: android.state + stability: experimental + requirement_level: + conditionally_required: if and only if `os.name` is `android` + brief: > + This attribute represents the state the application has transitioned into at the occurrence of the event. + note: > + The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), + and from which the `OS identifiers` are derived. + type: + allow_custom_values: false + members: + - id: created + value: 'created' + 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. + - 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. + - 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. \ No newline at end of file diff --git a/crates/weaver_forge/data/trace-exception.yaml b/crates/weaver_forge/data/trace-exception.yaml new file mode 100644 index 00000000..32c53f4b --- /dev/null +++ b/crates/weaver_forge/data/trace-exception.yaml @@ -0,0 +1,16 @@ +groups: + - id: trace-exception + prefix: exception + type: event + brief: > + This document defines the attributes used to + report a single exception associated with a span. + attributes: + - ref: exception.type + requirement_level: + conditionally_required: Required if `exception.message` is not set, recommended otherwise. + - ref: exception.message + requirement_level: + conditionally_required: Required if `exception.type` is not set, recommended otherwise. + - ref: exception.stacktrace + - ref: exception.escaped diff --git a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_attributes.json b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_attributes.json index f3b7465b..d398e239 100644 --- a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_attributes.json +++ b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_attributes.json @@ -1 +1 @@ -[{"brief":"The consistency level of the query. Based on consistency values from [CQL](https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/dml/dmlConfigConsistency.html).\n","name":"db.cassandra.consistency_level","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"all","note":null,"stability":null,"value":"all"},{"brief":null,"deprecated":null,"id":"each_quorum","note":null,"stability":null,"value":"each_quorum"},{"brief":null,"deprecated":null,"id":"quorum","note":null,"stability":null,"value":"quorum"},{"brief":null,"deprecated":null,"id":"local_quorum","note":null,"stability":null,"value":"local_quorum"},{"brief":null,"deprecated":null,"id":"one","note":null,"stability":null,"value":"one"},{"brief":null,"deprecated":null,"id":"two","note":null,"stability":null,"value":"two"},{"brief":null,"deprecated":null,"id":"three","note":null,"stability":null,"value":"three"},{"brief":null,"deprecated":null,"id":"local_one","note":null,"stability":null,"value":"local_one"},{"brief":null,"deprecated":null,"id":"any","note":null,"stability":null,"value":"any"},{"brief":null,"deprecated":null,"id":"serial","note":null,"stability":null,"value":"serial"},{"brief":null,"deprecated":null,"id":"local_serial","note":null,"stability":null,"value":"local_serial"}]}},{"brief":"The data center of the coordinating node for a query.\n","examples":"us-west-2","name":"db.cassandra.coordinator.dc","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The ID of the coordinating node for a query.\n","examples":"be13faa2-8574-4d71-926d-27f16cf8a7af","name":"db.cassandra.coordinator.id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"Whether or not the query is idempotent.\n","name":"db.cassandra.idempotence","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"boolean"},{"brief":"The fetch size used for paging, i.e. how many rows will be returned at once.\n","examples":[5000],"name":"db.cassandra.page_size","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The number of times a query was speculatively executed. Not set or `0` if the query was not executed speculatively.\n","examples":[0,2],"name":"db.cassandra.speculative_execution_count","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The name of the primary Cassandra table that the operation is acting upon, including the keyspace name (if applicable).","examples":"mytable","name":"db.cassandra.table","note":"This mirrors the db.sql.table attribute but references cassandra rather than sql. It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The connection string used to connect to the database. It is recommended to remove embedded credentials.\n","examples":"Server=(localdb)\\v11.0;Integrated Security=true;","name":"db.connection_string","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"Unique Cosmos client instance id.","examples":"3ba4827d-4422-483f-b59f-85b74211c11d","name":"db.cosmosdb.client_id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"Cosmos client connection mode.","name":"db.cosmosdb.connection_mode","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":false,"members":[{"brief":"Gateway (HTTP) connections mode","deprecated":null,"id":"gateway","note":null,"stability":null,"value":"gateway"},{"brief":"Direct connection.","deprecated":null,"id":"direct","note":null,"stability":null,"value":"direct"}]}},{"brief":"Cosmos DB container name.","examples":"anystring","name":"db.cosmosdb.container","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"CosmosDB Operation Type.","name":"db.cosmosdb.operation_type","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"invalid","note":null,"stability":null,"value":"Invalid"},{"brief":null,"deprecated":null,"id":"create","note":null,"stability":null,"value":"Create"},{"brief":null,"deprecated":null,"id":"patch","note":null,"stability":null,"value":"Patch"},{"brief":null,"deprecated":null,"id":"read","note":null,"stability":null,"value":"Read"},{"brief":null,"deprecated":null,"id":"read_feed","note":null,"stability":null,"value":"ReadFeed"},{"brief":null,"deprecated":null,"id":"delete","note":null,"stability":null,"value":"Delete"},{"brief":null,"deprecated":null,"id":"replace","note":null,"stability":null,"value":"Replace"},{"brief":null,"deprecated":null,"id":"execute","note":null,"stability":null,"value":"Execute"},{"brief":null,"deprecated":null,"id":"query","note":null,"stability":null,"value":"Query"},{"brief":null,"deprecated":null,"id":"head","note":null,"stability":null,"value":"Head"},{"brief":null,"deprecated":null,"id":"head_feed","note":null,"stability":null,"value":"HeadFeed"},{"brief":null,"deprecated":null,"id":"upsert","note":null,"stability":null,"value":"Upsert"},{"brief":null,"deprecated":null,"id":"batch","note":null,"stability":null,"value":"Batch"},{"brief":null,"deprecated":null,"id":"query_plan","note":null,"stability":null,"value":"QueryPlan"},{"brief":null,"deprecated":null,"id":"execute_javascript","note":null,"stability":null,"value":"ExecuteJavaScript"}]}},{"brief":"RU consumed for that operation","examples":[46.18,1.0],"name":"db.cosmosdb.request_charge","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"double"},{"brief":"Request payload size in bytes","name":"db.cosmosdb.request_content_length","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB status code.","examples":[200,201],"name":"db.cosmosdb.status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB sub status code.","examples":[1000,1002],"name":"db.cosmosdb.sub_status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Represents the identifier of an Elasticsearch cluster.\n","examples":["e9106fc68e3044f0b1475b04bf4ffd5f"],"name":"db.elasticsearch.cluster.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"Represents the human-readable identifier of the node/instance to which a request was routed.\n","examples":["instance-0000000001"],"name":"db.elasticsearch.node.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"A dynamic value in the url path.\n","examples":["db.elasticsearch.path_parts.index=test-index","db.elasticsearch.path_parts.doc_id=123"],"name":"db.elasticsearch.path_parts","note":"Many Elasticsearch url paths allow dynamic values. These SHOULD be recorded in span attributes in the format `db.elasticsearch.path_parts.\u003ckey\u003e`, where `\u003ckey\u003e` is the url path part name. The implementation SHOULD reference the [elasticsearch schema](https://raw.githubusercontent.com/elastic/elasticsearch-specification/main/output/schema/schema.json) in order to map the path part values to their names.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"template[string]"},{"brief":"An identifier (address, unique name, or any other identifier) of the database instance that is executing queries or mutations on the current connection. This is useful in cases where the database is running in a clustered environment and the instrumentation is able to record the node executing the query. The client may obtain this value in databases like MySQL using queries like `select @@hostname`.\n","examples":"mysql-e26b99z.example.com","name":"db.instance.id","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The fully-qualified class name of the [Java Database Connectivity (JDBC)](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/) driver used to connect.\n","examples":["org.postgresql.Driver","com.microsoft.sqlserver.jdbc.SQLServerDriver"],"name":"db.jdbc.driver_classname","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-jdbc","type":"string"},{"brief":"The MongoDB collection being accessed within the database stated in `db.name`.\n","examples":["customers","products"],"name":"db.mongodb.collection","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mongodb","type":"string"},{"brief":"The Microsoft SQL Server [instance name](https://docs.microsoft.com/sql/connect/jdbc/building-the-connection-url?view=sql-server-ver15) connecting to. This name is used to determine the port of a named instance.\n","examples":"MSSQLSERVER","name":"db.mssql.instance_name","note":"If setting a `db.mssql.instance_name`, `server.port` is no longer required (but still recommended if non-standard).\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mssql","type":"string"},{"brief":"This attribute is used to report the name of the database being accessed. For commands that switch the database, this should be set to the target database (even if the command fails).\n","examples":["customers","main"],"name":"db.name","note":"In some SQL databases, the database name to be used is called \"schema name\". In case there are multiple layers that could be considered for database name (e.g. Oracle instance name and schema name), the database name to be used is the more specific layer (e.g. Oracle schema name).\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The name of the operation being executed, e.g. the [MongoDB command name](https://docs.mongodb.com/manual/reference/command/#database-operations) such as `findAndModify`, or the SQL keyword.\n","examples":["findAndModify","HMSET","SELECT"],"name":"db.operation","note":"When setting this to an SQL keyword, it is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if the operation name is provided by the library being instrumented. If the SQL statement has an ambiguous operation, or performs more than one operation, this value may be omitted.\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The index of the database being accessed as used in the [`SELECT` command](https://redis.io/commands/select), provided as an integer. To be used instead of the generic `db.name` attribute.\n","examples":[0,1,15],"name":"db.redis.database_index","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-redis","type":"int"},{"brief":"The name of the primary table that the operation is acting upon, including the database name (if applicable).","examples":["public.users","customers"],"name":"db.sql.table","note":"It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-sql","type":"string"},{"brief":"The database statement being executed.\n","examples":["SELECT * FROM wuser_table","SET mykey \"WuValue\""],"name":"db.statement","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"An identifier for the database management system (DBMS) product being used. See below for a list of well-known identifiers.","name":"db.system","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":{"allow_custom_values":true,"members":[{"brief":"Some other SQL database. Fallback only. See notes.","deprecated":null,"id":"other_sql","note":null,"stability":null,"value":"other_sql"},{"brief":"Microsoft SQL Server","deprecated":null,"id":"mssql","note":null,"stability":null,"value":"mssql"},{"brief":"Microsoft SQL Server Compact","deprecated":null,"id":"mssqlcompact","note":null,"stability":null,"value":"mssqlcompact"},{"brief":"MySQL","deprecated":null,"id":"mysql","note":null,"stability":null,"value":"mysql"},{"brief":"Oracle Database","deprecated":null,"id":"oracle","note":null,"stability":null,"value":"oracle"},{"brief":"IBM Db2","deprecated":null,"id":"db2","note":null,"stability":null,"value":"db2"},{"brief":"PostgreSQL","deprecated":null,"id":"postgresql","note":null,"stability":null,"value":"postgresql"},{"brief":"Amazon Redshift","deprecated":null,"id":"redshift","note":null,"stability":null,"value":"redshift"},{"brief":"Apache Hive","deprecated":null,"id":"hive","note":null,"stability":null,"value":"hive"},{"brief":"Cloudscape","deprecated":null,"id":"cloudscape","note":null,"stability":null,"value":"cloudscape"},{"brief":"HyperSQL DataBase","deprecated":null,"id":"hsqldb","note":null,"stability":null,"value":"hsqldb"},{"brief":"Progress Database","deprecated":null,"id":"progress","note":null,"stability":null,"value":"progress"},{"brief":"SAP MaxDB","deprecated":null,"id":"maxdb","note":null,"stability":null,"value":"maxdb"},{"brief":"SAP HANA","deprecated":null,"id":"hanadb","note":null,"stability":null,"value":"hanadb"},{"brief":"Ingres","deprecated":null,"id":"ingres","note":null,"stability":null,"value":"ingres"},{"brief":"FirstSQL","deprecated":null,"id":"firstsql","note":null,"stability":null,"value":"firstsql"},{"brief":"EnterpriseDB","deprecated":null,"id":"edb","note":null,"stability":null,"value":"edb"},{"brief":"InterSystems Caché","deprecated":null,"id":"cache","note":null,"stability":null,"value":"cache"},{"brief":"Adabas (Adaptable Database System)","deprecated":null,"id":"adabas","note":null,"stability":null,"value":"adabas"},{"brief":"Firebird","deprecated":null,"id":"firebird","note":null,"stability":null,"value":"firebird"},{"brief":"Apache Derby","deprecated":null,"id":"derby","note":null,"stability":null,"value":"derby"},{"brief":"FileMaker","deprecated":null,"id":"filemaker","note":null,"stability":null,"value":"filemaker"},{"brief":"Informix","deprecated":null,"id":"informix","note":null,"stability":null,"value":"informix"},{"brief":"InstantDB","deprecated":null,"id":"instantdb","note":null,"stability":null,"value":"instantdb"},{"brief":"InterBase","deprecated":null,"id":"interbase","note":null,"stability":null,"value":"interbase"},{"brief":"MariaDB","deprecated":null,"id":"mariadb","note":null,"stability":null,"value":"mariadb"},{"brief":"Netezza","deprecated":null,"id":"netezza","note":null,"stability":null,"value":"netezza"},{"brief":"Pervasive PSQL","deprecated":null,"id":"pervasive","note":null,"stability":null,"value":"pervasive"},{"brief":"PointBase","deprecated":null,"id":"pointbase","note":null,"stability":null,"value":"pointbase"},{"brief":"SQLite","deprecated":null,"id":"sqlite","note":null,"stability":null,"value":"sqlite"},{"brief":"Sybase","deprecated":null,"id":"sybase","note":null,"stability":null,"value":"sybase"},{"brief":"Teradata","deprecated":null,"id":"teradata","note":null,"stability":null,"value":"teradata"},{"brief":"Vertica","deprecated":null,"id":"vertica","note":null,"stability":null,"value":"vertica"},{"brief":"H2","deprecated":null,"id":"h2","note":null,"stability":null,"value":"h2"},{"brief":"ColdFusion IMQ","deprecated":null,"id":"coldfusion","note":null,"stability":null,"value":"coldfusion"},{"brief":"Apache Cassandra","deprecated":null,"id":"cassandra","note":null,"stability":null,"value":"cassandra"},{"brief":"Apache HBase","deprecated":null,"id":"hbase","note":null,"stability":null,"value":"hbase"},{"brief":"MongoDB","deprecated":null,"id":"mongodb","note":null,"stability":null,"value":"mongodb"},{"brief":"Redis","deprecated":null,"id":"redis","note":null,"stability":null,"value":"redis"},{"brief":"Couchbase","deprecated":null,"id":"couchbase","note":null,"stability":null,"value":"couchbase"},{"brief":"CouchDB","deprecated":null,"id":"couchdb","note":null,"stability":null,"value":"couchdb"},{"brief":"Microsoft Azure Cosmos DB","deprecated":null,"id":"cosmosdb","note":null,"stability":null,"value":"cosmosdb"},{"brief":"Amazon DynamoDB","deprecated":null,"id":"dynamodb","note":null,"stability":null,"value":"dynamodb"},{"brief":"Neo4j","deprecated":null,"id":"neo4j","note":null,"stability":null,"value":"neo4j"},{"brief":"Apache Geode","deprecated":null,"id":"geode","note":null,"stability":null,"value":"geode"},{"brief":"Elasticsearch","deprecated":null,"id":"elasticsearch","note":null,"stability":null,"value":"elasticsearch"},{"brief":"Memcached","deprecated":null,"id":"memcached","note":null,"stability":null,"value":"memcached"},{"brief":"CockroachDB","deprecated":null,"id":"cockroachdb","note":null,"stability":null,"value":"cockroachdb"},{"brief":"OpenSearch","deprecated":null,"id":"opensearch","note":null,"stability":null,"value":"opensearch"},{"brief":"ClickHouse","deprecated":null,"id":"clickhouse","note":null,"stability":null,"value":"clickhouse"},{"brief":"Cloud Spanner","deprecated":null,"id":"spanner","note":null,"stability":null,"value":"spanner"},{"brief":"Trino","deprecated":null,"id":"trino","note":null,"stability":null,"value":"trino"}]}},{"brief":"Username for accessing the database.\n","examples":["readonly_user","reporting_user"],"name":"db.user","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The size of the request payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.\n","examples":3495,"name":"http.request.body.size","requirement_level":"recommended","root_namespace":"http","stability":"experimental","type":"int"},{"brief":"HTTP request headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.request.header.content-type=[\"application/json\"]","http.request.header.x-forwarded-for=[\"1.2.3.4\", \"1.2.3.5\"]"],"name":"http.request.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all request headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nThe `User-Agent` header is already captured in the `user_agent.original` attribute. Users MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"HTTP request method.","examples":["GET","POST","HEAD"],"name":"http.request.method","note":"HTTP request method value SHOULD be \"known\" to the instrumentation.\nBy default, this convention defines \"known\" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods)\nand the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html).\n\nIf the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`.\n\nIf the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override\nthe list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named\nOTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods\n(this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults).\n\nHTTP method names are case-sensitive and `http.request.method` attribute value MUST match a known HTTP method name exactly.\nInstrumentations for specific web frameworks that consider HTTP methods to be case insensitive, SHOULD populate a canonical equivalent.\nTracing instrumentations that do so, MUST also set `http.request.method_original` to the original value.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"CONNECT method.","deprecated":null,"id":"connect","note":null,"stability":null,"value":"CONNECT"},{"brief":"DELETE method.","deprecated":null,"id":"delete","note":null,"stability":null,"value":"DELETE"},{"brief":"GET method.","deprecated":null,"id":"get","note":null,"stability":null,"value":"GET"},{"brief":"HEAD method.","deprecated":null,"id":"head","note":null,"stability":null,"value":"HEAD"},{"brief":"OPTIONS method.","deprecated":null,"id":"options","note":null,"stability":null,"value":"OPTIONS"},{"brief":"PATCH method.","deprecated":null,"id":"patch","note":null,"stability":null,"value":"PATCH"},{"brief":"POST method.","deprecated":null,"id":"post","note":null,"stability":null,"value":"POST"},{"brief":"PUT method.","deprecated":null,"id":"put","note":null,"stability":null,"value":"PUT"},{"brief":"TRACE method.","deprecated":null,"id":"trace","note":null,"stability":null,"value":"TRACE"},{"brief":"Any HTTP method that the instrumentation has no prior knowledge of.","deprecated":null,"id":"other","note":null,"stability":null,"value":"_OTHER"}]}},{"brief":"Original HTTP method sent by the client in the request line.","examples":["GeT","ACL","foo"],"name":"http.request.method_original","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"},{"brief":"The ordinal number of request resending attempt (for any reason, including redirects).\n","examples":3,"name":"http.request.resend_count","note":"The resend count SHOULD be updated each time an HTTP request gets resent by the client, regardless of what was the cause of the resending (e.g. redirection, authorization failure, 503 Server Unavailable, network issues, or any other).\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"The size of the response payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.\n","examples":3495,"name":"http.response.body.size","requirement_level":"recommended","root_namespace":"http","stability":"experimental","type":"int"},{"brief":"HTTP response headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.response.header.content-type=[\"application/json\"]","http.response.header.my-custom-header=[\"abc\", \"def\"]"],"name":"http.response.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all response headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nUsers MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"[HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6).","examples":[200],"name":"http.response.status_code","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"The matched route, that is, the path template in the format used by the respective server framework.\n","examples":["/users/:userID?","{controller}/{action}/{id?}"],"name":"http.route","note":"MUST NOT be populated when this is not supported by the HTTP server framework as the route attribute should have low-cardinality and the URI path can NOT substitute it.\nSHOULD include the [application root](/docs/http/http-spans.md#http-server-definitions) if there is one.","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"},{"brief":"The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network.","examples":"DE","name":"network.carrier.icc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The mobile carrier country code.","examples":"310","name":"network.carrier.mcc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The mobile carrier network code.","examples":"001","name":"network.carrier.mnc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The name of the mobile carrier.","examples":"sprint","name":"network.carrier.name","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.","examples":"LTE","name":"network.connection.subtype","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":true,"members":[{"brief":"GPRS","deprecated":null,"id":"gprs","note":null,"stability":null,"value":"gprs"},{"brief":"EDGE","deprecated":null,"id":"edge","note":null,"stability":null,"value":"edge"},{"brief":"UMTS","deprecated":null,"id":"umts","note":null,"stability":null,"value":"umts"},{"brief":"CDMA","deprecated":null,"id":"cdma","note":null,"stability":null,"value":"cdma"},{"brief":"EVDO Rel. 0","deprecated":null,"id":"evdo_0","note":null,"stability":null,"value":"evdo_0"},{"brief":"EVDO Rev. A","deprecated":null,"id":"evdo_a","note":null,"stability":null,"value":"evdo_a"},{"brief":"CDMA2000 1XRTT","deprecated":null,"id":"cdma2000_1xrtt","note":null,"stability":null,"value":"cdma2000_1xrtt"},{"brief":"HSDPA","deprecated":null,"id":"hsdpa","note":null,"stability":null,"value":"hsdpa"},{"brief":"HSUPA","deprecated":null,"id":"hsupa","note":null,"stability":null,"value":"hsupa"},{"brief":"HSPA","deprecated":null,"id":"hspa","note":null,"stability":null,"value":"hspa"},{"brief":"IDEN","deprecated":null,"id":"iden","note":null,"stability":null,"value":"iden"},{"brief":"EVDO Rev. B","deprecated":null,"id":"evdo_b","note":null,"stability":null,"value":"evdo_b"},{"brief":"LTE","deprecated":null,"id":"lte","note":null,"stability":null,"value":"lte"},{"brief":"EHRPD","deprecated":null,"id":"ehrpd","note":null,"stability":null,"value":"ehrpd"},{"brief":"HSPAP","deprecated":null,"id":"hspap","note":null,"stability":null,"value":"hspap"},{"brief":"GSM","deprecated":null,"id":"gsm","note":null,"stability":null,"value":"gsm"},{"brief":"TD-SCDMA","deprecated":null,"id":"td_scdma","note":null,"stability":null,"value":"td_scdma"},{"brief":"IWLAN","deprecated":null,"id":"iwlan","note":null,"stability":null,"value":"iwlan"},{"brief":"5G NR (New Radio)","deprecated":null,"id":"nr","note":null,"stability":null,"value":"nr"},{"brief":"5G NRNSA (New Radio Non-Standalone)","deprecated":null,"id":"nrnsa","note":null,"stability":null,"value":"nrnsa"},{"brief":"LTE CA","deprecated":null,"id":"lte_ca","note":null,"stability":null,"value":"lte_ca"}]}},{"brief":"The internet connection type.","examples":"wifi","name":"network.connection.type","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"wifi","note":null,"stability":null,"value":"wifi"},{"brief":null,"deprecated":null,"id":"wired","note":null,"stability":null,"value":"wired"},{"brief":null,"deprecated":null,"id":"cell","note":null,"stability":null,"value":"cell"},{"brief":null,"deprecated":null,"id":"unavailable","note":null,"stability":null,"value":"unavailable"},{"brief":null,"deprecated":null,"id":"unknown","note":null,"stability":null,"value":"unknown"}]}},{"brief":"The network IO operation direction.","examples":["transmit"],"name":"network.io.direction","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":false,"members":[{"brief":null,"deprecated":null,"id":"transmit","note":null,"stability":null,"value":"transmit"},{"brief":null,"deprecated":null,"id":"receive","note":null,"stability":null,"value":"receive"}]}},{"brief":"Local address of the network connection - IP address or Unix domain socket name.","examples":["10.1.2.80","/tmp/my.sock"],"name":"network.local.address","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Local port number of the network connection.","examples":[65123],"name":"network.local.port","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"int"},{"brief":"Peer address of the network connection - IP address or Unix domain socket name.","examples":["10.1.2.80","/tmp/my.sock"],"name":"network.peer.address","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Peer port number of the network connection.","examples":[65123],"name":"network.peer.port","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"int"},{"brief":"[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.","examples":["amqp","http","mqtt"],"name":"network.protocol.name","note":"The value SHOULD be normalized to lowercase.","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Version of the protocol specified in `network.protocol.name`.","examples":"3.1.1","name":"network.protocol.version","note":"`network.protocol.version` refers to the version of the protocol used and might be different from the protocol client\u0027s version. If the HTTP client has a version of `0.27.2`, but sends HTTP version `1.1`, this attribute should be set to `1.1`.\n","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"[OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication).\n","examples":["tcp","udp"],"name":"network.transport","note":"The value SHOULD be normalized to lowercase.\n\nConsider always setting the transport when setting a port number, since\na port number is ambiguous without knowing the transport. For example\ndifferent processes could be listening on TCP port 12345 and UDP port 12345.\n","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"TCP","deprecated":null,"id":"tcp","note":null,"stability":null,"value":"tcp"},{"brief":"UDP","deprecated":null,"id":"udp","note":null,"stability":null,"value":"udp"},{"brief":"Named or anonymous pipe.","deprecated":null,"id":"pipe","note":null,"stability":null,"value":"pipe"},{"brief":"Unix domain socket","deprecated":null,"id":"unix","note":null,"stability":null,"value":"unix"}]}},{"brief":"[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.","examples":["ipv4","ipv6"],"name":"network.type","note":"The value SHOULD be normalized to lowercase.","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"IPv4","deprecated":null,"id":"ipv4","note":null,"stability":null,"value":"ipv4"},{"brief":"IPv6","deprecated":null,"id":"ipv6","note":null,"stability":null,"value":"ipv6"}]}},{"brief":"The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component","examples":["SemConv"],"name":"url.fragment","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986)","examples":["https://www.foo.bar/search?q=OpenTelemetry#SemConv","//localhost"],"name":"url.full","note":"For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless.\n`url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case username and password SHOULD be redacted and attribute\u0027s value SHOULD be `https://REDACTED:REDACTED@www.example.com/`.\n`url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed) and SHOULD NOT be validated or modified except for sanitizing purposes.\n","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component","examples":["/search"],"name":"url.path","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component","examples":["q=OpenTelemetry"],"name":"url.query","note":"Sensitive content provided in query string SHOULD be scrubbed when instrumentations can identify it.","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol.","examples":["https","ftp","telnet"],"name":"url.scheme","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"Value of the [HTTP User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) header sent by the client.\n","examples":["CERN-LineMode/2.15 libwww/2.17b3","Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1"],"name":"user_agent.original","requirement_level":"recommended","root_namespace":"user_agent","stability":"stable","type":"string"}] \ No newline at end of file +[{"brief":"The consistency level of the query. Based on consistency values from [CQL](https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/dml/dmlConfigConsistency.html).\n","name":"db.cassandra.consistency_level","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"all","note":null,"stability":null,"value":"all"},{"brief":null,"deprecated":null,"id":"each_quorum","note":null,"stability":null,"value":"each_quorum"},{"brief":null,"deprecated":null,"id":"quorum","note":null,"stability":null,"value":"quorum"},{"brief":null,"deprecated":null,"id":"local_quorum","note":null,"stability":null,"value":"local_quorum"},{"brief":null,"deprecated":null,"id":"one","note":null,"stability":null,"value":"one"},{"brief":null,"deprecated":null,"id":"two","note":null,"stability":null,"value":"two"},{"brief":null,"deprecated":null,"id":"three","note":null,"stability":null,"value":"three"},{"brief":null,"deprecated":null,"id":"local_one","note":null,"stability":null,"value":"local_one"},{"brief":null,"deprecated":null,"id":"any","note":null,"stability":null,"value":"any"},{"brief":null,"deprecated":null,"id":"serial","note":null,"stability":null,"value":"serial"},{"brief":null,"deprecated":null,"id":"local_serial","note":null,"stability":null,"value":"local_serial"}]}},{"brief":"The data center of the coordinating node for a query.\n","examples":"us-west-2","name":"db.cassandra.coordinator.dc","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The ID of the coordinating node for a query.\n","examples":"be13faa2-8574-4d71-926d-27f16cf8a7af","name":"db.cassandra.coordinator.id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"Whether or not the query is idempotent.\n","name":"db.cassandra.idempotence","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"boolean"},{"brief":"The fetch size used for paging, i.e. how many rows will be returned at once.\n","examples":[5000],"name":"db.cassandra.page_size","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The number of times a query was speculatively executed. Not set or `0` if the query was not executed speculatively.\n","examples":[0,2],"name":"db.cassandra.speculative_execution_count","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The name of the primary Cassandra table that the operation is acting upon, including the keyspace name (if applicable).","examples":"mytable","name":"db.cassandra.table","note":"This mirrors the db.sql.table attribute but references cassandra rather than sql. It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The connection string used to connect to the database. It is recommended to remove embedded credentials.\n","examples":"Server=(localdb)\\v11.0;Integrated Security=true;","name":"db.connection_string","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"Unique Cosmos client instance id.","examples":"3ba4827d-4422-483f-b59f-85b74211c11d","name":"db.cosmosdb.client_id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"Cosmos client connection mode.","name":"db.cosmosdb.connection_mode","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":false,"members":[{"brief":"Gateway (HTTP) connections mode","deprecated":null,"id":"gateway","note":null,"stability":null,"value":"gateway"},{"brief":"Direct connection.","deprecated":null,"id":"direct","note":null,"stability":null,"value":"direct"}]}},{"brief":"Cosmos DB container name.","examples":"anystring","name":"db.cosmosdb.container","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"CosmosDB Operation Type.","name":"db.cosmosdb.operation_type","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"invalid","note":null,"stability":null,"value":"Invalid"},{"brief":null,"deprecated":null,"id":"create","note":null,"stability":null,"value":"Create"},{"brief":null,"deprecated":null,"id":"patch","note":null,"stability":null,"value":"Patch"},{"brief":null,"deprecated":null,"id":"read","note":null,"stability":null,"value":"Read"},{"brief":null,"deprecated":null,"id":"read_feed","note":null,"stability":null,"value":"ReadFeed"},{"brief":null,"deprecated":null,"id":"delete","note":null,"stability":null,"value":"Delete"},{"brief":null,"deprecated":null,"id":"replace","note":null,"stability":null,"value":"Replace"},{"brief":null,"deprecated":null,"id":"execute","note":null,"stability":null,"value":"Execute"},{"brief":null,"deprecated":null,"id":"query","note":null,"stability":null,"value":"Query"},{"brief":null,"deprecated":null,"id":"head","note":null,"stability":null,"value":"Head"},{"brief":null,"deprecated":null,"id":"head_feed","note":null,"stability":null,"value":"HeadFeed"},{"brief":null,"deprecated":null,"id":"upsert","note":null,"stability":null,"value":"Upsert"},{"brief":null,"deprecated":null,"id":"batch","note":null,"stability":null,"value":"Batch"},{"brief":null,"deprecated":null,"id":"query_plan","note":null,"stability":null,"value":"QueryPlan"},{"brief":null,"deprecated":null,"id":"execute_javascript","note":null,"stability":null,"value":"ExecuteJavaScript"}]}},{"brief":"RU consumed for that operation","examples":[46.18,1.0],"name":"db.cosmosdb.request_charge","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"double"},{"brief":"Request payload size in bytes","name":"db.cosmosdb.request_content_length","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB status code.","examples":[200,201],"name":"db.cosmosdb.status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB sub status code.","examples":[1000,1002],"name":"db.cosmosdb.sub_status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Represents the identifier of an Elasticsearch cluster.\n","examples":["e9106fc68e3044f0b1475b04bf4ffd5f"],"name":"db.elasticsearch.cluster.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"Represents the human-readable identifier of the node/instance to which a request was routed.\n","examples":["instance-0000000001"],"name":"db.elasticsearch.node.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"A dynamic value in the url path.\n","examples":["db.elasticsearch.path_parts.index=test-index","db.elasticsearch.path_parts.doc_id=123"],"name":"db.elasticsearch.path_parts","note":"Many Elasticsearch url paths allow dynamic values. These SHOULD be recorded in span attributes in the format `db.elasticsearch.path_parts.\u003ckey\u003e`, where `\u003ckey\u003e` is the url path part name. The implementation SHOULD reference the [elasticsearch schema](https://raw.githubusercontent.com/elastic/elasticsearch-specification/main/output/schema/schema.json) in order to map the path part values to their names.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"template[string]"},{"brief":"An identifier (address, unique name, or any other identifier) of the database instance that is executing queries or mutations on the current connection. This is useful in cases where the database is running in a clustered environment and the instrumentation is able to record the node executing the query. The client may obtain this value in databases like MySQL using queries like `select @@hostname`.\n","examples":"mysql-e26b99z.example.com","name":"db.instance.id","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The fully-qualified class name of the [Java Database Connectivity (JDBC)](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/) driver used to connect.\n","examples":["org.postgresql.Driver","com.microsoft.sqlserver.jdbc.SQLServerDriver"],"name":"db.jdbc.driver_classname","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-jdbc","type":"string"},{"brief":"The MongoDB collection being accessed within the database stated in `db.name`.\n","examples":["customers","products"],"name":"db.mongodb.collection","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mongodb","type":"string"},{"brief":"The Microsoft SQL Server [instance name](https://docs.microsoft.com/sql/connect/jdbc/building-the-connection-url?view=sql-server-ver15) connecting to. This name is used to determine the port of a named instance.\n","examples":"MSSQLSERVER","name":"db.mssql.instance_name","note":"If setting a `db.mssql.instance_name`, `server.port` is no longer required (but still recommended if non-standard).\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mssql","type":"string"},{"brief":"This attribute is used to report the name of the database being accessed. For commands that switch the database, this should be set to the target database (even if the command fails).\n","examples":["customers","main"],"name":"db.name","note":"In some SQL databases, the database name to be used is called \"schema name\". In case there are multiple layers that could be considered for database name (e.g. Oracle instance name and schema name), the database name to be used is the more specific layer (e.g. Oracle schema name).\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The name of the operation being executed, e.g. the [MongoDB command name](https://docs.mongodb.com/manual/reference/command/#database-operations) such as `findAndModify`, or the SQL keyword.\n","examples":["findAndModify","HMSET","SELECT"],"name":"db.operation","note":"When setting this to an SQL keyword, it is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if the operation name is provided by the library being instrumented. If the SQL statement has an ambiguous operation, or performs more than one operation, this value may be omitted.\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The index of the database being accessed as used in the [`SELECT` command](https://redis.io/commands/select), provided as an integer. To be used instead of the generic `db.name` attribute.\n","examples":[0,1,15],"name":"db.redis.database_index","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-redis","type":"int"},{"brief":"The name of the primary table that the operation is acting upon, including the database name (if applicable).","examples":["public.users","customers"],"name":"db.sql.table","note":"It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-sql","type":"string"},{"brief":"The database statement being executed.\n","examples":["SELECT * FROM wuser_table","SET mykey \"WuValue\""],"name":"db.statement","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"An identifier for the database management system (DBMS) product being used. See below for a list of well-known identifiers.","name":"db.system","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":{"allow_custom_values":true,"members":[{"brief":"Some other SQL database. Fallback only. See notes.","deprecated":null,"id":"other_sql","note":null,"stability":null,"value":"other_sql"},{"brief":"Microsoft SQL Server","deprecated":null,"id":"mssql","note":null,"stability":null,"value":"mssql"},{"brief":"Microsoft SQL Server Compact","deprecated":null,"id":"mssqlcompact","note":null,"stability":null,"value":"mssqlcompact"},{"brief":"MySQL","deprecated":null,"id":"mysql","note":null,"stability":null,"value":"mysql"},{"brief":"Oracle Database","deprecated":null,"id":"oracle","note":null,"stability":null,"value":"oracle"},{"brief":"IBM Db2","deprecated":null,"id":"db2","note":null,"stability":null,"value":"db2"},{"brief":"PostgreSQL","deprecated":null,"id":"postgresql","note":null,"stability":null,"value":"postgresql"},{"brief":"Amazon Redshift","deprecated":null,"id":"redshift","note":null,"stability":null,"value":"redshift"},{"brief":"Apache Hive","deprecated":null,"id":"hive","note":null,"stability":null,"value":"hive"},{"brief":"Cloudscape","deprecated":null,"id":"cloudscape","note":null,"stability":null,"value":"cloudscape"},{"brief":"HyperSQL DataBase","deprecated":null,"id":"hsqldb","note":null,"stability":null,"value":"hsqldb"},{"brief":"Progress Database","deprecated":null,"id":"progress","note":null,"stability":null,"value":"progress"},{"brief":"SAP MaxDB","deprecated":null,"id":"maxdb","note":null,"stability":null,"value":"maxdb"},{"brief":"SAP HANA","deprecated":null,"id":"hanadb","note":null,"stability":null,"value":"hanadb"},{"brief":"Ingres","deprecated":null,"id":"ingres","note":null,"stability":null,"value":"ingres"},{"brief":"FirstSQL","deprecated":null,"id":"firstsql","note":null,"stability":null,"value":"firstsql"},{"brief":"EnterpriseDB","deprecated":null,"id":"edb","note":null,"stability":null,"value":"edb"},{"brief":"InterSystems Caché","deprecated":null,"id":"cache","note":null,"stability":null,"value":"cache"},{"brief":"Adabas (Adaptable Database System)","deprecated":null,"id":"adabas","note":null,"stability":null,"value":"adabas"},{"brief":"Firebird","deprecated":null,"id":"firebird","note":null,"stability":null,"value":"firebird"},{"brief":"Apache Derby","deprecated":null,"id":"derby","note":null,"stability":null,"value":"derby"},{"brief":"FileMaker","deprecated":null,"id":"filemaker","note":null,"stability":null,"value":"filemaker"},{"brief":"Informix","deprecated":null,"id":"informix","note":null,"stability":null,"value":"informix"},{"brief":"InstantDB","deprecated":null,"id":"instantdb","note":null,"stability":null,"value":"instantdb"},{"brief":"InterBase","deprecated":null,"id":"interbase","note":null,"stability":null,"value":"interbase"},{"brief":"MariaDB","deprecated":null,"id":"mariadb","note":null,"stability":null,"value":"mariadb"},{"brief":"Netezza","deprecated":null,"id":"netezza","note":null,"stability":null,"value":"netezza"},{"brief":"Pervasive PSQL","deprecated":null,"id":"pervasive","note":null,"stability":null,"value":"pervasive"},{"brief":"PointBase","deprecated":null,"id":"pointbase","note":null,"stability":null,"value":"pointbase"},{"brief":"SQLite","deprecated":null,"id":"sqlite","note":null,"stability":null,"value":"sqlite"},{"brief":"Sybase","deprecated":null,"id":"sybase","note":null,"stability":null,"value":"sybase"},{"brief":"Teradata","deprecated":null,"id":"teradata","note":null,"stability":null,"value":"teradata"},{"brief":"Vertica","deprecated":null,"id":"vertica","note":null,"stability":null,"value":"vertica"},{"brief":"H2","deprecated":null,"id":"h2","note":null,"stability":null,"value":"h2"},{"brief":"ColdFusion IMQ","deprecated":null,"id":"coldfusion","note":null,"stability":null,"value":"coldfusion"},{"brief":"Apache Cassandra","deprecated":null,"id":"cassandra","note":null,"stability":null,"value":"cassandra"},{"brief":"Apache HBase","deprecated":null,"id":"hbase","note":null,"stability":null,"value":"hbase"},{"brief":"MongoDB","deprecated":null,"id":"mongodb","note":null,"stability":null,"value":"mongodb"},{"brief":"Redis","deprecated":null,"id":"redis","note":null,"stability":null,"value":"redis"},{"brief":"Couchbase","deprecated":null,"id":"couchbase","note":null,"stability":null,"value":"couchbase"},{"brief":"CouchDB","deprecated":null,"id":"couchdb","note":null,"stability":null,"value":"couchdb"},{"brief":"Microsoft Azure Cosmos DB","deprecated":null,"id":"cosmosdb","note":null,"stability":null,"value":"cosmosdb"},{"brief":"Amazon DynamoDB","deprecated":null,"id":"dynamodb","note":null,"stability":null,"value":"dynamodb"},{"brief":"Neo4j","deprecated":null,"id":"neo4j","note":null,"stability":null,"value":"neo4j"},{"brief":"Apache Geode","deprecated":null,"id":"geode","note":null,"stability":null,"value":"geode"},{"brief":"Elasticsearch","deprecated":null,"id":"elasticsearch","note":null,"stability":null,"value":"elasticsearch"},{"brief":"Memcached","deprecated":null,"id":"memcached","note":null,"stability":null,"value":"memcached"},{"brief":"CockroachDB","deprecated":null,"id":"cockroachdb","note":null,"stability":null,"value":"cockroachdb"},{"brief":"OpenSearch","deprecated":null,"id":"opensearch","note":null,"stability":null,"value":"opensearch"},{"brief":"ClickHouse","deprecated":null,"id":"clickhouse","note":null,"stability":null,"value":"clickhouse"},{"brief":"Cloud Spanner","deprecated":null,"id":"spanner","note":null,"stability":null,"value":"spanner"},{"brief":"Trino","deprecated":null,"id":"trino","note":null,"stability":null,"value":"trino"}]}},{"brief":"Username for accessing the database.\n","examples":["readonly_user","reporting_user"],"name":"db.user","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"boolean"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"string"},{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"string"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"string"},{"brief":"The size of the request payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.\n","examples":3495,"name":"http.request.body.size","requirement_level":"recommended","root_namespace":"http","stability":"experimental","type":"int"},{"brief":"HTTP request headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.request.header.content-type=[\"application/json\"]","http.request.header.x-forwarded-for=[\"1.2.3.4\", \"1.2.3.5\"]"],"name":"http.request.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all request headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nThe `User-Agent` header is already captured in the `user_agent.original` attribute. Users MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"HTTP request method.","examples":["GET","POST","HEAD"],"name":"http.request.method","note":"HTTP request method value SHOULD be \"known\" to the instrumentation.\nBy default, this convention defines \"known\" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods)\nand the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html).\n\nIf the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`.\n\nIf the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override\nthe list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named\nOTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods\n(this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults).\n\nHTTP method names are case-sensitive and `http.request.method` attribute value MUST match a known HTTP method name exactly.\nInstrumentations for specific web frameworks that consider HTTP methods to be case insensitive, SHOULD populate a canonical equivalent.\nTracing instrumentations that do so, MUST also set `http.request.method_original` to the original value.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"CONNECT method.","deprecated":null,"id":"connect","note":null,"stability":null,"value":"CONNECT"},{"brief":"DELETE method.","deprecated":null,"id":"delete","note":null,"stability":null,"value":"DELETE"},{"brief":"GET method.","deprecated":null,"id":"get","note":null,"stability":null,"value":"GET"},{"brief":"HEAD method.","deprecated":null,"id":"head","note":null,"stability":null,"value":"HEAD"},{"brief":"OPTIONS method.","deprecated":null,"id":"options","note":null,"stability":null,"value":"OPTIONS"},{"brief":"PATCH method.","deprecated":null,"id":"patch","note":null,"stability":null,"value":"PATCH"},{"brief":"POST method.","deprecated":null,"id":"post","note":null,"stability":null,"value":"POST"},{"brief":"PUT method.","deprecated":null,"id":"put","note":null,"stability":null,"value":"PUT"},{"brief":"TRACE method.","deprecated":null,"id":"trace","note":null,"stability":null,"value":"TRACE"},{"brief":"Any HTTP method that the instrumentation has no prior knowledge of.","deprecated":null,"id":"other","note":null,"stability":null,"value":"_OTHER"}]}},{"brief":"Original HTTP method sent by the client in the request line.","examples":["GeT","ACL","foo"],"name":"http.request.method_original","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"},{"brief":"The ordinal number of request resending attempt (for any reason, including redirects).\n","examples":3,"name":"http.request.resend_count","note":"The resend count SHOULD be updated each time an HTTP request gets resent by the client, regardless of what was the cause of the resending (e.g. redirection, authorization failure, 503 Server Unavailable, network issues, or any other).\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"The size of the response payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.\n","examples":3495,"name":"http.response.body.size","requirement_level":"recommended","root_namespace":"http","stability":"experimental","type":"int"},{"brief":"HTTP response headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.response.header.content-type=[\"application/json\"]","http.response.header.my-custom-header=[\"abc\", \"def\"]"],"name":"http.response.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all response headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nUsers MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"[HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6).","examples":[200],"name":"http.response.status_code","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"The matched route, that is, the path template in the format used by the respective server framework.\n","examples":["/users/:userID?","{controller}/{action}/{id?}"],"name":"http.route","note":"MUST NOT be populated when this is not supported by the HTTP server framework as the route attribute should have low-cardinality and the URI path can NOT substitute it.\nSHOULD include the [application root](/docs/http/http-spans.md#http-server-definitions) if there is one.","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"},{"brief":"The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network.","examples":"DE","name":"network.carrier.icc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The mobile carrier country code.","examples":"310","name":"network.carrier.mcc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The mobile carrier network code.","examples":"001","name":"network.carrier.mnc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The name of the mobile carrier.","examples":"sprint","name":"network.carrier.name","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.","examples":"LTE","name":"network.connection.subtype","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":true,"members":[{"brief":"GPRS","deprecated":null,"id":"gprs","note":null,"stability":null,"value":"gprs"},{"brief":"EDGE","deprecated":null,"id":"edge","note":null,"stability":null,"value":"edge"},{"brief":"UMTS","deprecated":null,"id":"umts","note":null,"stability":null,"value":"umts"},{"brief":"CDMA","deprecated":null,"id":"cdma","note":null,"stability":null,"value":"cdma"},{"brief":"EVDO Rel. 0","deprecated":null,"id":"evdo_0","note":null,"stability":null,"value":"evdo_0"},{"brief":"EVDO Rev. A","deprecated":null,"id":"evdo_a","note":null,"stability":null,"value":"evdo_a"},{"brief":"CDMA2000 1XRTT","deprecated":null,"id":"cdma2000_1xrtt","note":null,"stability":null,"value":"cdma2000_1xrtt"},{"brief":"HSDPA","deprecated":null,"id":"hsdpa","note":null,"stability":null,"value":"hsdpa"},{"brief":"HSUPA","deprecated":null,"id":"hsupa","note":null,"stability":null,"value":"hsupa"},{"brief":"HSPA","deprecated":null,"id":"hspa","note":null,"stability":null,"value":"hspa"},{"brief":"IDEN","deprecated":null,"id":"iden","note":null,"stability":null,"value":"iden"},{"brief":"EVDO Rev. B","deprecated":null,"id":"evdo_b","note":null,"stability":null,"value":"evdo_b"},{"brief":"LTE","deprecated":null,"id":"lte","note":null,"stability":null,"value":"lte"},{"brief":"EHRPD","deprecated":null,"id":"ehrpd","note":null,"stability":null,"value":"ehrpd"},{"brief":"HSPAP","deprecated":null,"id":"hspap","note":null,"stability":null,"value":"hspap"},{"brief":"GSM","deprecated":null,"id":"gsm","note":null,"stability":null,"value":"gsm"},{"brief":"TD-SCDMA","deprecated":null,"id":"td_scdma","note":null,"stability":null,"value":"td_scdma"},{"brief":"IWLAN","deprecated":null,"id":"iwlan","note":null,"stability":null,"value":"iwlan"},{"brief":"5G NR (New Radio)","deprecated":null,"id":"nr","note":null,"stability":null,"value":"nr"},{"brief":"5G NRNSA (New Radio Non-Standalone)","deprecated":null,"id":"nrnsa","note":null,"stability":null,"value":"nrnsa"},{"brief":"LTE CA","deprecated":null,"id":"lte_ca","note":null,"stability":null,"value":"lte_ca"}]}},{"brief":"The internet connection type.","examples":"wifi","name":"network.connection.type","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"wifi","note":null,"stability":null,"value":"wifi"},{"brief":null,"deprecated":null,"id":"wired","note":null,"stability":null,"value":"wired"},{"brief":null,"deprecated":null,"id":"cell","note":null,"stability":null,"value":"cell"},{"brief":null,"deprecated":null,"id":"unavailable","note":null,"stability":null,"value":"unavailable"},{"brief":null,"deprecated":null,"id":"unknown","note":null,"stability":null,"value":"unknown"}]}},{"brief":"The network IO operation direction.","examples":["transmit"],"name":"network.io.direction","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":false,"members":[{"brief":null,"deprecated":null,"id":"transmit","note":null,"stability":null,"value":"transmit"},{"brief":null,"deprecated":null,"id":"receive","note":null,"stability":null,"value":"receive"}]}},{"brief":"Local address of the network connection - IP address or Unix domain socket name.","examples":["10.1.2.80","/tmp/my.sock"],"name":"network.local.address","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Local port number of the network connection.","examples":[65123],"name":"network.local.port","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"int"},{"brief":"Peer address of the network connection - IP address or Unix domain socket name.","examples":["10.1.2.80","/tmp/my.sock"],"name":"network.peer.address","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Peer port number of the network connection.","examples":[65123],"name":"network.peer.port","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"int"},{"brief":"[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.","examples":["amqp","http","mqtt"],"name":"network.protocol.name","note":"The value SHOULD be normalized to lowercase.","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Version of the protocol specified in `network.protocol.name`.","examples":"3.1.1","name":"network.protocol.version","note":"`network.protocol.version` refers to the version of the protocol used and might be different from the protocol client\u0027s version. If the HTTP client has a version of `0.27.2`, but sends HTTP version `1.1`, this attribute should be set to `1.1`.\n","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"[OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication).\n","examples":["tcp","udp"],"name":"network.transport","note":"The value SHOULD be normalized to lowercase.\n\nConsider always setting the transport when setting a port number, since\na port number is ambiguous without knowing the transport. For example\ndifferent processes could be listening on TCP port 12345 and UDP port 12345.\n","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"TCP","deprecated":null,"id":"tcp","note":null,"stability":null,"value":"tcp"},{"brief":"UDP","deprecated":null,"id":"udp","note":null,"stability":null,"value":"udp"},{"brief":"Named or anonymous pipe.","deprecated":null,"id":"pipe","note":null,"stability":null,"value":"pipe"},{"brief":"Unix domain socket","deprecated":null,"id":"unix","note":null,"stability":null,"value":"unix"}]}},{"brief":"[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.","examples":["ipv4","ipv6"],"name":"network.type","note":"The value SHOULD be normalized to lowercase.","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"IPv4","deprecated":null,"id":"ipv4","note":null,"stability":null,"value":"ipv4"},{"brief":"IPv6","deprecated":null,"id":"ipv6","note":null,"stability":null,"value":"ipv6"}]}},{"brief":"The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component","examples":["SemConv"],"name":"url.fragment","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986)","examples":["https://www.foo.bar/search?q=OpenTelemetry#SemConv","//localhost"],"name":"url.full","note":"For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless.\n`url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case username and password SHOULD be redacted and attribute\u0027s value SHOULD be `https://REDACTED:REDACTED@www.example.com/`.\n`url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed) and SHOULD NOT be validated or modified except for sanitizing purposes.\n","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component","examples":["/search"],"name":"url.path","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component","examples":["q=OpenTelemetry"],"name":"url.query","note":"Sensitive content provided in query string SHOULD be scrubbed when instrumentations can identify it.","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol.","examples":["https","ftp","telnet"],"name":"url.scheme","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"Value of the [HTTP User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) header sent by the client.\n","examples":["CERN-LineMode/2.15 libwww/2.17b3","Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1"],"name":"user_agent.original","requirement_level":"recommended","root_namespace":"user_agent","stability":"stable","type":"string"}] \ No newline at end of file diff --git a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json new file mode 100644 index 00000000..16f63a79 --- /dev/null +++ b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json @@ -0,0 +1 @@ +[{"attributes":[],"body":{"fields":[{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","name":"ios.state","note":"The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `ios`"},"stability":"experimental","type":{"allow_custom_values":false,"members":[{"brief":"The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n","deprecated":null,"id":"active","note":null,"stability":null,"value":"active"},{"brief":"The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n","deprecated":null,"id":"inactive","note":null,"stability":null,"value":"inactive"},{"brief":"The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"brief":"The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"},{"brief":"The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n","deprecated":null,"id":"terminate","note":null,"stability":null,"value":"terminate"}]}},{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","name":"android.state","note":"The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `android`"},"stability":"experimental","type":{"allow_custom_values":false,"members":[{"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.\n","deprecated":null,"id":"created","note":null,"stability":null,"value":"created"},{"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.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"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.","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"}]}}]},"brief":"This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n","event_namespace":"device.app","events":[],"id":"device.app.lifecycle","instrument":null,"lineage":{"source_file":"data/mobile-events.yaml"},"metric_name":null,"name":"device.app.lifecycle","note":"This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n","span_kind":null,"stability":"experimental","type":"event","unit":null},{"attributes":[{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","stability":"stable","type":"string"},{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","stability":"stable","type":"boolean"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":{"conditionally_required":"Required if `exception.message` is not set, recommended otherwise."},"stability":"stable","type":"string"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":{"conditionally_required":"Required if `exception.type` is not set, recommended otherwise."},"stability":"stable","type":"string"}],"brief":"This document defines the attributes used to report a single exception associated with a span.\n","event_namespace":"other","events":[],"id":"trace-exception","instrument":null,"lineage":{"attributes":{"exception.escaped":{"inherited_fields":["brief","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.message":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"},"exception.stacktrace":{"inherited_fields":["brief","examples","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.type":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"}},"source_file":"data/trace-exception.yaml"},"metric_name":null,"name":null,"prefix":"exception","span_kind":null,"type":"event","unit":null}] \ No newline at end of file diff --git a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_grouped_attributes.json b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_grouped_attributes.json index 7239c2dd..5b741812 100644 --- a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_grouped_attributes.json +++ b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_grouped_attributes.json @@ -1 +1 @@ -[{"attributes":[{"brief":"The consistency level of the query. Based on consistency values from [CQL](https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/dml/dmlConfigConsistency.html).\n","name":"db.cassandra.consistency_level","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"all","note":null,"stability":null,"value":"all"},{"brief":null,"deprecated":null,"id":"each_quorum","note":null,"stability":null,"value":"each_quorum"},{"brief":null,"deprecated":null,"id":"quorum","note":null,"stability":null,"value":"quorum"},{"brief":null,"deprecated":null,"id":"local_quorum","note":null,"stability":null,"value":"local_quorum"},{"brief":null,"deprecated":null,"id":"one","note":null,"stability":null,"value":"one"},{"brief":null,"deprecated":null,"id":"two","note":null,"stability":null,"value":"two"},{"brief":null,"deprecated":null,"id":"three","note":null,"stability":null,"value":"three"},{"brief":null,"deprecated":null,"id":"local_one","note":null,"stability":null,"value":"local_one"},{"brief":null,"deprecated":null,"id":"any","note":null,"stability":null,"value":"any"},{"brief":null,"deprecated":null,"id":"serial","note":null,"stability":null,"value":"serial"},{"brief":null,"deprecated":null,"id":"local_serial","note":null,"stability":null,"value":"local_serial"}]}},{"brief":"The data center of the coordinating node for a query.\n","examples":"us-west-2","name":"db.cassandra.coordinator.dc","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The ID of the coordinating node for a query.\n","examples":"be13faa2-8574-4d71-926d-27f16cf8a7af","name":"db.cassandra.coordinator.id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"Whether or not the query is idempotent.\n","name":"db.cassandra.idempotence","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"boolean"},{"brief":"The fetch size used for paging, i.e. how many rows will be returned at once.\n","examples":[5000],"name":"db.cassandra.page_size","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The number of times a query was speculatively executed. Not set or `0` if the query was not executed speculatively.\n","examples":[0,2],"name":"db.cassandra.speculative_execution_count","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The name of the primary Cassandra table that the operation is acting upon, including the keyspace name (if applicable).","examples":"mytable","name":"db.cassandra.table","note":"This mirrors the db.sql.table attribute but references cassandra rather than sql. It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The connection string used to connect to the database. It is recommended to remove embedded credentials.\n","examples":"Server=(localdb)\\v11.0;Integrated Security=true;","name":"db.connection_string","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"Unique Cosmos client instance id.","examples":"3ba4827d-4422-483f-b59f-85b74211c11d","name":"db.cosmosdb.client_id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"Cosmos client connection mode.","name":"db.cosmosdb.connection_mode","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":false,"members":[{"brief":"Gateway (HTTP) connections mode","deprecated":null,"id":"gateway","note":null,"stability":null,"value":"gateway"},{"brief":"Direct connection.","deprecated":null,"id":"direct","note":null,"stability":null,"value":"direct"}]}},{"brief":"Cosmos DB container name.","examples":"anystring","name":"db.cosmosdb.container","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"CosmosDB Operation Type.","name":"db.cosmosdb.operation_type","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"invalid","note":null,"stability":null,"value":"Invalid"},{"brief":null,"deprecated":null,"id":"create","note":null,"stability":null,"value":"Create"},{"brief":null,"deprecated":null,"id":"patch","note":null,"stability":null,"value":"Patch"},{"brief":null,"deprecated":null,"id":"read","note":null,"stability":null,"value":"Read"},{"brief":null,"deprecated":null,"id":"read_feed","note":null,"stability":null,"value":"ReadFeed"},{"brief":null,"deprecated":null,"id":"delete","note":null,"stability":null,"value":"Delete"},{"brief":null,"deprecated":null,"id":"replace","note":null,"stability":null,"value":"Replace"},{"brief":null,"deprecated":null,"id":"execute","note":null,"stability":null,"value":"Execute"},{"brief":null,"deprecated":null,"id":"query","note":null,"stability":null,"value":"Query"},{"brief":null,"deprecated":null,"id":"head","note":null,"stability":null,"value":"Head"},{"brief":null,"deprecated":null,"id":"head_feed","note":null,"stability":null,"value":"HeadFeed"},{"brief":null,"deprecated":null,"id":"upsert","note":null,"stability":null,"value":"Upsert"},{"brief":null,"deprecated":null,"id":"batch","note":null,"stability":null,"value":"Batch"},{"brief":null,"deprecated":null,"id":"query_plan","note":null,"stability":null,"value":"QueryPlan"},{"brief":null,"deprecated":null,"id":"execute_javascript","note":null,"stability":null,"value":"ExecuteJavaScript"}]}},{"brief":"RU consumed for that operation","examples":[46.18,1.0],"name":"db.cosmosdb.request_charge","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"double"},{"brief":"Request payload size in bytes","name":"db.cosmosdb.request_content_length","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB status code.","examples":[200,201],"name":"db.cosmosdb.status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB sub status code.","examples":[1000,1002],"name":"db.cosmosdb.sub_status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Represents the identifier of an Elasticsearch cluster.\n","examples":["e9106fc68e3044f0b1475b04bf4ffd5f"],"name":"db.elasticsearch.cluster.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"Represents the human-readable identifier of the node/instance to which a request was routed.\n","examples":["instance-0000000001"],"name":"db.elasticsearch.node.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"A dynamic value in the url path.\n","examples":["db.elasticsearch.path_parts.index=test-index","db.elasticsearch.path_parts.doc_id=123"],"name":"db.elasticsearch.path_parts","note":"Many Elasticsearch url paths allow dynamic values. These SHOULD be recorded in span attributes in the format `db.elasticsearch.path_parts.\u003ckey\u003e`, where `\u003ckey\u003e` is the url path part name. The implementation SHOULD reference the [elasticsearch schema](https://raw.githubusercontent.com/elastic/elasticsearch-specification/main/output/schema/schema.json) in order to map the path part values to their names.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"template[string]"},{"brief":"An identifier (address, unique name, or any other identifier) of the database instance that is executing queries or mutations on the current connection. This is useful in cases where the database is running in a clustered environment and the instrumentation is able to record the node executing the query. The client may obtain this value in databases like MySQL using queries like `select @@hostname`.\n","examples":"mysql-e26b99z.example.com","name":"db.instance.id","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The fully-qualified class name of the [Java Database Connectivity (JDBC)](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/) driver used to connect.\n","examples":["org.postgresql.Driver","com.microsoft.sqlserver.jdbc.SQLServerDriver"],"name":"db.jdbc.driver_classname","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-jdbc","type":"string"},{"brief":"The MongoDB collection being accessed within the database stated in `db.name`.\n","examples":["customers","products"],"name":"db.mongodb.collection","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mongodb","type":"string"},{"brief":"The Microsoft SQL Server [instance name](https://docs.microsoft.com/sql/connect/jdbc/building-the-connection-url?view=sql-server-ver15) connecting to. This name is used to determine the port of a named instance.\n","examples":"MSSQLSERVER","name":"db.mssql.instance_name","note":"If setting a `db.mssql.instance_name`, `server.port` is no longer required (but still recommended if non-standard).\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mssql","type":"string"},{"brief":"This attribute is used to report the name of the database being accessed. For commands that switch the database, this should be set to the target database (even if the command fails).\n","examples":["customers","main"],"name":"db.name","note":"In some SQL databases, the database name to be used is called \"schema name\". In case there are multiple layers that could be considered for database name (e.g. Oracle instance name and schema name), the database name to be used is the more specific layer (e.g. Oracle schema name).\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The name of the operation being executed, e.g. the [MongoDB command name](https://docs.mongodb.com/manual/reference/command/#database-operations) such as `findAndModify`, or the SQL keyword.\n","examples":["findAndModify","HMSET","SELECT"],"name":"db.operation","note":"When setting this to an SQL keyword, it is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if the operation name is provided by the library being instrumented. If the SQL statement has an ambiguous operation, or performs more than one operation, this value may be omitted.\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The index of the database being accessed as used in the [`SELECT` command](https://redis.io/commands/select), provided as an integer. To be used instead of the generic `db.name` attribute.\n","examples":[0,1,15],"name":"db.redis.database_index","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-redis","type":"int"},{"brief":"The name of the primary table that the operation is acting upon, including the database name (if applicable).","examples":["public.users","customers"],"name":"db.sql.table","note":"It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-sql","type":"string"},{"brief":"The database statement being executed.\n","examples":["SELECT * FROM wuser_table","SET mykey \"WuValue\""],"name":"db.statement","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"An identifier for the database management system (DBMS) product being used. See below for a list of well-known identifiers.","name":"db.system","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":{"allow_custom_values":true,"members":[{"brief":"Some other SQL database. Fallback only. See notes.","deprecated":null,"id":"other_sql","note":null,"stability":null,"value":"other_sql"},{"brief":"Microsoft SQL Server","deprecated":null,"id":"mssql","note":null,"stability":null,"value":"mssql"},{"brief":"Microsoft SQL Server Compact","deprecated":null,"id":"mssqlcompact","note":null,"stability":null,"value":"mssqlcompact"},{"brief":"MySQL","deprecated":null,"id":"mysql","note":null,"stability":null,"value":"mysql"},{"brief":"Oracle Database","deprecated":null,"id":"oracle","note":null,"stability":null,"value":"oracle"},{"brief":"IBM Db2","deprecated":null,"id":"db2","note":null,"stability":null,"value":"db2"},{"brief":"PostgreSQL","deprecated":null,"id":"postgresql","note":null,"stability":null,"value":"postgresql"},{"brief":"Amazon Redshift","deprecated":null,"id":"redshift","note":null,"stability":null,"value":"redshift"},{"brief":"Apache Hive","deprecated":null,"id":"hive","note":null,"stability":null,"value":"hive"},{"brief":"Cloudscape","deprecated":null,"id":"cloudscape","note":null,"stability":null,"value":"cloudscape"},{"brief":"HyperSQL DataBase","deprecated":null,"id":"hsqldb","note":null,"stability":null,"value":"hsqldb"},{"brief":"Progress Database","deprecated":null,"id":"progress","note":null,"stability":null,"value":"progress"},{"brief":"SAP MaxDB","deprecated":null,"id":"maxdb","note":null,"stability":null,"value":"maxdb"},{"brief":"SAP HANA","deprecated":null,"id":"hanadb","note":null,"stability":null,"value":"hanadb"},{"brief":"Ingres","deprecated":null,"id":"ingres","note":null,"stability":null,"value":"ingres"},{"brief":"FirstSQL","deprecated":null,"id":"firstsql","note":null,"stability":null,"value":"firstsql"},{"brief":"EnterpriseDB","deprecated":null,"id":"edb","note":null,"stability":null,"value":"edb"},{"brief":"InterSystems Caché","deprecated":null,"id":"cache","note":null,"stability":null,"value":"cache"},{"brief":"Adabas (Adaptable Database System)","deprecated":null,"id":"adabas","note":null,"stability":null,"value":"adabas"},{"brief":"Firebird","deprecated":null,"id":"firebird","note":null,"stability":null,"value":"firebird"},{"brief":"Apache Derby","deprecated":null,"id":"derby","note":null,"stability":null,"value":"derby"},{"brief":"FileMaker","deprecated":null,"id":"filemaker","note":null,"stability":null,"value":"filemaker"},{"brief":"Informix","deprecated":null,"id":"informix","note":null,"stability":null,"value":"informix"},{"brief":"InstantDB","deprecated":null,"id":"instantdb","note":null,"stability":null,"value":"instantdb"},{"brief":"InterBase","deprecated":null,"id":"interbase","note":null,"stability":null,"value":"interbase"},{"brief":"MariaDB","deprecated":null,"id":"mariadb","note":null,"stability":null,"value":"mariadb"},{"brief":"Netezza","deprecated":null,"id":"netezza","note":null,"stability":null,"value":"netezza"},{"brief":"Pervasive PSQL","deprecated":null,"id":"pervasive","note":null,"stability":null,"value":"pervasive"},{"brief":"PointBase","deprecated":null,"id":"pointbase","note":null,"stability":null,"value":"pointbase"},{"brief":"SQLite","deprecated":null,"id":"sqlite","note":null,"stability":null,"value":"sqlite"},{"brief":"Sybase","deprecated":null,"id":"sybase","note":null,"stability":null,"value":"sybase"},{"brief":"Teradata","deprecated":null,"id":"teradata","note":null,"stability":null,"value":"teradata"},{"brief":"Vertica","deprecated":null,"id":"vertica","note":null,"stability":null,"value":"vertica"},{"brief":"H2","deprecated":null,"id":"h2","note":null,"stability":null,"value":"h2"},{"brief":"ColdFusion IMQ","deprecated":null,"id":"coldfusion","note":null,"stability":null,"value":"coldfusion"},{"brief":"Apache Cassandra","deprecated":null,"id":"cassandra","note":null,"stability":null,"value":"cassandra"},{"brief":"Apache HBase","deprecated":null,"id":"hbase","note":null,"stability":null,"value":"hbase"},{"brief":"MongoDB","deprecated":null,"id":"mongodb","note":null,"stability":null,"value":"mongodb"},{"brief":"Redis","deprecated":null,"id":"redis","note":null,"stability":null,"value":"redis"},{"brief":"Couchbase","deprecated":null,"id":"couchbase","note":null,"stability":null,"value":"couchbase"},{"brief":"CouchDB","deprecated":null,"id":"couchdb","note":null,"stability":null,"value":"couchdb"},{"brief":"Microsoft Azure Cosmos DB","deprecated":null,"id":"cosmosdb","note":null,"stability":null,"value":"cosmosdb"},{"brief":"Amazon DynamoDB","deprecated":null,"id":"dynamodb","note":null,"stability":null,"value":"dynamodb"},{"brief":"Neo4j","deprecated":null,"id":"neo4j","note":null,"stability":null,"value":"neo4j"},{"brief":"Apache Geode","deprecated":null,"id":"geode","note":null,"stability":null,"value":"geode"},{"brief":"Elasticsearch","deprecated":null,"id":"elasticsearch","note":null,"stability":null,"value":"elasticsearch"},{"brief":"Memcached","deprecated":null,"id":"memcached","note":null,"stability":null,"value":"memcached"},{"brief":"CockroachDB","deprecated":null,"id":"cockroachdb","note":null,"stability":null,"value":"cockroachdb"},{"brief":"OpenSearch","deprecated":null,"id":"opensearch","note":null,"stability":null,"value":"opensearch"},{"brief":"ClickHouse","deprecated":null,"id":"clickhouse","note":null,"stability":null,"value":"clickhouse"},{"brief":"Cloud Spanner","deprecated":null,"id":"spanner","note":null,"stability":null,"value":"spanner"},{"brief":"Trino","deprecated":null,"id":"trino","note":null,"stability":null,"value":"trino"}]}},{"brief":"Username for accessing the database.\n","examples":["readonly_user","reporting_user"],"name":"db.user","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"}],"root_namespace":"db"},{"attributes":[{"brief":"The size of the request payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.\n","examples":3495,"name":"http.request.body.size","requirement_level":"recommended","root_namespace":"http","stability":"experimental","type":"int"},{"brief":"HTTP request headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.request.header.content-type=[\"application/json\"]","http.request.header.x-forwarded-for=[\"1.2.3.4\", \"1.2.3.5\"]"],"name":"http.request.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all request headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nThe `User-Agent` header is already captured in the `user_agent.original` attribute. Users MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"HTTP request method.","examples":["GET","POST","HEAD"],"name":"http.request.method","note":"HTTP request method value SHOULD be \"known\" to the instrumentation.\nBy default, this convention defines \"known\" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods)\nand the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html).\n\nIf the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`.\n\nIf the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override\nthe list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named\nOTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods\n(this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults).\n\nHTTP method names are case-sensitive and `http.request.method` attribute value MUST match a known HTTP method name exactly.\nInstrumentations for specific web frameworks that consider HTTP methods to be case insensitive, SHOULD populate a canonical equivalent.\nTracing instrumentations that do so, MUST also set `http.request.method_original` to the original value.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"CONNECT method.","deprecated":null,"id":"connect","note":null,"stability":null,"value":"CONNECT"},{"brief":"DELETE method.","deprecated":null,"id":"delete","note":null,"stability":null,"value":"DELETE"},{"brief":"GET method.","deprecated":null,"id":"get","note":null,"stability":null,"value":"GET"},{"brief":"HEAD method.","deprecated":null,"id":"head","note":null,"stability":null,"value":"HEAD"},{"brief":"OPTIONS method.","deprecated":null,"id":"options","note":null,"stability":null,"value":"OPTIONS"},{"brief":"PATCH method.","deprecated":null,"id":"patch","note":null,"stability":null,"value":"PATCH"},{"brief":"POST method.","deprecated":null,"id":"post","note":null,"stability":null,"value":"POST"},{"brief":"PUT method.","deprecated":null,"id":"put","note":null,"stability":null,"value":"PUT"},{"brief":"TRACE method.","deprecated":null,"id":"trace","note":null,"stability":null,"value":"TRACE"},{"brief":"Any HTTP method that the instrumentation has no prior knowledge of.","deprecated":null,"id":"other","note":null,"stability":null,"value":"_OTHER"}]}},{"brief":"Original HTTP method sent by the client in the request line.","examples":["GeT","ACL","foo"],"name":"http.request.method_original","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"},{"brief":"The ordinal number of request resending attempt (for any reason, including redirects).\n","examples":3,"name":"http.request.resend_count","note":"The resend count SHOULD be updated each time an HTTP request gets resent by the client, regardless of what was the cause of the resending (e.g. redirection, authorization failure, 503 Server Unavailable, network issues, or any other).\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"The size of the response payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.\n","examples":3495,"name":"http.response.body.size","requirement_level":"recommended","root_namespace":"http","stability":"experimental","type":"int"},{"brief":"HTTP response headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.response.header.content-type=[\"application/json\"]","http.response.header.my-custom-header=[\"abc\", \"def\"]"],"name":"http.response.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all response headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nUsers MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"[HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6).","examples":[200],"name":"http.response.status_code","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"The matched route, that is, the path template in the format used by the respective server framework.\n","examples":["/users/:userID?","{controller}/{action}/{id?}"],"name":"http.route","note":"MUST NOT be populated when this is not supported by the HTTP server framework as the route attribute should have low-cardinality and the URI path can NOT substitute it.\nSHOULD include the [application root](/docs/http/http-spans.md#http-server-definitions) if there is one.","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"}],"root_namespace":"http"},{"attributes":[{"brief":"The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network.","examples":"DE","name":"network.carrier.icc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The mobile carrier country code.","examples":"310","name":"network.carrier.mcc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The mobile carrier network code.","examples":"001","name":"network.carrier.mnc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The name of the mobile carrier.","examples":"sprint","name":"network.carrier.name","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.","examples":"LTE","name":"network.connection.subtype","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":true,"members":[{"brief":"GPRS","deprecated":null,"id":"gprs","note":null,"stability":null,"value":"gprs"},{"brief":"EDGE","deprecated":null,"id":"edge","note":null,"stability":null,"value":"edge"},{"brief":"UMTS","deprecated":null,"id":"umts","note":null,"stability":null,"value":"umts"},{"brief":"CDMA","deprecated":null,"id":"cdma","note":null,"stability":null,"value":"cdma"},{"brief":"EVDO Rel. 0","deprecated":null,"id":"evdo_0","note":null,"stability":null,"value":"evdo_0"},{"brief":"EVDO Rev. A","deprecated":null,"id":"evdo_a","note":null,"stability":null,"value":"evdo_a"},{"brief":"CDMA2000 1XRTT","deprecated":null,"id":"cdma2000_1xrtt","note":null,"stability":null,"value":"cdma2000_1xrtt"},{"brief":"HSDPA","deprecated":null,"id":"hsdpa","note":null,"stability":null,"value":"hsdpa"},{"brief":"HSUPA","deprecated":null,"id":"hsupa","note":null,"stability":null,"value":"hsupa"},{"brief":"HSPA","deprecated":null,"id":"hspa","note":null,"stability":null,"value":"hspa"},{"brief":"IDEN","deprecated":null,"id":"iden","note":null,"stability":null,"value":"iden"},{"brief":"EVDO Rev. B","deprecated":null,"id":"evdo_b","note":null,"stability":null,"value":"evdo_b"},{"brief":"LTE","deprecated":null,"id":"lte","note":null,"stability":null,"value":"lte"},{"brief":"EHRPD","deprecated":null,"id":"ehrpd","note":null,"stability":null,"value":"ehrpd"},{"brief":"HSPAP","deprecated":null,"id":"hspap","note":null,"stability":null,"value":"hspap"},{"brief":"GSM","deprecated":null,"id":"gsm","note":null,"stability":null,"value":"gsm"},{"brief":"TD-SCDMA","deprecated":null,"id":"td_scdma","note":null,"stability":null,"value":"td_scdma"},{"brief":"IWLAN","deprecated":null,"id":"iwlan","note":null,"stability":null,"value":"iwlan"},{"brief":"5G NR (New Radio)","deprecated":null,"id":"nr","note":null,"stability":null,"value":"nr"},{"brief":"5G NRNSA (New Radio Non-Standalone)","deprecated":null,"id":"nrnsa","note":null,"stability":null,"value":"nrnsa"},{"brief":"LTE CA","deprecated":null,"id":"lte_ca","note":null,"stability":null,"value":"lte_ca"}]}},{"brief":"The internet connection type.","examples":"wifi","name":"network.connection.type","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"wifi","note":null,"stability":null,"value":"wifi"},{"brief":null,"deprecated":null,"id":"wired","note":null,"stability":null,"value":"wired"},{"brief":null,"deprecated":null,"id":"cell","note":null,"stability":null,"value":"cell"},{"brief":null,"deprecated":null,"id":"unavailable","note":null,"stability":null,"value":"unavailable"},{"brief":null,"deprecated":null,"id":"unknown","note":null,"stability":null,"value":"unknown"}]}},{"brief":"The network IO operation direction.","examples":["transmit"],"name":"network.io.direction","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":false,"members":[{"brief":null,"deprecated":null,"id":"transmit","note":null,"stability":null,"value":"transmit"},{"brief":null,"deprecated":null,"id":"receive","note":null,"stability":null,"value":"receive"}]}},{"brief":"Local address of the network connection - IP address or Unix domain socket name.","examples":["10.1.2.80","/tmp/my.sock"],"name":"network.local.address","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Local port number of the network connection.","examples":[65123],"name":"network.local.port","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"int"},{"brief":"Peer address of the network connection - IP address or Unix domain socket name.","examples":["10.1.2.80","/tmp/my.sock"],"name":"network.peer.address","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Peer port number of the network connection.","examples":[65123],"name":"network.peer.port","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"int"},{"brief":"[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.","examples":["amqp","http","mqtt"],"name":"network.protocol.name","note":"The value SHOULD be normalized to lowercase.","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Version of the protocol specified in `network.protocol.name`.","examples":"3.1.1","name":"network.protocol.version","note":"`network.protocol.version` refers to the version of the protocol used and might be different from the protocol client\u0027s version. If the HTTP client has a version of `0.27.2`, but sends HTTP version `1.1`, this attribute should be set to `1.1`.\n","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"[OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication).\n","examples":["tcp","udp"],"name":"network.transport","note":"The value SHOULD be normalized to lowercase.\n\nConsider always setting the transport when setting a port number, since\na port number is ambiguous without knowing the transport. For example\ndifferent processes could be listening on TCP port 12345 and UDP port 12345.\n","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"TCP","deprecated":null,"id":"tcp","note":null,"stability":null,"value":"tcp"},{"brief":"UDP","deprecated":null,"id":"udp","note":null,"stability":null,"value":"udp"},{"brief":"Named or anonymous pipe.","deprecated":null,"id":"pipe","note":null,"stability":null,"value":"pipe"},{"brief":"Unix domain socket","deprecated":null,"id":"unix","note":null,"stability":null,"value":"unix"}]}},{"brief":"[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.","examples":["ipv4","ipv6"],"name":"network.type","note":"The value SHOULD be normalized to lowercase.","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"IPv4","deprecated":null,"id":"ipv4","note":null,"stability":null,"value":"ipv4"},{"brief":"IPv6","deprecated":null,"id":"ipv6","note":null,"stability":null,"value":"ipv6"}]}}],"root_namespace":"network"},{"attributes":[{"brief":"The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component","examples":["SemConv"],"name":"url.fragment","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986)","examples":["https://www.foo.bar/search?q=OpenTelemetry#SemConv","//localhost"],"name":"url.full","note":"For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless.\n`url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case username and password SHOULD be redacted and attribute\u0027s value SHOULD be `https://REDACTED:REDACTED@www.example.com/`.\n`url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed) and SHOULD NOT be validated or modified except for sanitizing purposes.\n","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component","examples":["/search"],"name":"url.path","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component","examples":["q=OpenTelemetry"],"name":"url.query","note":"Sensitive content provided in query string SHOULD be scrubbed when instrumentations can identify it.","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol.","examples":["https","ftp","telnet"],"name":"url.scheme","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"}],"root_namespace":"url"},{"attributes":[{"brief":"Value of the [HTTP User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) header sent by the client.\n","examples":["CERN-LineMode/2.15 libwww/2.17b3","Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1"],"name":"user_agent.original","requirement_level":"recommended","root_namespace":"user_agent","stability":"stable","type":"string"}],"root_namespace":"user_agent"}] \ No newline at end of file +[{"attributes":[{"brief":"The consistency level of the query. Based on consistency values from [CQL](https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/dml/dmlConfigConsistency.html).\n","name":"db.cassandra.consistency_level","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"all","note":null,"stability":null,"value":"all"},{"brief":null,"deprecated":null,"id":"each_quorum","note":null,"stability":null,"value":"each_quorum"},{"brief":null,"deprecated":null,"id":"quorum","note":null,"stability":null,"value":"quorum"},{"brief":null,"deprecated":null,"id":"local_quorum","note":null,"stability":null,"value":"local_quorum"},{"brief":null,"deprecated":null,"id":"one","note":null,"stability":null,"value":"one"},{"brief":null,"deprecated":null,"id":"two","note":null,"stability":null,"value":"two"},{"brief":null,"deprecated":null,"id":"three","note":null,"stability":null,"value":"three"},{"brief":null,"deprecated":null,"id":"local_one","note":null,"stability":null,"value":"local_one"},{"brief":null,"deprecated":null,"id":"any","note":null,"stability":null,"value":"any"},{"brief":null,"deprecated":null,"id":"serial","note":null,"stability":null,"value":"serial"},{"brief":null,"deprecated":null,"id":"local_serial","note":null,"stability":null,"value":"local_serial"}]}},{"brief":"The data center of the coordinating node for a query.\n","examples":"us-west-2","name":"db.cassandra.coordinator.dc","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The ID of the coordinating node for a query.\n","examples":"be13faa2-8574-4d71-926d-27f16cf8a7af","name":"db.cassandra.coordinator.id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"Whether or not the query is idempotent.\n","name":"db.cassandra.idempotence","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"boolean"},{"brief":"The fetch size used for paging, i.e. how many rows will be returned at once.\n","examples":[5000],"name":"db.cassandra.page_size","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The number of times a query was speculatively executed. Not set or `0` if the query was not executed speculatively.\n","examples":[0,2],"name":"db.cassandra.speculative_execution_count","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The name of the primary Cassandra table that the operation is acting upon, including the keyspace name (if applicable).","examples":"mytable","name":"db.cassandra.table","note":"This mirrors the db.sql.table attribute but references cassandra rather than sql. It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The connection string used to connect to the database. It is recommended to remove embedded credentials.\n","examples":"Server=(localdb)\\v11.0;Integrated Security=true;","name":"db.connection_string","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"Unique Cosmos client instance id.","examples":"3ba4827d-4422-483f-b59f-85b74211c11d","name":"db.cosmosdb.client_id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"Cosmos client connection mode.","name":"db.cosmosdb.connection_mode","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":false,"members":[{"brief":"Gateway (HTTP) connections mode","deprecated":null,"id":"gateway","note":null,"stability":null,"value":"gateway"},{"brief":"Direct connection.","deprecated":null,"id":"direct","note":null,"stability":null,"value":"direct"}]}},{"brief":"Cosmos DB container name.","examples":"anystring","name":"db.cosmosdb.container","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"CosmosDB Operation Type.","name":"db.cosmosdb.operation_type","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"invalid","note":null,"stability":null,"value":"Invalid"},{"brief":null,"deprecated":null,"id":"create","note":null,"stability":null,"value":"Create"},{"brief":null,"deprecated":null,"id":"patch","note":null,"stability":null,"value":"Patch"},{"brief":null,"deprecated":null,"id":"read","note":null,"stability":null,"value":"Read"},{"brief":null,"deprecated":null,"id":"read_feed","note":null,"stability":null,"value":"ReadFeed"},{"brief":null,"deprecated":null,"id":"delete","note":null,"stability":null,"value":"Delete"},{"brief":null,"deprecated":null,"id":"replace","note":null,"stability":null,"value":"Replace"},{"brief":null,"deprecated":null,"id":"execute","note":null,"stability":null,"value":"Execute"},{"brief":null,"deprecated":null,"id":"query","note":null,"stability":null,"value":"Query"},{"brief":null,"deprecated":null,"id":"head","note":null,"stability":null,"value":"Head"},{"brief":null,"deprecated":null,"id":"head_feed","note":null,"stability":null,"value":"HeadFeed"},{"brief":null,"deprecated":null,"id":"upsert","note":null,"stability":null,"value":"Upsert"},{"brief":null,"deprecated":null,"id":"batch","note":null,"stability":null,"value":"Batch"},{"brief":null,"deprecated":null,"id":"query_plan","note":null,"stability":null,"value":"QueryPlan"},{"brief":null,"deprecated":null,"id":"execute_javascript","note":null,"stability":null,"value":"ExecuteJavaScript"}]}},{"brief":"RU consumed for that operation","examples":[46.18,1.0],"name":"db.cosmosdb.request_charge","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"double"},{"brief":"Request payload size in bytes","name":"db.cosmosdb.request_content_length","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB status code.","examples":[200,201],"name":"db.cosmosdb.status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB sub status code.","examples":[1000,1002],"name":"db.cosmosdb.sub_status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Represents the identifier of an Elasticsearch cluster.\n","examples":["e9106fc68e3044f0b1475b04bf4ffd5f"],"name":"db.elasticsearch.cluster.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"Represents the human-readable identifier of the node/instance to which a request was routed.\n","examples":["instance-0000000001"],"name":"db.elasticsearch.node.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"A dynamic value in the url path.\n","examples":["db.elasticsearch.path_parts.index=test-index","db.elasticsearch.path_parts.doc_id=123"],"name":"db.elasticsearch.path_parts","note":"Many Elasticsearch url paths allow dynamic values. These SHOULD be recorded in span attributes in the format `db.elasticsearch.path_parts.\u003ckey\u003e`, where `\u003ckey\u003e` is the url path part name. The implementation SHOULD reference the [elasticsearch schema](https://raw.githubusercontent.com/elastic/elasticsearch-specification/main/output/schema/schema.json) in order to map the path part values to their names.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"template[string]"},{"brief":"An identifier (address, unique name, or any other identifier) of the database instance that is executing queries or mutations on the current connection. This is useful in cases where the database is running in a clustered environment and the instrumentation is able to record the node executing the query. The client may obtain this value in databases like MySQL using queries like `select @@hostname`.\n","examples":"mysql-e26b99z.example.com","name":"db.instance.id","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The fully-qualified class name of the [Java Database Connectivity (JDBC)](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/) driver used to connect.\n","examples":["org.postgresql.Driver","com.microsoft.sqlserver.jdbc.SQLServerDriver"],"name":"db.jdbc.driver_classname","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-jdbc","type":"string"},{"brief":"The MongoDB collection being accessed within the database stated in `db.name`.\n","examples":["customers","products"],"name":"db.mongodb.collection","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mongodb","type":"string"},{"brief":"The Microsoft SQL Server [instance name](https://docs.microsoft.com/sql/connect/jdbc/building-the-connection-url?view=sql-server-ver15) connecting to. This name is used to determine the port of a named instance.\n","examples":"MSSQLSERVER","name":"db.mssql.instance_name","note":"If setting a `db.mssql.instance_name`, `server.port` is no longer required (but still recommended if non-standard).\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mssql","type":"string"},{"brief":"This attribute is used to report the name of the database being accessed. For commands that switch the database, this should be set to the target database (even if the command fails).\n","examples":["customers","main"],"name":"db.name","note":"In some SQL databases, the database name to be used is called \"schema name\". In case there are multiple layers that could be considered for database name (e.g. Oracle instance name and schema name), the database name to be used is the more specific layer (e.g. Oracle schema name).\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The name of the operation being executed, e.g. the [MongoDB command name](https://docs.mongodb.com/manual/reference/command/#database-operations) such as `findAndModify`, or the SQL keyword.\n","examples":["findAndModify","HMSET","SELECT"],"name":"db.operation","note":"When setting this to an SQL keyword, it is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if the operation name is provided by the library being instrumented. If the SQL statement has an ambiguous operation, or performs more than one operation, this value may be omitted.\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The index of the database being accessed as used in the [`SELECT` command](https://redis.io/commands/select), provided as an integer. To be used instead of the generic `db.name` attribute.\n","examples":[0,1,15],"name":"db.redis.database_index","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-redis","type":"int"},{"brief":"The name of the primary table that the operation is acting upon, including the database name (if applicable).","examples":["public.users","customers"],"name":"db.sql.table","note":"It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-sql","type":"string"},{"brief":"The database statement being executed.\n","examples":["SELECT * FROM wuser_table","SET mykey \"WuValue\""],"name":"db.statement","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"An identifier for the database management system (DBMS) product being used. See below for a list of well-known identifiers.","name":"db.system","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":{"allow_custom_values":true,"members":[{"brief":"Some other SQL database. Fallback only. See notes.","deprecated":null,"id":"other_sql","note":null,"stability":null,"value":"other_sql"},{"brief":"Microsoft SQL Server","deprecated":null,"id":"mssql","note":null,"stability":null,"value":"mssql"},{"brief":"Microsoft SQL Server Compact","deprecated":null,"id":"mssqlcompact","note":null,"stability":null,"value":"mssqlcompact"},{"brief":"MySQL","deprecated":null,"id":"mysql","note":null,"stability":null,"value":"mysql"},{"brief":"Oracle Database","deprecated":null,"id":"oracle","note":null,"stability":null,"value":"oracle"},{"brief":"IBM Db2","deprecated":null,"id":"db2","note":null,"stability":null,"value":"db2"},{"brief":"PostgreSQL","deprecated":null,"id":"postgresql","note":null,"stability":null,"value":"postgresql"},{"brief":"Amazon Redshift","deprecated":null,"id":"redshift","note":null,"stability":null,"value":"redshift"},{"brief":"Apache Hive","deprecated":null,"id":"hive","note":null,"stability":null,"value":"hive"},{"brief":"Cloudscape","deprecated":null,"id":"cloudscape","note":null,"stability":null,"value":"cloudscape"},{"brief":"HyperSQL DataBase","deprecated":null,"id":"hsqldb","note":null,"stability":null,"value":"hsqldb"},{"brief":"Progress Database","deprecated":null,"id":"progress","note":null,"stability":null,"value":"progress"},{"brief":"SAP MaxDB","deprecated":null,"id":"maxdb","note":null,"stability":null,"value":"maxdb"},{"brief":"SAP HANA","deprecated":null,"id":"hanadb","note":null,"stability":null,"value":"hanadb"},{"brief":"Ingres","deprecated":null,"id":"ingres","note":null,"stability":null,"value":"ingres"},{"brief":"FirstSQL","deprecated":null,"id":"firstsql","note":null,"stability":null,"value":"firstsql"},{"brief":"EnterpriseDB","deprecated":null,"id":"edb","note":null,"stability":null,"value":"edb"},{"brief":"InterSystems Caché","deprecated":null,"id":"cache","note":null,"stability":null,"value":"cache"},{"brief":"Adabas (Adaptable Database System)","deprecated":null,"id":"adabas","note":null,"stability":null,"value":"adabas"},{"brief":"Firebird","deprecated":null,"id":"firebird","note":null,"stability":null,"value":"firebird"},{"brief":"Apache Derby","deprecated":null,"id":"derby","note":null,"stability":null,"value":"derby"},{"brief":"FileMaker","deprecated":null,"id":"filemaker","note":null,"stability":null,"value":"filemaker"},{"brief":"Informix","deprecated":null,"id":"informix","note":null,"stability":null,"value":"informix"},{"brief":"InstantDB","deprecated":null,"id":"instantdb","note":null,"stability":null,"value":"instantdb"},{"brief":"InterBase","deprecated":null,"id":"interbase","note":null,"stability":null,"value":"interbase"},{"brief":"MariaDB","deprecated":null,"id":"mariadb","note":null,"stability":null,"value":"mariadb"},{"brief":"Netezza","deprecated":null,"id":"netezza","note":null,"stability":null,"value":"netezza"},{"brief":"Pervasive PSQL","deprecated":null,"id":"pervasive","note":null,"stability":null,"value":"pervasive"},{"brief":"PointBase","deprecated":null,"id":"pointbase","note":null,"stability":null,"value":"pointbase"},{"brief":"SQLite","deprecated":null,"id":"sqlite","note":null,"stability":null,"value":"sqlite"},{"brief":"Sybase","deprecated":null,"id":"sybase","note":null,"stability":null,"value":"sybase"},{"brief":"Teradata","deprecated":null,"id":"teradata","note":null,"stability":null,"value":"teradata"},{"brief":"Vertica","deprecated":null,"id":"vertica","note":null,"stability":null,"value":"vertica"},{"brief":"H2","deprecated":null,"id":"h2","note":null,"stability":null,"value":"h2"},{"brief":"ColdFusion IMQ","deprecated":null,"id":"coldfusion","note":null,"stability":null,"value":"coldfusion"},{"brief":"Apache Cassandra","deprecated":null,"id":"cassandra","note":null,"stability":null,"value":"cassandra"},{"brief":"Apache HBase","deprecated":null,"id":"hbase","note":null,"stability":null,"value":"hbase"},{"brief":"MongoDB","deprecated":null,"id":"mongodb","note":null,"stability":null,"value":"mongodb"},{"brief":"Redis","deprecated":null,"id":"redis","note":null,"stability":null,"value":"redis"},{"brief":"Couchbase","deprecated":null,"id":"couchbase","note":null,"stability":null,"value":"couchbase"},{"brief":"CouchDB","deprecated":null,"id":"couchdb","note":null,"stability":null,"value":"couchdb"},{"brief":"Microsoft Azure Cosmos DB","deprecated":null,"id":"cosmosdb","note":null,"stability":null,"value":"cosmosdb"},{"brief":"Amazon DynamoDB","deprecated":null,"id":"dynamodb","note":null,"stability":null,"value":"dynamodb"},{"brief":"Neo4j","deprecated":null,"id":"neo4j","note":null,"stability":null,"value":"neo4j"},{"brief":"Apache Geode","deprecated":null,"id":"geode","note":null,"stability":null,"value":"geode"},{"brief":"Elasticsearch","deprecated":null,"id":"elasticsearch","note":null,"stability":null,"value":"elasticsearch"},{"brief":"Memcached","deprecated":null,"id":"memcached","note":null,"stability":null,"value":"memcached"},{"brief":"CockroachDB","deprecated":null,"id":"cockroachdb","note":null,"stability":null,"value":"cockroachdb"},{"brief":"OpenSearch","deprecated":null,"id":"opensearch","note":null,"stability":null,"value":"opensearch"},{"brief":"ClickHouse","deprecated":null,"id":"clickhouse","note":null,"stability":null,"value":"clickhouse"},{"brief":"Cloud Spanner","deprecated":null,"id":"spanner","note":null,"stability":null,"value":"spanner"},{"brief":"Trino","deprecated":null,"id":"trino","note":null,"stability":null,"value":"trino"}]}},{"brief":"Username for accessing the database.\n","examples":["readonly_user","reporting_user"],"name":"db.user","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"}],"root_namespace":"db"},{"attributes":[{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"boolean"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"string"},{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"string"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"string"}],"root_namespace":"exception"},{"attributes":[{"brief":"The size of the request payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.\n","examples":3495,"name":"http.request.body.size","requirement_level":"recommended","root_namespace":"http","stability":"experimental","type":"int"},{"brief":"HTTP request headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.request.header.content-type=[\"application/json\"]","http.request.header.x-forwarded-for=[\"1.2.3.4\", \"1.2.3.5\"]"],"name":"http.request.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all request headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nThe `User-Agent` header is already captured in the `user_agent.original` attribute. Users MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"HTTP request method.","examples":["GET","POST","HEAD"],"name":"http.request.method","note":"HTTP request method value SHOULD be \"known\" to the instrumentation.\nBy default, this convention defines \"known\" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods)\nand the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html).\n\nIf the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`.\n\nIf the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override\nthe list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named\nOTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods\n(this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults).\n\nHTTP method names are case-sensitive and `http.request.method` attribute value MUST match a known HTTP method name exactly.\nInstrumentations for specific web frameworks that consider HTTP methods to be case insensitive, SHOULD populate a canonical equivalent.\nTracing instrumentations that do so, MUST also set `http.request.method_original` to the original value.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"CONNECT method.","deprecated":null,"id":"connect","note":null,"stability":null,"value":"CONNECT"},{"brief":"DELETE method.","deprecated":null,"id":"delete","note":null,"stability":null,"value":"DELETE"},{"brief":"GET method.","deprecated":null,"id":"get","note":null,"stability":null,"value":"GET"},{"brief":"HEAD method.","deprecated":null,"id":"head","note":null,"stability":null,"value":"HEAD"},{"brief":"OPTIONS method.","deprecated":null,"id":"options","note":null,"stability":null,"value":"OPTIONS"},{"brief":"PATCH method.","deprecated":null,"id":"patch","note":null,"stability":null,"value":"PATCH"},{"brief":"POST method.","deprecated":null,"id":"post","note":null,"stability":null,"value":"POST"},{"brief":"PUT method.","deprecated":null,"id":"put","note":null,"stability":null,"value":"PUT"},{"brief":"TRACE method.","deprecated":null,"id":"trace","note":null,"stability":null,"value":"TRACE"},{"brief":"Any HTTP method that the instrumentation has no prior knowledge of.","deprecated":null,"id":"other","note":null,"stability":null,"value":"_OTHER"}]}},{"brief":"Original HTTP method sent by the client in the request line.","examples":["GeT","ACL","foo"],"name":"http.request.method_original","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"},{"brief":"The ordinal number of request resending attempt (for any reason, including redirects).\n","examples":3,"name":"http.request.resend_count","note":"The resend count SHOULD be updated each time an HTTP request gets resent by the client, regardless of what was the cause of the resending (e.g. redirection, authorization failure, 503 Server Unavailable, network issues, or any other).\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"The size of the response payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.\n","examples":3495,"name":"http.response.body.size","requirement_level":"recommended","root_namespace":"http","stability":"experimental","type":"int"},{"brief":"HTTP response headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.response.header.content-type=[\"application/json\"]","http.response.header.my-custom-header=[\"abc\", \"def\"]"],"name":"http.response.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all response headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nUsers MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"[HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6).","examples":[200],"name":"http.response.status_code","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"The matched route, that is, the path template in the format used by the respective server framework.\n","examples":["/users/:userID?","{controller}/{action}/{id?}"],"name":"http.route","note":"MUST NOT be populated when this is not supported by the HTTP server framework as the route attribute should have low-cardinality and the URI path can NOT substitute it.\nSHOULD include the [application root](/docs/http/http-spans.md#http-server-definitions) if there is one.","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"}],"root_namespace":"http"},{"attributes":[{"brief":"The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network.","examples":"DE","name":"network.carrier.icc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The mobile carrier country code.","examples":"310","name":"network.carrier.mcc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The mobile carrier network code.","examples":"001","name":"network.carrier.mnc","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"The name of the mobile carrier.","examples":"sprint","name":"network.carrier.name","requirement_level":"recommended","root_namespace":"network","type":"string"},{"brief":"This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.","examples":"LTE","name":"network.connection.subtype","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":true,"members":[{"brief":"GPRS","deprecated":null,"id":"gprs","note":null,"stability":null,"value":"gprs"},{"brief":"EDGE","deprecated":null,"id":"edge","note":null,"stability":null,"value":"edge"},{"brief":"UMTS","deprecated":null,"id":"umts","note":null,"stability":null,"value":"umts"},{"brief":"CDMA","deprecated":null,"id":"cdma","note":null,"stability":null,"value":"cdma"},{"brief":"EVDO Rel. 0","deprecated":null,"id":"evdo_0","note":null,"stability":null,"value":"evdo_0"},{"brief":"EVDO Rev. A","deprecated":null,"id":"evdo_a","note":null,"stability":null,"value":"evdo_a"},{"brief":"CDMA2000 1XRTT","deprecated":null,"id":"cdma2000_1xrtt","note":null,"stability":null,"value":"cdma2000_1xrtt"},{"brief":"HSDPA","deprecated":null,"id":"hsdpa","note":null,"stability":null,"value":"hsdpa"},{"brief":"HSUPA","deprecated":null,"id":"hsupa","note":null,"stability":null,"value":"hsupa"},{"brief":"HSPA","deprecated":null,"id":"hspa","note":null,"stability":null,"value":"hspa"},{"brief":"IDEN","deprecated":null,"id":"iden","note":null,"stability":null,"value":"iden"},{"brief":"EVDO Rev. B","deprecated":null,"id":"evdo_b","note":null,"stability":null,"value":"evdo_b"},{"brief":"LTE","deprecated":null,"id":"lte","note":null,"stability":null,"value":"lte"},{"brief":"EHRPD","deprecated":null,"id":"ehrpd","note":null,"stability":null,"value":"ehrpd"},{"brief":"HSPAP","deprecated":null,"id":"hspap","note":null,"stability":null,"value":"hspap"},{"brief":"GSM","deprecated":null,"id":"gsm","note":null,"stability":null,"value":"gsm"},{"brief":"TD-SCDMA","deprecated":null,"id":"td_scdma","note":null,"stability":null,"value":"td_scdma"},{"brief":"IWLAN","deprecated":null,"id":"iwlan","note":null,"stability":null,"value":"iwlan"},{"brief":"5G NR (New Radio)","deprecated":null,"id":"nr","note":null,"stability":null,"value":"nr"},{"brief":"5G NRNSA (New Radio Non-Standalone)","deprecated":null,"id":"nrnsa","note":null,"stability":null,"value":"nrnsa"},{"brief":"LTE CA","deprecated":null,"id":"lte_ca","note":null,"stability":null,"value":"lte_ca"}]}},{"brief":"The internet connection type.","examples":"wifi","name":"network.connection.type","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"wifi","note":null,"stability":null,"value":"wifi"},{"brief":null,"deprecated":null,"id":"wired","note":null,"stability":null,"value":"wired"},{"brief":null,"deprecated":null,"id":"cell","note":null,"stability":null,"value":"cell"},{"brief":null,"deprecated":null,"id":"unavailable","note":null,"stability":null,"value":"unavailable"},{"brief":null,"deprecated":null,"id":"unknown","note":null,"stability":null,"value":"unknown"}]}},{"brief":"The network IO operation direction.","examples":["transmit"],"name":"network.io.direction","requirement_level":"recommended","root_namespace":"network","type":{"allow_custom_values":false,"members":[{"brief":null,"deprecated":null,"id":"transmit","note":null,"stability":null,"value":"transmit"},{"brief":null,"deprecated":null,"id":"receive","note":null,"stability":null,"value":"receive"}]}},{"brief":"Local address of the network connection - IP address or Unix domain socket name.","examples":["10.1.2.80","/tmp/my.sock"],"name":"network.local.address","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Local port number of the network connection.","examples":[65123],"name":"network.local.port","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"int"},{"brief":"Peer address of the network connection - IP address or Unix domain socket name.","examples":["10.1.2.80","/tmp/my.sock"],"name":"network.peer.address","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Peer port number of the network connection.","examples":[65123],"name":"network.peer.port","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"int"},{"brief":"[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.","examples":["amqp","http","mqtt"],"name":"network.protocol.name","note":"The value SHOULD be normalized to lowercase.","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"Version of the protocol specified in `network.protocol.name`.","examples":"3.1.1","name":"network.protocol.version","note":"`network.protocol.version` refers to the version of the protocol used and might be different from the protocol client\u0027s version. If the HTTP client has a version of `0.27.2`, but sends HTTP version `1.1`, this attribute should be set to `1.1`.\n","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":"string"},{"brief":"[OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication).\n","examples":["tcp","udp"],"name":"network.transport","note":"The value SHOULD be normalized to lowercase.\n\nConsider always setting the transport when setting a port number, since\na port number is ambiguous without knowing the transport. For example\ndifferent processes could be listening on TCP port 12345 and UDP port 12345.\n","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"TCP","deprecated":null,"id":"tcp","note":null,"stability":null,"value":"tcp"},{"brief":"UDP","deprecated":null,"id":"udp","note":null,"stability":null,"value":"udp"},{"brief":"Named or anonymous pipe.","deprecated":null,"id":"pipe","note":null,"stability":null,"value":"pipe"},{"brief":"Unix domain socket","deprecated":null,"id":"unix","note":null,"stability":null,"value":"unix"}]}},{"brief":"[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.","examples":["ipv4","ipv6"],"name":"network.type","note":"The value SHOULD be normalized to lowercase.","requirement_level":"recommended","root_namespace":"network","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"IPv4","deprecated":null,"id":"ipv4","note":null,"stability":null,"value":"ipv4"},{"brief":"IPv6","deprecated":null,"id":"ipv6","note":null,"stability":null,"value":"ipv6"}]}}],"root_namespace":"network"},{"attributes":[{"brief":"The [URI fragment](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) component","examples":["SemConv"],"name":"url.fragment","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"Absolute URL describing a network resource according to [RFC3986](https://www.rfc-editor.org/rfc/rfc3986)","examples":["https://www.foo.bar/search?q=OpenTelemetry#SemConv","//localhost"],"name":"url.full","note":"For network calls, URL usually has `scheme://host[:port][path][?query][#fragment]` format, where the fragment is not transmitted over HTTP, but if it is known, it SHOULD be included nevertheless.\n`url.full` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case username and password SHOULD be redacted and attribute\u0027s value SHOULD be `https://REDACTED:REDACTED@www.example.com/`.\n`url.full` SHOULD capture the absolute URL when it is available (or can be reconstructed) and SHOULD NOT be validated or modified except for sanitizing purposes.\n","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI path](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) component","examples":["/search"],"name":"url.path","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI query](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) component","examples":["q=OpenTelemetry"],"name":"url.query","note":"Sensitive content provided in query string SHOULD be scrubbed when instrumentations can identify it.","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"},{"brief":"The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol.","examples":["https","ftp","telnet"],"name":"url.scheme","requirement_level":"recommended","root_namespace":"url","stability":"stable","type":"string"}],"root_namespace":"url"},{"attributes":[{"brief":"Value of the [HTTP User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) header sent by the client.\n","examples":["CERN-LineMode/2.15 libwww/2.17b3","Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1"],"name":"user_agent.original","requirement_level":"recommended","root_namespace":"user_agent","stability":"stable","type":"string"}],"root_namespace":"user_agent"}] \ No newline at end of file diff --git a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_grouped_attributes_without_experimental.json b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_grouped_attributes_without_experimental.json index 83d7e2ed..b3113708 100644 --- a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_grouped_attributes_without_experimental.json +++ b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_grouped_attributes_without_experimental.json @@ -1 +1 @@ -[{"attributes":[{"brief":"The consistency level of the query. Based on consistency values from [CQL](https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/dml/dmlConfigConsistency.html).\n","name":"db.cassandra.consistency_level","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"all","note":null,"stability":null,"value":"all"},{"brief":null,"deprecated":null,"id":"each_quorum","note":null,"stability":null,"value":"each_quorum"},{"brief":null,"deprecated":null,"id":"quorum","note":null,"stability":null,"value":"quorum"},{"brief":null,"deprecated":null,"id":"local_quorum","note":null,"stability":null,"value":"local_quorum"},{"brief":null,"deprecated":null,"id":"one","note":null,"stability":null,"value":"one"},{"brief":null,"deprecated":null,"id":"two","note":null,"stability":null,"value":"two"},{"brief":null,"deprecated":null,"id":"three","note":null,"stability":null,"value":"three"},{"brief":null,"deprecated":null,"id":"local_one","note":null,"stability":null,"value":"local_one"},{"brief":null,"deprecated":null,"id":"any","note":null,"stability":null,"value":"any"},{"brief":null,"deprecated":null,"id":"serial","note":null,"stability":null,"value":"serial"},{"brief":null,"deprecated":null,"id":"local_serial","note":null,"stability":null,"value":"local_serial"}]}},{"brief":"The data center of the coordinating node for a query.\n","examples":"us-west-2","name":"db.cassandra.coordinator.dc","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The ID of the coordinating node for a query.\n","examples":"be13faa2-8574-4d71-926d-27f16cf8a7af","name":"db.cassandra.coordinator.id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"Whether or not the query is idempotent.\n","name":"db.cassandra.idempotence","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"boolean"},{"brief":"The fetch size used for paging, i.e. how many rows will be returned at once.\n","examples":[5000],"name":"db.cassandra.page_size","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The number of times a query was speculatively executed. Not set or `0` if the query was not executed speculatively.\n","examples":[0,2],"name":"db.cassandra.speculative_execution_count","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The name of the primary Cassandra table that the operation is acting upon, including the keyspace name (if applicable).","examples":"mytable","name":"db.cassandra.table","note":"This mirrors the db.sql.table attribute but references cassandra rather than sql. It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The connection string used to connect to the database. It is recommended to remove embedded credentials.\n","examples":"Server=(localdb)\\v11.0;Integrated Security=true;","name":"db.connection_string","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"Unique Cosmos client instance id.","examples":"3ba4827d-4422-483f-b59f-85b74211c11d","name":"db.cosmosdb.client_id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"Cosmos client connection mode.","name":"db.cosmosdb.connection_mode","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":false,"members":[{"brief":"Gateway (HTTP) connections mode","deprecated":null,"id":"gateway","note":null,"stability":null,"value":"gateway"},{"brief":"Direct connection.","deprecated":null,"id":"direct","note":null,"stability":null,"value":"direct"}]}},{"brief":"Cosmos DB container name.","examples":"anystring","name":"db.cosmosdb.container","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"CosmosDB Operation Type.","name":"db.cosmosdb.operation_type","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"invalid","note":null,"stability":null,"value":"Invalid"},{"brief":null,"deprecated":null,"id":"create","note":null,"stability":null,"value":"Create"},{"brief":null,"deprecated":null,"id":"patch","note":null,"stability":null,"value":"Patch"},{"brief":null,"deprecated":null,"id":"read","note":null,"stability":null,"value":"Read"},{"brief":null,"deprecated":null,"id":"read_feed","note":null,"stability":null,"value":"ReadFeed"},{"brief":null,"deprecated":null,"id":"delete","note":null,"stability":null,"value":"Delete"},{"brief":null,"deprecated":null,"id":"replace","note":null,"stability":null,"value":"Replace"},{"brief":null,"deprecated":null,"id":"execute","note":null,"stability":null,"value":"Execute"},{"brief":null,"deprecated":null,"id":"query","note":null,"stability":null,"value":"Query"},{"brief":null,"deprecated":null,"id":"head","note":null,"stability":null,"value":"Head"},{"brief":null,"deprecated":null,"id":"head_feed","note":null,"stability":null,"value":"HeadFeed"},{"brief":null,"deprecated":null,"id":"upsert","note":null,"stability":null,"value":"Upsert"},{"brief":null,"deprecated":null,"id":"batch","note":null,"stability":null,"value":"Batch"},{"brief":null,"deprecated":null,"id":"query_plan","note":null,"stability":null,"value":"QueryPlan"},{"brief":null,"deprecated":null,"id":"execute_javascript","note":null,"stability":null,"value":"ExecuteJavaScript"}]}},{"brief":"RU consumed for that operation","examples":[46.18,1.0],"name":"db.cosmosdb.request_charge","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"double"},{"brief":"Request payload size in bytes","name":"db.cosmosdb.request_content_length","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB status code.","examples":[200,201],"name":"db.cosmosdb.status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB sub status code.","examples":[1000,1002],"name":"db.cosmosdb.sub_status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Represents the identifier of an Elasticsearch cluster.\n","examples":["e9106fc68e3044f0b1475b04bf4ffd5f"],"name":"db.elasticsearch.cluster.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"Represents the human-readable identifier of the node/instance to which a request was routed.\n","examples":["instance-0000000001"],"name":"db.elasticsearch.node.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"A dynamic value in the url path.\n","examples":["db.elasticsearch.path_parts.index=test-index","db.elasticsearch.path_parts.doc_id=123"],"name":"db.elasticsearch.path_parts","note":"Many Elasticsearch url paths allow dynamic values. These SHOULD be recorded in span attributes in the format `db.elasticsearch.path_parts.\u003ckey\u003e`, where `\u003ckey\u003e` is the url path part name. The implementation SHOULD reference the [elasticsearch schema](https://raw.githubusercontent.com/elastic/elasticsearch-specification/main/output/schema/schema.json) in order to map the path part values to their names.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"template[string]"},{"brief":"An identifier (address, unique name, or any other identifier) of the database instance that is executing queries or mutations on the current connection. This is useful in cases where the database is running in a clustered environment and the instrumentation is able to record the node executing the query. The client may obtain this value in databases like MySQL using queries like `select @@hostname`.\n","examples":"mysql-e26b99z.example.com","name":"db.instance.id","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The fully-qualified class name of the [Java Database Connectivity (JDBC)](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/) driver used to connect.\n","examples":["org.postgresql.Driver","com.microsoft.sqlserver.jdbc.SQLServerDriver"],"name":"db.jdbc.driver_classname","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-jdbc","type":"string"},{"brief":"The MongoDB collection being accessed within the database stated in `db.name`.\n","examples":["customers","products"],"name":"db.mongodb.collection","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mongodb","type":"string"},{"brief":"The Microsoft SQL Server [instance name](https://docs.microsoft.com/sql/connect/jdbc/building-the-connection-url?view=sql-server-ver15) connecting to. This name is used to determine the port of a named instance.\n","examples":"MSSQLSERVER","name":"db.mssql.instance_name","note":"If setting a `db.mssql.instance_name`, `server.port` is no longer required (but still recommended if non-standard).\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mssql","type":"string"},{"brief":"This attribute is used to report the name of the database being accessed. For commands that switch the database, this should be set to the target database (even if the command fails).\n","examples":["customers","main"],"name":"db.name","note":"In some SQL databases, the database name to be used is called \"schema name\". In case there are multiple layers that could be considered for database name (e.g. Oracle instance name and schema name), the database name to be used is the more specific layer (e.g. Oracle schema name).\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The name of the operation being executed, e.g. the [MongoDB command name](https://docs.mongodb.com/manual/reference/command/#database-operations) such as `findAndModify`, or the SQL keyword.\n","examples":["findAndModify","HMSET","SELECT"],"name":"db.operation","note":"When setting this to an SQL keyword, it is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if the operation name is provided by the library being instrumented. If the SQL statement has an ambiguous operation, or performs more than one operation, this value may be omitted.\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The index of the database being accessed as used in the [`SELECT` command](https://redis.io/commands/select), provided as an integer. To be used instead of the generic `db.name` attribute.\n","examples":[0,1,15],"name":"db.redis.database_index","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-redis","type":"int"},{"brief":"The name of the primary table that the operation is acting upon, including the database name (if applicable).","examples":["public.users","customers"],"name":"db.sql.table","note":"It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-sql","type":"string"},{"brief":"The database statement being executed.\n","examples":["SELECT * FROM wuser_table","SET mykey \"WuValue\""],"name":"db.statement","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"An identifier for the database management system (DBMS) product being used. See below for a list of well-known identifiers.","name":"db.system","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":{"allow_custom_values":true,"members":[{"brief":"Some other SQL database. Fallback only. See notes.","deprecated":null,"id":"other_sql","note":null,"stability":null,"value":"other_sql"},{"brief":"Microsoft SQL Server","deprecated":null,"id":"mssql","note":null,"stability":null,"value":"mssql"},{"brief":"Microsoft SQL Server Compact","deprecated":null,"id":"mssqlcompact","note":null,"stability":null,"value":"mssqlcompact"},{"brief":"MySQL","deprecated":null,"id":"mysql","note":null,"stability":null,"value":"mysql"},{"brief":"Oracle Database","deprecated":null,"id":"oracle","note":null,"stability":null,"value":"oracle"},{"brief":"IBM Db2","deprecated":null,"id":"db2","note":null,"stability":null,"value":"db2"},{"brief":"PostgreSQL","deprecated":null,"id":"postgresql","note":null,"stability":null,"value":"postgresql"},{"brief":"Amazon Redshift","deprecated":null,"id":"redshift","note":null,"stability":null,"value":"redshift"},{"brief":"Apache Hive","deprecated":null,"id":"hive","note":null,"stability":null,"value":"hive"},{"brief":"Cloudscape","deprecated":null,"id":"cloudscape","note":null,"stability":null,"value":"cloudscape"},{"brief":"HyperSQL DataBase","deprecated":null,"id":"hsqldb","note":null,"stability":null,"value":"hsqldb"},{"brief":"Progress Database","deprecated":null,"id":"progress","note":null,"stability":null,"value":"progress"},{"brief":"SAP MaxDB","deprecated":null,"id":"maxdb","note":null,"stability":null,"value":"maxdb"},{"brief":"SAP HANA","deprecated":null,"id":"hanadb","note":null,"stability":null,"value":"hanadb"},{"brief":"Ingres","deprecated":null,"id":"ingres","note":null,"stability":null,"value":"ingres"},{"brief":"FirstSQL","deprecated":null,"id":"firstsql","note":null,"stability":null,"value":"firstsql"},{"brief":"EnterpriseDB","deprecated":null,"id":"edb","note":null,"stability":null,"value":"edb"},{"brief":"InterSystems Caché","deprecated":null,"id":"cache","note":null,"stability":null,"value":"cache"},{"brief":"Adabas (Adaptable Database System)","deprecated":null,"id":"adabas","note":null,"stability":null,"value":"adabas"},{"brief":"Firebird","deprecated":null,"id":"firebird","note":null,"stability":null,"value":"firebird"},{"brief":"Apache Derby","deprecated":null,"id":"derby","note":null,"stability":null,"value":"derby"},{"brief":"FileMaker","deprecated":null,"id":"filemaker","note":null,"stability":null,"value":"filemaker"},{"brief":"Informix","deprecated":null,"id":"informix","note":null,"stability":null,"value":"informix"},{"brief":"InstantDB","deprecated":null,"id":"instantdb","note":null,"stability":null,"value":"instantdb"},{"brief":"InterBase","deprecated":null,"id":"interbase","note":null,"stability":null,"value":"interbase"},{"brief":"MariaDB","deprecated":null,"id":"mariadb","note":null,"stability":null,"value":"mariadb"},{"brief":"Netezza","deprecated":null,"id":"netezza","note":null,"stability":null,"value":"netezza"},{"brief":"Pervasive PSQL","deprecated":null,"id":"pervasive","note":null,"stability":null,"value":"pervasive"},{"brief":"PointBase","deprecated":null,"id":"pointbase","note":null,"stability":null,"value":"pointbase"},{"brief":"SQLite","deprecated":null,"id":"sqlite","note":null,"stability":null,"value":"sqlite"},{"brief":"Sybase","deprecated":null,"id":"sybase","note":null,"stability":null,"value":"sybase"},{"brief":"Teradata","deprecated":null,"id":"teradata","note":null,"stability":null,"value":"teradata"},{"brief":"Vertica","deprecated":null,"id":"vertica","note":null,"stability":null,"value":"vertica"},{"brief":"H2","deprecated":null,"id":"h2","note":null,"stability":null,"value":"h2"},{"brief":"ColdFusion IMQ","deprecated":null,"id":"coldfusion","note":null,"stability":null,"value":"coldfusion"},{"brief":"Apache Cassandra","deprecated":null,"id":"cassandra","note":null,"stability":null,"value":"cassandra"},{"brief":"Apache HBase","deprecated":null,"id":"hbase","note":null,"stability":null,"value":"hbase"},{"brief":"MongoDB","deprecated":null,"id":"mongodb","note":null,"stability":null,"value":"mongodb"},{"brief":"Redis","deprecated":null,"id":"redis","note":null,"stability":null,"value":"redis"},{"brief":"Couchbase","deprecated":null,"id":"couchbase","note":null,"stability":null,"value":"couchbase"},{"brief":"CouchDB","deprecated":null,"id":"couchdb","note":null,"stability":null,"value":"couchdb"},{"brief":"Microsoft Azure Cosmos DB","deprecated":null,"id":"cosmosdb","note":null,"stability":null,"value":"cosmosdb"},{"brief":"Amazon DynamoDB","deprecated":null,"id":"dynamodb","note":null,"stability":null,"value":"dynamodb"},{"brief":"Neo4j","deprecated":null,"id":"neo4j","note":null,"stability":null,"value":"neo4j"},{"brief":"Apache Geode","deprecated":null,"id":"geode","note":null,"stability":null,"value":"geode"},{"brief":"Elasticsearch","deprecated":null,"id":"elasticsearch","note":null,"stability":null,"value":"elasticsearch"},{"brief":"Memcached","deprecated":null,"id":"memcached","note":null,"stability":null,"value":"memcached"},{"brief":"CockroachDB","deprecated":null,"id":"cockroachdb","note":null,"stability":null,"value":"cockroachdb"},{"brief":"OpenSearch","deprecated":null,"id":"opensearch","note":null,"stability":null,"value":"opensearch"},{"brief":"ClickHouse","deprecated":null,"id":"clickhouse","note":null,"stability":null,"value":"clickhouse"},{"brief":"Cloud Spanner","deprecated":null,"id":"spanner","note":null,"stability":null,"value":"spanner"},{"brief":"Trino","deprecated":null,"id":"trino","note":null,"stability":null,"value":"trino"}]}},{"brief":"Username for accessing the database.\n","examples":["readonly_user","reporting_user"],"name":"db.user","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"}],"root_namespace":"db"},{"attributes":[{"brief":"HTTP request headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.request.header.content-type=[\"application/json\"]","http.request.header.x-forwarded-for=[\"1.2.3.4\", \"1.2.3.5\"]"],"name":"http.request.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all request headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nThe `User-Agent` header is already captured in the `user_agent.original` attribute. Users MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"HTTP request method.","examples":["GET","POST","HEAD"],"name":"http.request.method","note":"HTTP request method value SHOULD be \"known\" to the instrumentation.\nBy default, this convention defines \"known\" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods)\nand the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html).\n\nIf the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`.\n\nIf the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override\nthe list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named\nOTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods\n(this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults).\n\nHTTP method names are case-sensitive and `http.request.method` attribute value MUST match a known HTTP method name exactly.\nInstrumentations for specific web frameworks that consider HTTP methods to be case insensitive, SHOULD populate a canonical equivalent.\nTracing instrumentations that do so, MUST also set `http.request.method_original` to the original value.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"CONNECT method.","deprecated":null,"id":"connect","note":null,"stability":null,"value":"CONNECT"},{"brief":"DELETE method.","deprecated":null,"id":"delete","note":null,"stability":null,"value":"DELETE"},{"brief":"GET method.","deprecated":null,"id":"get","note":null,"stability":null,"value":"GET"},{"brief":"HEAD method.","deprecated":null,"id":"head","note":null,"stability":null,"value":"HEAD"},{"brief":"OPTIONS method.","deprecated":null,"id":"options","note":null,"stability":null,"value":"OPTIONS"},{"brief":"PATCH method.","deprecated":null,"id":"patch","note":null,"stability":null,"value":"PATCH"},{"brief":"POST method.","deprecated":null,"id":"post","note":null,"stability":null,"value":"POST"},{"brief":"PUT method.","deprecated":null,"id":"put","note":null,"stability":null,"value":"PUT"},{"brief":"TRACE method.","deprecated":null,"id":"trace","note":null,"stability":null,"value":"TRACE"},{"brief":"Any HTTP method that the instrumentation has no prior knowledge of.","deprecated":null,"id":"other","note":null,"stability":null,"value":"_OTHER"}]}},{"brief":"Original HTTP method sent by the client in the request line.","examples":["GeT","ACL","foo"],"name":"http.request.method_original","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"},{"brief":"The ordinal number of request resending attempt (for any reason, including redirects).\n","examples":3,"name":"http.request.resend_count","note":"The resend count SHOULD be updated each time an HTTP request gets resent by the client, regardless of what was the cause of the resending (e.g. redirection, authorization failure, 503 Server Unavailable, network issues, or any other).\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"HTTP response headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.response.header.content-type=[\"application/json\"]","http.response.header.my-custom-header=[\"abc\", \"def\"]"],"name":"http.response.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all response headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nUsers MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"[HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6).","examples":[200],"name":"http.response.status_code","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"The matched route, that is, the path template in the format used by the respective server framework.\n","examples":["/users/:userID?","{controller}/{action}/{id?}"],"name":"http.route","note":"MUST NOT be populated when this is not supported by the HTTP server framework as the route attribute should have low-cardinality and the URI path can NOT substitute it.\nSHOULD include the [application root](/docs/http/http-spans.md#http-server-definitions) if there is one.","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"}],"root_namespace":"http"},{"attributes":[{"brief":"Value of the [HTTP User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) header sent by the client.\n","examples":["CERN-LineMode/2.15 libwww/2.17b3","Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1"],"name":"user_agent.original","requirement_level":"recommended","root_namespace":"user_agent","stability":"stable","type":"string"}],"root_namespace":"user_agent"}] \ No newline at end of file +[{"attributes":[{"brief":"The consistency level of the query. Based on consistency values from [CQL](https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/dml/dmlConfigConsistency.html).\n","name":"db.cassandra.consistency_level","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"all","note":null,"stability":null,"value":"all"},{"brief":null,"deprecated":null,"id":"each_quorum","note":null,"stability":null,"value":"each_quorum"},{"brief":null,"deprecated":null,"id":"quorum","note":null,"stability":null,"value":"quorum"},{"brief":null,"deprecated":null,"id":"local_quorum","note":null,"stability":null,"value":"local_quorum"},{"brief":null,"deprecated":null,"id":"one","note":null,"stability":null,"value":"one"},{"brief":null,"deprecated":null,"id":"two","note":null,"stability":null,"value":"two"},{"brief":null,"deprecated":null,"id":"three","note":null,"stability":null,"value":"three"},{"brief":null,"deprecated":null,"id":"local_one","note":null,"stability":null,"value":"local_one"},{"brief":null,"deprecated":null,"id":"any","note":null,"stability":null,"value":"any"},{"brief":null,"deprecated":null,"id":"serial","note":null,"stability":null,"value":"serial"},{"brief":null,"deprecated":null,"id":"local_serial","note":null,"stability":null,"value":"local_serial"}]}},{"brief":"The data center of the coordinating node for a query.\n","examples":"us-west-2","name":"db.cassandra.coordinator.dc","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The ID of the coordinating node for a query.\n","examples":"be13faa2-8574-4d71-926d-27f16cf8a7af","name":"db.cassandra.coordinator.id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"Whether or not the query is idempotent.\n","name":"db.cassandra.idempotence","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"boolean"},{"brief":"The fetch size used for paging, i.e. how many rows will be returned at once.\n","examples":[5000],"name":"db.cassandra.page_size","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The number of times a query was speculatively executed. Not set or `0` if the query was not executed speculatively.\n","examples":[0,2],"name":"db.cassandra.speculative_execution_count","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"int"},{"brief":"The name of the primary Cassandra table that the operation is acting upon, including the keyspace name (if applicable).","examples":"mytable","name":"db.cassandra.table","note":"This mirrors the db.sql.table attribute but references cassandra rather than sql. It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cassandra","type":"string"},{"brief":"The connection string used to connect to the database. It is recommended to remove embedded credentials.\n","examples":"Server=(localdb)\\v11.0;Integrated Security=true;","name":"db.connection_string","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"Unique Cosmos client instance id.","examples":"3ba4827d-4422-483f-b59f-85b74211c11d","name":"db.cosmosdb.client_id","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"Cosmos client connection mode.","name":"db.cosmosdb.connection_mode","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":false,"members":[{"brief":"Gateway (HTTP) connections mode","deprecated":null,"id":"gateway","note":null,"stability":null,"value":"gateway"},{"brief":"Direct connection.","deprecated":null,"id":"direct","note":null,"stability":null,"value":"direct"}]}},{"brief":"Cosmos DB container name.","examples":"anystring","name":"db.cosmosdb.container","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"string"},{"brief":"CosmosDB Operation Type.","name":"db.cosmosdb.operation_type","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":{"allow_custom_values":true,"members":[{"brief":null,"deprecated":null,"id":"invalid","note":null,"stability":null,"value":"Invalid"},{"brief":null,"deprecated":null,"id":"create","note":null,"stability":null,"value":"Create"},{"brief":null,"deprecated":null,"id":"patch","note":null,"stability":null,"value":"Patch"},{"brief":null,"deprecated":null,"id":"read","note":null,"stability":null,"value":"Read"},{"brief":null,"deprecated":null,"id":"read_feed","note":null,"stability":null,"value":"ReadFeed"},{"brief":null,"deprecated":null,"id":"delete","note":null,"stability":null,"value":"Delete"},{"brief":null,"deprecated":null,"id":"replace","note":null,"stability":null,"value":"Replace"},{"brief":null,"deprecated":null,"id":"execute","note":null,"stability":null,"value":"Execute"},{"brief":null,"deprecated":null,"id":"query","note":null,"stability":null,"value":"Query"},{"brief":null,"deprecated":null,"id":"head","note":null,"stability":null,"value":"Head"},{"brief":null,"deprecated":null,"id":"head_feed","note":null,"stability":null,"value":"HeadFeed"},{"brief":null,"deprecated":null,"id":"upsert","note":null,"stability":null,"value":"Upsert"},{"brief":null,"deprecated":null,"id":"batch","note":null,"stability":null,"value":"Batch"},{"brief":null,"deprecated":null,"id":"query_plan","note":null,"stability":null,"value":"QueryPlan"},{"brief":null,"deprecated":null,"id":"execute_javascript","note":null,"stability":null,"value":"ExecuteJavaScript"}]}},{"brief":"RU consumed for that operation","examples":[46.18,1.0],"name":"db.cosmosdb.request_charge","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"double"},{"brief":"Request payload size in bytes","name":"db.cosmosdb.request_content_length","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB status code.","examples":[200,201],"name":"db.cosmosdb.status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Cosmos DB sub status code.","examples":[1000,1002],"name":"db.cosmosdb.sub_status_code","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-cosmosdb","type":"int"},{"brief":"Represents the identifier of an Elasticsearch cluster.\n","examples":["e9106fc68e3044f0b1475b04bf4ffd5f"],"name":"db.elasticsearch.cluster.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"Represents the human-readable identifier of the node/instance to which a request was routed.\n","examples":["instance-0000000001"],"name":"db.elasticsearch.node.name","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"string"},{"brief":"A dynamic value in the url path.\n","examples":["db.elasticsearch.path_parts.index=test-index","db.elasticsearch.path_parts.doc_id=123"],"name":"db.elasticsearch.path_parts","note":"Many Elasticsearch url paths allow dynamic values. These SHOULD be recorded in span attributes in the format `db.elasticsearch.path_parts.\u003ckey\u003e`, where `\u003ckey\u003e` is the url path part name. The implementation SHOULD reference the [elasticsearch schema](https://raw.githubusercontent.com/elastic/elasticsearch-specification/main/output/schema/schema.json) in order to map the path part values to their names.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-elasticsearch","type":"template[string]"},{"brief":"An identifier (address, unique name, or any other identifier) of the database instance that is executing queries or mutations on the current connection. This is useful in cases where the database is running in a clustered environment and the instrumentation is able to record the node executing the query. The client may obtain this value in databases like MySQL using queries like `select @@hostname`.\n","examples":"mysql-e26b99z.example.com","name":"db.instance.id","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The fully-qualified class name of the [Java Database Connectivity (JDBC)](https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/) driver used to connect.\n","examples":["org.postgresql.Driver","com.microsoft.sqlserver.jdbc.SQLServerDriver"],"name":"db.jdbc.driver_classname","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-jdbc","type":"string"},{"brief":"The MongoDB collection being accessed within the database stated in `db.name`.\n","examples":["customers","products"],"name":"db.mongodb.collection","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mongodb","type":"string"},{"brief":"The Microsoft SQL Server [instance name](https://docs.microsoft.com/sql/connect/jdbc/building-the-connection-url?view=sql-server-ver15) connecting to. This name is used to determine the port of a named instance.\n","examples":"MSSQLSERVER","name":"db.mssql.instance_name","note":"If setting a `db.mssql.instance_name`, `server.port` is no longer required (but still recommended if non-standard).\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-mssql","type":"string"},{"brief":"This attribute is used to report the name of the database being accessed. For commands that switch the database, this should be set to the target database (even if the command fails).\n","examples":["customers","main"],"name":"db.name","note":"In some SQL databases, the database name to be used is called \"schema name\". In case there are multiple layers that could be considered for database name (e.g. Oracle instance name and schema name), the database name to be used is the more specific layer (e.g. Oracle schema name).\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The name of the operation being executed, e.g. the [MongoDB command name](https://docs.mongodb.com/manual/reference/command/#database-operations) such as `findAndModify`, or the SQL keyword.\n","examples":["findAndModify","HMSET","SELECT"],"name":"db.operation","note":"When setting this to an SQL keyword, it is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if the operation name is provided by the library being instrumented. If the SQL statement has an ambiguous operation, or performs more than one operation, this value may be omitted.\n","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"The index of the database being accessed as used in the [`SELECT` command](https://redis.io/commands/select), provided as an integer. To be used instead of the generic `db.name` attribute.\n","examples":[0,1,15],"name":"db.redis.database_index","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-redis","type":"int"},{"brief":"The name of the primary table that the operation is acting upon, including the database name (if applicable).","examples":["public.users","customers"],"name":"db.sql.table","note":"It is not recommended to attempt any client-side parsing of `db.statement` just to get this property, but it should be set if it is provided by the library being instrumented. If the operation is acting upon an anonymous table, or more than one table, this value MUST NOT be set.\n","requirement_level":"recommended","root_namespace":"db","tag":"tech-specific-sql","type":"string"},{"brief":"The database statement being executed.\n","examples":["SELECT * FROM wuser_table","SET mykey \"WuValue\""],"name":"db.statement","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"},{"brief":"An identifier for the database management system (DBMS) product being used. See below for a list of well-known identifiers.","name":"db.system","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":{"allow_custom_values":true,"members":[{"brief":"Some other SQL database. Fallback only. See notes.","deprecated":null,"id":"other_sql","note":null,"stability":null,"value":"other_sql"},{"brief":"Microsoft SQL Server","deprecated":null,"id":"mssql","note":null,"stability":null,"value":"mssql"},{"brief":"Microsoft SQL Server Compact","deprecated":null,"id":"mssqlcompact","note":null,"stability":null,"value":"mssqlcompact"},{"brief":"MySQL","deprecated":null,"id":"mysql","note":null,"stability":null,"value":"mysql"},{"brief":"Oracle Database","deprecated":null,"id":"oracle","note":null,"stability":null,"value":"oracle"},{"brief":"IBM Db2","deprecated":null,"id":"db2","note":null,"stability":null,"value":"db2"},{"brief":"PostgreSQL","deprecated":null,"id":"postgresql","note":null,"stability":null,"value":"postgresql"},{"brief":"Amazon Redshift","deprecated":null,"id":"redshift","note":null,"stability":null,"value":"redshift"},{"brief":"Apache Hive","deprecated":null,"id":"hive","note":null,"stability":null,"value":"hive"},{"brief":"Cloudscape","deprecated":null,"id":"cloudscape","note":null,"stability":null,"value":"cloudscape"},{"brief":"HyperSQL DataBase","deprecated":null,"id":"hsqldb","note":null,"stability":null,"value":"hsqldb"},{"brief":"Progress Database","deprecated":null,"id":"progress","note":null,"stability":null,"value":"progress"},{"brief":"SAP MaxDB","deprecated":null,"id":"maxdb","note":null,"stability":null,"value":"maxdb"},{"brief":"SAP HANA","deprecated":null,"id":"hanadb","note":null,"stability":null,"value":"hanadb"},{"brief":"Ingres","deprecated":null,"id":"ingres","note":null,"stability":null,"value":"ingres"},{"brief":"FirstSQL","deprecated":null,"id":"firstsql","note":null,"stability":null,"value":"firstsql"},{"brief":"EnterpriseDB","deprecated":null,"id":"edb","note":null,"stability":null,"value":"edb"},{"brief":"InterSystems Caché","deprecated":null,"id":"cache","note":null,"stability":null,"value":"cache"},{"brief":"Adabas (Adaptable Database System)","deprecated":null,"id":"adabas","note":null,"stability":null,"value":"adabas"},{"brief":"Firebird","deprecated":null,"id":"firebird","note":null,"stability":null,"value":"firebird"},{"brief":"Apache Derby","deprecated":null,"id":"derby","note":null,"stability":null,"value":"derby"},{"brief":"FileMaker","deprecated":null,"id":"filemaker","note":null,"stability":null,"value":"filemaker"},{"brief":"Informix","deprecated":null,"id":"informix","note":null,"stability":null,"value":"informix"},{"brief":"InstantDB","deprecated":null,"id":"instantdb","note":null,"stability":null,"value":"instantdb"},{"brief":"InterBase","deprecated":null,"id":"interbase","note":null,"stability":null,"value":"interbase"},{"brief":"MariaDB","deprecated":null,"id":"mariadb","note":null,"stability":null,"value":"mariadb"},{"brief":"Netezza","deprecated":null,"id":"netezza","note":null,"stability":null,"value":"netezza"},{"brief":"Pervasive PSQL","deprecated":null,"id":"pervasive","note":null,"stability":null,"value":"pervasive"},{"brief":"PointBase","deprecated":null,"id":"pointbase","note":null,"stability":null,"value":"pointbase"},{"brief":"SQLite","deprecated":null,"id":"sqlite","note":null,"stability":null,"value":"sqlite"},{"brief":"Sybase","deprecated":null,"id":"sybase","note":null,"stability":null,"value":"sybase"},{"brief":"Teradata","deprecated":null,"id":"teradata","note":null,"stability":null,"value":"teradata"},{"brief":"Vertica","deprecated":null,"id":"vertica","note":null,"stability":null,"value":"vertica"},{"brief":"H2","deprecated":null,"id":"h2","note":null,"stability":null,"value":"h2"},{"brief":"ColdFusion IMQ","deprecated":null,"id":"coldfusion","note":null,"stability":null,"value":"coldfusion"},{"brief":"Apache Cassandra","deprecated":null,"id":"cassandra","note":null,"stability":null,"value":"cassandra"},{"brief":"Apache HBase","deprecated":null,"id":"hbase","note":null,"stability":null,"value":"hbase"},{"brief":"MongoDB","deprecated":null,"id":"mongodb","note":null,"stability":null,"value":"mongodb"},{"brief":"Redis","deprecated":null,"id":"redis","note":null,"stability":null,"value":"redis"},{"brief":"Couchbase","deprecated":null,"id":"couchbase","note":null,"stability":null,"value":"couchbase"},{"brief":"CouchDB","deprecated":null,"id":"couchdb","note":null,"stability":null,"value":"couchdb"},{"brief":"Microsoft Azure Cosmos DB","deprecated":null,"id":"cosmosdb","note":null,"stability":null,"value":"cosmosdb"},{"brief":"Amazon DynamoDB","deprecated":null,"id":"dynamodb","note":null,"stability":null,"value":"dynamodb"},{"brief":"Neo4j","deprecated":null,"id":"neo4j","note":null,"stability":null,"value":"neo4j"},{"brief":"Apache Geode","deprecated":null,"id":"geode","note":null,"stability":null,"value":"geode"},{"brief":"Elasticsearch","deprecated":null,"id":"elasticsearch","note":null,"stability":null,"value":"elasticsearch"},{"brief":"Memcached","deprecated":null,"id":"memcached","note":null,"stability":null,"value":"memcached"},{"brief":"CockroachDB","deprecated":null,"id":"cockroachdb","note":null,"stability":null,"value":"cockroachdb"},{"brief":"OpenSearch","deprecated":null,"id":"opensearch","note":null,"stability":null,"value":"opensearch"},{"brief":"ClickHouse","deprecated":null,"id":"clickhouse","note":null,"stability":null,"value":"clickhouse"},{"brief":"Cloud Spanner","deprecated":null,"id":"spanner","note":null,"stability":null,"value":"spanner"},{"brief":"Trino","deprecated":null,"id":"trino","note":null,"stability":null,"value":"trino"}]}},{"brief":"Username for accessing the database.\n","examples":["readonly_user","reporting_user"],"name":"db.user","requirement_level":"recommended","root_namespace":"db","tag":"db-generic","type":"string"}],"root_namespace":"db"},{"attributes":[{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"boolean"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"string"},{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"string"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":"recommended","root_namespace":"exception","stability":"stable","type":"string"}],"root_namespace":"exception"},{"attributes":[{"brief":"HTTP request headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.request.header.content-type=[\"application/json\"]","http.request.header.x-forwarded-for=[\"1.2.3.4\", \"1.2.3.5\"]"],"name":"http.request.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all request headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nThe `User-Agent` header is already captured in the `user_agent.original` attribute. Users MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"HTTP request method.","examples":["GET","POST","HEAD"],"name":"http.request.method","note":"HTTP request method value SHOULD be \"known\" to the instrumentation.\nBy default, this convention defines \"known\" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods)\nand the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html).\n\nIf the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`.\n\nIf the HTTP instrumentation could end up converting valid HTTP request methods to `_OTHER`, then it MUST provide a way to override\nthe list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named\nOTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods\n(this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults).\n\nHTTP method names are case-sensitive and `http.request.method` attribute value MUST match a known HTTP method name exactly.\nInstrumentations for specific web frameworks that consider HTTP methods to be case insensitive, SHOULD populate a canonical equivalent.\nTracing instrumentations that do so, MUST also set `http.request.method_original` to the original value.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":{"allow_custom_values":true,"members":[{"brief":"CONNECT method.","deprecated":null,"id":"connect","note":null,"stability":null,"value":"CONNECT"},{"brief":"DELETE method.","deprecated":null,"id":"delete","note":null,"stability":null,"value":"DELETE"},{"brief":"GET method.","deprecated":null,"id":"get","note":null,"stability":null,"value":"GET"},{"brief":"HEAD method.","deprecated":null,"id":"head","note":null,"stability":null,"value":"HEAD"},{"brief":"OPTIONS method.","deprecated":null,"id":"options","note":null,"stability":null,"value":"OPTIONS"},{"brief":"PATCH method.","deprecated":null,"id":"patch","note":null,"stability":null,"value":"PATCH"},{"brief":"POST method.","deprecated":null,"id":"post","note":null,"stability":null,"value":"POST"},{"brief":"PUT method.","deprecated":null,"id":"put","note":null,"stability":null,"value":"PUT"},{"brief":"TRACE method.","deprecated":null,"id":"trace","note":null,"stability":null,"value":"TRACE"},{"brief":"Any HTTP method that the instrumentation has no prior knowledge of.","deprecated":null,"id":"other","note":null,"stability":null,"value":"_OTHER"}]}},{"brief":"Original HTTP method sent by the client in the request line.","examples":["GeT","ACL","foo"],"name":"http.request.method_original","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"},{"brief":"The ordinal number of request resending attempt (for any reason, including redirects).\n","examples":3,"name":"http.request.resend_count","note":"The resend count SHOULD be updated each time an HTTP request gets resent by the client, regardless of what was the cause of the resending (e.g. redirection, authorization failure, 503 Server Unavailable, network issues, or any other).\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"HTTP response headers, `\u003ckey\u003e` being the normalized HTTP Header name (lowercase), the value being the header values.\n","examples":["http.response.header.content-type=[\"application/json\"]","http.response.header.my-custom-header=[\"abc\", \"def\"]"],"name":"http.response.header","note":"Instrumentations SHOULD require an explicit configuration of which headers are to be captured. Including all response headers can be a security risk - explicit configuration helps avoid leaking sensitive information.\nUsers MAY explicitly configure instrumentations to capture them even though it is not recommended.\nThe attribute value MUST consist of either multiple header values as an array of strings or a single-item array containing a possibly comma-concatenated string, depending on the way the HTTP library provides access to headers.\n","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"template[string[]]"},{"brief":"[HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6).","examples":[200],"name":"http.response.status_code","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"int"},{"brief":"The matched route, that is, the path template in the format used by the respective server framework.\n","examples":["/users/:userID?","{controller}/{action}/{id?}"],"name":"http.route","note":"MUST NOT be populated when this is not supported by the HTTP server framework as the route attribute should have low-cardinality and the URI path can NOT substitute it.\nSHOULD include the [application root](/docs/http/http-spans.md#http-server-definitions) if there is one.","requirement_level":"recommended","root_namespace":"http","stability":"stable","type":"string"}],"root_namespace":"http"},{"attributes":[{"brief":"Value of the [HTTP User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) header sent by the client.\n","examples":["CERN-LineMode/2.15 libwww/2.17b3","Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1"],"name":"user_agent.original","requirement_level":"recommended","root_namespace":"user_agent","stability":"stable","type":"string"}],"root_namespace":"user_agent"}] \ No newline at end of file diff --git a/crates/weaver_forge/expected_output/test/attribute_group/exception.md b/crates/weaver_forge/expected_output/test/attribute_group/exception.md new file mode 100644 index 00000000..005f1c33 --- /dev/null +++ b/crates/weaver_forge/expected_output/test/attribute_group/exception.md @@ -0,0 +1,79 @@ +## Namespace `exception` + +### Attributes + + +#### Attribute `exception.escaped` + +SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span. + + +An exception is considered to have escaped (or left) the scope of a span, +if that span is ended while the exception is still logically "in flight". +This may be actually "in flight" in some languages (e.g. if the exception +is passed to a Context manager's `__exit__` method in Python) but will +usually be caught at the point of recording the exception in most languages. + +It is usually not possible to determine at the point where an exception is thrown +whether it will escape the scope of a span. +However, it is trivial to know that an exception +will escape, if one checks for an active exception just before ending the span, +as done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception). + +It follows that an exception may still escape the scope of the span +even if the `exception.escaped` attribute was not set or set to false, +since the event might have been recorded at a time where it was not +clear whether the exception will escape. + +- Requirement Level: Recommended + +- Type: boolean + +- Stability: Stable + + +#### Attribute `exception.message` + +The exception message. + + +- Requirement Level: Recommended + +- Type: string +- Examples: [ + "Division by zero", + "Can't convert 'int' object to str implicitly", +] + +- Stability: Stable + + +#### Attribute `exception.stacktrace` + +A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG. + + +- Requirement Level: Recommended + +- Type: string +- Examples: Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5) + +- Stability: Stable + + +#### Attribute `exception.type` + +The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it. + + +- Requirement Level: Recommended + +- Type: string +- Examples: [ + "java.net.ConnectException", + "OSError", +] + +- Stability: Stable + + \ No newline at end of file diff --git a/crates/weaver_forge/expected_output/test/attribute_groups.md b/crates/weaver_forge/expected_output/test/attribute_groups.md index e831b7ca..e48c279f 100644 --- a/crates/weaver_forge/expected_output/test/attribute_groups.md +++ b/crates/weaver_forge/expected_output/test/attribute_groups.md @@ -472,6 +472,89 @@ Username for accessing the database. +## Namespace `exception` + +### Attributes + + +#### Attribute `exception.escaped` + +SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span. + + + +An exception is considered to have escaped (or left) the scope of a span, +if that span is ended while the exception is still logically "in flight". +This may be actually "in flight" in some languages (e.g. if the exception +is passed to a Context manager's `__exit__` method in Python) but will +usually be caught at the point of recording the exception in most languages. + +It is usually not possible to determine at the point where an exception is thrown +whether it will escape the scope of a span. +However, it is trivial to know that an exception +will escape, if one checks for an active exception just before ending the span, +as done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception). + +It follows that an exception may still escape the scope of the span +even if the `exception.escaped` attribute was not set or set to false, +since the event might have been recorded at a time where it was not +clear whether the exception will escape. + +- Requirement Level: Recommended + +- Type: boolean + +- Stability: Stable + + +#### Attribute `exception.message` + +The exception message. + + +- Requirement Level: Recommended + +- Type: string +- Examples: [ + "Division by zero", + "Can't convert 'int' object to str implicitly", +] + +- Stability: Stable + + +#### Attribute `exception.stacktrace` + +A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG. + + + +- Requirement Level: Recommended + +- Type: string +- Examples: Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5) + +- Stability: Stable + + +#### Attribute `exception.type` + +The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it. + + + +- Requirement Level: Recommended + +- Type: string +- Examples: [ + "java.net.ConnectException", + "OSError", +] + +- Stability: Stable + + + ## Namespace `http` ### Attributes diff --git a/crates/weaver_forge/expected_output/test/event/device_app.md b/crates/weaver_forge/expected_output/test/event/device_app.md new file mode 100644 index 00000000..aee2a21d --- /dev/null +++ b/crates/weaver_forge/expected_output/test/event/device_app.md @@ -0,0 +1,16 @@ +## Events Namespace `device.app` + + +## Event `device.app.lifecycle` + +Note: This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive. + +Brief: This event represents an occurrence of a lifecycle transition on Android or iOS platform. + +Requirement level: +Stability: experimental + +### Attributes + + + \ No newline at end of file diff --git a/crates/weaver_forge/expected_output/test/event/lifecycle.md b/crates/weaver_forge/expected_output/test/event/lifecycle.md deleted file mode 100644 index 456ecbc5..00000000 --- a/crates/weaver_forge/expected_output/test/event/lifecycle.md +++ /dev/null @@ -1,57 +0,0 @@ -## Events Namespace `lifecycle` - - -## Event `device.app.lifecycle` - -Note: -Brief: This event represents an occurrence of a lifecycle transition on the iOS platform. - -Requirement level: -Stability: - -### Attributes - - -#### Attribute `ios.state` - -This attribute represents the state the application has transitioned into at the occurrence of the event. - - - -The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived. - -- Requirement Level: Required - -- Type: Enum [active, inactive, background, foreground, terminate] - -- Stability: Experimental - - - -## Event `device.app.lifecycle` - -Note: -Brief: This event represents an occurrence of a lifecycle transition on the Android platform. - -Requirement level: -Stability: - -### Attributes - - -#### Attribute `android.state` - -This attribute represents the state the application has transitioned into at the occurrence of the event. - - - -The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived. - -- Requirement Level: Required - -- Type: Enum [created, background, foreground] - -- Stability: Experimental - - - \ No newline at end of file diff --git a/crates/weaver_forge/expected_output/test/event/other.md b/crates/weaver_forge/expected_output/test/event/other.md new file mode 100644 index 00000000..98a1a84e --- /dev/null +++ b/crates/weaver_forge/expected_output/test/event/other.md @@ -0,0 +1,92 @@ +## Events Namespace `other` + + +## Event `trace-exception` + +Note: +Brief: This document defines the attributes used to report a single exception associated with a span. + +Requirement level: +Stability: + +### Attributes + + +#### Attribute `exception.stacktrace` + +A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG. + + + +- Requirement Level: Recommended + +- Type: string +- Examples: Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5) + +- Stability: Stable + + +#### Attribute `exception.escaped` + +SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span. + + + +An exception is considered to have escaped (or left) the scope of a span, +if that span is ended while the exception is still logically "in flight". +This may be actually "in flight" in some languages (e.g. if the exception +is passed to a Context manager's `__exit__` method in Python) but will +usually be caught at the point of recording the exception in most languages. + +It is usually not possible to determine at the point where an exception is thrown +whether it will escape the scope of a span. +However, it is trivial to know that an exception +will escape, if one checks for an active exception just before ending the span, +as done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception). + +It follows that an exception may still escape the scope of the span +even if the `exception.escaped` attribute was not set or set to false, +since the event might have been recorded at a time where it was not +clear whether the exception will escape. + +- Requirement Level: Recommended + +- Type: boolean + +- Stability: Stable + + +#### Attribute `exception.type` + +The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it. + + + +- Requirement Level: Conditionally Required - Required if `exception.message` is not set, recommended otherwise. + +- Type: string +- Examples: [ + "java.net.ConnectException", + "OSError", +] + +- Stability: Stable + + +#### Attribute `exception.message` + +The exception message. + + +- Requirement Level: Conditionally Required - Required if `exception.type` is not set, recommended otherwise. + +- Type: string +- Examples: [ + "Division by zero", + "Can't convert 'int' object to str implicitly", +] + +- Stability: Stable + + + \ No newline at end of file diff --git a/crates/weaver_forge/expected_output/test/events.md b/crates/weaver_forge/expected_output/test/events.md index 3f6033f1..75e2d7fe 100644 --- a/crates/weaver_forge/expected_output/test/events.md +++ b/crates/weaver_forge/expected_output/test/events.md @@ -1,11 +1,28 @@ -# Events Namespace `lifecycle` +# Events Namespace `device.app` ## Event `device.app.lifecycle` +Note: This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive. + +Brief: This event represents an occurrence of a lifecycle transition on Android or iOS platform. + +Requirement level: +Stability: experimental + +### Attributes + + + + +# Events Namespace `other` + + +## Event `trace-exception` + Note: -Brief: This event represents an occurrence of a lifecycle transition on the iOS platform. +Brief: This document defines the attributes used to report a single exception associated with a span. Requirement level: Stability: @@ -13,46 +30,81 @@ Stability: ### Attributes -#### Attribute `ios.state` +#### Attribute `exception.stacktrace` -This attribute represents the state the application has transitioned into at the occurrence of the event. +A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG. -The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived. - -- Requirement Level: Required - -- Type: Enum [active, inactive, background, foreground, terminate] +- Requirement Level: Recommended -- Stability: Experimental +- Type: string +- Examples: Exception in thread "main" java.lang.RuntimeException: Test exception\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n at com.example.GenerateTrace.main(GenerateTrace.java:5) +- Stability: Stable -## Event `device.app.lifecycle` +#### Attribute `exception.escaped` -Note: -Brief: This event represents an occurrence of a lifecycle transition on the Android platform. +SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span. -Requirement level: -Stability: -### Attributes +An exception is considered to have escaped (or left) the scope of a span, +if that span is ended while the exception is still logically "in flight". +This may be actually "in flight" in some languages (e.g. if the exception +is passed to a Context manager's `__exit__` method in Python) but will +usually be caught at the point of recording the exception in most languages. + +It is usually not possible to determine at the point where an exception is thrown +whether it will escape the scope of a span. +However, it is trivial to know that an exception +will escape, if one checks for an active exception just before ending the span, +as done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception). -#### Attribute `android.state` +It follows that an exception may still escape the scope of the span +even if the `exception.escaped` attribute was not set or set to false, +since the event might have been recorded at a time where it was not +clear whether the exception will escape. -This attribute represents the state the application has transitioned into at the occurrence of the event. +- Requirement Level: Recommended + +- Type: boolean + +- Stability: Stable + + +#### Attribute `exception.type` +The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it. + + + +- Requirement Level: Conditionally Required - Required if `exception.message` is not set, recommended otherwise. + +- Type: string +- Examples: [ + "java.net.ConnectException", + "OSError", +] + +- Stability: Stable + + +#### Attribute `exception.message` +The exception message. -The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived. -- Requirement Level: Required +- Requirement Level: Conditionally Required - Required if `exception.type` is not set, recommended otherwise. -- Type: Enum [created, background, foreground] +- Type: string +- Examples: [ + "Division by zero", + "Can't convert 'int' object to str implicitly", +] -- Stability: Experimental +- Stability: Stable diff --git a/crates/weaver_forge/expected_output/test/registry.md b/crates/weaver_forge/expected_output/test/registry.md index e26e8cc5..e362df68 100644 --- a/crates/weaver_forge/expected_output/test/registry.md +++ b/crates/weaver_forge/expected_output/test/registry.md @@ -4,6 +4,7 @@ Url: # Attribute Groups +- [registry.exception](attribute_group/registry_exception.md) - [attributes.jvm.memory](attribute_group/attributes_jvm_memory.md) - [registry.db](attribute_group/registry_db.md) - [registry.http](attribute_group/registry_http.md) @@ -14,8 +15,8 @@ Url: # Events -- [ios.lifecycle.events](event/ios_lifecycle_events.md) -- [android.lifecycle.events](event/android_lifecycle_events.md) +- [device.app.lifecycle](event/device_app_lifecycle.md) +- [trace-exception](event/trace_exception.md) # Metrics diff --git a/crates/weaver_forge/expected_output/whitespace_control/registry.md b/crates/weaver_forge/expected_output/whitespace_control/registry.md index e2d11600..d1f6bb78 100644 --- a/crates/weaver_forge/expected_output/whitespace_control/registry.md +++ b/crates/weaver_forge/expected_output/whitespace_control/registry.md @@ -4,6 +4,7 @@ Url: ## Attribute Groups +- [registry.exception](attribute_group/registry_exception.md) - [attributes.jvm.memory](attribute_group/attributes_jvm_memory.md) - [registry.db](attribute_group/registry_db.md) - [registry.http](attribute_group/registry_http.md) @@ -14,8 +15,8 @@ Url: ## Events -- [ios.lifecycle.events](event/ios_lifecycle_events.md) -- [android.lifecycle.events](event/android_lifecycle_events.md) +- [device.app.lifecycle](event/device_app_lifecycle.md) +- [trace-exception](event/trace_exception.md) ## Metrics diff --git a/crates/weaver_forge/src/registry.rs b/crates/weaver_forge/src/registry.rs index 07cc629d..56e73a6c 100644 --- a/crates/weaver_forge/src/registry.rs +++ b/crates/weaver_forge/src/registry.rs @@ -8,6 +8,7 @@ use crate::error::Error; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use weaver_resolved_schema::attribute::Attribute; +use weaver_resolved_schema::body::Body; use weaver_resolved_schema::catalog::Catalog; use weaver_resolved_schema::lineage::GroupLineage; use weaver_resolved_schema::registry::{Constraint, Group, Registry}; @@ -104,6 +105,9 @@ pub struct ResolvedGroup { /// The readable name for attribute groups used when generating registry tables. #[serde(skip_serializing_if = "Option::is_none")] pub display_name: Option, + /// The body specification used for event semantic conventions. + #[serde(skip_serializing_if = "Option::is_none")] + pub body: Option, } impl ResolvedGroup { @@ -134,6 +138,7 @@ impl ResolvedGroup { }) .collect(); let lineage = group.lineage.clone(); + if !errors.is_empty() { return Err(Error::CompoundError(errors)); } @@ -156,6 +161,7 @@ impl ResolvedGroup { name: group.name.clone(), lineage, display_name: group.display_name.clone(), + body: group.body.clone(), }) } } @@ -196,6 +202,7 @@ impl ResolvedRegistry { }) .collect(); let lineage = group.lineage.clone(); + ResolvedGroup { id, r#type: group_type, @@ -215,6 +222,7 @@ impl ResolvedRegistry { name: group.name.clone(), lineage, display_name: group.display_name.clone(), + body: group.body.clone(), } }) .collect(); diff --git a/crates/weaver_forge/templates/semconv_jq_fn/semconv_events.json b/crates/weaver_forge/templates/semconv_jq_fn/semconv_events.json new file mode 100644 index 00000000..760f1e67 --- /dev/null +++ b/crates/weaver_forge/templates/semconv_jq_fn/semconv_events.json @@ -0,0 +1 @@ +{{ ctx | tojson }} \ No newline at end of file diff --git a/crates/weaver_forge/templates/semconv_jq_fn/weaver.yaml b/crates/weaver_forge/templates/semconv_jq_fn/weaver.yaml index bd76963c..387094cc 100644 --- a/crates/weaver_forge/templates/semconv_jq_fn/weaver.yaml +++ b/crates/weaver_forge/templates/semconv_jq_fn/weaver.yaml @@ -20,3 +20,12 @@ templates: filter: > semconv_grouped_metrics({"exclude_stability": ["experimental"]}) application_mode: single + - pattern: semconv_events.json + filter: > + .groups + | map(select(.type == "event")) + | map(. + { + event_namespace: (if .id | index(".") then (.id | split(".") | .[0:-1] | join(".")) else "other" end) + }) + | sort_by(.event_namespace, .id) + application_mode: single diff --git a/crates/weaver_forge/templates/test/event.md b/crates/weaver_forge/templates/test/event.md index b15e5680..c4bebd2b 100644 --- a/crates/weaver_forge/templates/test/event.md +++ b/crates/weaver_forge/templates/test/event.md @@ -1,10 +1,10 @@ -{%- set file_name = ctx.root_namespace | snake_case -%} +{%- set file_name = ctx.event_namespace | snake_case -%} {{- template.set_file_name("event/" ~ file_name ~ ".md") -}} -## Events Namespace `{{ ctx.root_namespace }}` +## Events Namespace `{{ ctx.event_namespace }}` {% for event in ctx.events %} -## Event `{{ event.name }}` +## Event `{{ event.id }}` Note: {{ event.note }} Brief: {{ event.brief }} diff --git a/crates/weaver_forge/templates/test/events.md b/crates/weaver_forge/templates/test/events.md index d8bba381..ac4d85cb 100644 --- a/crates/weaver_forge/templates/test/events.md +++ b/crates/weaver_forge/templates/test/events.md @@ -1,8 +1,8 @@ {% for grouped_events in ctx %} -# Events Namespace `{{ grouped_events.root_namespace }}` +# Events Namespace `{{ grouped_events.event_namespace }}` {% for event in grouped_events.events %} -## Event `{{ event.name }}` +## Event `{{ event.id }}` Note: {{ event.note }} Brief: {{ event.brief }} diff --git a/crates/weaver_forge/templates/test/weaver.yaml b/crates/weaver_forge/templates/test/weaver.yaml index 228b389a..6f036fa4 100644 --- a/crates/weaver_forge/templates/test/weaver.yaml +++ b/crates/weaver_forge/templates/test/weaver.yaml @@ -28,15 +28,25 @@ templates: application_mode: single - template: "**/event.md" filter: > - semconv_signal("event"; {}) - | group_by(.root_namespace) - | map({ root_namespace: .[0].root_namespace, events: . | sort_by(.name) }) + .groups + | map(select(.type == "event")) + | map(. + { + event_namespace: (if .id | index(".") then (.id | split(".") | .[0:-1] | join(".")) else "other" end) + }) + | sort_by(.event_namespace, .id) + | group_by(.event_namespace) + | map({ event_namespace: .[0].event_namespace, events: . | sort_by(.id) }) application_mode: each - template: "**/events.md" filter: > - semconv_signal("event"; {}) - | group_by(.root_namespace) - | map({ root_namespace: .[0].root_namespace, events: . | sort_by(.name) }) + .groups + | map(select(.type == "event")) + | map(. + { + event_namespace: (if .id | index(".") then (.id | split(".") | .[0:-1] | join(".")) else "other" end) + }) + | sort_by(.event_namespace, .id) + | group_by(.event_namespace) + | map({ event_namespace: .[0].event_namespace, events: . | sort_by(.id) }) application_mode: single - template: "**/metric.md" filter: semconv_grouped_metrics diff --git a/crates/weaver_resolved_schema/src/attribute.rs b/crates/weaver_resolved_schema/src/attribute.rs index 8326a9c1..42b75c35 100644 --- a/crates/weaver_resolved_schema/src/attribute.rs +++ b/crates/weaver_resolved_schema/src/attribute.rs @@ -91,7 +91,7 @@ pub struct UnresolvedAttribute { /// An internal reference to an attribute in the catalog. #[derive( - Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, JsonSchema, + Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, JsonSchema, )] pub struct AttributeRef(pub u32); diff --git a/crates/weaver_resolved_schema/src/body.rs b/crates/weaver_resolved_schema/src/body.rs new file mode 100644 index 00000000..3595b8d7 --- /dev/null +++ b/crates/weaver_resolved_schema/src/body.rs @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: Apache-2.0 + +#![allow(rustdoc::invalid_html_tags)] + +//! Specification of a resolved `BodyField`. + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use weaver_semconv::attribute::{AttributeType, Examples, RequirementLevel}; +use weaver_semconv::body::{BodyFieldSpec, BodySpec}; +use weaver_semconv::stability::Stability; + +/// A `Body` definition. +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] +#[serde(deny_unknown_fields)] +pub struct Body { + /// The body specification. + #[serde(skip_serializing_if = "Option::is_none")] + pub fields: Option>, + // Not yet defined in the spec or implemented in the resolver + // The body value when there are no fields + // #[serde(skip_serializing_if = "Option::is_none")] + // pub value: Option +} + +/// A `BodyField` definition. +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] +#[serde(deny_unknown_fields)] +pub struct BodyField { + /// Field name. + pub name: String, + /// Either a string literal denoting the type as a primitive or an + /// array type, a template type or an enum definition. + pub r#type: AttributeType, + /// A brief description of the field. + #[serde(skip_serializing_if = "String::is_empty")] + pub brief: String, + /// Sequence of example values for the field or single example + /// value. They are required only for string and string array + /// fields. Example values must be of the same type of the + /// field. If only a single example is provided, it can directly + /// be reported without encapsulating it into a sequence/dictionary. + #[serde(skip_serializing_if = "Option::is_none")] + pub examples: Option, + /// Specifies if the field is mandatory. Can be "required", + /// "conditionally_required", "recommended" or "opt_in". When omitted, + /// the field is "recommended". When set to + /// "conditionally_required", the string provided as MUST + /// specify the conditions under which the field is required. + pub requirement_level: RequirementLevel, + /// A more elaborate description of the field. + /// It defaults to an empty string. + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + pub note: String, + /// Specifies the stability of the field. + /// Note that, if stability is missing but deprecated is present, it will + /// automatically set the stability to deprecated. If deprecated is + /// present and stability differs from deprecated, this will result in an + /// error. + #[serde(skip_serializing_if = "Option::is_none")] + pub stability: Option, + /// Specifies if the field is deprecated. The string + /// provided as MUST specify why it's deprecated and/or what + /// to use instead. See also stability. + #[serde(skip_serializing_if = "Option::is_none")] + pub deprecated: Option, +} + +/// An unresolved body definition. +#[derive(Debug, Deserialize, Clone)] +pub struct UnresolvedBody { + /// The body specification. + pub spec: BodySpec, +} + +/// An unresolved body field definition. +#[derive(Debug, Deserialize, Clone)] +pub struct UnresolvedBodyField { + /// The body field specification. + pub spec: BodyFieldSpec, +} diff --git a/crates/weaver_resolved_schema/src/error.rs b/crates/weaver_resolved_schema/src/error.rs index f38f43ff..39cdb2cb 100644 --- a/crates/weaver_resolved_schema/src/error.rs +++ b/crates/weaver_resolved_schema/src/error.rs @@ -2,11 +2,13 @@ //! Error types and utilities. +use serde::{Deserialize, Serialize}; + use crate::attribute::AttributeRef; -use crate::error::Error::{AttributeNotFound, CompoundError}; +use crate::error::Error::{AttributeNotFound, CompoundError, NotImplemented}; /// Errors emitted by this crate. -#[derive(thiserror::Error, Debug, Clone)] +#[derive(thiserror::Error, Debug, Clone, Deserialize, Serialize)] pub enum Error { /// Attribute reference not found in the catalog. #[error("Attribute reference {attr_ref} (group: {group_id}) not found in the catalog")] @@ -20,6 +22,13 @@ pub enum Error { /// A generic container for multiple errors. #[error("Errors:\n{0:#?}")] CompoundError(Vec), + + /// A generic error identifying a feature that has not yet been implemented. + #[error("Not Implemented: {message}")] + NotImplemented { + /// A message describing the feature that has not been implemented. + message: String, + }, } /// Handles a list of errors and returns a compound error if the list is not @@ -35,6 +44,7 @@ pub fn handle_errors(errors: Vec) -> Result<(), Error> { impl Error { /// Creates a compound error from a list of errors. /// Note: All compound errors are flattened. + #[must_use] pub fn compound_error(errors: Vec) -> Self { CompoundError( errors @@ -42,6 +52,7 @@ impl Error { .flat_map(|e| match e { CompoundError(errors) => errors, e @ AttributeNotFound { .. } => vec![e], + e @ NotImplemented { .. } => vec![e], }) .collect(), ) diff --git a/crates/weaver_resolved_schema/src/lib.rs b/crates/weaver_resolved_schema/src/lib.rs index 61ed0ed7..d88d872e 100644 --- a/crates/weaver_resolved_schema/src/lib.rs +++ b/crates/weaver_resolved_schema/src/lib.rs @@ -14,8 +14,9 @@ use std::collections::HashMap; use weaver_version::Versions; pub mod attribute; +pub mod body; pub mod catalog; -mod error; +pub mod error; pub mod instrumentation_library; pub mod lineage; pub mod metric; diff --git a/crates/weaver_resolved_schema/src/registry.rs b/crates/weaver_resolved_schema/src/registry.rs index c41fc405..604c1c90 100644 --- a/crates/weaver_resolved_schema/src/registry.rs +++ b/crates/weaver_resolved_schema/src/registry.rs @@ -13,6 +13,7 @@ use weaver_semconv::group::{GroupType, InstrumentSpec, SpanKindSpec}; use weaver_semconv::stability::Stability; use crate::attribute::{Attribute, AttributeRef}; +use crate::body::Body; use crate::catalog::Catalog; use crate::error::{handle_errors, Error}; use crate::lineage::GroupLineage; @@ -126,6 +127,10 @@ pub struct Group { /// The readable name for attribute groups used when generating registry tables. #[serde(skip_serializing_if = "Option::is_none")] pub display_name: Option, + /// The body of the event. + /// This fields is only used for event groups. + #[serde(skip_serializing_if = "Option::is_none")] + pub body: Option, } /// Common statistics for a group. diff --git a/crates/weaver_resolved_schema/src/signal.rs b/crates/weaver_resolved_schema/src/signal.rs index a702191c..0c609abb 100644 --- a/crates/weaver_resolved_schema/src/signal.rs +++ b/crates/weaver_resolved_schema/src/signal.rs @@ -6,6 +6,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::attribute::AttributeRef; +use crate::body::Body; use crate::metric::MetricRef; use crate::tags::Tags; @@ -44,7 +45,7 @@ pub struct MultivariateMetric { tags: Option, } -/// An event signal. +/// An event specification, used for both Span and Log events. #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(deny_unknown_fields)] pub struct Event { @@ -53,8 +54,6 @@ pub struct Event { /// References to attributes defined in the catalog. #[serde(skip_serializing_if = "Vec::is_empty")] attributes: Vec, - /// The domain of the event. - domain: String, /// Brief description of the event. brief: Option, /// Longer description. @@ -63,6 +62,9 @@ pub struct Event { /// A set of tags for the event. #[serde(skip_serializing_if = "Option::is_none")] tags: Option, + /// The body of the event, not used for Span events. + #[serde(skip_serializing_if = "Option::is_none")] + body: Option, } /// A span signal. @@ -79,7 +81,7 @@ pub struct Span { kind: Option, /// The events of the span. #[serde(skip_serializing_if = "Vec::is_empty")] - events: Vec, + events: Vec, /// The links of the span. #[serde(skip_serializing_if = "Vec::is_empty")] links: Vec, @@ -108,25 +110,6 @@ pub enum SpanKind { Consumer, } -/// A span event specification. -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(deny_unknown_fields)] -pub struct SpanEvent { - /// The name of the span event. - pub event_name: String, - /// The attributes of the span event. - #[serde(skip_serializing_if = "Vec::is_empty")] - pub attributes: Vec, - /// Brief description of the span event. - pub brief: Option, - /// Longer description. - /// It defaults to an empty string. - pub note: Option, - /// A set of tags for the span event. - #[serde(skip_serializing_if = "Option::is_none")] - pub tags: Option, -} - /// A span link specification. #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(deny_unknown_fields)] diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json b/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json index dcd9d812..210bbf71 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json @@ -1,73 +1,1411 @@ [ { - "name": "ios.state", + "name": "browser.brands", + "type": "string[]", + "brief": "Array of brand name and version separated by a space", + "examples": [ + [ + " Not A;Brand 99", + "Chromium 99", + "Chrome 99" + ] + ], + "requirement_level": "recommended", + "note": "This value is intended to be taken from the [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) (`navigator.userAgentData.brands`).\n" + }, + { + "name": "browser.platform", + "type": "string", + "brief": "The platform on which the browser is running", + "examples": [ + "Windows", + "macOS", + "Android", + "iOS", + "Linux" + ], + "requirement_level": "recommended", + "note": "This value is intended to be taken from the [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) (`navigator.userAgentData.platform`). If unavailable, the legacy `navigator.platform` API SHOULD NOT be used instead and this attribute SHOULD be left unset in order for the values to be consistent. The list of possible values is defined in the [W3C User-Agent Client Hints specification](https://wicg.github.io/ua-client-hints/#sec-ch-ua-platform). Note that some (but not all) of these values can overlap with values in the [`os.type` and `os.name` attributes](./os.md). However, for consistency, the values in the `browser.platform` attribute should capture the exact value that the user agent provides.\n" + }, + { + "name": "browser.mobile", + "type": "boolean", + "brief": "A boolean that is true if the browser is running on a mobile device", + "requirement_level": "recommended", + "note": "This value is intended to be taken from the [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) (`navigator.userAgentData.mobile`). If unavailable, this attribute SHOULD be left unset.\n" + }, + { + "name": "browser.language", + "type": "string", + "brief": "Preferred language of the user using the browser", + "examples": [ + "en", + "en-US", + "en-AU", + "fr", + "fr-FR" + ], + "requirement_level": "recommended", + "note": "This value is intended to be taken from the Navigator API `navigator.language`.\n" + }, + { + "name": "client.name", + "type": "string", + "brief": "The name of the client that reported the exception.\n", + "examples": [ + "myclient" + ], + "requirement_level": "recommended" + }, + { + "name": "browser.platform", + "type": "string", + "brief": "The browser platform", + "examples": [ + "Windows", + "macOS", + "Android" + ], + "requirement_level": "recommended", + "note": "Test value.", + "stability": "stable" + }, + { + "name": "http.url", + "type": "string", + "brief": "The Url", + "examples": [ + "https://example.com" + ], + "requirement_level": "recommended", + "note": "Test url value.", + "stability": "stable" + }, + { + "name": "log.event.attr", + "type": "string", + "brief": "Just making sure the referenced attributes are defined", + "examples": "some value", + "requirement_level": "recommended", + "note": "Test value.", + "stability": "stable" + }, + { + "name": "session.id", + "type": "string", + "brief": "The session id", + "examples": "127836abcdef98", + "requirement_level": "recommended", + "note": "Test value.", + "stability": "stable" + }, + { + "name": "client.address", + "type": "string", + "brief": "Client address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name.", + "examples": [ + "client.example.com", + "10.1.2.80", + "/tmp/my.sock" + ], + "requirement_level": "recommended", + "note": "When observed from the server side, and when communicating through an intermediary, `client.address` SHOULD represent the client address behind any intermediaries, for example proxies, if it's available.\n", + "stability": "stable" + }, + { + "name": "client.port", + "type": "int", + "brief": "Client port number.", + "examples": [ + 65123 + ], + "requirement_level": "recommended", + "note": "When observed from the server side, and when communicating through an intermediary, `client.port` SHOULD represent the client port behind any intermediaries, for example proxies, if it's available.\n", + "stability": "stable" + }, + { + "name": "exception.type", + "type": "string", + "brief": "The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n", + "examples": [ + "java.net.ConnectException", + "OSError" + ], + "requirement_level": "recommended", + "stability": "stable" + }, + { + "name": "exception.message", + "type": "string", + "brief": "The exception message.", + "examples": [ + "Division by zero", + "Can't convert 'int' object to str implicitly" + ], + "requirement_level": "recommended", + "stability": "stable" + }, + { + "name": "exception.stacktrace", + "type": "string", + "brief": "A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n", + "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)", + "requirement_level": "recommended", + "stability": "stable" + }, + { + "name": "exception.escaped", + "type": "boolean", + "brief": "SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n", + "requirement_level": "recommended", + "note": "An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager's `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.", + "stability": "stable" + }, + { + "name": "gen_ai.system", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "openai", + "value": "openai", + "brief": "OpenAI", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "vertex_ai", + "value": "vertex_ai", + "brief": "Vertex AI", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "anthropic", + "value": "anthropic", + "brief": "Anthropic", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "cohere", + "value": "cohere", + "brief": "Cohere", + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The Generative AI product as identified by the client or server instrumentation.", + "examples": "openai", + "requirement_level": "recommended", + "note": "The `gen_ai.system` describes a family of GenAI models with specific model identified\nby `gen_ai.request.model` and `gen_ai.response.model` attributes.\n\nThe actual GenAI product may differ from the one identified by the client.\nFor example, when using OpenAI client libraries to communicate with Mistral, the `gen_ai.system`\nis set to `openai` based on the instrumentation's best knowledge.\n\nFor custom model, a custom friendly name SHOULD be used.\nIf none of these options apply, the `gen_ai.system` SHOULD be set to `_OTHER`.\n", + "stability": "experimental" + }, + { + "name": "gen_ai.request.model", + "type": "string", + "brief": "The name of the GenAI model a request is being made to.", + "examples": "gpt-4", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.request.max_tokens", + "type": "int", + "brief": "The maximum number of tokens the model generates for a request.", + "examples": [ + 100 + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.request.temperature", + "type": "double", + "brief": "The temperature setting for the GenAI request.", + "examples": [ + 0.0 + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.request.top_p", + "type": "double", + "brief": "The top_p sampling setting for the GenAI request.", + "examples": [ + 1.0 + ], + "tag": "llm-generic-request", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.request.top_k", + "type": "double", + "brief": "The top_k sampling setting for the GenAI request.", + "examples": [ + 1.0 + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.request.stop_sequences", + "type": "string[]", + "brief": "List of sequences that the model will use to stop generating further tokens.", + "examples": [ + [ + "forest", + "lived" + ] + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.request.frequency_penalty", + "type": "double", + "brief": "The frequency penalty setting for the GenAI request.", + "examples": [ + 0.1 + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.request.presence_penalty", + "type": "double", + "brief": "The presence penalty setting for the GenAI request.", + "examples": [ + 0.1 + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.response.id", + "type": "string", + "brief": "The unique identifier for the completion.", + "examples": [ + "chatcmpl-123" + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.response.model", + "type": "string", + "brief": "The name of the model that generated the response.", + "examples": [ + "gpt-4-0613" + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.response.finish_reasons", + "type": "string[]", + "brief": "Array of reasons the model stopped generating tokens, corresponding to each generation received.", + "examples": [ + [ + "stop" + ] + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.usage.input_tokens", + "type": "int", + "brief": "The number of tokens used in the GenAI input (prompt).", + "examples": [ + 100 + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.usage.output_tokens", + "type": "int", + "brief": "The number of tokens used in the GenAI response (completion).", + "examples": [ + 180 + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.token.type", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "input", + "value": "input", + "brief": "Input tokens (prompt, input, etc.)", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "completion", + "value": "output", + "brief": "Output tokens (completion, response, etc.)", + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The type of token being counted.", + "examples": [ + "input", + "output" + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "gen_ai.prompt", + "type": "string", + "brief": "The full prompt sent to the GenAI model.", + "examples": [ + "[{'role': 'user', 'content': 'What is the capital of France?'}]" + ], + "requirement_level": "recommended", + "note": "It's RECOMMENDED to format prompts as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation)", + "stability": "experimental" + }, + { + "name": "gen_ai.completion", + "type": "string", + "brief": "The full response received from the GenAI model.", + "examples": [ + "[{'role': 'assistant', 'content': 'The capital of France is Paris.'}]" + ], + "requirement_level": "recommended", + "note": "It's RECOMMENDED to format completions as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation)", + "stability": "experimental" + }, + { + "name": "gen_ai.operation.name", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "chat", + "value": "chat", + "brief": "Chat completion operation such as [OpenAI Chat API](https://platform.openai.com/docs/api-reference/chat)", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "text_completion", + "value": "text_completion", + "brief": "Text completions operation such as [OpenAI Completions API (Legacy)](https://platform.openai.com/docs/api-reference/completions)", + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The name of the operation being performed.", + "requirement_level": "recommended", + "note": "If one of the predefined values applies, but specific system uses a different name it's RECOMMENDED to document it in the semantic conventions for specific GenAI system and use system-specific name in the instrumentation. If a different name is not documented, instrumentation libraries SHOULD use applicable predefined value.\n", + "stability": "experimental" + }, + { + "name": "network.carrier.icc", + "type": "string", + "brief": "The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network.", + "examples": "DE", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "network.carrier.mcc", + "type": "string", + "brief": "The mobile carrier country code.", + "examples": "310", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "network.carrier.mnc", + "type": "string", + "brief": "The mobile carrier network code.", + "examples": "001", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "network.carrier.name", + "type": "string", + "brief": "The name of the mobile carrier.", + "examples": "sprint", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "network.connection.subtype", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "gprs", + "value": "gprs", + "brief": "GPRS", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "edge", + "value": "edge", + "brief": "EDGE", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "umts", + "value": "umts", + "brief": "UMTS", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "cdma", + "value": "cdma", + "brief": "CDMA", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "evdo_0", + "value": "evdo_0", + "brief": "EVDO Rel. 0", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "evdo_a", + "value": "evdo_a", + "brief": "EVDO Rev. A", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "cdma2000_1xrtt", + "value": "cdma2000_1xrtt", + "brief": "CDMA2000 1XRTT", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "hsdpa", + "value": "hsdpa", + "brief": "HSDPA", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "hsupa", + "value": "hsupa", + "brief": "HSUPA", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "hspa", + "value": "hspa", + "brief": "HSPA", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "iden", + "value": "iden", + "brief": "IDEN", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "evdo_b", + "value": "evdo_b", + "brief": "EVDO Rev. B", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "lte", + "value": "lte", + "brief": "LTE", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "ehrpd", + "value": "ehrpd", + "brief": "EHRPD", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "hspap", + "value": "hspap", + "brief": "HSPAP", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "gsm", + "value": "gsm", + "brief": "GSM", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "td_scdma", + "value": "td_scdma", + "brief": "TD-SCDMA", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "iwlan", + "value": "iwlan", + "brief": "IWLAN", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "nr", + "value": "nr", + "brief": "5G NR (New Radio)", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "nrnsa", + "value": "nrnsa", + "brief": "5G NRNSA (New Radio Non-Standalone)", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "lte_ca", + "value": "lte_ca", + "brief": "LTE CA", + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.", + "examples": "LTE", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "network.connection.type", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "wifi", + "value": "wifi", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "wired", + "value": "wired", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "cell", + "value": "cell", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unavailable", + "value": "unavailable", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unknown", + "value": "unknown", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The internet connection type.", + "examples": "wifi", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "network.local.address", + "type": "string", + "brief": "Local address of the network connection - IP address or Unix domain socket name.", + "examples": [ + "10.1.2.80", + "/tmp/my.sock" + ], + "requirement_level": "recommended", + "stability": "stable" + }, + { + "name": "network.local.port", + "type": "int", + "brief": "Local port number of the network connection.", + "examples": [ + 65123 + ], + "requirement_level": "recommended", + "stability": "stable" + }, + { + "name": "network.peer.address", + "type": "string", + "brief": "Peer address of the network connection - IP address or Unix domain socket name.", + "examples": [ + "10.1.2.80", + "/tmp/my.sock" + ], + "requirement_level": "recommended", + "stability": "stable" + }, + { + "name": "network.peer.port", + "type": "int", + "brief": "Peer port number of the network connection.", + "examples": [ + 65123 + ], + "requirement_level": "recommended", + "stability": "stable" + }, + { + "name": "network.protocol.name", + "type": "string", + "brief": "[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.", + "examples": [ + "amqp", + "http", + "mqtt" + ], + "requirement_level": "recommended", + "note": "The value SHOULD be normalized to lowercase.", + "stability": "stable" + }, + { + "name": "network.protocol.version", + "type": "string", + "brief": "The actual version of the protocol used for network communication.", + "examples": [ + "1.1", + "2" + ], + "requirement_level": "recommended", + "note": "If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set.\n", + "stability": "stable" + }, + { + "name": "network.transport", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "tcp", + "value": "tcp", + "brief": "TCP", + "note": null, + "stability": "stable", + "deprecated": null + }, + { + "id": "udp", + "value": "udp", + "brief": "UDP", + "note": null, + "stability": "stable", + "deprecated": null + }, + { + "id": "pipe", + "value": "pipe", + "brief": "Named or anonymous pipe.", + "note": null, + "stability": "stable", + "deprecated": null + }, + { + "id": "unix", + "value": "unix", + "brief": "Unix domain socket", + "note": null, + "stability": "stable", + "deprecated": null + } + ] + }, + "brief": "[OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication).\n", + "examples": [ + "tcp", + "udp" + ], + "requirement_level": "recommended", + "note": "The value SHOULD be normalized to lowercase.\n\nConsider always setting the transport when setting a port number, since\na port number is ambiguous without knowing the transport. For example\ndifferent processes could be listening on TCP port 12345 and UDP port 12345.\n", + "stability": "stable" + }, + { + "name": "network.type", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "ipv4", + "value": "ipv4", + "brief": "IPv4", + "note": null, + "stability": "stable", + "deprecated": null + }, + { + "id": "ipv6", + "value": "ipv6", + "brief": "IPv6", + "note": null, + "stability": "stable", + "deprecated": null + } + ] + }, + "brief": "[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.", + "examples": [ + "ipv4", + "ipv6" + ], + "requirement_level": "recommended", + "note": "The value SHOULD be normalized to lowercase.", + "stability": "stable" + }, + { + "name": "network.io.direction", + "type": { + "allow_custom_values": false, + "members": [ + { + "id": "transmit", + "value": "transmit", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "receive", + "value": "receive", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The network IO operation direction.", + "examples": [ + "transmit" + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.connect_rpc.error_code", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "cancelled", + "value": "cancelled", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unknown", + "value": "unknown", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "invalid_argument", + "value": "invalid_argument", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "deadline_exceeded", + "value": "deadline_exceeded", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "not_found", + "value": "not_found", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "already_exists", + "value": "already_exists", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "permission_denied", + "value": "permission_denied", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "resource_exhausted", + "value": "resource_exhausted", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "failed_precondition", + "value": "failed_precondition", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "aborted", + "value": "aborted", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "out_of_range", + "value": "out_of_range", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unimplemented", + "value": "unimplemented", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "internal", + "value": "internal", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unavailable", + "value": "unavailable", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "data_loss", + "value": "data_loss", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unauthenticated", + "value": "unauthenticated", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The [error codes](https://connect.build/docs/protocol/#error-codes) of the Connect request. Error codes are always string values.", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.connect_rpc.request.metadata", + "type": "template[string[]]", + "brief": "Connect request metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values.\n", + "examples": [ + "rpc.request.metadata.my-custom-metadata-attribute=[\"1.2.3.4\", \"1.2.3.5\"]" + ], + "requirement_level": "recommended", + "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", + "stability": "experimental" + }, + { + "name": "rpc.connect_rpc.response.metadata", + "type": "template[string[]]", + "brief": "Connect response metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values.\n", + "examples": [ + "rpc.response.metadata.my-custom-metadata-attribute=[\"attribute_value\"]" + ], + "requirement_level": "recommended", + "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", + "stability": "experimental" + }, + { + "name": "rpc.grpc.status_code", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "ok", + "value": 0, + "brief": "OK", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "cancelled", + "value": 1, + "brief": "CANCELLED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unknown", + "value": 2, + "brief": "UNKNOWN", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "invalid_argument", + "value": 3, + "brief": "INVALID_ARGUMENT", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "deadline_exceeded", + "value": 4, + "brief": "DEADLINE_EXCEEDED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "not_found", + "value": 5, + "brief": "NOT_FOUND", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "already_exists", + "value": 6, + "brief": "ALREADY_EXISTS", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "permission_denied", + "value": 7, + "brief": "PERMISSION_DENIED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "resource_exhausted", + "value": 8, + "brief": "RESOURCE_EXHAUSTED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "failed_precondition", + "value": 9, + "brief": "FAILED_PRECONDITION", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "aborted", + "value": 10, + "brief": "ABORTED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "out_of_range", + "value": 11, + "brief": "OUT_OF_RANGE", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unimplemented", + "value": 12, + "brief": "UNIMPLEMENTED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "internal", + "value": 13, + "brief": "INTERNAL", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unavailable", + "value": 14, + "brief": "UNAVAILABLE", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "data_loss", + "value": 15, + "brief": "DATA_LOSS", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unauthenticated", + "value": 16, + "brief": "UNAUTHENTICATED", + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The [numeric status code](https://github.com/grpc/grpc/blob/v1.33.2/doc/statuscodes.md) of the gRPC request.", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.grpc.request.metadata", + "type": "template[string[]]", + "brief": "gRPC request metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values.\n", + "examples": [ + "rpc.grpc.request.metadata.my-custom-metadata-attribute=[\"1.2.3.4\", \"1.2.3.5\"]" + ], + "requirement_level": "recommended", + "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", + "stability": "experimental" + }, + { + "name": "rpc.grpc.response.metadata", + "type": "template[string[]]", + "brief": "gRPC response metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values.\n", + "examples": [ + "rpc.grpc.response.metadata.my-custom-metadata-attribute=[\"attribute_value\"]" + ], + "requirement_level": "recommended", + "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", + "stability": "experimental" + }, + { + "name": "rpc.jsonrpc.error_code", + "type": "int", + "brief": "`error.code` property of response if it is an error response.", + "examples": [ + -32700, + 100 + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.jsonrpc.error_message", + "type": "string", + "brief": "`error.message` property of response if it is an error response.", + "examples": [ + "Parse error", + "User already exists" + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.jsonrpc.request_id", + "type": "string", + "brief": "`id` property of request or response. Since protocol allows id to be int, string, `null` or missing (for notifications), value is expected to be cast to string for simplicity. Use empty string in case of `null` value. Omit entirely if this is a notification.\n", + "examples": [ + "10", + "request-7", + "" + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.jsonrpc.version", + "type": "string", + "brief": "Protocol version as in `jsonrpc` property of request/response. Since JSON-RPC 1.0 doesn't specify this, the value can be omitted.", + "examples": [ + "2.0", + "1.0" + ], + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.method", + "type": "string", + "brief": "The name of the (logical) method being called, must be equal to the $method part in the span name.", + "examples": "exampleMethod", + "requirement_level": "recommended", + "note": "This is the logical name of the method from the RPC interface perspective, which can be different from the name of any implementing method/function. The `code.function` attribute may be used to store the latter (e.g., method actually executing the call on the server side, RPC client stub method on the client side).\n", + "stability": "experimental" + }, + { + "name": "rpc.service", + "type": "string", + "brief": "The full (logical) name of the service being called, including its package name, if applicable.", + "examples": "myservice.EchoService", + "requirement_level": "recommended", + "note": "This is the logical name of the service from the RPC interface perspective, which can be different from the name of any implementing class. The `code.namespace` attribute may be used to store the latter (despite the attribute name, it may include a class name; e.g., class with method actually executing the call on the server side, RPC client stub class on the client side).\n", + "stability": "experimental" + }, + { + "name": "rpc.system", "type": { - "allow_custom_values": false, + "allow_custom_values": true, "members": [ { - "id": "active", - "value": "active", - "brief": "The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n", - "note": null + "id": "grpc", + "value": "grpc", + "brief": "gRPC", + "note": null, + "stability": "experimental", + "deprecated": null }, { - "id": "inactive", - "value": "inactive", - "brief": "The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n", - "note": null + "id": "java_rmi", + "value": "java_rmi", + "brief": "Java RMI", + "note": null, + "stability": "experimental", + "deprecated": null }, { - "id": "background", - "value": "background", - "brief": "The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n", - "note": null + "id": "dotnet_wcf", + "value": "dotnet_wcf", + "brief": ".NET WCF", + "note": null, + "stability": "experimental", + "deprecated": null }, { - "id": "foreground", - "value": "foreground", - "brief": "The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n", - "note": null + "id": "apache_dubbo", + "value": "apache_dubbo", + "brief": "Apache Dubbo", + "note": null, + "stability": "experimental", + "deprecated": null }, { - "id": "terminate", - "value": "terminate", - "brief": "The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n", - "note": null + "id": "connect_rpc", + "value": "connect_rpc", + "brief": "Connect RPC", + "note": null, + "stability": "experimental", + "deprecated": null } ] }, - "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", - "requirement_level": "required", - "note": "The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n" + "brief": "A string identifying the remoting system. See below for a list of well-known identifiers.", + "requirement_level": "recommended", + "stability": "experimental" }, { - "name": "android.state", + "name": "rpc.message.type", "type": { - "allow_custom_values": false, + "allow_custom_values": true, "members": [ { - "id": "created", - "value": "created", - "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.\n", - "note": null + "id": "sent", + "value": "SENT", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null }, { - "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.\n", - "note": null - }, - { - "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.", - "note": null + "id": "received", + "value": "RECEIVED", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null } ] }, - "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", - "requirement_level": "required", - "note": "The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n" + "brief": "Whether this is a received or sent message.", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.message.id", + "type": "int", + "brief": "MUST be calculated as two different counters starting from `1` one for sent messages and one for received message.", + "requirement_level": "recommended", + "note": "This way we guarantee that the values will be consistent between different implementations.", + "stability": "experimental" + }, + { + "name": "rpc.message.compressed_size", + "type": "int", + "brief": "Compressed size of the message in bytes.", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.message.uncompressed_size", + "type": "int", + "brief": "Uncompressed size of the message in bytes.", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "server.address", + "type": "string", + "brief": "Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name.", + "examples": [ + "example.com", + "10.1.2.80", + "/tmp/my.sock" + ], + "requirement_level": "recommended", + "note": "When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available.\n", + "stability": "stable" + }, + { + "name": "server.port", + "type": "int", + "brief": "Server port number.", + "examples": [ + 80, + 8080, + 443 + ], + "requirement_level": "recommended", + "note": "When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available.\n", + "stability": "stable" + }, + { + "name": "exception.type", + "type": "string", + "brief": "The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n", + "examples": [ + "java.net.ConnectException", + "OSError" + ], + "requirement_level": { + "conditionally_required": "Required if `exception.message` is not set, recommended otherwise." + }, + "stability": "stable" + }, + { + "name": "exception.message", + "type": "string", + "brief": "The exception message.", + "examples": [ + "Division by zero", + "Can't convert 'int' object to str implicitly" + ], + "requirement_level": { + "conditionally_required": "Required if `exception.type` is not set, recommended otherwise." + }, + "stability": "stable" }, { "name": "feature_flag.key", @@ -98,5 +1436,616 @@ ], "requirement_level": "recommended", "note": "A semantic identifier, commonly referred to as a variant, provides a means\nfor referring to a value without including the value itself. This can\nprovide additional context for understanding the meaning behind a value.\nFor example, the variant `red` maybe be used for the value `#c05543`.\n\nA stringified version of the value can be used in situations where a\nsemantic identifier is unavailable. String representation of the value\nshould be determined by the implementer." + }, + { + "name": "gen_ai.system", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "openai", + "value": "openai", + "brief": "OpenAI", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "vertex_ai", + "value": "vertex_ai", + "brief": "Vertex AI", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "anthropic", + "value": "anthropic", + "brief": "Anthropic", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "cohere", + "value": "cohere", + "brief": "Cohere", + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The Generative AI product as identified by the client or server instrumentation.", + "examples": "openai", + "requirement_level": "required", + "note": "The `gen_ai.system` describes a family of GenAI models with specific model identified\nby `gen_ai.request.model` and `gen_ai.response.model` attributes.\n\nThe actual GenAI product may differ from the one identified by the client.\nFor example, when using OpenAI client libraries to communicate with Mistral, the `gen_ai.system`\nis set to `openai` based on the instrumentation's best knowledge.\n\nFor custom model, a custom friendly name SHOULD be used.\nIf none of these options apply, the `gen_ai.system` SHOULD be set to `_OTHER`.\n", + "stability": "experimental" + }, + { + "name": "gen_ai.request.model", + "type": "string", + "brief": "The name of the GenAI model a request is being made to.", + "examples": "gpt-4", + "requirement_level": "required", + "note": "The name of the GenAI model a request is being made to. If the model is supplied by a vendor, then the value must be the exact name of the model requested. If the model is a fine-tuned custom model, the value should have a more specific name than the base model that's been fine-tuned.\n", + "stability": "experimental" + }, + { + "name": "gen_ai.operation.name", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "chat", + "value": "chat", + "brief": "Chat completion operation such as [OpenAI Chat API](https://platform.openai.com/docs/api-reference/chat)", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "text_completion", + "value": "text_completion", + "brief": "Text completions operation such as [OpenAI Completions API (Legacy)](https://platform.openai.com/docs/api-reference/completions)", + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The name of the operation being performed.", + "requirement_level": "required", + "note": "If one of the predefined values applies, but specific system uses a different name it's RECOMMENDED to document it in the semantic conventions for specific GenAI system and use system-specific name in the instrumentation. If a different name is not documented, instrumentation libraries SHOULD use applicable predefined value.\n", + "stability": "experimental" + }, + { + "name": "gen_ai.response.model", + "type": "string", + "brief": "The name of the model that generated the response.", + "examples": [ + "gpt-4-0613" + ], + "requirement_level": "recommended", + "note": "If available. The name of the GenAI model that provided the response. If the model is supplied by a vendor, then the value must be the exact name of the model actually used. If the model is a fine-tuned custom model, the value should have a more specific name than the base model that's been fine-tuned.\n", + "stability": "experimental" + }, + { + "name": "gen_ai.prompt", + "type": "string", + "brief": "The full prompt sent to the GenAI model.", + "examples": [ + "[{'role': 'user', 'content': 'What is the capital of France?'}]" + ], + "requirement_level": { + "conditionally_required": "if and only if corresponding event is enabled" + }, + "note": "It's RECOMMENDED to format prompts as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation)\n", + "stability": "experimental" + }, + { + "name": "gen_ai.completion", + "type": "string", + "brief": "The full response received from the GenAI model.", + "examples": [ + "[{'role': 'assistant', 'content': 'The capital of France is Paris.'}]" + ], + "requirement_level": { + "conditionally_required": "if and only if corresponding event is enabled" + }, + "note": "It's RECOMMENDED to format completions as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation)\n", + "stability": "experimental" + }, + { + "name": "rpc.system", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "grpc", + "value": "grpc", + "brief": "gRPC", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "java_rmi", + "value": "java_rmi", + "brief": "Java RMI", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "dotnet_wcf", + "value": "dotnet_wcf", + "brief": ".NET WCF", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "apache_dubbo", + "value": "apache_dubbo", + "brief": "Apache Dubbo", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "connect_rpc", + "value": "connect_rpc", + "brief": "Connect RPC", + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "A string identifying the remoting system. See below for a list of well-known identifiers.", + "requirement_level": "required", + "stability": "experimental" + }, + { + "name": "server.address", + "type": "string", + "brief": "RPC server [host name](https://grpc.github.io/grpc/core/md_doc_naming.html).\n", + "examples": [ + "example.com", + "10.1.2.80", + "/tmp/my.sock" + ], + "requirement_level": "required", + "note": "May contain server IP address, DNS name, or local socket name. When host component is an IP address, instrumentations SHOULD NOT do a reverse proxy lookup to obtain DNS name and SHOULD set `server.address` to the IP address provided in the host component.\n", + "stability": "stable" + }, + { + "name": "server.port", + "type": "int", + "brief": "Server port number.", + "examples": [ + 80, + 8080, + 443 + ], + "requirement_level": { + "conditionally_required": "if the port is supported by the network transport used for communication." + }, + "note": "When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available.\n", + "stability": "stable" + }, + { + "name": "network.peer.port", + "type": "int", + "brief": "Peer port number of the network connection.", + "examples": [ + 65123 + ], + "requirement_level": { + "recommended": "If `network.peer.address` is set." + }, + "stability": "stable" + }, + { + "name": "rpc.grpc.request.metadata", + "type": "template[string[]]", + "brief": "gRPC request metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values.\n", + "examples": [ + "rpc.grpc.request.metadata.my-custom-metadata-attribute=[\"1.2.3.4\", \"1.2.3.5\"]" + ], + "tag": "grpc-tech-specific", + "requirement_level": "opt_in", + "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", + "stability": "experimental" + }, + { + "name": "rpc.grpc.response.metadata", + "type": "template[string[]]", + "brief": "gRPC response metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values.\n", + "examples": [ + "rpc.grpc.response.metadata.my-custom-metadata-attribute=[\"attribute_value\"]" + ], + "tag": "grpc-tech-specific", + "requirement_level": "opt_in", + "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", + "stability": "experimental" + }, + { + "name": "rpc.grpc.status_code", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "ok", + "value": 0, + "brief": "OK", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "cancelled", + "value": 1, + "brief": "CANCELLED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unknown", + "value": 2, + "brief": "UNKNOWN", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "invalid_argument", + "value": 3, + "brief": "INVALID_ARGUMENT", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "deadline_exceeded", + "value": 4, + "brief": "DEADLINE_EXCEEDED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "not_found", + "value": 5, + "brief": "NOT_FOUND", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "already_exists", + "value": 6, + "brief": "ALREADY_EXISTS", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "permission_denied", + "value": 7, + "brief": "PERMISSION_DENIED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "resource_exhausted", + "value": 8, + "brief": "RESOURCE_EXHAUSTED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "failed_precondition", + "value": 9, + "brief": "FAILED_PRECONDITION", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "aborted", + "value": 10, + "brief": "ABORTED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "out_of_range", + "value": 11, + "brief": "OUT_OF_RANGE", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unimplemented", + "value": 12, + "brief": "UNIMPLEMENTED", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "internal", + "value": 13, + "brief": "INTERNAL", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unavailable", + "value": 14, + "brief": "UNAVAILABLE", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "data_loss", + "value": 15, + "brief": "DATA_LOSS", + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unauthenticated", + "value": 16, + "brief": "UNAUTHENTICATED", + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The [numeric status code](https://github.com/grpc/grpc/blob/v1.33.2/doc/statuscodes.md) of the gRPC request.", + "tag": "grpc-tech-specific", + "requirement_level": "required", + "stability": "experimental" + }, + { + "name": "rpc.jsonrpc.error_code", + "type": "int", + "brief": "`error.code` property of response if it is an error response.", + "examples": [ + -32700, + 100 + ], + "tag": "jsonrpc-tech-specific", + "requirement_level": { + "conditionally_required": "If response is not successful." + }, + "stability": "experimental" + }, + { + "name": "rpc.jsonrpc.error_message", + "type": "string", + "brief": "`error.message` property of response if it is an error response.", + "examples": [ + "Parse error", + "User already exists" + ], + "tag": "jsonrpc-tech-specific", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.jsonrpc.request_id", + "type": "string", + "brief": "`id` property of request or response. Since protocol allows id to be int, string, `null` or missing (for notifications), value is expected to be cast to string for simplicity. Use empty string in case of `null` value. Omit entirely if this is a notification.\n", + "examples": [ + "10", + "request-7", + "" + ], + "tag": "jsonrpc-tech-specific", + "requirement_level": "recommended", + "stability": "experimental" + }, + { + "name": "rpc.jsonrpc.version", + "type": "string", + "brief": "Protocol version as in `jsonrpc` property of request/response. Since JSON-RPC 1.0 doesn't specify this, the value can be omitted.", + "examples": [ + "2.0", + "1.0" + ], + "tag": "jsonrpc-tech-specific", + "requirement_level": { + "conditionally_required": "If other than the default version (`1.0`)" + }, + "stability": "experimental" + }, + { + "name": "rpc.method", + "type": "string", + "brief": "The name of the (logical) method being called, must be equal to the $method part in the span name.", + "examples": "exampleMethod", + "tag": "jsonrpc-tech-specific", + "requirement_level": "required", + "note": "This is always required for jsonrpc. See the note in the general RPC conventions for more information.\n", + "stability": "experimental" + }, + { + "name": "rpc.connect_rpc.error_code", + "type": { + "allow_custom_values": true, + "members": [ + { + "id": "cancelled", + "value": "cancelled", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unknown", + "value": "unknown", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "invalid_argument", + "value": "invalid_argument", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "deadline_exceeded", + "value": "deadline_exceeded", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "not_found", + "value": "not_found", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "already_exists", + "value": "already_exists", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "permission_denied", + "value": "permission_denied", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "resource_exhausted", + "value": "resource_exhausted", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "failed_precondition", + "value": "failed_precondition", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "aborted", + "value": "aborted", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "out_of_range", + "value": "out_of_range", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unimplemented", + "value": "unimplemented", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "internal", + "value": "internal", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unavailable", + "value": "unavailable", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "data_loss", + "value": "data_loss", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + }, + { + "id": "unauthenticated", + "value": "unauthenticated", + "brief": null, + "note": null, + "stability": "experimental", + "deprecated": null + } + ] + }, + "brief": "The [error codes](https://connect.build/docs/protocol/#error-codes) of the Connect request. Error codes are always string values.", + "tag": "connect_rpc-tech-specific", + "requirement_level": { + "conditionally_required": "If response is not successful and if error code available." + }, + "stability": "experimental" + }, + { + "name": "rpc.connect_rpc.request.metadata", + "type": "template[string[]]", + "brief": "Connect request metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values.\n", + "examples": [ + "rpc.request.metadata.my-custom-metadata-attribute=[\"1.2.3.4\", \"1.2.3.5\"]" + ], + "tag": "connect_rpc-tech-specific", + "requirement_level": "opt_in", + "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", + "stability": "experimental" + }, + { + "name": "rpc.connect_rpc.response.metadata", + "type": "template[string[]]", + "brief": "Connect response metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values.\n", + "examples": [ + "rpc.response.metadata.my-custom-metadata-attribute=[\"attribute_value\"]" + ], + "tag": "connect_rpc-tech-specific", + "requirement_level": "opt_in", + "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", + "stability": "experimental" } ] \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-events.json b/crates/weaver_resolver/data/registry-test-4-events/expected-events.json new file mode 100644 index 00000000..b0986c21 --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-events.json @@ -0,0 +1,221 @@ +[ + { + "attributes": [], + "body": { + "fields": [ + { + "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", + "name": "ios.state", + "note": "The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n", + "requirement_level": { + "conditionally_required": "if and only if `os.name` is `ios`" + }, + "stability": "experimental", + "type": { + "allow_custom_values": false, + "members": [ + { + "brief": "The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n", + "deprecated": null, + "id": "active", + "note": null, + "stability": null, + "value": "active" + }, + { + "brief": "The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n", + "deprecated": null, + "id": "inactive", + "note": null, + "stability": null, + "value": "inactive" + }, + { + "brief": "The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n", + "deprecated": null, + "id": "background", + "note": null, + "stability": null, + "value": "background" + }, + { + "brief": "The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n", + "deprecated": null, + "id": "foreground", + "note": null, + "stability": null, + "value": "foreground" + }, + { + "brief": "The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n", + "deprecated": null, + "id": "terminate", + "note": null, + "stability": null, + "value": "terminate" + } + ] + } + }, + { + "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", + "name": "android.state", + "note": "The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n", + "requirement_level": { + "conditionally_required": "if and only if `os.name` is `android`" + }, + "stability": "experimental", + "type": { + "allow_custom_values": false, + "members": [ + { + "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.\n", + "deprecated": null, + "id": "created", + "note": null, + "stability": null, + "value": "created" + }, + { + "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.\n", + "deprecated": null, + "id": "background", + "note": null, + "stability": null, + "value": "background" + }, + { + "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.", + "deprecated": null, + "id": "foreground", + "note": null, + "stability": null, + "value": "foreground" + } + ] + } + } + ] + }, + "brief": "This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n", + "event_namespace": "device.app", + "events": [], + "id": "device.app.lifecycle", + "instrument": null, + "lineage": { + "source_file": "data/mobile-events.yaml" + }, + "metric_name": null, + "name": "device.app.lifecycle", + "note": "This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n", + "span_kind": null, + "stability": "experimental", + "type": "event", + "unit": null + }, + { + "attributes": [ + { + "brief": "A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n", + "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)", + "name": "exception.stacktrace", + "requirement_level": "recommended", + "stability": "stable", + "type": "string" + }, + { + "brief": "SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n", + "name": "exception.escaped", + "note": "An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager's `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.", + "requirement_level": "recommended", + "stability": "stable", + "type": "boolean" + }, + { + "brief": "The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n", + "examples": [ + "java.net.ConnectException", + "OSError" + ], + "name": "exception.type", + "requirement_level": { + "conditionally_required": "Required if `exception.message` is not set, recommended otherwise." + }, + "stability": "stable", + "type": "string" + }, + { + "brief": "The exception message.", + "examples": [ + "Division by zero", + "Can't convert 'int' object to str implicitly" + ], + "name": "exception.message", + "requirement_level": { + "conditionally_required": "Required if `exception.type` is not set, recommended otherwise." + }, + "stability": "stable", + "type": "string" + } + ], + "brief": "This document defines the attributes used to report a single exception associated with a span.\n", + "event_namespace": "other", + "events": [], + "id": "trace-exception", + "instrument": null, + "lineage": { + "attributes": { + "exception.escaped": { + "inherited_fields": [ + "brief", + "note", + "requirement_level", + "stability" + ], + "source_group": "registry.exception" + }, + "exception.message": { + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ], + "source_group": "registry.exception" + }, + "exception.stacktrace": { + "inherited_fields": [ + "brief", + "examples", + "note", + "requirement_level", + "stability" + ], + "source_group": "registry.exception" + }, + "exception.type": { + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ], + "source_group": "registry.exception" + } + }, + "source_file": "data/trace-exception.yaml" + }, + "metric_name": null, + "name": null, + "prefix": "exception", + "span_kind": null, + "type": "event", + "unit": null + } +] \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json b/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json index d2db1ae2..34e82263 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json @@ -1,15 +1,120 @@ { "registry_url": "https://127.0.0.1", "groups": [ + { + "id": "registry.browser", + "type": "event", + "brief": "An event that adds global attributes for reuse.\n", + "prefix": "browser", + "attributes": [ + 0, + 1, + 2, + 3 + ], + "name": "browser.test.event", + "lineage": { + "source_file": "data/registry-test-4-events/registry/browser-event.yaml" + }, + "body": { + "fields": [ + { + "name": "some.field", + "type": "string", + "brief": "A field that is not referenced in the attributes", + "examples": [ + "some value", + "another value" + ], + "requirement_level": "recommended", + "note": "This field is not referenced in the attributes" + } + ] + } + }, + { + "id": "client.exception.event", + "type": "event", + "brief": "This document defines the log event used to report a client exception.\n", + "attributes": [ + 4 + ], + "name": "client.exception.event", + "lineage": { + "source_file": "data/registry-test-4-events/registry/client-exception-event.yaml" + }, + "body": { + "fields": [ + { + "name": "type", + "type": "string", + "brief": "The type of the exception.\n", + "examples": [ + "java.net.ConnectException", + "OSError" + ], + "requirement_level": "recommended" + }, + { + "name": "message", + "type": "string", + "brief": "The exception message.", + "examples": [ + "Division by zero", + "Can't convert 'int' object to str implicitly" + ], + "requirement_level": "recommended" + }, + { + "name": "stacktrace", + "type": "string", + "brief": "A stacktrace.\n", + "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)", + "requirement_level": "recommended" + }, + { + "name": "escaped", + "type": "boolean", + "brief": "SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n", + "requirement_level": "recommended", + "note": "An exception is considered to have escaped." + } + ] + } + }, + { + "id": "log_event_attributes_only", + "type": "event", + "brief": "brief", + "attributes": [ + 7 + ], + "name": "some.event", + "lineage": { + "source_file": "data/registry-test-4-events/registry/log-event.yaml", + "attributes": { + "log.event.attr": { + "source_group": "referenced.attributes", + "inherited_fields": [ + "brief", + "examples", + "note", + "requirement_level", + "stability" + ] + } + } + } + }, { "id": "log-feature_flag", "type": "event", "brief": "This document defines attributes for feature flag evaluations represented using Log Records.\n", "prefix": "feature_flag", "attributes": [ - 2, - 3, - 4 + 69, + 70, + 71 ], "lineage": { "source_file": "data/registry-test-4-events/registry/log-feature_flag.yaml", @@ -45,29 +150,319 @@ } }, { - "id": "ios.lifecycle.events", + "id": "device.app.lifecycle", "type": "event", - "brief": "This event represents an occurrence of a lifecycle transition on the iOS platform.\n", - "prefix": "ios", - "attributes": [ - 0 - ], + "brief": "This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n", + "note": "This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n", + "stability": "experimental", + "attributes": [], "name": "device.app.lifecycle", "lineage": { "source_file": "data/registry-test-4-events/registry/mobile-events.yaml" + }, + "body": { + "fields": [ + { + "name": "ios.state", + "type": { + "allow_custom_values": false, + "members": [ + { + "id": "active", + "value": "active", + "brief": "The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "id": "inactive", + "value": "inactive", + "brief": "The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "id": "background", + "value": "background", + "brief": "The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "id": "foreground", + "value": "foreground", + "brief": "The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "id": "terminate", + "value": "terminate", + "brief": "The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n", + "note": null, + "stability": null, + "deprecated": null + } + ] + }, + "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", + "requirement_level": { + "conditionally_required": "if and only if `os.name` is `ios`" + }, + "note": "The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n", + "stability": "experimental" + }, + { + "name": "android.state", + "type": { + "allow_custom_values": false, + "members": [ + { + "id": "created", + "value": "created", + "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.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "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.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "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.", + "note": null, + "stability": null, + "deprecated": null + } + ] + }, + "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", + "requirement_level": { + "conditionally_required": "if and only if `os.name` is `android`" + }, + "note": "The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n", + "stability": "experimental" + } + ] } }, { - "id": "android.lifecycle.events", + "id": "log_event_empty", "type": "event", - "brief": "This event represents an occurrence of a lifecycle transition on the Android platform.\n", - "prefix": "android", + "brief": "brief", + "attributes": [], + "name": "ping.event", + "lineage": { + "source_file": "data/registry-test-4-events/registry/ping-event.yaml" + } + }, + { + "id": "referenced.attributes", + "type": "attribute_group", + "brief": "These attributes are used as references for the test below\n", "attributes": [ - 1 + 5, + 6, + 7, + 8 ], - "name": "device.app.lifecycle", "lineage": { - "source_file": "data/registry-test-4-events/registry/mobile-events.yaml" + "source_file": "data/registry-test-4-events/registry/referenced-attributes.yaml" + } + }, + { + "id": "registry.client", + "type": "attribute_group", + "brief": "These attributes may be used to describe the client in a connection-based network interaction where there is one side that initiates the connection (the client is the side that initiates the connection). This covers all TCP network interactions since TCP is connection-based and one side initiates the connection (an exception is made for peer-to-peer communication over TCP where the \"user-facing\" surface of the protocol / API doesn't expose a clear notion of client and server). This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS.\n", + "prefix": "client", + "attributes": [ + 9, + 10 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/referenced-client.yaml" + } + }, + { + "id": "registry.exception", + "type": "attribute_group", + "brief": "This document defines the shared attributes used to report a single exception associated with a span or log.\n", + "prefix": "exception", + "attributes": [ + 11, + 12, + 13, + 14 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/referenced-exception.yaml" + } + }, + { + "id": "registry.gen_ai", + "type": "attribute_group", + "brief": "This document defines the attributes used to describe telemetry in the context of Generative Artificial Intelligence (GenAI) Models requests and responses.\n", + "prefix": "gen_ai", + "attributes": [ + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/referenced-gen_ai.yaml" + } + }, + { + "id": "registry.network", + "type": "attribute_group", + "brief": "These attributes may be used for any network related operation.\n", + "prefix": "network", + "attributes": [ + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/referenced-network.yaml" + } + }, + { + "id": "registry.rpc", + "type": "attribute_group", + "brief": "This document defines attributes for remote procedure calls.", + "prefix": "rpc", + "attributes": [ + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/referenced-rpc.yaml" + } + }, + { + "id": "registry.server", + "type": "attribute_group", + "brief": "These attributes may be used to describe the server in a connection-based network interaction where there is one side that initiates the connection (the client is the side that initiates the connection). This covers all TCP network interactions since TCP is connection-based and one side initiates the connection (an exception is made for peer-to-peer communication over TCP where the \"user-facing\" surface of the protocol / API doesn't expose a clear notion of client and server). This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS.\n", + "prefix": "server", + "attributes": [ + 65, + 66 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/referenced-server.yaml" + } + }, + { + "id": "trace-exception", + "type": "event", + "brief": "This document defines the attributes used to report a single exception associated with a span.\n", + "prefix": "exception", + "attributes": [ + 13, + 14, + 67, + 68 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-exception.yaml", + "attributes": { + "exception.escaped": { + "source_group": "registry.exception", + "inherited_fields": [ + "brief", + "note", + "requirement_level", + "stability" + ] + }, + "exception.message": { + "source_group": "registry.exception", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "exception.stacktrace": { + "source_group": "registry.exception", + "inherited_fields": [ + "brief", + "examples", + "note", + "requirement_level", + "stability" + ] + }, + "exception.type": { + "source_group": "registry.exception", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + } + } } }, { @@ -76,13 +471,1172 @@ "brief": "This semantic convention defines the attributes used to represent a feature flag evaluation as an event.\n", "prefix": "feature_flag", "attributes": [ - 2, - 3, - 4 + 69, + 70, + 71 ], "lineage": { "source_file": "data/registry-test-4-events/registry/trace-feature-flag.yaml" } + }, + { + "id": "trace.gen_ai.client", + "type": "span", + "brief": "Describes GenAI operation span.\n", + "attributes": [ + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 26, + 27, + 28, + 72, + 73, + 74, + 75 + ], + "events": [ + "gen_ai.content.prompt", + "gen_ai.content.completion" + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-gen-ai.yaml", + "attributes": { + "gen_ai.operation.name": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.request.frequency_penalty": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.request.max_tokens": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.request.model": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "stability" + ], + "locally_overridden_fields": [ + "note", + "requirement_level" + ] + }, + "gen_ai.request.presence_penalty": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.request.stop_sequences": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.request.temperature": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.request.top_k": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.request.top_p": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability", + "tag" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.response.finish_reasons": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.response.id": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.response.model": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "stability" + ], + "locally_overridden_fields": [ + "note", + "requirement_level" + ] + }, + "gen_ai.system": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.usage.input_tokens": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "gen_ai.usage.output_tokens": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + } + } + } + }, + { + "id": "gen_ai.content.prompt", + "type": "event", + "brief": "In the lifetime of an GenAI span, events for prompts sent and completions received may be created, depending on the configuration of the instrumentation.\n", + "attributes": [ + 76 + ], + "name": "gen_ai.content.prompt", + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-gen-ai.yaml", + "attributes": { + "gen_ai.prompt": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "stability" + ], + "locally_overridden_fields": [ + "note", + "requirement_level" + ] + } + } + } + }, + { + "id": "gen_ai.content.completion", + "type": "event", + "brief": "In the lifetime of an GenAI span, events for prompts sent and completions received may be created, depending on the configuration of the instrumentation.\n", + "attributes": [ + 77 + ], + "name": "gen_ai.content.completion", + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-gen-ai.yaml", + "attributes": { + "gen_ai.completion": { + "source_group": "registry.gen_ai", + "inherited_fields": [ + "brief", + "examples", + "stability" + ], + "locally_overridden_fields": [ + "note", + "requirement_level" + ] + } + } + } + }, + { + "id": "rpc", + "type": "span", + "brief": "This document defines semantic conventions for remote procedure calls.", + "prefix": "rpc", + "attributes": [ + 45, + 46, + 58, + 59, + 78, + 79, + 80 + ], + "events": [ + "rpc.message" + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", + "attributes": { + "network.transport": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.type": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.method": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.service": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.system": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "server.address": { + "source_group": "registry.server", + "inherited_fields": [ + "examples", + "stability" + ], + "locally_overridden_fields": [ + "brief", + "note", + "requirement_level" + ] + }, + "server.port": { + "source_group": "registry.server", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + } + } + } + }, + { + "id": "rpc.client", + "type": "span", + "brief": "This document defines semantic conventions for remote procedure call client spans.", + "attributes": [ + 41, + 45, + 46, + 58, + 59, + 78, + 79, + 80, + 81 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", + "attributes": { + "network.peer.address": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.peer.port": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.transport": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.type": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.method": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.service": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.system": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "server.address": { + "source_group": "registry.server", + "inherited_fields": [ + "examples", + "stability" + ], + "locally_overridden_fields": [ + "brief", + "note", + "requirement_level" + ] + }, + "server.port": { + "source_group": "registry.server", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + } + } + } + }, + { + "id": "rpc.server", + "type": "span", + "brief": "Semantic Convention for RPC server spans", + "attributes": [ + 9, + 10, + 41, + 45, + 46, + 58, + 59, + 78, + 79, + 80, + 81 + ], + "span_kind": "server", + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", + "attributes": { + "client.address": { + "source_group": "registry.client", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "client.port": { + "source_group": "registry.client", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.peer.address": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.peer.port": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.transport": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.type": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.method": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.service": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.system": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "server.address": { + "source_group": "registry.server", + "inherited_fields": [ + "examples", + "stability" + ], + "locally_overridden_fields": [ + "brief", + "note", + "requirement_level" + ] + }, + "server.port": { + "source_group": "registry.server", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + } + } + } + }, + { + "id": "rpc.grpc", + "type": "span", + "brief": "Tech-specific attributes for gRPC.", + "attributes": [ + 45, + 46, + 58, + 59, + 78, + 79, + 80, + 82, + 83, + 84 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", + "attributes": { + "network.transport": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.type": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.grpc.request.metadata": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level", + "tag" + ] + }, + "rpc.grpc.response.metadata": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level", + "tag" + ] + }, + "rpc.grpc.status_code": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level", + "tag" + ] + }, + "rpc.method": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.service": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.system": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "server.address": { + "source_group": "registry.server", + "inherited_fields": [ + "examples", + "stability" + ], + "locally_overridden_fields": [ + "brief", + "note", + "requirement_level" + ] + }, + "server.port": { + "source_group": "registry.server", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + } + } + } + }, + { + "id": "rpc.jsonrpc", + "type": "span", + "brief": "Tech-specific attributes for [JSON RPC](https://www.jsonrpc.org/).", + "prefix": "rpc.jsonrpc", + "attributes": [ + 45, + 46, + 59, + 78, + 79, + 80, + 85, + 86, + 87, + 88, + 89 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", + "attributes": { + "network.transport": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.type": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.jsonrpc.error_code": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level", + "tag" + ] + }, + "rpc.jsonrpc.error_message": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level", + "tag" + ] + }, + "rpc.jsonrpc.request_id": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level", + "tag" + ] + }, + "rpc.jsonrpc.version": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level", + "tag" + ] + }, + "rpc.method": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "stability" + ], + "locally_overridden_fields": [ + "note", + "requirement_level", + "tag" + ] + }, + "rpc.service": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.system": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "server.address": { + "source_group": "registry.server", + "inherited_fields": [ + "examples", + "stability" + ], + "locally_overridden_fields": [ + "brief", + "note", + "requirement_level" + ] + }, + "server.port": { + "source_group": "registry.server", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + } + } + } + }, + { + "id": "rpc.message", + "type": "event", + "brief": "RPC received/sent message.", + "prefix": "rpc.message", + "attributes": [ + 61, + 62, + 63, + 64 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", + "attributes": { + "rpc.message.compressed_size": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.message.id": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.message.type": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.message.uncompressed_size": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + } + } + } + }, + { + "id": "rpc.connect_rpc", + "type": "span", + "brief": "Tech-specific attributes for Connect RPC.", + "attributes": [ + 45, + 46, + 58, + 59, + 78, + 79, + 80, + 90, + 91, + 92 + ], + "lineage": { + "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", + "attributes": { + "network.transport": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "network.type": { + "source_group": "registry.network", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.connect_rpc.error_code": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level", + "tag" + ] + }, + "rpc.connect_rpc.request.metadata": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level", + "tag" + ] + }, + "rpc.connect_rpc.response.metadata": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level", + "tag" + ] + }, + "rpc.method": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.service": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "rpc.system": { + "source_group": "registry.rpc", + "inherited_fields": [ + "brief", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + }, + "server.address": { + "source_group": "registry.server", + "inherited_fields": [ + "examples", + "stability" + ], + "locally_overridden_fields": [ + "brief", + "note", + "requirement_level" + ] + }, + "server.port": { + "source_group": "registry.server", + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ] + } + } + } } ] } \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/observed-events.json b/crates/weaver_resolver/data/registry-test-4-events/observed-events.json new file mode 100644 index 00000000..4f5390da --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/observed-events.json @@ -0,0 +1,219 @@ +[ + { + "attributes": [], + "body": { + "fields": [ + { + "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", + "name": "ios.state", + "note": "The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n", + "requirement_level": { + "conditionally_required": "if and only if `os.name` is `ios`" + }, + "stability": "experimental", + "type": { + "allow_custom_values": false, + "members": [ + { + "brief": "The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n", + "deprecated": null, + "id": "active", + "note": null, + "stability": null, + "value": "active" + }, + { + "brief": "The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n", + "deprecated": null, + "id": "inactive", + "note": null, + "stability": null, + "value": "inactive" + }, + { + "brief": "The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n", + "deprecated": null, + "id": "background", + "note": null, + "stability": null, + "value": "background" + }, + { + "brief": "The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n", + "deprecated": null, + "id": "foreground", + "note": null, + "stability": null, + "value": "foreground" + }, + { + "brief": "The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n", + "deprecated": null, + "id": "terminate", + "note": null, + "stability": null, + "value": "terminate" + } + ] + } + }, + { + "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", + "name": "android.state", + "note": "The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n", + "requirement_level": { + "conditionally_required": "if and only if `os.name` is `android`" + }, + "stability": "experimental", + "type": { + "allow_custom_values": false, + "members": [ + { + "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.\n", + "deprecated": null, + "id": "created", + "note": null, + "stability": null, + "value": "created" + }, + { + "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.\n", + "deprecated": null, + "id": "background", + "note": null, + "stability": null, + "value": "background" + }, + { + "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.", + "deprecated": null, + "id": "foreground", + "note": null, + "stability": null, + "value": "foreground" + } + ] + } + } + ] + }, + "brief": "This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n", + "events": [], + "id": "device.app.lifecycle", + "instrument": null, + "lineage": { + "source_file": "data/mobile-events.yaml" + }, + "metric_name": null, + "name": "device.app.lifecycle", + "note": "This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n", + "span_kind": null, + "stability": "experimental", + "type": "event", + "unit": null + }, + { + "attributes": [ + { + "brief": "A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n", + "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)", + "name": "exception.stacktrace", + "requirement_level": "recommended", + "stability": "stable", + "type": "string" + }, + { + "brief": "SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n", + "name": "exception.escaped", + "note": "An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager's `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.", + "requirement_level": "recommended", + "stability": "stable", + "type": "boolean" + }, + { + "brief": "The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n", + "examples": [ + "java.net.ConnectException", + "OSError" + ], + "name": "exception.type", + "requirement_level": { + "conditionally_required": "Required if `exception.message` is not set, recommended otherwise." + }, + "stability": "stable", + "type": "string" + }, + { + "brief": "The exception message.", + "examples": [ + "Division by zero", + "Can't convert 'int' object to str implicitly" + ], + "name": "exception.message", + "requirement_level": { + "conditionally_required": "Required if `exception.type` is not set, recommended otherwise." + }, + "stability": "stable", + "type": "string" + } + ], + "brief": "This document defines the attributes used to report a single exception associated with a span.\n", + "events": [], + "id": "trace-exception", + "instrument": null, + "lineage": { + "attributes": { + "exception.escaped": { + "inherited_fields": [ + "brief", + "note", + "requirement_level", + "stability" + ], + "source_group": "registry.exception" + }, + "exception.message": { + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ], + "source_group": "registry.exception" + }, + "exception.stacktrace": { + "inherited_fields": [ + "brief", + "examples", + "note", + "requirement_level", + "stability" + ], + "source_group": "registry.exception" + }, + "exception.type": { + "inherited_fields": [ + "brief", + "examples", + "note", + "stability" + ], + "locally_overridden_fields": [ + "requirement_level" + ], + "source_group": "registry.exception" + } + }, + "source_file": "data/trace-exception.yaml" + }, + "metric_name": null, + "name": null, + "prefix": "exception", + "span_kind": null, + "type": "event", + "unit": null + } +] \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml new file mode 100644 index 00000000..126a24a6 --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml @@ -0,0 +1,54 @@ +groups: + - id: registry.browser + name: browser.test.event + prefix: browser + type: event + brief: > + An event that adds global attributes for reuse. + attributes: + - id: brands + type: string[] + brief: 'Array of brand name and version separated by a space' + note: > + This value is intended to be taken from the + [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) + (`navigator.userAgentData.brands`). + examples: [ [ " Not A;Brand 99", "Chromium 99", "Chrome 99" ] ] + - id: platform + type: string + brief: 'The platform on which the browser is running' + note: > + This value is intended to be taken from the + [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) + (`navigator.userAgentData.platform`). If unavailable, the legacy + `navigator.platform` API SHOULD NOT be used instead and this attribute + SHOULD be left unset in order for the values to be consistent. + The list of possible values is defined in the + [W3C User-Agent Client Hints specification](https://wicg.github.io/ua-client-hints/#sec-ch-ua-platform). + Note that some (but not all) of these values can overlap with values + in the [`os.type` and `os.name` attributes](./os.md). + However, for consistency, the values in the `browser.platform` attribute + should capture the exact value that the user agent provides. + examples: [ "Windows", "macOS", "Android", "iOS", "Linux" ] + - id: mobile + type: boolean + brief: 'A boolean that is true if the browser is running on a mobile device' + note: > + This value is intended to be taken from the + [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) + (`navigator.userAgentData.mobile`). If unavailable, this attribute + SHOULD be left unset. + - id: language + type: string + brief: 'Preferred language of the user using the browser' + note: > + This value is intended to be taken from the Navigator API + `navigator.language`. + examples: [ "en", "en-US", "en-AU", "fr", "fr-FR" ] + body: + fields: + - id: some.field + type: string + brief: 'A field that is not referenced in the attributes' + note: 'This field is not referenced in the attributes' + examples: [ "some value", "another value" ] \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml new file mode 100644 index 00000000..5e6819fa --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml @@ -0,0 +1,39 @@ +groups: + - id: client.exception.event + name: client.exception.event + type: event + brief: > + This document defines the log event used to + report a client exception. + body: + fields: + - id: type + type: string + brief: > + The type of the exception. + examples: ["java.net.ConnectException","OSError"] + - id: message + type: string + brief: The exception message. + examples: ["Division by zero","Can't convert 'int' object to str implicitly"] + - id: stacktrace + type: string + brief: > + A stacktrace. + examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n + at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n + at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n + at com.example.GenerateTrace.main(GenerateTrace.java:5)' + - id: escaped + type: boolean + brief: > + SHOULD be set to true if the exception event is recorded at a point where + it is known that the exception is escaping the scope of the span. + note: |- + An exception is considered to have escaped. + attributes: + - id: client.name + type: string + brief: > + The name of the client that reported the exception. + examples: ["myclient"] \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/log-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/log-event.yaml new file mode 100644 index 00000000..e2556e1b --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/log-event.yaml @@ -0,0 +1,7 @@ +groups: + - id: log_event_attributes_only + name: some.event + type: event + brief: brief + attributes: + - ref: log.event.attr diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml index 94f93ebb..b1b219d5 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml @@ -1,72 +1,74 @@ groups: - - id: ios.lifecycle.events + - id: device.app.lifecycle + stability: experimental type: event - prefix: ios name: device.app.lifecycle brief: > - This event represents an occurrence of a lifecycle transition on the iOS platform. - attributes: - - id: state - requirement_level: "required" - note: > - The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), - and from which the `OS terminology` column values are derived. - brief: > - This attribute represents the state the application has transitioned into at the occurrence of the event. - type: - allow_custom_values: false - members: - - id: active - value: 'active' - brief: > - The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. - - id: inactive - value: 'inactive' - brief: > - The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. - - id: background - value: 'background' - brief: > - The app is now in the background. - This value is associated with UIKit notification `applicationDidEnterBackground`. - - id: foreground - value: 'foreground' - brief: > - The app is now in the foreground. - This value is associated with UIKit notification `applicationWillEnterForeground`. - - id: terminate - value: 'terminate' - brief: > - The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. - - id: android.lifecycle.events - type: event - prefix: android - name: device.app.lifecycle - brief: > - This event represents an occurrence of a lifecycle transition on the Android platform. - attributes: - - id: state - requirement_level: required - brief: > - This attribute represents the state the application has transitioned into at the occurrence of the event. - note: > - The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), - and from which the `OS identifiers` are derived. - type: - allow_custom_values: false - members: - - id: created - value: 'created' - 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. - - 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. - - 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. \ No newline at end of file + This event represents an occurrence of a lifecycle transition on Android or iOS platform. + note: > + This event identifies the fields that are common to all lifecycle events for android and iOS using + the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are + mutually exclusive. + body: + fields: + - id: ios.state + stability: experimental + requirement_level: + conditionally_required: if and only if `os.name` is `ios` + note: > + The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), + and from which the `OS terminology` column values are derived. + brief: > + This attribute represents the state the application has transitioned into at the occurrence of the event. + type: + allow_custom_values: false + members: + - id: active + value: 'active' + brief: > + The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. + - id: inactive + value: 'inactive' + brief: > + The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. + - id: background + value: 'background' + brief: > + The app is now in the background. + This value is associated with UIKit notification `applicationDidEnterBackground`. + - id: foreground + value: 'foreground' + brief: > + The app is now in the foreground. + This value is associated with UIKit notification `applicationWillEnterForeground`. + - id: terminate + value: 'terminate' + brief: > + The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. + - id: android.state + stability: experimental + requirement_level: + conditionally_required: if and only if `os.name` is `android` + brief: > + This attribute represents the state the application has transitioned into at the occurrence of the event. + note: > + The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), + and from which the `OS identifiers` are derived. + type: + allow_custom_values: false + members: + - id: created + value: 'created' + 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. + - 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. + - 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. \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/ping-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/ping-event.yaml new file mode 100644 index 00000000..a9ea856e --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/ping-event.yaml @@ -0,0 +1,5 @@ +groups: + - id: log_event_empty + name: ping.event + type: event + brief: brief \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-attributes.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-attributes.yaml new file mode 100644 index 00000000..8dad8dd0 --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-attributes.yaml @@ -0,0 +1,32 @@ +groups: + + # As the tests are only loading a subset of files we need to define any referenced attributes before they can be resolved for body fields + - id: referenced.attributes + type: attribute_group + brief: > + These attributes are used as references for the test below + attributes: + - id: browser.platform + stability: stable + type: string + brief: 'The browser platform' + note: Test value. + examples: ['Windows', 'macOS', 'Android'] + - id: http.url + stability: stable + type: string + brief: 'The Url' + note: Test url value. + examples: ['https://example.com'] + - id: log.event.attr + stability: stable + type: string + brief: 'Just making sure the referenced attributes are defined' + note: Test value. + examples: some value + - id: session.id + stability: stable + type: string + brief: 'The session id' + note: Test value. + examples: 127836abcdef98 diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-client.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-client.yaml new file mode 100644 index 00000000..3b17ed8b --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-client.yaml @@ -0,0 +1,28 @@ +groups: + - id: registry.client + prefix: client + type: attribute_group + brief: > + These attributes may be used to describe the client in a connection-based network interaction + where there is one side that initiates the connection (the client is the side that initiates the connection). + This covers all TCP network interactions since TCP is connection-based and one side initiates the + connection (an exception is made for peer-to-peer communication over TCP where the "user-facing" surface of the + protocol / API doesn't expose a clear notion of client and server). + This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS. + attributes: + - id: address + stability: stable + type: string + brief: "Client address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name." + note: > + When observed from the server side, and when communicating through an intermediary, `client.address` SHOULD represent + the client address behind any intermediaries, for example proxies, if it's available. + examples: ['client.example.com', '10.1.2.80', '/tmp/my.sock'] + - id: port + stability: stable + type: int + brief: Client port number. + examples: [65123] + note: > + When observed from the server side, and when communicating through an intermediary, `client.port` SHOULD represent + the client port behind any intermediaries, for example proxies, if it's available. diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-exception.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-exception.yaml new file mode 100644 index 00000000..3044fe69 --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-exception.yaml @@ -0,0 +1,55 @@ +groups: + - id: registry.exception + type: attribute_group + prefix: exception + brief: > + This document defines the shared attributes used to + report a single exception associated with a span or log. + attributes: + - id: type + type: string + stability: stable + brief: > + The type of the exception (its fully-qualified class name, if applicable). + The dynamic type of the exception should be preferred over the static type + in languages that support it. + examples: ["java.net.ConnectException", "OSError"] + - id: message + type: string + stability: stable + brief: The exception message. + examples: ["Division by zero", "Can't convert 'int' object to str implicitly"] + - id: stacktrace + type: string + stability: stable + brief: > + A stacktrace as a string in the natural representation for the language runtime. + The representation is to be determined and documented by each language SIG. + examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n + at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n + at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n + at com.example.GenerateTrace.main(GenerateTrace.java:5)' + - id: escaped + type: boolean + stability: stable + brief: > + SHOULD be set to true if the exception event is recorded at a point where + it is known that the exception is escaping the scope of the span. + note: |- + An exception is considered to have escaped (or left) the scope of a span, + if that span is ended while the exception is still logically "in flight". + This may be actually "in flight" in some languages (e.g. if the exception + is passed to a Context manager's `__exit__` method in Python) but will + usually be caught at the point of recording the exception in most languages. + + It is usually not possible to determine at the point where an exception is thrown + whether it will escape the scope of a span. + However, it is trivial to know that an exception + will escape, if one checks for an active exception just before ending the span, + as done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception). + + It follows that an exception may still escape the scope of the span + even if the `exception.escaped` attribute was not set or set to false, + since the event might have been recorded at a time where it was not + clear whether the exception will escape. + diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-gen_ai.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-gen_ai.yaml new file mode 100644 index 00000000..d05e09ea --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-gen_ai.yaml @@ -0,0 +1,148 @@ +groups: + - id: registry.gen_ai + prefix: gen_ai + type: attribute_group + brief: > + This document defines the attributes used to describe telemetry in the context of Generative Artificial Intelligence (GenAI) Models requests and responses. + attributes: + - id: system + stability: experimental + type: + members: + - id: openai + stability: experimental + value: "openai" + brief: 'OpenAI' + - id: vertex_ai + stability: experimental + value: "vertex_ai" + brief: 'Vertex AI' + - id: anthropic + stability: experimental + value: "anthropic" + brief: 'Anthropic' + - id: cohere + stability: experimental + value: "cohere" + brief: 'Cohere' + brief: The Generative AI product as identified by the client or server instrumentation. + note: | + The `gen_ai.system` describes a family of GenAI models with specific model identified + by `gen_ai.request.model` and `gen_ai.response.model` attributes. + + The actual GenAI product may differ from the one identified by the client. + For example, when using OpenAI client libraries to communicate with Mistral, the `gen_ai.system` + is set to `openai` based on the instrumentation's best knowledge. + + For custom model, a custom friendly name SHOULD be used. + If none of these options apply, the `gen_ai.system` SHOULD be set to `_OTHER`. + examples: 'openai' + - id: request.model + stability: experimental + type: string + brief: The name of the GenAI model a request is being made to. + examples: 'gpt-4' + - id: request.max_tokens + stability: experimental + type: int + brief: The maximum number of tokens the model generates for a request. + examples: [100] + - id: request.temperature + stability: experimental + type: double + brief: The temperature setting for the GenAI request. + examples: [0.0] + - id: request.top_p + stability: experimental + type: double + brief: The top_p sampling setting for the GenAI request. + examples: [1.0] + tag: llm-generic-request + - id: request.top_k + stability: experimental + type: double + brief: The top_k sampling setting for the GenAI request. + examples: [1.0] + - id: request.stop_sequences + stability: experimental + type: string[] + brief: List of sequences that the model will use to stop generating further tokens. + examples: [ [ 'forest', 'lived' ]] + - id: request.frequency_penalty + stability: experimental + type: double + brief: The frequency penalty setting for the GenAI request. + examples: [0.1] + - id: request.presence_penalty + stability: experimental + type: double + brief: The presence penalty setting for the GenAI request. + examples: [0.1] + - id: response.id + stability: experimental + type: string + brief: The unique identifier for the completion. + examples: ['chatcmpl-123'] + - id: response.model + stability: experimental + type: string + brief: The name of the model that generated the response. + examples: ['gpt-4-0613'] + - id: response.finish_reasons + stability: experimental + type: string[] + brief: Array of reasons the model stopped generating tokens, corresponding to each generation received. + examples: [ [ 'stop' ] ] + - id: usage.input_tokens + stability: experimental + type: int + brief: The number of tokens used in the GenAI input (prompt). + examples: [100] + - id: usage.output_tokens + stability: experimental + type: int + brief: The number of tokens used in the GenAI response (completion). + examples: [180] + - id: token.type + stability: experimental + type: + members: + - id: input + stability: experimental + value: "input" + brief: 'Input tokens (prompt, input, etc.)' + - id: completion + stability: experimental + value: "output" + brief: 'Output tokens (completion, response, etc.)' + brief: The type of token being counted. + examples: ['input', 'output'] + - id: prompt + stability: experimental + type: string + brief: The full prompt sent to the GenAI model. + note: It's RECOMMENDED to format prompts as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation) + examples: ["[{'role': 'user', 'content': 'What is the capital of France?'}]"] + - id: completion + stability: experimental + type: string + brief: The full response received from the GenAI model. + note: It's RECOMMENDED to format completions as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation) + examples: ["[{'role': 'assistant', 'content': 'The capital of France is Paris.'}]"] + - id: operation.name + stability: experimental + type: + members: + - id: chat + value: "chat" + brief: 'Chat completion operation such as [OpenAI Chat API](https://platform.openai.com/docs/api-reference/chat)' + stability: experimental + - id: text_completion + value: "text_completion" + brief: 'Text completions operation such as [OpenAI Completions API (Legacy)](https://platform.openai.com/docs/api-reference/completions)' + stability: experimental + brief: The name of the operation being performed. + note: > + If one of the predefined values applies, but specific system uses a different name it's RECOMMENDED to document it in the semantic + conventions for specific GenAI system and use system-specific name in the instrumentation. + If a different name is not documented, instrumentation libraries SHOULD use applicable predefined value. diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-network.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-network.yaml new file mode 100644 index 00000000..2f3f1957 --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-network.yaml @@ -0,0 +1,235 @@ +groups: + - id: registry.network + prefix: network + type: attribute_group + brief: > + These attributes may be used for any network related operation. + attributes: + - id: carrier.icc + type: string + stability: experimental + brief: "The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network." + examples: "DE" + - id: carrier.mcc + type: string + stability: experimental + brief: "The mobile carrier country code." + examples: "310" + - id: carrier.mnc + type: string + stability: experimental + brief: "The mobile carrier network code." + examples: "001" + - id: carrier.name + type: string + stability: experimental + brief: "The name of the mobile carrier." + examples: "sprint" + - id: connection.subtype + type: + allow_custom_values: true + members: + - id: gprs + brief: GPRS + value: "gprs" + stability: experimental + - id: edge + brief: EDGE + value: "edge" + stability: experimental + - id: umts + brief: UMTS + value: "umts" + stability: experimental + - id: cdma + brief: CDMA + value: "cdma" + stability: experimental + - id: evdo_0 + brief: EVDO Rel. 0 + value: "evdo_0" + stability: experimental + - id: evdo_a + brief: "EVDO Rev. A" + value: "evdo_a" + stability: experimental + - id: cdma2000_1xrtt + brief: CDMA2000 1XRTT + value: "cdma2000_1xrtt" + stability: experimental + - id: hsdpa + brief: HSDPA + value: "hsdpa" + stability: experimental + - id: hsupa + brief: HSUPA + value: "hsupa" + stability: experimental + - id: hspa + brief: HSPA + value: "hspa" + stability: experimental + - id: iden + brief: IDEN + value: "iden" + stability: experimental + - id: evdo_b + brief: "EVDO Rev. B" + value: "evdo_b" + stability: experimental + - id: lte + brief: LTE + value: "lte" + stability: experimental + - id: ehrpd + brief: EHRPD + value: "ehrpd" + stability: experimental + - id: hspap + brief: HSPAP + value: "hspap" + stability: experimental + - id: gsm + brief: GSM + value: "gsm" + stability: experimental + - id: td_scdma + brief: TD-SCDMA + value: "td_scdma" + stability: experimental + - id: iwlan + brief: IWLAN + value: "iwlan" + stability: experimental + - id: nr + brief: "5G NR (New Radio)" + value: "nr" + stability: experimental + - id: nrnsa + brief: "5G NRNSA (New Radio Non-Standalone)" + value: "nrnsa" + stability: experimental + - id: lte_ca + brief: LTE CA + value: "lte_ca" + stability: experimental + stability: experimental + brief: 'This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.' + examples: 'LTE' + - id: connection.type + type: + allow_custom_values: true + members: + - id: wifi + value: "wifi" + stability: experimental + - id: wired + value: "wired" + stability: experimental + - id: cell + value: "cell" + stability: experimental + - id: unavailable + value: "unavailable" + stability: experimental + - id: unknown + value: "unknown" + stability: experimental + stability: experimental + brief: 'The internet connection type.' + examples: 'wifi' + - id: local.address + stability: stable + type: string + brief: Local address of the network connection - IP address or Unix domain socket name. + examples: ['10.1.2.80', '/tmp/my.sock'] + - id: local.port + stability: stable + type: int + brief: Local port number of the network connection. + examples: [65123] + - id: peer.address + stability: stable + type: string + brief: Peer address of the network connection - IP address or Unix domain socket name. + examples: ['10.1.2.80', '/tmp/my.sock'] + - id: peer.port + stability: stable + type: int + brief: Peer port number of the network connection. + examples: [65123] + - id: protocol.name + stability: stable + type: string + brief: '[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.' + note: The value SHOULD be normalized to lowercase. + examples: ['amqp', 'http', 'mqtt'] + - id: protocol.version + stability: stable + type: string + brief: The actual version of the protocol used for network communication. + examples: ['1.1', '2'] + note: > + If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), + this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, + this attribute SHOULD NOT be set. + - id: transport + stability: stable + type: + allow_custom_values: true + members: + - id: tcp + value: 'tcp' + brief: "TCP" + stability: stable + - id: udp + value: 'udp' + brief: "UDP" + stability: stable + - id: pipe + value: "pipe" + brief: 'Named or anonymous pipe.' + stability: stable + - id: unix + value: 'unix' + brief: "Unix domain socket" + stability: stable + brief: > + [OSI transport layer](https://osi-model.com/transport-layer/) or + [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). + note: | + The value SHOULD be normalized to lowercase. + + Consider always setting the transport when setting a port number, since + a port number is ambiguous without knowing the transport. For example + different processes could be listening on TCP port 12345 and UDP port 12345. + examples: ['tcp', 'udp'] + - id: type + stability: stable + type: + allow_custom_values: true + members: + - id: ipv4 + value: 'ipv4' + brief: "IPv4" + stability: stable + - id: ipv6 + value: 'ipv6' + brief: "IPv6" + stability: stable + brief: '[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.' + note: The value SHOULD be normalized to lowercase. + examples: ['ipv4', 'ipv6'] + - id: io.direction + type: + allow_custom_values: false + members: + - id: transmit + value: 'transmit' + stability: experimental + - id: receive + value: 'receive' + stability: experimental + stability: experimental + brief: "The network IO operation direction." + examples: ["transmit"] diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-rpc.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-rpc.yaml new file mode 100644 index 00000000..d1e0aa05 --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-rpc.yaml @@ -0,0 +1,265 @@ +groups: + - id: registry.rpc + prefix: rpc + type: attribute_group + brief: 'This document defines attributes for remote procedure calls.' + attributes: + - id: connect_rpc.error_code + type: + members: + - id: cancelled + value: cancelled + stability: experimental + - id: unknown + value: unknown + stability: experimental + - id: invalid_argument + value: invalid_argument + stability: experimental + - id: deadline_exceeded + value: deadline_exceeded + stability: experimental + - id: not_found + value: not_found + stability: experimental + - id: already_exists + value: already_exists + stability: experimental + - id: permission_denied + value: permission_denied + stability: experimental + - id: resource_exhausted + value: resource_exhausted + stability: experimental + - id: failed_precondition + value: failed_precondition + stability: experimental + - id: aborted + value: aborted + stability: experimental + - id: out_of_range + value: out_of_range + stability: experimental + - id: unimplemented + value: unimplemented + stability: experimental + - id: internal + value: internal + stability: experimental + - id: unavailable + value: unavailable + stability: experimental + - id: data_loss + value: data_loss + stability: experimental + - id: unauthenticated + value: unauthenticated + stability: experimental + stability: experimental + brief: "The [error codes](https://connect.build/docs/protocol/#error-codes) of the Connect request. Error codes are always string values." + - id: connect_rpc.request.metadata + type: template[string[]] + stability: experimental + brief: > + Connect request metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values. + note: > + Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. + Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information. + examples: ['rpc.request.metadata.my-custom-metadata-attribute=["1.2.3.4", "1.2.3.5"]'] + - id: connect_rpc.response.metadata + type: template[string[]] + stability: experimental + brief: > + Connect response metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values. + note: > + Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. + Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information. + examples: ['rpc.response.metadata.my-custom-metadata-attribute=["attribute_value"]'] + - id: grpc.status_code + type: + members: + - id: ok + brief: OK + stability: experimental + value: 0 + - id: cancelled + brief: CANCELLED + stability: experimental + value: 1 + - id: unknown + brief: UNKNOWN + stability: experimental + value: 2 + - id: invalid_argument + brief: INVALID_ARGUMENT + stability: experimental + value: 3 + - id: deadline_exceeded + brief: DEADLINE_EXCEEDED + stability: experimental + value: 4 + - id: not_found + brief: NOT_FOUND + stability: experimental + value: 5 + - id: already_exists + brief: ALREADY_EXISTS + stability: experimental + value: 6 + - id: permission_denied + brief: PERMISSION_DENIED + stability: experimental + value: 7 + - id: resource_exhausted + brief: RESOURCE_EXHAUSTED + stability: experimental + value: 8 + - id: failed_precondition + brief: FAILED_PRECONDITION + stability: experimental + value: 9 + - id: aborted + brief: ABORTED + stability: experimental + value: 10 + - id: out_of_range + brief: OUT_OF_RANGE + stability: experimental + value: 11 + - id: unimplemented + brief: UNIMPLEMENTED + stability: experimental + value: 12 + - id: internal + brief: INTERNAL + stability: experimental + value: 13 + - id: unavailable + brief: UNAVAILABLE + stability: experimental + value: 14 + - id: data_loss + brief: DATA_LOSS + stability: experimental + value: 15 + - id: unauthenticated + brief: UNAUTHENTICATED + stability: experimental + value: 16 + stability: experimental + brief: "The [numeric status code](https://github.com/grpc/grpc/blob/v1.33.2/doc/statuscodes.md) of the gRPC request." + - id: grpc.request.metadata + type: template[string[]] + stability: experimental + brief: > + gRPC request metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values. + note: > + Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. + Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information. + examples: ['rpc.grpc.request.metadata.my-custom-metadata-attribute=["1.2.3.4", "1.2.3.5"]'] + - id: grpc.response.metadata + type: template[string[]] + stability: experimental + brief: > + gRPC response metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values. + note: > + Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. + Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information. + examples: ['rpc.grpc.response.metadata.my-custom-metadata-attribute=["attribute_value"]'] + - id: jsonrpc.error_code + type: int + stability: experimental + brief: "`error.code` property of response if it is an error response." + examples: [-32700, 100] + - id: jsonrpc.error_message + type: string + stability: experimental + brief: "`error.message` property of response if it is an error response." + examples: ['Parse error', 'User already exists'] + - id: jsonrpc.request_id + type: string + stability: experimental + brief: > + `id` property of request or response. + Since protocol allows id to be int, string, `null` or missing (for notifications), + value is expected to be cast to string for simplicity. + Use empty string in case of `null` value. Omit entirely if this is a notification. + examples: ['10', 'request-7', ''] + - id: jsonrpc.version + type: string + stability: experimental + brief: "Protocol version as in `jsonrpc` property of request/response. Since JSON-RPC 1.0 doesn't specify this, the value can be omitted." + examples: ['2.0', '1.0'] + - id: method + type: string + stability: experimental + brief: 'The name of the (logical) method being called, must be equal to the $method part in the span name.' + note: > + This is the logical name of the method from the RPC interface perspective, + which can be different from the name of any implementing method/function. + The `code.function` attribute may be used to store the latter + (e.g., method actually executing the call on the server side, + RPC client stub method on the client side). + examples: "exampleMethod" + - id: service + type: string + stability: experimental + brief: 'The full (logical) name of the service being called, including its package name, if applicable.' + note: > + This is the logical name of the service from the RPC interface perspective, + which can be different from the name of any implementing class. + The `code.namespace` attribute may be used to store the latter + (despite the attribute name, it may include a class name; + e.g., class with method actually executing the call on the server side, + RPC client stub class on the client side). + examples: "myservice.EchoService" + - id: system + brief: 'A string identifying the remoting system. See below for a list of well-known identifiers.' + type: + allow_custom_values: true + members: + - id: grpc + value: 'grpc' + brief: 'gRPC' + stability: experimental + - id: java_rmi + value: 'java_rmi' + brief: 'Java RMI' + stability: experimental + - id: dotnet_wcf + value: 'dotnet_wcf' + brief: '.NET WCF' + stability: experimental + - id: apache_dubbo + value: 'apache_dubbo' + brief: 'Apache Dubbo' + stability: experimental + - id: connect_rpc + value: 'connect_rpc' + brief: 'Connect RPC' + stability: experimental + stability: experimental + - id: message.type + type: + members: + - id: sent + value: "SENT" + stability: experimental + - id: received + value: "RECEIVED" + stability: experimental + stability: experimental + brief: "Whether this is a received or sent message." + - id: message.id + type: int + stability: experimental + brief: "MUST be calculated as two different counters starting from `1` one for sent messages and one for received message." + note: "This way we guarantee that the values will be consistent between different implementations." + - id: message.compressed_size + type: int + stability: experimental + brief: "Compressed size of the message in bytes." + - id: message.uncompressed_size + type: int + stability: experimental + brief: "Uncompressed size of the message in bytes." diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-server.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-server.yaml new file mode 100644 index 00000000..d6927fe9 --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-server.yaml @@ -0,0 +1,28 @@ +groups: + - id: registry.server + prefix: server + type: attribute_group + brief: > + These attributes may be used to describe the server in a connection-based network interaction + where there is one side that initiates the connection (the client is the side that initiates the connection). + This covers all TCP network interactions since TCP is connection-based and one side initiates the + connection (an exception is made for peer-to-peer communication over TCP where the "user-facing" surface of the + protocol / API doesn't expose a clear notion of client and server). + This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS. + attributes: + - id: address + stability: stable + type: string + brief: "Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name." + note: > + When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent + the server address behind any intermediaries, for example proxies, if it's available. + examples: ['example.com', '10.1.2.80', '/tmp/my.sock'] + - id: port + stability: stable + type: int + brief: Server port number. + note: > + When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent + the server port behind any intermediaries, for example proxies, if it's available. + examples: [80, 8080, 443] diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-exception.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-exception.yaml new file mode 100644 index 00000000..32c53f4b --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-exception.yaml @@ -0,0 +1,16 @@ +groups: + - id: trace-exception + prefix: exception + type: event + brief: > + This document defines the attributes used to + report a single exception associated with a span. + attributes: + - ref: exception.type + requirement_level: + conditionally_required: Required if `exception.message` is not set, recommended otherwise. + - ref: exception.message + requirement_level: + conditionally_required: Required if `exception.type` is not set, recommended otherwise. + - ref: exception.stacktrace + - ref: exception.escaped diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-gen-ai.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-gen-ai.yaml new file mode 100644 index 00000000..d036c197 --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-gen-ai.yaml @@ -0,0 +1,73 @@ +groups: + - id: trace.gen_ai.client + type: span + brief: > + Describes GenAI operation span. + attributes: + - ref: gen_ai.system + requirement_level: required + - ref: gen_ai.request.model + requirement_level: required + note: > + The name of the GenAI model a request is being made to. If the model is supplied by a vendor, + then the value must be the exact name of the model requested. If the model is a fine-tuned + custom model, the value should have a more specific name than the base model that's been fine-tuned. + - ref: gen_ai.operation.name + requirement_level: required + - ref: gen_ai.request.max_tokens + requirement_level: recommended + - ref: gen_ai.request.temperature + requirement_level: recommended + - ref: gen_ai.request.top_p + requirement_level: recommended + - ref: gen_ai.request.top_k + requirement_level: recommended + - ref: gen_ai.request.stop_sequences + requirement_level: recommended + - ref: gen_ai.request.frequency_penalty + requirement_level: recommended + - ref: gen_ai.request.presence_penalty + requirement_level: recommended + - ref: gen_ai.response.id + requirement_level: recommended + - ref: gen_ai.response.model + requirement_level: recommended + note: > + If available. The name of the GenAI model that provided the response. If the model is supplied by a vendor, + then the value must be the exact name of the model actually used. If the model is a + fine-tuned custom model, the value should have a more specific name than the base model that's been fine-tuned. + - ref: gen_ai.response.finish_reasons + requirement_level: recommended + - ref: gen_ai.usage.input_tokens + requirement_level: recommended + - ref: gen_ai.usage.output_tokens + requirement_level: recommended + events: + - gen_ai.content.prompt + - gen_ai.content.completion + + - id: gen_ai.content.prompt + name: gen_ai.content.prompt + type: event + brief: > + In the lifetime of an GenAI span, events for prompts sent and completions received + may be created, depending on the configuration of the instrumentation. + attributes: + - ref: gen_ai.prompt + requirement_level: + conditionally_required: if and only if corresponding event is enabled + note: > + It's RECOMMENDED to format prompts as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation) + + - id: gen_ai.content.completion + name: gen_ai.content.completion + type: event + brief: > + In the lifetime of an GenAI span, events for prompts sent and completions received + may be created, depending on the configuration of the instrumentation. + attributes: + - ref: gen_ai.completion + requirement_level: + conditionally_required: if and only if corresponding event is enabled + note: > + It's RECOMMENDED to format completions as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation) diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-rpc.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-rpc.yaml new file mode 100644 index 00000000..d578c6ba --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-rpc.yaml @@ -0,0 +1,131 @@ +groups: + - id: rpc + prefix: rpc + type: span + brief: 'This document defines semantic conventions for remote procedure calls.' + events: [rpc.message] + attributes: + - ref: rpc.system + requirement_level: required + - ref: rpc.service + requirement_level: recommended + - ref: rpc.method + requirement_level: recommended + - ref: network.transport + requirement_level: recommended + - ref: network.type + requirement_level: recommended + - ref: server.address + requirement_level: required + brief: > + RPC server [host name](https://grpc.github.io/grpc/core/md_doc_naming.html). + note: > + May contain server IP address, DNS name, or local socket name. When host component is an IP address, + instrumentations SHOULD NOT do a reverse proxy lookup to obtain DNS name and SHOULD set + `server.address` to the IP address provided in the host component. + - ref: server.port + requirement_level: + conditionally_required: if the port is supported by the network transport used for communication. + + - id: rpc.client + type: span + brief: 'This document defines semantic conventions for remote procedure call client spans.' + extends: rpc + attributes: + - ref: network.peer.address + requirement_level: recommended + - ref: network.peer.port + requirement_level: + recommended: If `network.peer.address` is set. + + - id: rpc.server + type: span + extends: rpc + span_kind: server + brief: 'Semantic Convention for RPC server spans' + attributes: + - ref: client.address + requirement_level: recommended + - ref: client.port + requirement_level: recommended + - ref: network.peer.address + requirement_level: recommended + - ref: network.peer.port + requirement_level: + recommended: If `network.peer.address` is set. + - ref: network.transport + requirement_level: recommended + - ref: network.type + requirement_level: recommended + + - id: rpc.grpc + type: span + extends: rpc + brief: 'Tech-specific attributes for gRPC.' + attributes: + - ref: rpc.grpc.status_code + tag: grpc-tech-specific + requirement_level: required + - ref: rpc.grpc.request.metadata + tag: grpc-tech-specific + requirement_level: opt_in + - ref: rpc.grpc.response.metadata + tag: grpc-tech-specific + requirement_level: opt_in + + - id: rpc.jsonrpc + prefix: rpc.jsonrpc + type: span + extends: rpc + brief: 'Tech-specific attributes for [JSON RPC](https://www.jsonrpc.org/).' + attributes: + - ref: rpc.jsonrpc.version + tag: jsonrpc-tech-specific + requirement_level: + conditionally_required: If other than the default version (`1.0`) + - ref: rpc.jsonrpc.request_id + tag: jsonrpc-tech-specific + requirement_level: recommended + - ref: rpc.jsonrpc.error_code + tag: jsonrpc-tech-specific + requirement_level: + conditionally_required: If response is not successful. + - ref: rpc.jsonrpc.error_message + tag: jsonrpc-tech-specific + requirement_level: recommended + - ref: rpc.method + tag: jsonrpc-tech-specific + requirement_level: required + note: > + This is always required for jsonrpc. See the note in the general + RPC conventions for more information. + + - id: rpc.message + prefix: rpc.message + type: event + brief: "RPC received/sent message." + attributes: + - ref: rpc.message.type + requirement_level: recommended + - ref: rpc.message.id + requirement_level: recommended + - ref: rpc.message.compressed_size + requirement_level: recommended + - ref: rpc.message.uncompressed_size + requirement_level: recommended + + - id: rpc.connect_rpc + type: span + extends: rpc + brief: 'Tech-specific attributes for Connect RPC.' + attributes: + - ref: rpc.connect_rpc.error_code + tag: connect_rpc-tech-specific + requirement_level: + conditionally_required: If response is not successful and if error code available. + - ref: rpc.connect_rpc.request.metadata + tag: connect_rpc-tech-specific + requirement_level: opt_in + - ref: rpc.connect_rpc.response.metadata + tag: connect_rpc-tech-specific + requirement_level: opt_in diff --git a/crates/weaver_resolver/src/attribute.rs b/crates/weaver_resolver/src/attribute.rs index bd617df5..ec4fe3f4 100644 --- a/crates/weaver_resolver/src/attribute.rs +++ b/crates/weaver_resolver/src/attribute.rs @@ -23,12 +23,21 @@ pub struct AttributeCatalog { } #[derive(Debug, PartialEq)] -struct AttributeWithGroupId { +/// The Attribute with its group ID. +pub struct AttributeWithGroupId { + /// The attribute. pub attribute: attribute::Attribute, + /// The group ID. pub group_id: String, } impl AttributeCatalog { + /// Returns the given attribute from the catalog. + #[must_use] + pub fn get_attribute(&self, name: &str) -> Option<&AttributeWithGroupId> { + self.root_attributes.get(name) + } + /// Returns the reference of the given attribute or creates a new reference if the attribute /// does not exist in the catalog. pub fn attribute_ref(&mut self, attr: attribute::Attribute) -> AttributeRef { diff --git a/crates/weaver_resolver/src/body.rs b/crates/weaver_resolver/src/body.rs new file mode 100644 index 00000000..a1177c57 --- /dev/null +++ b/crates/weaver_resolver/src/body.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! Functions to resolve a semantic convention body. + +use weaver_resolved_schema::{ + body::{Body, BodyField}, + error::{handle_errors, Error}, +}; +use weaver_semconv::body::{BodyFieldSpec, BodySpec}; + +/// Resolve a `Body` specification into a resolved `Body`. +pub fn resolve_body_spec(body: &BodySpec) -> Result, Error> { + match body { + BodySpec::Fields { fields } => { + let mut errors = vec![]; + let mut body_fields = Vec::new(); + for field in fields.iter() { + match resolve_body_field_spec(field) { + Ok(r) => body_fields.push(r), + Err(e) => errors.push(e), + } + } + handle_errors(errors)?; + Ok(Some(Body { + fields: Some(body_fields), + // value: None, // Not yet implemented + })) + } + BodySpec::Value { value: _ } => { + // Add as a placeholder for now of where to resolve the value. + Err(Error::NotImplemented { + message: "Value type for body is not currently implemented.".to_owned(), + }) + } + } +} + +/// Resolve a `BodyField`` specification into a resolved `BodyField``. +pub fn resolve_body_field_spec(field: &BodyFieldSpec) -> Result { + Ok(BodyField { + name: field.id.clone(), + r#type: field.r#type.clone(), + brief: field.brief.clone().unwrap_or_else(|| "".to_owned()), + examples: field.examples.clone(), + requirement_level: field.requirement_level.clone(), + note: field.note.clone(), + stability: field.stability.clone(), + deprecated: field.deprecated.clone(), + }) +} diff --git a/crates/weaver_resolver/src/lib.rs b/crates/weaver_resolver/src/lib.rs index 5ce6e280..7fec3d3a 100644 --- a/crates/weaver_resolver/src/lib.rs +++ b/crates/weaver_resolver/src/lib.rs @@ -26,6 +26,7 @@ use crate::attribute::AttributeCatalog; use crate::registry::resolve_semconv_registry; pub mod attribute; +pub mod body; mod constraint; pub mod registry; @@ -145,6 +146,17 @@ pub enum Error { /// A container for multiple errors. #[error("{:?}", format_errors(.0))] CompoundError(#[related] Vec), + + /// An error indicating that the Body references are not resolved. + #[error("The following body reference is not resolved.\nBody reference: {group_id}\nProvenance: {provenance}\nError: {error}")] + UnresolvedBody { + /// The unresolved body reference. + group_id: String, + /// The provenance of the reference (URL or path). + provenance: String, + /// The errors that occurred. + error: weaver_resolved_schema::error::Error, + }, } impl WeaverError for Error { diff --git a/crates/weaver_resolver/src/registry.rs b/crates/weaver_resolver/src/registry.rs index db324169..f1aa82ce 100644 --- a/crates/weaver_resolver/src/registry.rs +++ b/crates/weaver_resolver/src/registry.rs @@ -8,6 +8,7 @@ use serde::Deserialize; use weaver_common::error::handle_errors; use weaver_resolved_schema::attribute::UnresolvedAttribute; +use weaver_resolved_schema::body::UnresolvedBody; use weaver_resolved_schema::lineage::{AttributeLineage, GroupLineage}; use weaver_resolved_schema::registry::{Constraint, Group, Registry}; use weaver_semconv::attribute::AttributeSpec; @@ -15,6 +16,7 @@ use weaver_semconv::group::GroupSpecWithProvenance; use weaver_semconv::registry::SemConvRegistry; use crate::attribute::AttributeCatalog; +use crate::body::resolve_body_spec; use crate::constraint::resolve_constraints; use crate::{Error, UnsatisfiedAnyOfConstraint}; @@ -42,6 +44,9 @@ pub struct UnresolvedGroup { /// and other signals, into the group field once they are resolved. pub attributes: Vec, + /// The unresolved body that belongs to this group + pub body: Option, + /// The provenance of the group (URL or path). pub provenance: String, } @@ -82,6 +87,8 @@ pub fn resolve_semconv_registry( resolve_include_constraints(&mut ureg)?; + resolve_body(&mut ureg)?; + // Sort the attribute internal references in each group. // This is needed to ensure that the resolved registry is easy to compare // in unit tests. @@ -330,8 +337,10 @@ fn group_from_spec(group: GroupSpecWithProvenance) -> UnresolvedGroup { name: group.spec.name, lineage: Some(GroupLineage::new(&group.provenance)), display_name: group.spec.display_name, + body: None, // The body is resolved and populated later. }, attributes: attrs, + body: { group.spec.body.map(|body| UnresolvedBody { spec: body }) }, provenance: group.provenance, } } @@ -757,6 +766,30 @@ fn resolve_inheritance_attr( } } +fn resolve_body(ureg: &mut UnresolvedRegistry) -> Result<(), Error> { + let mut errors = vec![]; + + for unresolved_group in ureg.groups.iter_mut() { + if let Some(body) = &unresolved_group.body { + match resolve_body_spec(&body.spec) { + Ok(resolved_body) => { + unresolved_group.group.body = resolved_body; + } + Err(e) => { + errors.push(Error::UnresolvedBody { + group_id: unresolved_group.group.id.clone(), + provenance: unresolved_group.provenance.clone(), + error: e, + }); + } + } + } + } + + handle_errors(errors)?; + Ok(()) +} + #[cfg(test)] mod tests { use std::collections::HashSet; diff --git a/crates/weaver_semconv/data/event.yaml b/crates/weaver_semconv/data/event.yaml new file mode 100644 index 00000000..241f88b7 --- /dev/null +++ b/crates/weaver_semconv/data/event.yaml @@ -0,0 +1,149 @@ +groups: + - id: device.app.lifecycle + stability: experimental + type: event + name: device.app.lifecycle + brief: > + This event represents an occurrence of a lifecycle transition on Android or iOS platform. + note: > + This event identifies the fields that are common to all lifecycle events for android and iOS using + the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are + mutually exclusive. + body: + fields: + - id: ios.state + stability: experimental + requirement_level: + conditionally_required: if and only if `os.name` is `ios` + note: > + The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), + and from which the `OS terminology` column values are derived. + brief: > + This attribute represents the state the application has transitioned into at the occurrence of the event. + type: + allow_custom_values: false + members: + - id: active + value: 'active' + brief: > + The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. + - id: inactive + value: 'inactive' + brief: > + The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. + - id: background + value: 'background' + brief: > + The app is now in the background. + This value is associated with UIKit notification `applicationDidEnterBackground`. + - id: foreground + value: 'foreground' + brief: > + The app is now in the foreground. + This value is associated with UIKit notification `applicationWillEnterForeground`. + - id: terminate + value: 'terminate' + brief: > + The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. + - id: android.state + stability: experimental + requirement_level: + conditionally_required: if and only if `os.name` is `android` + brief: > + This attribute represents the state the application has transitioned into at the occurrence of the event. + note: > + The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), + and from which the `OS identifiers` are derived. + type: + allow_custom_values: false + members: + - id: created + value: 'created' + 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. + - 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. + - 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. + + - id: span.event.test.no_name + stability: experimental + type: event + prefix: span.event.test + brief: > + This event represents an occurrence of a span event. + attributes: + - id: attribute1 + type: string + brief: 'The attribute1' + examples: ['value1', 'value2'] + requirement_level: + conditionally_required: Required if `attribute2` is not set, recommended otherwise. + - id: attribute2 + type: string + brief: 'The attribute2' + examples: ['value1', 'value2'] + requirement_level: + conditionally_required: Required if `attribute1` is not set, recommended otherwise. + + - id: span.event.test.with_name + name: span.event.test.with_name + stability: experimental + type: event + prefix: span.event.test.with_name + brief: > + This event represents an occurrence of a span event. + attributes: + - id: attribute1 + type: string + brief: 'The attribute1' + examples: ['value1', 'value2'] + requirement_level: + conditionally_required: Required if `attribute2` is not set, recommended otherwise. + - id: attribute2 + type: string + brief: 'The attribute2' + examples: ['value1', 'value2'] + requirement_level: + conditionally_required: Required if `attribute1` is not set, recommended otherwise. + + - id: test.event.with_attributes + name: test.event.with_attributes + stability: experimental + type: event + brief: > + This event represents an occurrence of a test event. + attributes: + - id: attribute1 + type: string + brief: 'The attribute1' + examples: ['value1', 'value2'] + requirement_level: + conditionally_required: Required if `attribute2` is not set, recommended otherwise. + - id: attribute2 + type: string + brief: 'The attribute2' + examples: ['value1', 'value2'] + requirement_level: + conditionally_required: Required if `attribute1` is not set, recommended otherwise. + body: + fields: + - id: field1 + type: string + brief: 'The field1' + examples: ['value1', 'value2'] + requirement_level: + conditionally_required: Required if `field2` is not set, recommended otherwise. + - id: field2 + type: string + brief: 'The field2' + examples: ['value1', 'value2'] + requirement_level: + conditionally_required: Required if `field1` is not set, recommended otherwise. \ No newline at end of file diff --git a/crates/weaver_semconv/src/body.rs b/crates/weaver_semconv/src/body.rs new file mode 100644 index 00000000..19a70660 --- /dev/null +++ b/crates/weaver_semconv/src/body.rs @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: Apache-2.0 + +#![allow(rustdoc::invalid_html_tags)] + +//! Body Field specification. + +use serde::{Deserialize, Serialize}; + +use crate::attribute::{ + AttributeType, BasicRequirementLevelSpec, Examples, RequirementLevel, ValueSpec, +}; +use crate::stability::Stability; + +/// A body specification +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(deny_unknown_fields)] +#[serde(untagged)] +#[serde(rename_all = "snake_case")] +pub enum BodySpec { + /// The collection of body fields associated with a body definition + Fields { + /// The collection of body fields associated with a body definition + #[serde(skip_serializing_if = "Vec::is_empty")] + fields: Vec, + }, + /// The body field value. + Value { + /// The body field value. + value: ValueSpec, + }, +} + +impl BodySpec { + /// Returns true if the body field is required. + #[must_use] + pub fn has_fields(&self) -> bool { + match self { + BodySpec::Fields { fields } => !fields.is_empty(), + BodySpec::Value { value: _ } => false, + } + } +} + +/// A `BodyField` specification. +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(deny_unknown_fields)] +#[serde(rename_all = "snake_case")] +pub struct BodyFieldSpec { + /// String that uniquely identifies the body field. + pub id: String, + /// Either a string literal denoting the type as a primitive or an + /// array type, a template type or an enum definition. + pub r#type: AttributeType, + /// A brief description of the body field. + pub brief: Option, + /// Sequence of example values for the body field or single example + /// value. They are required only for string and string array + /// fields. Example values must be of the same type of the + /// body field. If only a single example is provided, it can directly + /// be reported without encapsulating it into a sequence/dictionary. + #[serde(skip_serializing_if = "Option::is_none")] + pub examples: Option, + /// Specifies if the body field is mandatory. Can be "required", + /// "conditionally_required", "recommended" or "opt_in". When omitted, + /// the body field is "recommended". When set to + /// "conditionally_required", the string provided as MUST + /// specify the conditions under which the body field is required. + #[serde(default)] + pub requirement_level: RequirementLevel, + /// A more elaborate description of the body field. + /// It defaults to an empty string. + #[serde(default)] + pub note: String, + /// Specifies the stability of the body field. + /// Note that, if stability is missing but deprecated is present, it will + /// automatically set the stability to deprecated. If deprecated is + /// present and stability differs from deprecated, this will result in an + /// error. + #[serde(skip_serializing_if = "Option::is_none")] + pub stability: Option, + /// Specifies if the body field is deprecated. The string + /// provided as MUST specify why it's deprecated and/or what + /// to use instead. See also stability. + #[serde(skip_serializing_if = "Option::is_none")] + pub deprecated: Option, +} + +impl BodyFieldSpec { + /// Returns true if the body field is required. + #[must_use] + pub fn is_required(&self) -> bool { + matches!( + self, + BodyFieldSpec { + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), + .. + } + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::attribute::{ + EnumEntriesSpec, PrimitiveOrArrayTypeSpec, TemplateTypeSpec, ValueSpec, + }; + + #[test] + fn test_body_field_type_display() { + assert_eq!( + format!( + "{}", + AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Boolean) + ), + "boolean" + ); + assert_eq!( + format!( + "{}", + AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Int) + ), + "int" + ); + assert_eq!( + format!( + "{}", + AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Double) + ), + "double" + ); + assert_eq!( + format!( + "{}", + AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::String) + ), + "string" + ); + assert_eq!( + format!( + "{}", + AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Strings) + ), + "string[]" + ); + assert_eq!( + format!( + "{}", + AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Ints) + ), + "int[]" + ); + assert_eq!( + format!( + "{}", + AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Doubles) + ), + "double[]" + ); + assert_eq!( + format!( + "{}", + AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Booleans) + ), + "boolean[]" + ); + assert_eq!( + format!("{}", AttributeType::Template(TemplateTypeSpec::Boolean)), + "template[boolean]" + ); + assert_eq!( + format!("{}", AttributeType::Template(TemplateTypeSpec::Int)), + "template[int]" + ); + assert_eq!( + format!("{}", AttributeType::Template(TemplateTypeSpec::Double)), + "template[double]" + ); + assert_eq!( + format!("{}", AttributeType::Template(TemplateTypeSpec::String)), + "template[string]" + ); + assert_eq!( + format!("{}", AttributeType::Template(TemplateTypeSpec::Strings)), + "template[string[]]" + ); + assert_eq!( + format!("{}", AttributeType::Template(TemplateTypeSpec::Ints)), + "template[int[]]" + ); + assert_eq!( + format!("{}", AttributeType::Template(TemplateTypeSpec::Doubles)), + "template[double[]]" + ); + assert_eq!( + format!("{}", AttributeType::Template(TemplateTypeSpec::Booleans)), + "template[boolean[]]" + ); + assert_eq!( + format!( + "{}", + AttributeType::Enum { + allow_custom_values: true, + members: vec![EnumEntriesSpec { + id: "id".to_owned(), + value: ValueSpec::Int(42), + brief: Some("brief".to_owned()), + note: Some("note".to_owned()), + stability: None, + deprecated: None, + }] + } + ), + "enum {id}" + ); + } + + #[test] + fn test_body_field() { + let field = BodyFieldSpec { + id: "id".to_owned(), + r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Int), + brief: Some("brief".to_owned()), + examples: Some(Examples::Int(42)), + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), + note: "note".to_owned(), + stability: Some(Stability::Stable), + deprecated: Some("deprecated".to_owned()), + }; + assert_eq!(field.id, "id"); + assert_eq!(field.brief.to_owned(), Some("brief".to_owned())); + assert_eq!(field.note, "note"); + assert!(field.is_required()); + } +} + +/// A Body Field definition with its provenance (path or URL). +#[derive(Debug, Clone)] +pub struct BodyFieldSpecWithProvenance { + /// The body field definition. + pub body_field: BodyFieldSpec, + /// The provenance of the body field (path or URL). + pub provenance: String, +} diff --git a/crates/weaver_semconv/src/group.rs b/crates/weaver_semconv/src/group.rs index a0211432..d580081d 100644 --- a/crates/weaver_semconv/src/group.rs +++ b/crates/weaver_semconv/src/group.rs @@ -10,6 +10,7 @@ use std::fmt::{Display, Formatter}; use serde::{Deserialize, Serialize}; use crate::attribute::{AttributeSpec, AttributeType, PrimitiveOrArrayTypeSpec}; +use crate::body::BodySpec; use crate::group::InstrumentSpec::{Counter, Gauge, Histogram, UpDownCounter}; use crate::stability::Stability; use crate::Error; @@ -86,6 +87,9 @@ pub struct GroupSpec { pub name: Option, /// The readable name for attribute groups used when generating registry tables. pub display_name: Option, + /// The event body definition + /// Note: only valid if type is event + pub body: Option, } impl GroupSpec { @@ -114,11 +118,30 @@ impl GroupSpec { } // Field name is required if prefix is empty and if type is event. - if self.r#type == GroupType::Event && self.prefix.is_empty() && self.name.is_none() { + if self.r#type == GroupType::Event { + if self.body.is_some() && self.name.is_none() { + // Must have a name which is assigned to event.name for log based events + errors.push(Error::InvalidGroup { + path_or_url: path_or_url.to_owned(), + group_id: self.id.clone(), + error: "This group contains an event type with a body definition but the name is not set.".to_owned(), + }); + } + if self.name.is_none() && self.prefix.is_empty() { + // Must have a name (whether explicit or via a prefix which will derive the name) + errors.push(Error::InvalidGroup { + path_or_url: path_or_url.to_owned(), + group_id: self.id.clone(), + error: "This group contains an event type but the name is not set and no prefix is defined.".to_owned(), + }); + } + } else if self.body.is_some() { + // Make sure that body is only used for events errors.push(Error::InvalidGroup { path_or_url: path_or_url.to_owned(), group_id: self.id.clone(), - error: "This group contains an event type but the prefix is empty and the name is not set.".to_owned(), + error: "This group contains a body field but the type is not set to event." + .to_owned(), }); } @@ -348,6 +371,7 @@ mod tests { unit: None, name: None, display_name: None, + body: None, }; assert!(group .validate("") @@ -413,7 +437,7 @@ mod tests { InvalidGroup { path_or_url: "".to_owned(), group_id: "test".to_owned(), - error: "This group contains an event type but the prefix is empty and the name is not set.".to_owned(), + error: "This group contains an event type but the name is not set and no prefix is defined.".to_owned(), }, ], ), @@ -451,6 +475,7 @@ mod tests { unit: None, name: None, display_name: None, + body: None, }; assert!(group .validate("") diff --git a/crates/weaver_semconv/src/lib.rs b/crates/weaver_semconv/src/lib.rs index fc43344c..6131ceb0 100644 --- a/crates/weaver_semconv/src/lib.rs +++ b/crates/weaver_semconv/src/lib.rs @@ -9,6 +9,7 @@ use weaver_common::diagnostic::{DiagnosticMessage, DiagnosticMessages}; use weaver_common::error::{format_errors, WeaverError}; pub mod attribute; +pub mod body; pub mod group; pub mod metric; pub mod registry; @@ -178,6 +179,7 @@ mod tests { "data/cloudevents.yaml", "data/database.yaml", "data/database-metrics.yaml", + "data/event.yaml", "data/exception.yaml", "data/faas.yaml", "data/faas-common.yaml", diff --git a/crates/weaver_semconv/src/registry.rs b/crates/weaver_semconv/src/registry.rs index 5e4b7978..352528bf 100644 --- a/crates/weaver_semconv/src/registry.rs +++ b/crates/weaver_semconv/src/registry.rs @@ -280,6 +280,7 @@ mod tests { events: vec![], name: None, display_name: Some("Group 1".to_owned()), + body: None, }], }, ), @@ -304,6 +305,7 @@ mod tests { events: vec![], name: None, display_name: Some("Group 2".to_owned()), + body: None, }], }, ), From 2316b620cbb9084efcb338bf65dd0d76048b166f Mon Sep 17 00:00:00 2001 From: Nev Wylie <54870357+MSNev@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:18:21 -0700 Subject: [PATCH 2/8] feat: Add event body spec to schema files --- schemas/semconv-syntax.md | 87 +++++++++++++++++- schemas/semconv.schema.json | 170 ++++++++++++++++++++++++++++++------ 2 files changed, 225 insertions(+), 32 deletions(-) diff --git a/schemas/semconv-syntax.md b/schemas/semconv-syntax.md index 88597346..ade9af87 100644 --- a/schemas/semconv-syntax.md +++ b/schemas/semconv-syntax.md @@ -15,6 +15,9 @@ Then, the semantic of each field is described. - [Semantic Convention](#semantic-convention) - [Span semantic convention](#span-semantic-convention) - [Event semantic convention](#event-semantic-convention) + - [Event Body semantic convention](#event-body-semantic-convention) + - [Event Body Field semantic convention](#event-body-field-semantic-convention) + - [Event semantic convention example](#event-semantic-convention-example) - [Metric Group semantic convention](#metric-group-semantic-convention) - [Metric semantic convention](#metric-semantic-convention) - [Attribute group semantic convention](#attribute-group-semantic-convention) @@ -45,8 +48,8 @@ semconv ::= id [convtype] brief [note] [extends] stability [deprecated] [display id ::= string convtype ::= "span" # Default if not specified - | "resource" # see spanspecificfields - | "event" # see eventspecificfields + | "resource" # see spansfields + | "event" # see eventfields | "metric" # see metricfields | "attribute_group" # no specific fields defined @@ -62,7 +65,7 @@ deprecated ::= display_name ::= string -attributes ::= (id type brief examples | ref [brief] [examples]) [tag] stability [deprecated] [required] [sampling_relevant] [note] +attributes ::= (id type brief examples | ref [brief] [examples]) [tag] stability [deprecated] [requirement_level] [sampling_relevant] [note] # ref MUST point to an existing attribute id ref ::= id @@ -102,7 +105,12 @@ specificfields ::= spanfields | metricfields spanfields ::= [events] [span_kind] -eventfields ::= [name] + +eventfields ::= [name] [body] + +body ::= body_fields + +body_fields ::= id type brief [examples] stability [deprecated] [requirement_level] [note] span_kind ::= "client" | "server" @@ -159,6 +167,77 @@ The following is only valid if `type` is `span` (the default): The following is only valid if `type` is `event`: - `name`, required, string. The name of the event. +- `body`, optional, object. Describes the body of the event. + +#### Event Body semantic convention + +The following is only valid if `type` is `event` and `body` is present: + +- `fields`, required, list of fields that describe the event body. + +#### Event Body Field semantic convention + +The following is only valid if `type` is `event` and `body` is present and `fields` is present: + +- `id`, required, string. The name of the field. +- `type`, either a string literal denoting the type as a primitive or an array type, a template type or an enum definition (See later). Required. + The accepted string literals are: + * _primitive and array types as string literals:_ + * `"string"`: String attributes. + * `"int"`: Integer attributes. + * `"double"`: Double attributes. + * `"boolean"`: Boolean attributes. + * `"string[]"`: Array of strings attributes. + * `"int[]"`: Array of integer attributes. + * `"double[]"`: Array of double attributes. + * `"boolean[]"`: Array of boolean attributes. + * _template type as string literal:_ `"template[]"` (See [below](#template-type)) + See the [specification of Attributes](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/common/README.md#attribute) for the definition of the value types. +- `stability`, required, enum. The stability of the field. +- `requirement_level`, optional. Specifies if the field is mandatory. + Can be "required", "conditionally_required", "recommended" or "opt_in". When omitted, the field is "recommended". + When set to "conditionally_required", the string provided as `` MUST specify + the conditions under which the field is required. +- `brief`, `note`, `deprecated`, same meaning as for the whole + [semantic convention](#semantic-convention), but per field. +- `examples`, sequence of example values for the field or single example value. + They are required only for string and string array fields. + Example values must be of the same type of the field. + If only a single example is provided, it can directly be reported without encapsulating it into a sequence/dictionary. See [below](#examples-for-examples). + +#### Event semantic convention example + + ```yaml + - id: event.some_event + name: the.event.name + type: event + brief: "Describes the event." + stability: experimental + attributes: # Optional + - id: registry.attribute.id + type: string + requirement_level: required + brief: Adds a standard attribute to the global registry. + examples: ["some_value"] + - ref: registry.some.attribute.id # Reference to an existing global attribute + body: # Optional + fields: + - id: method + type: string + stability: experimental + brief: "The HTTP method used in the request." + examples: ['GET', 'POST'] + - id: url + type: string + stability: experimental + brief: "The URL of the request." + examples: ['http://example.com'] + - id: status_code + type: int + stability: experimental + brief: "The status code of the response." + examples: [200, 404] + ``` #### Metric Group semantic convention diff --git a/schemas/semconv.schema.json b/schemas/semconv.schema.json index a4d89018..5f15af06 100644 --- a/schemas/semconv.schema.json +++ b/schemas/semconv.schema.json @@ -150,6 +150,9 @@ "name": { "type": "string", "description": "The name of the event." + }, + "body": { + "$ref": "#/$defs/BodySemanticConvention" } }, "anyOf": [ @@ -160,6 +163,113 @@ } ] }, + "BodySemanticConvention": { + "type": "object", + "required": [ + "fields" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "$ref": "#/$defs/BodyFieldSemanticContention" + } + } + } + }, + "BodyFieldSemanticContention": { + "type": "object", + "required": [ + "id", + "type", + "brief", + "stability" + ], + "properties": { + "id": { + "type": "string", + "description": "unique string" + }, + "type": { + "$ref": "#/$defs/AttributeType" + }, + "brief": { + "type": "string", + "description": "a brief description of the field." + }, + "note": { + "type": "string", + "description": "a more elaborate description of the field. It defaults to an empty string." + }, + "deprecated": { + "type": "string", + "description": "specifies if the field is deprecated. The string provided as MUST specify why it's deprecated and/or what to use instead." + }, + "stability": { + "allOf": [ + { + "$ref": "#/$defs/StabilityLevel" + } + ] + }, + "requirement_level": { + "description": "specifies the field requirement level. Can be 'required', 'conditionally_required', 'recommended', or 'opt_in'. When omitted, the field is 'recommended'. When set to 'conditionally_required', the string provided MUST specify the conditions under which the field is required.", + "oneOf": [ + { + "const": "required" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "conditionally_required" + ], + "properties": { + "conditionally_required": { + "type": "string" + } + } + }, + { + "oneOf": [ + { + "const": "recommended" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "recommended" + ], + "properties": { + "recommended": { + "type": "string" + } + } + } + ] + }, + { + "const": "opt_in" + } + ] + }, + "examples": { + "anyOf": [ + { + "$ref": "#/$defs/ValueType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ValueType" + } + } + ], + "description": "sequence/dictionary of example values for the field. They are optional for boolean, int, double, and enum attributes. Example values must be of the same type of the field. If only a single example is provided, it can directly be reported without encapsulating it into a sequence/dictionary." + } + } + }, "MetricSemanticConvention": { "allOf": [ { @@ -280,34 +390,8 @@ "description": "unique string" }, "type": { - "oneOf": [ - { - "type": "string", - "enum": [ - "string", - "int", - "double", - "boolean", - "string[]", - "int[]", - "double[]", - "boolean[]", - "template[string]", - "template[int]", - "template[double]", - "template[boolean]", - "template[string[]]", - "template[int[]]", - "template[double[]]", - "template[boolean[]]" - ], - "description": "literal denoting the type" - }, - { - "$ref": "#/$defs/AttributeEnumType" - } - ] - } + "$ref": "#/$defs/AttributeType" + } } }, "AttributeReference": { @@ -442,6 +526,36 @@ ] } ] + }, + "AttributeType": { + "description": "specifies the supported attribute types.", + "oneOf": [ + { + "type": "string", + "enum": [ + "string", + "int", + "double", + "boolean", + "string[]", + "int[]", + "double[]", + "boolean[]", + "template[string]", + "template[int]", + "template[double]", + "template[boolean]", + "template[string[]]", + "template[int[]]", + "template[double[]]", + "template[boolean[]]" + ], + "description": "literal denoting the type" + }, + { + "$ref": "#/$defs/AttributeEnumType" + } + ] } } } From c10b39606a9476a4eff5014c89dd60ce5c8c6900 Mon Sep 17 00:00:00 2001 From: Nev Wylie <54870357+MSNev@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:18:51 -0700 Subject: [PATCH 3/8] - address review comments --- .../weaver_resolved_schema/src/attribute.rs | 2 +- crates/weaver_resolver/src/body.rs | 34 +++++++------------ 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/crates/weaver_resolved_schema/src/attribute.rs b/crates/weaver_resolved_schema/src/attribute.rs index 42b75c35..8326a9c1 100644 --- a/crates/weaver_resolved_schema/src/attribute.rs +++ b/crates/weaver_resolved_schema/src/attribute.rs @@ -91,7 +91,7 @@ pub struct UnresolvedAttribute { /// An internal reference to an attribute in the catalog. #[derive( - Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, JsonSchema, + Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, JsonSchema, )] pub struct AttributeRef(pub u32); diff --git a/crates/weaver_resolver/src/body.rs b/crates/weaver_resolver/src/body.rs index a1177c57..ee70af9f 100644 --- a/crates/weaver_resolver/src/body.rs +++ b/crates/weaver_resolver/src/body.rs @@ -4,23 +4,27 @@ use weaver_resolved_schema::{ body::{Body, BodyField}, - error::{handle_errors, Error}, + error::Error, }; -use weaver_semconv::body::{BodyFieldSpec, BodySpec}; +use weaver_semconv::body::BodySpec; /// Resolve a `Body` specification into a resolved `Body`. pub fn resolve_body_spec(body: &BodySpec) -> Result, Error> { match body { BodySpec::Fields { fields } => { - let mut errors = vec![]; let mut body_fields = Vec::new(); for field in fields.iter() { - match resolve_body_field_spec(field) { - Ok(r) => body_fields.push(r), - Err(e) => errors.push(e), - } + body_fields.push(BodyField { + name: field.id.clone(), + r#type: field.r#type.clone(), + brief: field.brief.clone().unwrap_or_else(|| "".to_owned()), + examples: field.examples.clone(), + requirement_level: field.requirement_level.clone(), + note: field.note.clone(), + stability: field.stability.clone(), + deprecated: field.deprecated.clone(), + }); } - handle_errors(errors)?; Ok(Some(Body { fields: Some(body_fields), // value: None, // Not yet implemented @@ -34,17 +38,3 @@ pub fn resolve_body_spec(body: &BodySpec) -> Result, Error> { } } } - -/// Resolve a `BodyField`` specification into a resolved `BodyField``. -pub fn resolve_body_field_spec(field: &BodyFieldSpec) -> Result { - Ok(BodyField { - name: field.id.clone(), - r#type: field.r#type.clone(), - brief: field.brief.clone().unwrap_or_else(|| "".to_owned()), - examples: field.examples.clone(), - requirement_level: field.requirement_level.clone(), - note: field.note.clone(), - stability: field.stability.clone(), - deprecated: field.deprecated.clone(), - }) -} From 160a9adf4655571bfe78e72a114035b6a2b41fbf Mon Sep 17 00:00:00 2001 From: Nev Wylie <54870357+MSNev@users.noreply.github.com> Date: Mon, 26 Aug 2024 15:13:21 -0700 Subject: [PATCH 4/8] Update body definition to include - type - brief - note - stability - examples --- crates/weaver_forge/data/mobile-events.yaml | 1 + .../semconv_jq_fn/semconv_events.json | 2 +- crates/weaver_resolved_schema/src/body.rs | 29 +++- crates/weaver_resolved_schema/src/error.rs | 13 +- crates/weaver_resolved_schema/src/signal.rs | 2 +- .../expected-attribute-catalog.json | 2 +- .../expected-events.json | 3 +- .../expected-registry.json | 83 +++++++++- .../registry/browser-event.yaml | 33 ++-- .../registry/client-exception-event.yaml | 1 + .../registry/mobile-events.yaml | 1 + .../registry/stringbody-event.yaml | 31 ++++ crates/weaver_resolver/src/body.rs | 45 ++++-- crates/weaver_semconv/data/event.yaml | 28 +++- crates/weaver_semconv/src/body.rs | 143 ++++++++++++++++-- crates/weaver_semconv/src/group.rs | 1 + schemas/semconv-syntax.md | 16 +- schemas/semconv.schema.json | 47 +++++- 18 files changed, 418 insertions(+), 63 deletions(-) create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml diff --git a/crates/weaver_forge/data/mobile-events.yaml b/crates/weaver_forge/data/mobile-events.yaml index b1b219d5..568048cc 100644 --- a/crates/weaver_forge/data/mobile-events.yaml +++ b/crates/weaver_forge/data/mobile-events.yaml @@ -10,6 +10,7 @@ groups: the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive. body: + type: map fields: - id: ios.state stability: experimental diff --git a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json index 16f63a79..94dd5e18 100644 --- a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json +++ b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json @@ -1 +1 @@ -[{"attributes":[],"body":{"fields":[{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","name":"ios.state","note":"The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `ios`"},"stability":"experimental","type":{"allow_custom_values":false,"members":[{"brief":"The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n","deprecated":null,"id":"active","note":null,"stability":null,"value":"active"},{"brief":"The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n","deprecated":null,"id":"inactive","note":null,"stability":null,"value":"inactive"},{"brief":"The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"brief":"The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"},{"brief":"The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n","deprecated":null,"id":"terminate","note":null,"stability":null,"value":"terminate"}]}},{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","name":"android.state","note":"The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `android`"},"stability":"experimental","type":{"allow_custom_values":false,"members":[{"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.\n","deprecated":null,"id":"created","note":null,"stability":null,"value":"created"},{"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.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"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.","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"}]}}]},"brief":"This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n","event_namespace":"device.app","events":[],"id":"device.app.lifecycle","instrument":null,"lineage":{"source_file":"data/mobile-events.yaml"},"metric_name":null,"name":"device.app.lifecycle","note":"This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n","span_kind":null,"stability":"experimental","type":"event","unit":null},{"attributes":[{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","stability":"stable","type":"string"},{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","stability":"stable","type":"boolean"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":{"conditionally_required":"Required if `exception.message` is not set, recommended otherwise."},"stability":"stable","type":"string"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":{"conditionally_required":"Required if `exception.type` is not set, recommended otherwise."},"stability":"stable","type":"string"}],"brief":"This document defines the attributes used to report a single exception associated with a span.\n","event_namespace":"other","events":[],"id":"trace-exception","instrument":null,"lineage":{"attributes":{"exception.escaped":{"inherited_fields":["brief","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.message":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"},"exception.stacktrace":{"inherited_fields":["brief","examples","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.type":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"}},"source_file":"data/trace-exception.yaml"},"metric_name":null,"name":null,"prefix":"exception","span_kind":null,"type":"event","unit":null}] \ No newline at end of file +[{"attributes":[],"body":{"fields":[{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","name":"ios.state","note":"The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `ios`"},"stability":"experimental","type":{"allow_custom_values":false,"members":[{"brief":"The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n","deprecated":null,"id":"active","note":null,"stability":null,"value":"active"},{"brief":"The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n","deprecated":null,"id":"inactive","note":null,"stability":null,"value":"inactive"},{"brief":"The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"brief":"The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"},{"brief":"The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n","deprecated":null,"id":"terminate","note":null,"stability":null,"value":"terminate"}]}},{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","name":"android.state","note":"The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `android`"},"stability":"experimental","type":{"allow_custom_values":false,"members":[{"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.\n","deprecated":null,"id":"created","note":null,"stability":null,"value":"created"},{"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.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"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.","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"}]}}],"type":"map"},"brief":"This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n","event_namespace":"device.app","events":[],"id":"device.app.lifecycle","instrument":null,"lineage":{"source_file":"data/mobile-events.yaml"},"metric_name":null,"name":"device.app.lifecycle","note":"This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n","span_kind":null,"stability":"experimental","type":"event","unit":null},{"attributes":[{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","stability":"stable","type":"string"},{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","stability":"stable","type":"boolean"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":{"conditionally_required":"Required if `exception.message` is not set, recommended otherwise."},"stability":"stable","type":"string"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":{"conditionally_required":"Required if `exception.type` is not set, recommended otherwise."},"stability":"stable","type":"string"}],"brief":"This document defines the attributes used to report a single exception associated with a span.\n","event_namespace":"other","events":[],"id":"trace-exception","instrument":null,"lineage":{"attributes":{"exception.escaped":{"inherited_fields":["brief","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.message":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"},"exception.stacktrace":{"inherited_fields":["brief","examples","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.type":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"}},"source_file":"data/trace-exception.yaml"},"metric_name":null,"name":null,"prefix":"exception","span_kind":null,"type":"event","unit":null}] \ No newline at end of file diff --git a/crates/weaver_resolved_schema/src/body.rs b/crates/weaver_resolved_schema/src/body.rs index 3595b8d7..3dc0ec19 100644 --- a/crates/weaver_resolved_schema/src/body.rs +++ b/crates/weaver_resolved_schema/src/body.rs @@ -7,20 +7,37 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use weaver_semconv::attribute::{AttributeType, Examples, RequirementLevel}; -use weaver_semconv::body::{BodyFieldSpec, BodySpec}; +use weaver_semconv::body::{BodyFieldSpec, BodySpec, BodyType}; use weaver_semconv::stability::Stability; /// A `Body` definition. #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] #[serde(deny_unknown_fields)] pub struct Body { - /// The body specification. + /// Identifies the type of the body. It can be "map", "string". + pub r#type: BodyType, + /// A brief description of the body. + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + pub brief: String, + /// A more elaborate description of the body. + /// It defaults to an empty string. + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + pub note: String, + /// Specifies the stability of the body. + #[serde(skip_serializing_if = "Option::is_none")] + pub stability: Option, + /// Sequence of example values for the body or single example + /// value. They are required only for string types. Example values + /// must be of the same type of the body. If only a single example is + /// provided, it can directly be reported without encapsulating it + /// into a sequence/dictionary. + #[serde(skip_serializing_if = "Option::is_none")] + pub examples: Option, + /// Identifies the definition of the "fields" of the body when the body type is "map". #[serde(skip_serializing_if = "Option::is_none")] pub fields: Option>, - // Not yet defined in the spec or implemented in the resolver - // The body value when there are no fields - // #[serde(skip_serializing_if = "Option::is_none")] - // pub value: Option } /// A `BodyField` definition. diff --git a/crates/weaver_resolved_schema/src/error.rs b/crates/weaver_resolved_schema/src/error.rs index 39cdb2cb..b716910b 100644 --- a/crates/weaver_resolved_schema/src/error.rs +++ b/crates/weaver_resolved_schema/src/error.rs @@ -3,9 +3,10 @@ //! Error types and utilities. use serde::{Deserialize, Serialize}; +use weaver_semconv::body::BodySpec; use crate::attribute::AttributeRef; -use crate::error::Error::{AttributeNotFound, CompoundError, NotImplemented}; +use crate::error::Error::{AttributeNotFound, CompoundError, InvalidBody}; /// Errors emitted by this crate. #[derive(thiserror::Error, Debug, Clone, Deserialize, Serialize)] @@ -24,10 +25,10 @@ pub enum Error { CompoundError(Vec), /// A generic error identifying a feature that has not yet been implemented. - #[error("Not Implemented: {message}")] - NotImplemented { - /// A message describing the feature that has not been implemented. - message: String, + #[error("Unsupported BodySpec")] + InvalidBody { + /// The body specification that is not supported. + body: BodySpec, }, } @@ -52,7 +53,7 @@ impl Error { .flat_map(|e| match e { CompoundError(errors) => errors, e @ AttributeNotFound { .. } => vec![e], - e @ NotImplemented { .. } => vec![e], + e @ InvalidBody { .. } => vec![e], }) .collect(), ) diff --git a/crates/weaver_resolved_schema/src/signal.rs b/crates/weaver_resolved_schema/src/signal.rs index 0c609abb..095f7291 100644 --- a/crates/weaver_resolved_schema/src/signal.rs +++ b/crates/weaver_resolved_schema/src/signal.rs @@ -49,7 +49,7 @@ pub struct MultivariateMetric { #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(deny_unknown_fields)] pub struct Event { - /// The name of the event. + /// The name of the event name: String, /// References to attributes defined in the catalog. #[serde(skip_serializing_if = "Vec::is_empty")] diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json b/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json index 210bbf71..1050f62e 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json @@ -25,7 +25,7 @@ "Linux" ], "requirement_level": "recommended", - "note": "This value is intended to be taken from the [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) (`navigator.userAgentData.platform`). If unavailable, the legacy `navigator.platform` API SHOULD NOT be used instead and this attribute SHOULD be left unset in order for the values to be consistent. The list of possible values is defined in the [W3C User-Agent Client Hints specification](https://wicg.github.io/ua-client-hints/#sec-ch-ua-platform). Note that some (but not all) of these values can overlap with values in the [`os.type` and `os.name` attributes](./os.md). However, for consistency, the values in the `browser.platform` attribute should capture the exact value that the user agent provides.\n" + "note": "This value is intended to be taken from the [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) (`navigator.userAgentData.platform`). \n" }, { "name": "browser.mobile", diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-events.json b/crates/weaver_resolver/data/registry-test-4-events/expected-events.json index b0986c21..2ccc397e 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/expected-events.json +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-events.json @@ -95,7 +95,8 @@ ] } } - ] + ], + "type": "map" }, "brief": "This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n", "event_namespace": "device.app", diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json b/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json index 34e82263..06b0b3fe 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json @@ -2,7 +2,7 @@ "registry_url": "https://127.0.0.1", "groups": [ { - "id": "registry.browser", + "id": "browser.test.event_with_fields", "type": "event", "brief": "An event that adds global attributes for reuse.\n", "prefix": "browser", @@ -12,11 +12,44 @@ 2, 3 ], - "name": "browser.test.event", + "name": "browser.test.event_with_fields", "lineage": { "source_file": "data/registry-test-4-events/registry/browser-event.yaml" }, "body": { + "type": "map", + "fields": [ + { + "name": "some.field", + "type": "string", + "brief": "A field that is not referenced in the attributes", + "examples": [ + "some value", + "another value" + ], + "requirement_level": "recommended", + "note": "This field is not referenced in the attributes" + } + ] + } + }, + { + "id": "browser.test.event_with_body_details", + "type": "event", + "brief": "An event that adds global attributes for reuse.\n", + "attributes": [], + "name": "browser.test.event_with_body_details", + "lineage": { + "source_file": "data/registry-test-4-events/registry/browser-event.yaml" + }, + "body": { + "type": "map", + "brief": "A map of fields that are not referenced in the attributes", + "note": "This map is not referenced in the attributes", + "stability": "experimental", + "examples": [ + "{ \"some.field\": \"some value\" }" + ], "fields": [ { "name": "some.field", @@ -79,7 +112,8 @@ "requirement_level": "recommended", "note": "An exception is considered to have escaped." } - ] + ], + "type": "map" } }, { @@ -254,7 +288,8 @@ "note": "The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n", "stability": "experimental" } - ] + ], + "type": "map" } }, { @@ -405,6 +440,46 @@ "source_file": "data/registry-test-4-events/registry/referenced-server.yaml" } }, + { + "id": "some.string.body.event", + "type": "event", + "brief": "This event represents an occurrence of a something.\n", + "note": "This event transmits the body as a JSON encoded string.\n", + "stability": "experimental", + "attributes": [], + "name": "string.body.event", + "lineage": { + "source_file": "data/registry-test-4-events/registry/stringbody-event.yaml" + }, + "body": { + "type": "string", + "brief": "This is the body of the event which is a JSON encoded string.\n", + "examples": [ + "{\"key1\":\"value1\",\"key2\":\"value2\"}" + ] + } + }, + { + "id": "some.string.body.detailed.event", + "type": "event", + "brief": "This event represents an occurrence of a something.\n", + "note": "This event transmits the body as a JSON encoded string.\n", + "stability": "experimental", + "attributes": [], + "name": "string.body.event", + "lineage": { + "source_file": "data/registry-test-4-events/registry/stringbody-event.yaml" + }, + "body": { + "type": "string", + "brief": "This is the body of the event which is a JSON encoded string.\n", + "note": "This is a detailed note about the body.\n", + "stability": "experimental", + "examples": [ + "{\"key1\":\"value1\",\"key2\":\"value2\"}" + ] + } + }, { "id": "trace-exception", "type": "event", diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml index 126a24a6..00560e0c 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml @@ -1,6 +1,6 @@ groups: - - id: registry.browser - name: browser.test.event + - id: browser.test.event_with_fields + name: browser.test.event_with_fields prefix: browser type: event brief: > @@ -20,15 +20,7 @@ groups: note: > This value is intended to be taken from the [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) - (`navigator.userAgentData.platform`). If unavailable, the legacy - `navigator.platform` API SHOULD NOT be used instead and this attribute - SHOULD be left unset in order for the values to be consistent. - The list of possible values is defined in the - [W3C User-Agent Client Hints specification](https://wicg.github.io/ua-client-hints/#sec-ch-ua-platform). - Note that some (but not all) of these values can overlap with values - in the [`os.type` and `os.name` attributes](./os.md). - However, for consistency, the values in the `browser.platform` attribute - should capture the exact value that the user agent provides. + (`navigator.userAgentData.platform`). examples: [ "Windows", "macOS", "Android", "iOS", "Linux" ] - id: mobile type: boolean @@ -46,6 +38,25 @@ groups: `navigator.language`. examples: [ "en", "en-US", "en-AU", "fr", "fr-FR" ] body: + type: map + fields: + - id: some.field + type: string + brief: 'A field that is not referenced in the attributes' + note: 'This field is not referenced in the attributes' + examples: [ "some value", "another value" ] + + - id: browser.test.event_with_body_details + name: browser.test.event_with_body_details + type: event + brief: > + An event that adds global attributes for reuse. + body: + type: map + brief: A map of fields that are not referenced in the attributes + note: This map is not referenced in the attributes + stability: experimental + examples: [ '{ "some.field": "some value" }' ] fields: - id: some.field type: string diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml index 5e6819fa..84a0df0d 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml @@ -6,6 +6,7 @@ groups: This document defines the log event used to report a client exception. body: + type: map fields: - id: type type: string diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml index b1b219d5..568048cc 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml @@ -10,6 +10,7 @@ groups: the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive. body: + type: map fields: - id: ios.state stability: experimental diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml new file mode 100644 index 00000000..17b37d70 --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml @@ -0,0 +1,31 @@ +groups: + - id: some.string.body.event + stability: experimental + type: event + name: string.body.event + brief: > + This event represents an occurrence of a something. + note: > + This event transmits the body as a JSON encoded string. + body: + type: string + brief: > + This is the body of the event which is a JSON encoded string. + examples: ['{"key1":"value1","key2":"value2"}'] + + - id: some.string.body.detailed.event + stability: experimental + type: event + name: string.body.event + brief: > + This event represents an occurrence of a something. + note: > + This event transmits the body as a JSON encoded string. + body: + type: string + brief: > + This is the body of the event which is a JSON encoded string. + note: > + This is a detailed note about the body. + stability: experimental + examples: ['{"key1":"value1","key2":"value2"}'] \ No newline at end of file diff --git a/crates/weaver_resolver/src/body.rs b/crates/weaver_resolver/src/body.rs index ee70af9f..ae28eac5 100644 --- a/crates/weaver_resolver/src/body.rs +++ b/crates/weaver_resolver/src/body.rs @@ -6,18 +6,26 @@ use weaver_resolved_schema::{ body::{Body, BodyField}, error::Error, }; -use weaver_semconv::body::BodySpec; +use weaver_semconv::body::{BodySpec, BodyType}; /// Resolve a `Body` specification into a resolved `Body`. pub fn resolve_body_spec(body: &BodySpec) -> Result, Error> { match body { - BodySpec::Fields { fields } => { + BodySpec::Fields { + r#type: BodyType::Map, + brief, + note, + stability, + examples, + fields, + .. + } => { let mut body_fields = Vec::new(); for field in fields.iter() { body_fields.push(BodyField { name: field.id.clone(), r#type: field.r#type.clone(), - brief: field.brief.clone().unwrap_or_else(|| "".to_owned()), + brief: field.brief.clone(), examples: field.examples.clone(), requirement_level: field.requirement_level.clone(), note: field.note.clone(), @@ -26,15 +34,34 @@ pub fn resolve_body_spec(body: &BodySpec) -> Result, Error> { }); } Ok(Some(Body { + r#type: BodyType::Map, + brief: brief.clone(), + note: note.clone(), + stability: stability.clone(), + examples: examples.clone(), fields: Some(body_fields), - // value: None, // Not yet implemented })) } - BodySpec::Value { value: _ } => { - // Add as a placeholder for now of where to resolve the value. - Err(Error::NotImplemented { - message: "Value type for body is not currently implemented.".to_owned(), - }) + BodySpec::String { + r#type: BodyType::String, + brief, + note, + stability, + examples, + } => { + // string types must have a brief and examples + if brief.is_empty() || examples.is_none() { + return Err(Error::InvalidBody { body: body.clone() }); + } + Ok(Some(Body { + r#type: BodyType::String, + brief: brief.clone(), + note: note.clone(), + stability: stability.clone(), + examples: examples.clone(), + fields: None, + })) } + _ => Err(Error::InvalidBody { body: body.clone() }), } } diff --git a/crates/weaver_semconv/data/event.yaml b/crates/weaver_semconv/data/event.yaml index 241f88b7..6ea2084d 100644 --- a/crates/weaver_semconv/data/event.yaml +++ b/crates/weaver_semconv/data/event.yaml @@ -10,6 +10,7 @@ groups: the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive. body: + type: map fields: - id: ios.state stability: experimental @@ -134,6 +135,7 @@ groups: requirement_level: conditionally_required: Required if `attribute1` is not set, recommended otherwise. body: + type: map fields: - id: field1 type: string @@ -146,4 +148,28 @@ groups: brief: 'The field2' examples: ['value1', 'value2'] requirement_level: - conditionally_required: Required if `field1` is not set, recommended otherwise. \ No newline at end of file + conditionally_required: Required if `field1` is not set, recommended otherwise. + + - id: test.event.with_string_body + name: test.event.with_string_body + stability: experimental + type: event + brief: > + This event represents an occurrence of a test event. + attributes: + - id: attribute1 + type: string + brief: 'The attribute1' + examples: ['value1', 'value2'] + requirement_level: + conditionally_required: Required if `attribute2` is not set, recommended otherwise. + - id: attribute2 + type: string + brief: 'The attribute2' + examples: ['value1', 'value2'] + requirement_level: + conditionally_required: Required if `attribute1` is not set, recommended otherwise. + body: + type: string + brief: 'The body of the event' + examples: ['{ name: "thename", content: ... }', '{ name: "thename", content: ... }'] diff --git a/crates/weaver_semconv/src/body.rs b/crates/weaver_semconv/src/body.rs index 19a70660..eb6ba229 100644 --- a/crates/weaver_semconv/src/body.rs +++ b/crates/weaver_semconv/src/body.rs @@ -4,11 +4,11 @@ //! Body Field specification. +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use std::fmt::{Display, Formatter}; -use crate::attribute::{ - AttributeType, BasicRequirementLevelSpec, Examples, RequirementLevel, ValueSpec, -}; +use crate::attribute::{AttributeType, BasicRequirementLevelSpec, Examples, RequirementLevel}; use crate::stability::Stability; /// A body specification @@ -19,14 +19,54 @@ use crate::stability::Stability; pub enum BodySpec { /// The collection of body fields associated with a body definition Fields { - /// The collection of body fields associated with a body definition + /// Identifies that the type of the body is a map of fields or a string. + r#type: BodyType, + /// A brief description of the body. + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + brief: String, + /// A more elaborate description of the body. + /// It defaults to an empty string. + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + note: String, + /// Specifies the stability of the body. + #[serde(skip_serializing_if = "Option::is_none")] + stability: Option, + /// Sequence of example values for the body or single example + /// value. They are required only for string types. Example values + /// must be of the same type of the body. If only a single example is + /// provided, it can directly be reported without encapsulating it + /// into a sequence/dictionary. + #[serde(skip_serializing_if = "Option::is_none")] + examples: Option, + /// Identifies the definition of the "fields" of the body when the body type is "map". #[serde(skip_serializing_if = "Vec::is_empty")] fields: Vec, }, - /// The body field value. - Value { - /// The body field value. - value: ValueSpec, + /// The body will just be a string. + String { + /// Identifies that the type of the body is a string. + r#type: BodyType, + /// A brief description of the body. + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + brief: String, + /// A more elaborate description of the body. + /// It defaults to an empty string. + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + note: String, + /// Specifies the stability of the body. + #[serde(skip_serializing_if = "Option::is_none")] + stability: Option, + /// Sequence of example values for the body or single example + /// value. They are required only for string types. Example values + /// must be of the same type of the body. If only a single example is + /// provided, it can directly be reported without encapsulating it + /// into a sequence/dictionary. + #[serde(skip_serializing_if = "Option::is_none")] + examples: Option, }, } @@ -35,8 +75,28 @@ impl BodySpec { #[must_use] pub fn has_fields(&self) -> bool { match self { - BodySpec::Fields { fields } => !fields.is_empty(), - BodySpec::Value { value: _ } => false, + BodySpec::Fields { fields, .. } => !fields.is_empty(), + BodySpec::String { .. } => false, + } + } +} + +/// Identifies the different types of body (specification). +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum BodyType { + /// A map body type. + Map, + /// A string body type. + String, +} + +/// Implements a human readable display for PrimitiveOrArrayType. +impl Display for BodyType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + BodyType::String => write!(f, "string"), + BodyType::Map => write!(f, "map"), } } } @@ -52,7 +112,7 @@ pub struct BodyFieldSpec { /// array type, a template type or an enum definition. pub r#type: AttributeType, /// A brief description of the body field. - pub brief: Option, + pub brief: String, /// Sequence of example values for the body field or single example /// value. They are required only for string and string array /// fields. Example values must be of the same type of the @@ -215,12 +275,69 @@ mod tests { ); } + #[test] + fn test_field_body() { + let body = BodySpec::Fields { + r#type: BodyType::Map, + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: Some(Stability::Stable), + examples: Some(Examples::Int(42)), + fields: vec![BodyFieldSpec { + id: "id".to_owned(), + r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Int), + brief: "brief".to_owned(), + examples: Some(Examples::Int(42)), + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), + note: "note".to_owned(), + stability: Some(Stability::Stable), + deprecated: Some("deprecated".to_owned()), + }], + }; + + assert!(matches!(body, BodySpec::Fields { .. })); + assert!(!matches!(body, BodySpec::String { .. })); + assert!(body.has_fields()); + + if let BodySpec::Fields { + brief, + note, + fields, + .. + } = body + { + assert_eq!(brief, "brief"); + assert_eq!(note, "note"); + assert!(fields.len() == 1); + } + } + + #[test] + fn test_string_body() { + let body = BodySpec::String { + r#type: BodyType::String, + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: Some(Stability::Stable), + examples: Some(Examples::String("{key: value}".to_owned())), + }; + + assert!(matches!(body, BodySpec::String { .. })); + assert!(!matches!(body, BodySpec::Fields { .. })); + assert!(!body.has_fields()); + + if let BodySpec::String { brief, note, .. } = body { + assert_eq!(brief, "brief"); + assert_eq!(note, "note"); + } + } + #[test] fn test_body_field() { let field = BodyFieldSpec { id: "id".to_owned(), r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Int), - brief: Some("brief".to_owned()), + brief: "brief".to_owned(), examples: Some(Examples::Int(42)), requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), note: "note".to_owned(), @@ -228,7 +345,7 @@ mod tests { deprecated: Some("deprecated".to_owned()), }; assert_eq!(field.id, "id"); - assert_eq!(field.brief.to_owned(), Some("brief".to_owned())); + assert_eq!(field.brief.to_owned(), "brief".to_owned()); assert_eq!(field.note, "note"); assert!(field.is_required()); } diff --git a/crates/weaver_semconv/src/group.rs b/crates/weaver_semconv/src/group.rs index d580081d..1724af70 100644 --- a/crates/weaver_semconv/src/group.rs +++ b/crates/weaver_semconv/src/group.rs @@ -89,6 +89,7 @@ pub struct GroupSpec { pub display_name: Option, /// The event body definition /// Note: only valid if type is event + #[serde(skip_serializing_if = "Option::is_none")] pub body: Option, } diff --git a/schemas/semconv-syntax.md b/schemas/semconv-syntax.md index ade9af87..221f35f2 100644 --- a/schemas/semconv-syntax.md +++ b/schemas/semconv-syntax.md @@ -106,9 +106,12 @@ specificfields ::= spanfields spanfields ::= [events] [span_kind] -eventfields ::= [name] [body] +eventfields ::= name [body] -body ::= body_fields +body ::= body_type [brief] [examples] [stability] [note] [body_fields] + +body_type ::= "map" + | "string" body_fields ::= id type brief [examples] stability [deprecated] [requirement_level] [note] @@ -214,13 +217,10 @@ The following is only valid if `type` is `event` and `body` is present and `fiel brief: "Describes the event." stability: experimental attributes: # Optional - - id: registry.attribute.id - type: string - requirement_level: required - brief: Adds a standard attribute to the global registry. - examples: ["some_value"] - - ref: registry.some.attribute.id # Reference to an existing global attribute + - ref: registry.attribute.id + - ref: registry.some_other.attribute.id # Reference to an existing global attribute body: # Optional + type: map fields: - id: method type: string diff --git a/schemas/semconv.schema.json b/schemas/semconv.schema.json index 5f15af06..819ce020 100644 --- a/schemas/semconv.schema.json +++ b/schemas/semconv.schema.json @@ -166,9 +166,41 @@ "BodySemanticConvention": { "type": "object", "required": [ - "fields" + "type" ], "properties": { + "type": { + "$ref": "#/$defs/BodyType" + }, + "brief": { + "type": "string", + "description": "a brief description of the field." + }, + "note": { + "type": "string", + "description": "a more elaborate description of the field. It defaults to an empty string." + }, + "stability": { + "allOf": [ + { + "$ref": "#/$defs/StabilityLevel" + } + ] + }, + "examples": { + "anyOf": [ + { + "$ref": "#/$defs/ValueType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ValueType" + } + } + ], + "description": "sequence/dictionary of example values for the field. They are optional for boolean, int, double, and enum attributes. Example values must be of the same type of the field. If only a single example is provided, it can directly be reported without encapsulating it into a sequence/dictionary." + }, "fields": { "type": "array", "items": { @@ -556,6 +588,19 @@ "$ref": "#/$defs/AttributeEnumType" } ] + }, + "BodyType": { + "description": "specifies the supported body types.", + "oneOf": [ + { + "type": "string", + "enum": [ + "string", + "map" + ], + "description": "literal denoting the type" + } + ] } } } From 4223318077c726601a94a101d4c757238b47350b Mon Sep 17 00:00:00 2001 From: Nev Wylie <54870357+MSNev@users.noreply.github.com> Date: Thu, 12 Sep 2024 16:27:07 -0700 Subject: [PATCH 5/8] Refactor Body to AnyValue --- Cargo.lock | 1 + crates/weaver_forge/data/mobile-events.yaml | 88 +- .../semconv_jq_fn/semconv_events.json | 2 +- crates/weaver_forge/src/registry.rs | 4 +- .../weaver_resolved_schema/src/any_value.rs | 71 ++ crates/weaver_resolved_schema/src/body.rs | 99 --- crates/weaver_resolved_schema/src/error.rs | 11 +- crates/weaver_resolved_schema/src/lib.rs | 2 +- crates/weaver_resolved_schema/src/registry.rs | 4 +- crates/weaver_resolved_schema/src/signal.rs | 4 +- .../expected-registry.json | 196 +++-- .../registry/browser-event.yaml | 8 +- .../registry/client-exception-event.yaml | 12 +- .../registry/mobile-events.yaml | 88 +- .../registry/stringbody-event.yaml | 4 + crates/weaver_resolver/src/any_value.rs | 55 ++ crates/weaver_resolver/src/body.rs | 67 -- crates/weaver_resolver/src/lib.rs | 2 +- crates/weaver_resolver/src/registry.rs | 35 +- crates/weaver_semconv/Cargo.toml | 3 + crates/weaver_semconv/data/event.yaml | 92 +- .../data/expected/any_value.json | 1 + .../data/expected/any_value.yaml | 102 +++ crates/weaver_semconv/src/any_value.rs | 816 ++++++++++++++++++ crates/weaver_semconv/src/body.rs | 361 -------- crates/weaver_semconv/src/group.rs | 4 +- crates/weaver_semconv/src/lib.rs | 2 +- 27 files changed, 1333 insertions(+), 801 deletions(-) create mode 100644 crates/weaver_resolved_schema/src/any_value.rs delete mode 100644 crates/weaver_resolved_schema/src/body.rs create mode 100644 crates/weaver_resolver/src/any_value.rs delete mode 100644 crates/weaver_resolver/src/body.rs create mode 100644 crates/weaver_semconv/data/expected/any_value.json create mode 100644 crates/weaver_semconv/data/expected/any_value.yaml create mode 100644 crates/weaver_semconv/src/any_value.rs delete mode 100644 crates/weaver_semconv/src/body.rs diff --git a/Cargo.lock b/Cargo.lock index 647da046..6c671a52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4335,6 +4335,7 @@ dependencies = [ "ordered-float", "schemars", "serde", + "serde_json", "serde_yaml", "thiserror", "ureq", diff --git a/crates/weaver_forge/data/mobile-events.yaml b/crates/weaver_forge/data/mobile-events.yaml index 568048cc..a8008d98 100644 --- a/crates/weaver_forge/data/mobile-events.yaml +++ b/crates/weaver_forge/data/mobile-events.yaml @@ -11,6 +11,8 @@ groups: mutually exclusive. body: type: map + id: device.app.lifecycle.fields + requirement_level: required fields: - id: ios.state stability: experimental @@ -21,31 +23,31 @@ groups: and from which the `OS terminology` column values are derived. brief: > This attribute represents the state the application has transitioned into at the occurrence of the event. - type: - allow_custom_values: false - members: - - id: active - value: 'active' - brief: > - The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. - - id: inactive - value: 'inactive' - brief: > - The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. - - id: background - value: 'background' - brief: > - The app is now in the background. - This value is associated with UIKit notification `applicationDidEnterBackground`. - - id: foreground - value: 'foreground' - brief: > - The app is now in the foreground. - This value is associated with UIKit notification `applicationWillEnterForeground`. - - id: terminate - value: 'terminate' - brief: > - The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. + type: enum + allow_custom_values: false + members: + - id: active + value: 'active' + brief: > + The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. + - id: inactive + value: 'inactive' + brief: > + The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. + - id: background + value: 'background' + brief: > + The app is now in the background. + This value is associated with UIKit notification `applicationDidEnterBackground`. + - id: foreground + value: 'foreground' + brief: > + The app is now in the foreground. + This value is associated with UIKit notification `applicationWillEnterForeground`. + - id: terminate + value: 'terminate' + brief: > + The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. - id: android.state stability: experimental requirement_level: @@ -55,21 +57,21 @@ groups: note: > The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived. - type: - allow_custom_values: false - members: - - id: created - value: 'created' - 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. - - 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. - - 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. \ No newline at end of file + type: enum + allow_custom_values: false + members: + - id: created + value: 'created' + 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. + - 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. + - 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. \ No newline at end of file diff --git a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json index 94dd5e18..2cb781cd 100644 --- a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json +++ b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json @@ -1 +1 @@ -[{"attributes":[],"body":{"fields":[{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","name":"ios.state","note":"The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `ios`"},"stability":"experimental","type":{"allow_custom_values":false,"members":[{"brief":"The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n","deprecated":null,"id":"active","note":null,"stability":null,"value":"active"},{"brief":"The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n","deprecated":null,"id":"inactive","note":null,"stability":null,"value":"inactive"},{"brief":"The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"brief":"The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"},{"brief":"The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n","deprecated":null,"id":"terminate","note":null,"stability":null,"value":"terminate"}]}},{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","name":"android.state","note":"The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `android`"},"stability":"experimental","type":{"allow_custom_values":false,"members":[{"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.\n","deprecated":null,"id":"created","note":null,"stability":null,"value":"created"},{"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.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"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.","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"}]}}],"type":"map"},"brief":"This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n","event_namespace":"device.app","events":[],"id":"device.app.lifecycle","instrument":null,"lineage":{"source_file":"data/mobile-events.yaml"},"metric_name":null,"name":"device.app.lifecycle","note":"This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n","span_kind":null,"stability":"experimental","type":"event","unit":null},{"attributes":[{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","stability":"stable","type":"string"},{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","stability":"stable","type":"boolean"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":{"conditionally_required":"Required if `exception.message` is not set, recommended otherwise."},"stability":"stable","type":"string"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":{"conditionally_required":"Required if `exception.type` is not set, recommended otherwise."},"stability":"stable","type":"string"}],"brief":"This document defines the attributes used to report a single exception associated with a span.\n","event_namespace":"other","events":[],"id":"trace-exception","instrument":null,"lineage":{"attributes":{"exception.escaped":{"inherited_fields":["brief","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.message":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"},"exception.stacktrace":{"inherited_fields":["brief","examples","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.type":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"}},"source_file":"data/trace-exception.yaml"},"metric_name":null,"name":null,"prefix":"exception","span_kind":null,"type":"event","unit":null}] \ No newline at end of file +[{"attributes":[],"body":{"fields":[{"allow_custom_values":false,"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","members":[{"brief":"The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n","deprecated":null,"id":"active","note":null,"stability":null,"value":"active"},{"brief":"The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n","deprecated":null,"id":"inactive","note":null,"stability":null,"value":"inactive"},{"brief":"The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"brief":"The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"},{"brief":"The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n","deprecated":null,"id":"terminate","note":null,"stability":null,"value":"terminate"}],"name":"ios.state","note":"The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `ios`"},"stability":"experimental","type":"enum","type_display":"enum\u003cios.state\u003e {active, inactive, background, foreground, terminate}"},{"allow_custom_values":false,"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","members":[{"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.\n","deprecated":null,"id":"created","note":null,"stability":null,"value":"created"},{"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.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"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.","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"}],"name":"android.state","note":"The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `android`"},"stability":"experimental","type":"enum","type_display":"enum\u003candroid.state\u003e {created, background, foreground}"}],"name":"device.app.lifecycle.fields","requirement_level":"required","type":"map","type_display":"map\u003cdevice.app.lifecycle.fields\u003e{ enum\u003cios.state\u003e {active, inactive, background, foreground, terminate}, enum\u003candroid.state\u003e {created, background, foreground} }"},"brief":"This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n","event_namespace":"device.app","events":[],"id":"device.app.lifecycle","instrument":null,"lineage":{"source_file":"data/mobile-events.yaml"},"metric_name":null,"name":"device.app.lifecycle","note":"This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n","span_kind":null,"stability":"experimental","type":"event","unit":null},{"attributes":[{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","stability":"stable","type":"string"},{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","stability":"stable","type":"boolean"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":{"conditionally_required":"Required if `exception.message` is not set, recommended otherwise."},"stability":"stable","type":"string"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":{"conditionally_required":"Required if `exception.type` is not set, recommended otherwise."},"stability":"stable","type":"string"}],"brief":"This document defines the attributes used to report a single exception associated with a span.\n","event_namespace":"other","events":[],"id":"trace-exception","instrument":null,"lineage":{"attributes":{"exception.escaped":{"inherited_fields":["brief","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.message":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"},"exception.stacktrace":{"inherited_fields":["brief","examples","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.type":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"}},"source_file":"data/trace-exception.yaml"},"metric_name":null,"name":null,"prefix":"exception","span_kind":null,"type":"event","unit":null}] \ No newline at end of file diff --git a/crates/weaver_forge/src/registry.rs b/crates/weaver_forge/src/registry.rs index 56e73a6c..9ca549a1 100644 --- a/crates/weaver_forge/src/registry.rs +++ b/crates/weaver_forge/src/registry.rs @@ -7,8 +7,8 @@ use crate::error::Error; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use weaver_resolved_schema::any_value::AnyValue; use weaver_resolved_schema::attribute::Attribute; -use weaver_resolved_schema::body::Body; use weaver_resolved_schema::catalog::Catalog; use weaver_resolved_schema::lineage::GroupLineage; use weaver_resolved_schema::registry::{Constraint, Group, Registry}; @@ -107,7 +107,7 @@ pub struct ResolvedGroup { pub display_name: Option, /// The body specification used for event semantic conventions. #[serde(skip_serializing_if = "Option::is_none")] - pub body: Option, + pub body: Option, } impl ResolvedGroup { diff --git a/crates/weaver_resolved_schema/src/any_value.rs b/crates/weaver_resolved_schema/src/any_value.rs new file mode 100644 index 00000000..e3add63c --- /dev/null +++ b/crates/weaver_resolved_schema/src/any_value.rs @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: Apache-2.0 + +#![allow(rustdoc::invalid_html_tags)] + +//! Specification of a resolved `AnyValue`. + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use weaver_semconv::attribute::{EnumEntriesSpec, Examples, RequirementLevel}; +use weaver_semconv::stability::Stability; + +/// An `AnyValue` definition. +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] +#[serde(deny_unknown_fields)] +pub struct AnyValue { + /// AnyValue name. + pub name: String, + /// Either a string literal denoting the type as a primitive or an + /// array type, a template type or an enum definition. + pub r#type: String, + /// A description of the type of the AnyValue + /// e.g. "string", "string[]", "int", "enum", "map{ int, string }" + #[serde(skip_serializing_if = "Option::is_none")] + pub type_display: Option, + /// A brief description of the AnyValue. + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + pub brief: String, + /// Sequence of example values for the AnyValue or single example + /// value. They are required only for primitive and primitive array + /// values. Example values must be of the same type of the type. + /// If only a single example is provided, it can directly be reported + /// without encapsulating it into a sequence/dictionary. + #[serde(skip_serializing_if = "Option::is_none")] + pub examples: Option, + /// Specifies if the value is mandatory. Can be "required", + /// "conditionally_required", "recommended" or "opt_in". When omitted, + /// the value is "recommended". When set to + /// "conditionally_required", the string provided as MUST + /// specify the conditions under which the value is required. + pub requirement_level: RequirementLevel, + /// A more elaborate description of the any value. + /// It defaults to an empty string. + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + pub note: String, + /// Specifies the stability of the any value. + /// Note that, if stability is missing but deprecated is present, it will + /// automatically set the stability to deprecated. If deprecated is + /// present and stability differs from deprecated, this will result in an + /// error. + #[serde(skip_serializing_if = "Option::is_none")] + pub stability: Option, + /// Specifies if the value is deprecated. The string + /// provided as MUST specify why it's deprecated and/or what + /// to use instead. See also stability. + #[serde(skip_serializing_if = "Option::is_none")] + pub deprecated: Option, + /// Identifies the definition of the "fields" of the value when the type is "map". + #[serde(skip_serializing_if = "Option::is_none")] + pub fields: Option>, + /// Used when the type is "enum". + /// Set to false to not accept values other than the specified members. + /// It defaults to true. + #[serde(skip_serializing_if = "Option::is_none")] + pub allow_custom_values: Option, + /// Used when the type is "enum". + /// List of enum entries. + #[serde(skip_serializing_if = "Option::is_none")] + pub members: Option>, +} diff --git a/crates/weaver_resolved_schema/src/body.rs b/crates/weaver_resolved_schema/src/body.rs deleted file mode 100644 index 3dc0ec19..00000000 --- a/crates/weaver_resolved_schema/src/body.rs +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -#![allow(rustdoc::invalid_html_tags)] - -//! Specification of a resolved `BodyField`. - -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use weaver_semconv::attribute::{AttributeType, Examples, RequirementLevel}; -use weaver_semconv::body::{BodyFieldSpec, BodySpec, BodyType}; -use weaver_semconv::stability::Stability; - -/// A `Body` definition. -#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] -#[serde(deny_unknown_fields)] -pub struct Body { - /// Identifies the type of the body. It can be "map", "string". - pub r#type: BodyType, - /// A brief description of the body. - #[serde(skip_serializing_if = "String::is_empty")] - #[serde(default)] - pub brief: String, - /// A more elaborate description of the body. - /// It defaults to an empty string. - #[serde(skip_serializing_if = "String::is_empty")] - #[serde(default)] - pub note: String, - /// Specifies the stability of the body. - #[serde(skip_serializing_if = "Option::is_none")] - pub stability: Option, - /// Sequence of example values for the body or single example - /// value. They are required only for string types. Example values - /// must be of the same type of the body. If only a single example is - /// provided, it can directly be reported without encapsulating it - /// into a sequence/dictionary. - #[serde(skip_serializing_if = "Option::is_none")] - pub examples: Option, - /// Identifies the definition of the "fields" of the body when the body type is "map". - #[serde(skip_serializing_if = "Option::is_none")] - pub fields: Option>, -} - -/// A `BodyField` definition. -#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] -#[serde(deny_unknown_fields)] -pub struct BodyField { - /// Field name. - pub name: String, - /// Either a string literal denoting the type as a primitive or an - /// array type, a template type or an enum definition. - pub r#type: AttributeType, - /// A brief description of the field. - #[serde(skip_serializing_if = "String::is_empty")] - pub brief: String, - /// Sequence of example values for the field or single example - /// value. They are required only for string and string array - /// fields. Example values must be of the same type of the - /// field. If only a single example is provided, it can directly - /// be reported without encapsulating it into a sequence/dictionary. - #[serde(skip_serializing_if = "Option::is_none")] - pub examples: Option, - /// Specifies if the field is mandatory. Can be "required", - /// "conditionally_required", "recommended" or "opt_in". When omitted, - /// the field is "recommended". When set to - /// "conditionally_required", the string provided as MUST - /// specify the conditions under which the field is required. - pub requirement_level: RequirementLevel, - /// A more elaborate description of the field. - /// It defaults to an empty string. - #[serde(skip_serializing_if = "String::is_empty")] - #[serde(default)] - pub note: String, - /// Specifies the stability of the field. - /// Note that, if stability is missing but deprecated is present, it will - /// automatically set the stability to deprecated. If deprecated is - /// present and stability differs from deprecated, this will result in an - /// error. - #[serde(skip_serializing_if = "Option::is_none")] - pub stability: Option, - /// Specifies if the field is deprecated. The string - /// provided as MUST specify why it's deprecated and/or what - /// to use instead. See also stability. - #[serde(skip_serializing_if = "Option::is_none")] - pub deprecated: Option, -} - -/// An unresolved body definition. -#[derive(Debug, Deserialize, Clone)] -pub struct UnresolvedBody { - /// The body specification. - pub spec: BodySpec, -} - -/// An unresolved body field definition. -#[derive(Debug, Deserialize, Clone)] -pub struct UnresolvedBodyField { - /// The body field specification. - pub spec: BodyFieldSpec, -} diff --git a/crates/weaver_resolved_schema/src/error.rs b/crates/weaver_resolved_schema/src/error.rs index b716910b..58e8d23c 100644 --- a/crates/weaver_resolved_schema/src/error.rs +++ b/crates/weaver_resolved_schema/src/error.rs @@ -3,10 +3,9 @@ //! Error types and utilities. use serde::{Deserialize, Serialize}; -use weaver_semconv::body::BodySpec; use crate::attribute::AttributeRef; -use crate::error::Error::{AttributeNotFound, CompoundError, InvalidBody}; +use crate::error::Error::{AttributeNotFound, CompoundError}; /// Errors emitted by this crate. #[derive(thiserror::Error, Debug, Clone, Deserialize, Serialize)] @@ -23,13 +22,6 @@ pub enum Error { /// A generic container for multiple errors. #[error("Errors:\n{0:#?}")] CompoundError(Vec), - - /// A generic error identifying a feature that has not yet been implemented. - #[error("Unsupported BodySpec")] - InvalidBody { - /// The body specification that is not supported. - body: BodySpec, - }, } /// Handles a list of errors and returns a compound error if the list is not @@ -53,7 +45,6 @@ impl Error { .flat_map(|e| match e { CompoundError(errors) => errors, e @ AttributeNotFound { .. } => vec![e], - e @ InvalidBody { .. } => vec![e], }) .collect(), ) diff --git a/crates/weaver_resolved_schema/src/lib.rs b/crates/weaver_resolved_schema/src/lib.rs index d88d872e..1a0dd865 100644 --- a/crates/weaver_resolved_schema/src/lib.rs +++ b/crates/weaver_resolved_schema/src/lib.rs @@ -13,8 +13,8 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use weaver_version::Versions; +pub mod any_value; pub mod attribute; -pub mod body; pub mod catalog; pub mod error; pub mod instrumentation_library; diff --git a/crates/weaver_resolved_schema/src/registry.rs b/crates/weaver_resolved_schema/src/registry.rs index 604c1c90..aa3b7da0 100644 --- a/crates/weaver_resolved_schema/src/registry.rs +++ b/crates/weaver_resolved_schema/src/registry.rs @@ -12,8 +12,8 @@ use serde::{Deserialize, Serialize}; use weaver_semconv::group::{GroupType, InstrumentSpec, SpanKindSpec}; use weaver_semconv::stability::Stability; +use crate::any_value::AnyValue; use crate::attribute::{Attribute, AttributeRef}; -use crate::body::Body; use crate::catalog::Catalog; use crate::error::{handle_errors, Error}; use crate::lineage::GroupLineage; @@ -130,7 +130,7 @@ pub struct Group { /// The body of the event. /// This fields is only used for event groups. #[serde(skip_serializing_if = "Option::is_none")] - pub body: Option, + pub body: Option, } /// Common statistics for a group. diff --git a/crates/weaver_resolved_schema/src/signal.rs b/crates/weaver_resolved_schema/src/signal.rs index 095f7291..0f5d3f26 100644 --- a/crates/weaver_resolved_schema/src/signal.rs +++ b/crates/weaver_resolved_schema/src/signal.rs @@ -5,8 +5,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use crate::any_value::AnyValue; use crate::attribute::AttributeRef; -use crate::body::Body; use crate::metric::MetricRef; use crate::tags::Tags; @@ -64,7 +64,7 @@ pub struct Event { tags: Option, /// The body of the event, not used for Span events. #[serde(skip_serializing_if = "Option::is_none")] - body: Option, + body: Option, } /// A span signal. diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json b/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json index 06b0b3fe..c3d8b4fe 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json @@ -17,17 +17,21 @@ "source_file": "data/registry-test-4-events/registry/browser-event.yaml" }, "body": { + "name": "browser.test.event_with_body.fields", "type": "map", + "type_display": "map{ string }", + "requirement_level": "required", "fields": [ { "name": "some.field", "type": "string", + "type_display": "string", "brief": "A field that is not referenced in the attributes", "examples": [ "some value", "another value" ], - "requirement_level": "recommended", + "requirement_level": "required", "note": "This field is not referenced in the attributes" } ] @@ -43,23 +47,27 @@ "source_file": "data/registry-test-4-events/registry/browser-event.yaml" }, "body": { + "name": "browser.test.event_with_body_details.fields", "type": "map", + "type_display": "map{ string }", "brief": "A map of fields that are not referenced in the attributes", "note": "This map is not referenced in the attributes", "stability": "experimental", "examples": [ "{ \"some.field\": \"some value\" }" ], + "requirement_level": "required", "fields": [ { "name": "some.field", "type": "string", + "type_display": "string", "brief": "A field that is not referenced in the attributes", "examples": [ "some value", "another value" ], - "requirement_level": "recommended", + "requirement_level": "optional", "note": "This field is not referenced in the attributes" } ] @@ -77,43 +85,50 @@ "source_file": "data/registry-test-4-events/registry/client-exception-event.yaml" }, "body": { + "name": "client.exception.event.fields", + "type": "map", + "type_display": "map{ string, string, string, boolean }", + "requirement_level": "optional", "fields": [ { "name": "type", "type": "string", + "type_display": "string", "brief": "The type of the exception.\n", "examples": [ "java.net.ConnectException", "OSError" ], - "requirement_level": "recommended" + "requirement_level": "optional" }, { "name": "message", "type": "string", + "type_display": "string", "brief": "The exception message.", "examples": [ "Division by zero", "Can't convert 'int' object to str implicitly" ], - "requirement_level": "recommended" + "requirement_level": "optional" }, { "name": "stacktrace", "type": "string", + "type_display": "string", "brief": "A stacktrace.\n", "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)", - "requirement_level": "recommended" + "requirement_level": "optional" }, { "name": "escaped", "type": "boolean", + "type_display": "boolean", "brief": "SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n", - "requirement_level": "recommended", + "requirement_level": "optional", "note": "An exception is considered to have escaped." } - ], - "type": "map" + ] } }, { @@ -195,54 +210,58 @@ "source_file": "data/registry-test-4-events/registry/mobile-events.yaml" }, "body": { + "name": "device.app.lifecycle.fields", + "type": "map", + "type_display": "map{ enum {active, inactive, background, foreground, terminate}, enum {created, background, foreground} }", + "requirement_level": "required", "fields": [ { "name": "ios.state", - "type": { - "allow_custom_values": false, - "members": [ - { - "id": "active", - "value": "active", - "brief": "The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n", - "note": null, - "stability": null, - "deprecated": null - }, - { - "id": "inactive", - "value": "inactive", - "brief": "The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n", - "note": null, - "stability": null, - "deprecated": null - }, - { - "id": "background", - "value": "background", - "brief": "The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n", - "note": null, - "stability": null, - "deprecated": null - }, - { - "id": "foreground", - "value": "foreground", - "brief": "The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n", - "note": null, - "stability": null, - "deprecated": null - }, - { - "id": "terminate", - "value": "terminate", - "brief": "The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n", - "note": null, - "stability": null, - "deprecated": null - } - ] - }, + "type": "enum", + "type_display": "enum {active, inactive, background, foreground, terminate}", + "allow_custom_values": false, + "members": [ + { + "id": "active", + "value": "active", + "brief": "The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "id": "inactive", + "value": "inactive", + "brief": "The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "id": "background", + "value": "background", + "brief": "The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "id": "foreground", + "value": "foreground", + "brief": "The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "id": "terminate", + "value": "terminate", + "brief": "The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n", + "note": null, + "stability": null, + "deprecated": null + } + ], "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", "requirement_level": { "conditionally_required": "if and only if `os.name` is `ios`" @@ -252,35 +271,35 @@ }, { "name": "android.state", - "type": { - "allow_custom_values": false, - "members": [ - { - "id": "created", - "value": "created", - "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.\n", - "note": null, - "stability": null, - "deprecated": null - }, - { - "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.\n", - "note": null, - "stability": null, - "deprecated": null - }, - { - "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.", - "note": null, - "stability": null, - "deprecated": null - } - ] - }, + "type": "enum", + "type_display": "enum {created, background, foreground}", + "allow_custom_values": false, + "members": [ + { + "id": "created", + "value": "created", + "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.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "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.\n", + "note": null, + "stability": null, + "deprecated": null + }, + { + "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.", + "note": null, + "stability": null, + "deprecated": null + } + ], "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", "requirement_level": { "conditionally_required": "if and only if `os.name` is `android`" @@ -288,8 +307,7 @@ "note": "The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n", "stability": "experimental" } - ], - "type": "map" + ] } }, { @@ -452,11 +470,14 @@ "source_file": "data/registry-test-4-events/registry/stringbody-event.yaml" }, "body": { + "name": "some.string.body.event.fields", "type": "string", + "type_display": "string", "brief": "This is the body of the event which is a JSON encoded string.\n", "examples": [ "{\"key1\":\"value1\",\"key2\":\"value2\"}" - ] + ], + "requirement_level": "required" } }, { @@ -471,13 +492,16 @@ "source_file": "data/registry-test-4-events/registry/stringbody-event.yaml" }, "body": { + "name": "some.string.body.event.fields", "type": "string", + "type_display": "string", "brief": "This is the body of the event which is a JSON encoded string.\n", "note": "This is a detailed note about the body.\n", "stability": "experimental", "examples": [ "{\"key1\":\"value1\",\"key2\":\"value2\"}" - ] + ], + "requirement_level": "required" } }, { diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml index 00560e0c..2575c9c3 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml @@ -38,13 +38,16 @@ groups: `navigator.language`. examples: [ "en", "en-US", "en-AU", "fr", "fr-FR" ] body: + id: browser.test.event_with_body.fields type: map + requirement_level: required fields: - id: some.field type: string brief: 'A field that is not referenced in the attributes' note: 'This field is not referenced in the attributes' examples: [ "some value", "another value" ] + requirement_level: required - id: browser.test.event_with_body_details name: browser.test.event_with_body_details @@ -52,14 +55,17 @@ groups: brief: > An event that adds global attributes for reuse. body: + id: browser.test.event_with_body_details.fields type: map brief: A map of fields that are not referenced in the attributes note: This map is not referenced in the attributes stability: experimental examples: [ '{ "some.field": "some value" }' ] + requirement_level: required fields: - id: some.field type: string brief: 'A field that is not referenced in the attributes' note: 'This field is not referenced in the attributes' - examples: [ "some value", "another value" ] \ No newline at end of file + examples: [ "some value", "another value" ] + requirement_level: optional \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml index 84a0df0d..1c686939 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml @@ -6,25 +6,30 @@ groups: This document defines the log event used to report a client exception. body: + id: client.exception.event.fields type: map + requirement_level: optional fields: - id: type type: string brief: > The type of the exception. examples: ["java.net.ConnectException","OSError"] + requirement_level: optional - id: message type: string brief: The exception message. examples: ["Division by zero","Can't convert 'int' object to str implicitly"] + requirement_level: optional - id: stacktrace type: string brief: > A stacktrace. examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n - at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n - at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n - at com.example.GenerateTrace.main(GenerateTrace.java:5)' + at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n + at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n + at com.example.GenerateTrace.main(GenerateTrace.java:5)' + requirement_level: optional - id: escaped type: boolean brief: > @@ -32,6 +37,7 @@ groups: it is known that the exception is escaping the scope of the span. note: |- An exception is considered to have escaped. + requirement_level: optional attributes: - id: client.name type: string diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml index 568048cc..f0e0b79e 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml @@ -10,7 +10,9 @@ groups: the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive. body: + id: device.app.lifecycle.fields type: map + requirement_level: required fields: - id: ios.state stability: experimental @@ -21,31 +23,31 @@ groups: and from which the `OS terminology` column values are derived. brief: > This attribute represents the state the application has transitioned into at the occurrence of the event. - type: - allow_custom_values: false - members: - - id: active - value: 'active' - brief: > - The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. - - id: inactive - value: 'inactive' - brief: > - The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. - - id: background - value: 'background' - brief: > - The app is now in the background. - This value is associated with UIKit notification `applicationDidEnterBackground`. - - id: foreground - value: 'foreground' - brief: > - The app is now in the foreground. - This value is associated with UIKit notification `applicationWillEnterForeground`. - - id: terminate - value: 'terminate' - brief: > - The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. + type: enum + allow_custom_values: false + members: + - id: active + value: 'active' + brief: > + The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. + - id: inactive + value: 'inactive' + brief: > + The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. + - id: background + value: 'background' + brief: > + The app is now in the background. + This value is associated with UIKit notification `applicationDidEnterBackground`. + - id: foreground + value: 'foreground' + brief: > + The app is now in the foreground. + This value is associated with UIKit notification `applicationWillEnterForeground`. + - id: terminate + value: 'terminate' + brief: > + The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. - id: android.state stability: experimental requirement_level: @@ -55,21 +57,21 @@ groups: note: > The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived. - type: - allow_custom_values: false - members: - - id: created - value: 'created' - 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. - - 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. - - 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. \ No newline at end of file + type: enum + allow_custom_values: false + members: + - id: created + value: 'created' + 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. + - 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. + - 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. \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml index 17b37d70..4cfdf06a 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml @@ -8,7 +8,9 @@ groups: note: > This event transmits the body as a JSON encoded string. body: + id: some.string.body.event.fields type: string + requirement_level: required brief: > This is the body of the event which is a JSON encoded string. examples: ['{"key1":"value1","key2":"value2"}'] @@ -22,7 +24,9 @@ groups: note: > This event transmits the body as a JSON encoded string. body: + id: some.string.body.event.fields type: string + requirement_level: required brief: > This is the body of the event which is a JSON encoded string. note: > diff --git a/crates/weaver_resolver/src/any_value.rs b/crates/weaver_resolver/src/any_value.rs new file mode 100644 index 00000000..a8c97e53 --- /dev/null +++ b/crates/weaver_resolver/src/any_value.rs @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! Functions to resolve a semantic convention body. + +use weaver_resolved_schema::any_value::AnyValue; +use weaver_semconv::{any_value::AnyValueSpec, attribute::EnumEntriesSpec}; + +/// Resolve a `Body` specification into a resolved `Body`. +#[must_use] +pub fn resolve_any_value_spec(value: &AnyValueSpec) -> AnyValue { + match value { + AnyValueSpec::Map { fields, .. } => { + let resolved_fields: Vec = + fields.iter().map(resolve_any_value_spec).collect(); + + construct_any_value_common(value, Some(resolved_fields), None, None) + } + AnyValueSpec::Enum { + allow_custom_values, + members, + .. + } => construct_any_value_common( + value, + None, + Some(*allow_custom_values), + Some(members.to_vec()), + ), + _ => construct_any_value_common(value, None, None, None), + } +} + +/// Construct an AnyValue with common fields. +fn construct_any_value_common( + value: &AnyValueSpec, + resolved_fields: Option>, + allow_custom_values: Option, + members: Option>, +) -> AnyValue { + let common = value.common(); + + AnyValue { + name: value.id(), + r#type: value.type_name(), + type_display: Some(value.to_string()), + brief: value.brief(), + note: value.note(), + stability: common.stability.clone(), + examples: common.examples.clone(), + fields: resolved_fields, + requirement_level: common.requirement_level.clone(), + deprecated: common.deprecated.clone(), + allow_custom_values, + members, + } +} diff --git a/crates/weaver_resolver/src/body.rs b/crates/weaver_resolver/src/body.rs deleted file mode 100644 index ae28eac5..00000000 --- a/crates/weaver_resolver/src/body.rs +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Functions to resolve a semantic convention body. - -use weaver_resolved_schema::{ - body::{Body, BodyField}, - error::Error, -}; -use weaver_semconv::body::{BodySpec, BodyType}; - -/// Resolve a `Body` specification into a resolved `Body`. -pub fn resolve_body_spec(body: &BodySpec) -> Result, Error> { - match body { - BodySpec::Fields { - r#type: BodyType::Map, - brief, - note, - stability, - examples, - fields, - .. - } => { - let mut body_fields = Vec::new(); - for field in fields.iter() { - body_fields.push(BodyField { - name: field.id.clone(), - r#type: field.r#type.clone(), - brief: field.brief.clone(), - examples: field.examples.clone(), - requirement_level: field.requirement_level.clone(), - note: field.note.clone(), - stability: field.stability.clone(), - deprecated: field.deprecated.clone(), - }); - } - Ok(Some(Body { - r#type: BodyType::Map, - brief: brief.clone(), - note: note.clone(), - stability: stability.clone(), - examples: examples.clone(), - fields: Some(body_fields), - })) - } - BodySpec::String { - r#type: BodyType::String, - brief, - note, - stability, - examples, - } => { - // string types must have a brief and examples - if brief.is_empty() || examples.is_none() { - return Err(Error::InvalidBody { body: body.clone() }); - } - Ok(Some(Body { - r#type: BodyType::String, - brief: brief.clone(), - note: note.clone(), - stability: stability.clone(), - examples: examples.clone(), - fields: None, - })) - } - _ => Err(Error::InvalidBody { body: body.clone() }), - } -} diff --git a/crates/weaver_resolver/src/lib.rs b/crates/weaver_resolver/src/lib.rs index 7fec3d3a..40b1a545 100644 --- a/crates/weaver_resolver/src/lib.rs +++ b/crates/weaver_resolver/src/lib.rs @@ -25,8 +25,8 @@ use weaver_semconv::semconv::SemConvSpec; use crate::attribute::AttributeCatalog; use crate::registry::resolve_semconv_registry; +pub mod any_value; pub mod attribute; -pub mod body; mod constraint; pub mod registry; diff --git a/crates/weaver_resolver/src/registry.rs b/crates/weaver_resolver/src/registry.rs index f1aa82ce..53d95e1a 100644 --- a/crates/weaver_resolver/src/registry.rs +++ b/crates/weaver_resolver/src/registry.rs @@ -8,15 +8,14 @@ use serde::Deserialize; use weaver_common::error::handle_errors; use weaver_resolved_schema::attribute::UnresolvedAttribute; -use weaver_resolved_schema::body::UnresolvedBody; use weaver_resolved_schema::lineage::{AttributeLineage, GroupLineage}; use weaver_resolved_schema::registry::{Constraint, Group, Registry}; use weaver_semconv::attribute::AttributeSpec; use weaver_semconv::group::GroupSpecWithProvenance; use weaver_semconv::registry::SemConvRegistry; +use crate::any_value::resolve_any_value_spec; use crate::attribute::AttributeCatalog; -use crate::body::resolve_body_spec; use crate::constraint::resolve_constraints; use crate::{Error, UnsatisfiedAnyOfConstraint}; @@ -44,9 +43,6 @@ pub struct UnresolvedGroup { /// and other signals, into the group field once they are resolved. pub attributes: Vec, - /// The unresolved body that belongs to this group - pub body: Option, - /// The provenance of the group (URL or path). pub provenance: String, } @@ -87,8 +83,6 @@ pub fn resolve_semconv_registry( resolve_include_constraints(&mut ureg)?; - resolve_body(&mut ureg)?; - // Sort the attribute internal references in each group. // This is needed to ensure that the resolved registry is easy to compare // in unit tests. @@ -337,10 +331,9 @@ fn group_from_spec(group: GroupSpecWithProvenance) -> UnresolvedGroup { name: group.spec.name, lineage: Some(GroupLineage::new(&group.provenance)), display_name: group.spec.display_name, - body: None, // The body is resolved and populated later. + body: group.spec.body.map(|body| resolve_any_value_spec(&body)), }, attributes: attrs, - body: { group.spec.body.map(|body| UnresolvedBody { spec: body }) }, provenance: group.provenance, } } @@ -766,30 +759,6 @@ fn resolve_inheritance_attr( } } -fn resolve_body(ureg: &mut UnresolvedRegistry) -> Result<(), Error> { - let mut errors = vec![]; - - for unresolved_group in ureg.groups.iter_mut() { - if let Some(body) = &unresolved_group.body { - match resolve_body_spec(&body.spec) { - Ok(resolved_body) => { - unresolved_group.group.body = resolved_body; - } - Err(e) => { - errors.push(Error::UnresolvedBody { - group_id: unresolved_group.group.id.clone(), - provenance: unresolved_group.provenance.clone(), - error: e, - }); - } - } - } - } - - handle_errors(errors)?; - Ok(()) -} - #[cfg(test)] mod tests { use std::collections::HashSet; diff --git a/crates/weaver_semconv/Cargo.toml b/crates/weaver_semconv/Cargo.toml index 006d5b14..7a7d94ba 100644 --- a/crates/weaver_semconv/Cargo.toml +++ b/crates/weaver_semconv/Cargo.toml @@ -11,6 +11,9 @@ rust-version.workspace = true [lints] workspace = true +[dev-dependencies] +serde_json.workspace = true + [dependencies] weaver_common = { path = "../weaver_common" } diff --git a/crates/weaver_semconv/data/event.yaml b/crates/weaver_semconv/data/event.yaml index 6ea2084d..d17481a8 100644 --- a/crates/weaver_semconv/data/event.yaml +++ b/crates/weaver_semconv/data/event.yaml @@ -10,7 +10,9 @@ groups: the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive. body: + id: device_lifecycle type: map + requirement_level: optional fields: - id: ios.state stability: experimental @@ -21,31 +23,31 @@ groups: and from which the `OS terminology` column values are derived. brief: > This attribute represents the state the application has transitioned into at the occurrence of the event. - type: - allow_custom_values: false - members: - - id: active - value: 'active' - brief: > - The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. - - id: inactive - value: 'inactive' - brief: > - The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. - - id: background - value: 'background' - brief: > - The app is now in the background. - This value is associated with UIKit notification `applicationDidEnterBackground`. - - id: foreground - value: 'foreground' - brief: > - The app is now in the foreground. - This value is associated with UIKit notification `applicationWillEnterForeground`. - - id: terminate - value: 'terminate' - brief: > - The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. + type: enum + allow_custom_values: false + members: + - id: active + value: 'active' + brief: > + The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. + - id: inactive + value: 'inactive' + brief: > + The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. + - id: background + value: 'background' + brief: > + The app is now in the background. + This value is associated with UIKit notification `applicationDidEnterBackground`. + - id: foreground + value: 'foreground' + brief: > + The app is now in the foreground. + This value is associated with UIKit notification `applicationWillEnterForeground`. + - id: terminate + value: 'terminate' + brief: > + The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. - id: android.state stability: experimental requirement_level: @@ -55,24 +57,24 @@ groups: note: > The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived. - type: - allow_custom_values: false - members: - - id: created - value: 'created' - 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. - - 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. - - 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. + type: enum + allow_custom_values: false + members: + - id: created + value: 'created' + 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. + - 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. + - 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. - id: span.event.test.no_name stability: experimental @@ -135,7 +137,9 @@ groups: requirement_level: conditionally_required: Required if `attribute1` is not set, recommended otherwise. body: + id: body_name type: map + requirement_level: required fields: - id: field1 type: string @@ -170,6 +174,8 @@ groups: requirement_level: conditionally_required: Required if `attribute1` is not set, recommended otherwise. body: + id: body_name type: string brief: 'The body of the event' + requirement_level: required examples: ['{ name: "thename", content: ... }', '{ name: "thename", content: ... }'] diff --git a/crates/weaver_semconv/data/expected/any_value.json b/crates/weaver_semconv/data/expected/any_value.json new file mode 100644 index 00000000..97479e72 --- /dev/null +++ b/crates/weaver_semconv/data/expected/any_value.json @@ -0,0 +1 @@ +{"body":{"type":"map","id":"id","brief":"brief","note":"note","requirement_level":"optional","fields":[{"type":"enum","id":"id_enum","brief":"brief","note":"note","requirement_level":"optional","allow_custom_values":true,"members":[{"id":"id","value":42,"brief":"brief","note":"note","stability":null,"deprecated":null}]},{"type":"map","id":"id_map","brief":"brief","note":"note","requirement_level":"optional","fields":[{"type":"int","id":"id_int","brief":"brief","note":"note","requirement_level":"required"},{"type":"bytes","id":"id_bytes","brief":"brief","note":"note","requirement_level":"required"},{"type":"string","id":"id_string","brief":"brief","note":"note","requirement_level":"optional"},{"type":"boolean","id":"id_bool","brief":"brief","note":"note","requirement_level":"optional"},{"type":"map","id":"id_nested_map","brief":"brief","note":"note","requirement_level":"optional","fields":[{"type":"int[]","id":"id_nested_int","brief":"brief","note":"note","requirement_level":"optional"},{"type":"double[]","id":"id_nested_bytes","brief":"brief","note":"note","requirement_level":"optional"},{"type":"string[]","id":"id_nested_string","brief":"brief","note":"note","requirement_level":"optional"},{"type":"boolean[]","id":"id_nested_bool","brief":"brief","note":"note","requirement_level":"optional"}]}]},{"type":"int","id":"id_int","brief":"brief","note":"note","requirement_level":"optional"},{"type":"bytes","id":"id_bytes","brief":"brief","note":"note","requirement_level":"optional"},{"type":"string","id":"id_string","brief":"brief","note":"note","requirement_level":"recommended"},{"type":"boolean","id":"id_bool","brief":"brief","note":"note","requirement_level":"optional"},{"type":"double","id":"id_double","brief":"brief","note":"note","requirement_level":"optional"},{"type":"double[]","id":"id_doubles","brief":"brief","note":"note","requirement_level":"optional"}]}} \ No newline at end of file diff --git a/crates/weaver_semconv/data/expected/any_value.yaml b/crates/weaver_semconv/data/expected/any_value.yaml new file mode 100644 index 00000000..b3555d79 --- /dev/null +++ b/crates/weaver_semconv/data/expected/any_value.yaml @@ -0,0 +1,102 @@ +body: + type: map + id: id + brief: brief + note: note + requirement_level: optional + fields: + - type: enum + id: id_enum + brief: brief + note: note + requirement_level: optional + allow_custom_values: true + members: + - id: id + value: 42 + brief: brief + note: note + stability: null + deprecated: null + - type: map + id: id_map + brief: brief + note: note + requirement_level: optional + fields: + - type: int + id: id_int + brief: brief + note: note + requirement_level: required + - type: bytes + id: id_bytes + brief: brief + note: note + requirement_level: required + - type: string + id: id_string + brief: brief + note: note + requirement_level: optional + - type: boolean + id: id_bool + brief: brief + note: note + requirement_level: optional + - type: map + id: id_nested_map + brief: brief + note: note + requirement_level: optional + fields: + - type: int[] + id: id_nested_int + brief: brief + note: note + requirement_level: optional + - type: double[] + id: id_nested_bytes + brief: brief + note: note + requirement_level: optional + - type: string[] + id: id_nested_string + brief: brief + note: note + requirement_level: optional + - type: boolean[] + id: id_nested_bool + brief: brief + note: note + requirement_level: optional + - type: int + id: id_int + brief: brief + note: note + requirement_level: optional + - type: bytes + id: id_bytes + brief: brief + note: note + requirement_level: optional + - type: string + id: id_string + brief: brief + note: note + requirement_level: recommended + - type: boolean + id: id_bool + brief: brief + note: note + requirement_level: optional + - type: double + id: id_double + brief: brief + note: note + requirement_level: optional + - type: double[] + id: id_doubles + brief: brief + note: note + requirement_level: optional diff --git a/crates/weaver_semconv/src/any_value.rs b/crates/weaver_semconv/src/any_value.rs new file mode 100644 index 00000000..90e3d277 --- /dev/null +++ b/crates/weaver_semconv/src/any_value.rs @@ -0,0 +1,816 @@ +// SPDX-License-Identifier: Apache-2.0 + +#![allow(rustdoc::invalid_html_tags)] + +//! AnyValue specification. + +use std::fmt::{Display, Formatter}; + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use crate::attribute::{BasicRequirementLevelSpec, EnumEntriesSpec, Examples, RequirementLevel}; +use crate::stability::Stability; + +/// The AnyValueTypeSpec is a specification of a value that can be of any type. +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] +#[serde(rename_all = "snake_case")] +#[serde(tag = "type")] +pub enum AnyValueSpec { + /// A boolean attribute. + Boolean { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + }, + + /// A integer attribute (signed 64 bit integer). + Int { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + }, + + /// A double attribute (double precision floating point (IEEE 754-1985)). + Double { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + }, + + /// A string attribute. + String { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + }, + + /// An array of strings attribute. + #[serde(rename = "string[]")] + Strings { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + }, + + /// An array of integer attribute. + #[serde(rename = "int[]")] + Ints { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + }, + + /// An array of double attribute. + #[serde(rename = "double[]")] + Doubles { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + }, + + /// An array of boolean attribute. + #[serde(rename = "boolean[]")] + Booleans { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + }, + + /// The value type is a map of key, value pairs + Map { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + /// The collection of key, values where the value is an `AnyValueSpec` + fields: Vec, + }, + + /// The value type will just be a bytes. + Bytes { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + }, + + /// The value type is not specified. + Undefined { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + }, + + /// An enum definition type. + Enum { + /// The common value specification + #[serde(flatten)] + common: AnyValueCommonSpec, + + /// Set to false to not accept values other than the specified members. + /// It defaults to true. + #[serde(default = "default_as_true")] + allow_custom_values: bool, + /// List of enum entries. + members: Vec, + }, +} + +/// The Common Value specification for properties associated with an "AnyValue", this +/// is similar to the current `AttributeSpec` as at the proto level an Attribute +/// is defined as a "KeyValue". +/// While this is (currently) a duplication of the existing AttributeSpec, this is +/// to reduce the size of the change set. +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] +#[serde(deny_unknown_fields)] +#[serde(rename_all = "snake_case")] +pub struct AnyValueCommonSpec { + /// String that uniquely identifies the enum entry. + pub id: String, + /// A brief description of the value + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + pub brief: String, + /// A more elaborate description of the value. + /// It defaults to an empty string. + #[serde(skip_serializing_if = "String::is_empty")] + #[serde(default)] + pub note: String, + /// Specifies the stability of the value. + #[serde(skip_serializing_if = "Option::is_none")] + pub stability: Option, + /// Sequence of examples for the value or single example + /// value. If only a single example is provided, it can + /// directly be reported without encapsulating it + /// into a sequence/dictionary. + #[serde(skip_serializing_if = "Option::is_none")] + pub examples: Option, + /// Specifies if the field is mandatory. Can be "required", + /// "conditionally_required", "recommended" or "opt_in". When omitted, + /// the field is "recommended". When set to + /// "conditionally_required", the string provided as MUST + /// specify the conditions under which the field is required. + pub requirement_level: RequirementLevel, + /// Specifies if the body field is deprecated. The string + /// provided as MUST specify why it's deprecated and/or what + /// to use instead. See also stability. + #[serde(skip_serializing_if = "Option::is_none")] + pub deprecated: Option, +} + +/// Implements a human readable display for AnyValueType, used to populate the type_display field. +impl Display for AnyValueSpec { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + AnyValueSpec::Map { fields, .. } => { + let entries = fields + .iter() + .map(|v| format!("{}", v)) + .collect::>() + .join(", "); + write!(f, "map<{}>{{ {} }}", self.id(), entries) + } + AnyValueSpec::Boolean { .. } => write!(f, "boolean"), + AnyValueSpec::Int { .. } => write!(f, "int"), + AnyValueSpec::Double { .. } => write!(f, "double"), + AnyValueSpec::String { .. } => write!(f, "string"), + AnyValueSpec::Strings { .. } => write!(f, "string[]"), + AnyValueSpec::Ints { .. } => write!(f, "int[]"), + AnyValueSpec::Doubles { .. } => write!(f, "double[]"), + AnyValueSpec::Booleans { .. } => write!(f, "boolean[]"), + AnyValueSpec::Bytes { .. } => write!(f, "byte[]"), + AnyValueSpec::Undefined { .. } => write!(f, "undefined"), + AnyValueSpec::Enum { members, .. } => { + let entries = members + .iter() + .map(|m| m.id.clone()) + .collect::>() + .join(", "); + write!(f, "enum<{}> {{{}}}", self.id(), entries) + } + } + } +} + +impl AnyValueSpec { + /// Returns the common value specification for each type. + #[must_use] + pub fn common(&self) -> &AnyValueCommonSpec { + match self { + AnyValueSpec::Boolean { common, .. } => common, + AnyValueSpec::Int { common, .. } => common, + AnyValueSpec::Double { common, .. } => common, + AnyValueSpec::String { common, .. } => common, + AnyValueSpec::Strings { common, .. } => common, + AnyValueSpec::Ints { common, .. } => common, + AnyValueSpec::Doubles { common, .. } => common, + AnyValueSpec::Booleans { common, .. } => common, + AnyValueSpec::Map { common, .. } => common, + AnyValueSpec::Bytes { common, .. } => common, + AnyValueSpec::Undefined { common, .. } => common, + AnyValueSpec::Enum { common, .. } => common, + } + } + + /// Returns true if the any value is required. + #[must_use] + pub fn is_required(&self) -> bool { + matches!( + self.common(), + AnyValueCommonSpec { + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), + .. + } + ) + } + + /// Returns the id of the any value. + #[must_use] + pub fn id(&self) -> String { + let AnyValueCommonSpec { id, .. } = self.common(); + id.clone() + } + + /// Returns the brief of the any value. + #[must_use] + pub fn brief(&self) -> String { + let AnyValueCommonSpec { brief, .. } = self.common(); + brief.clone() + } + + /// Returns the note of the any value. + #[must_use] + pub fn note(&self) -> String { + let AnyValueCommonSpec { note, .. } = self.common(); + note.clone() + } + + /// Provides a string representation of the type of the value, with the id for + /// enum and map types. + #[must_use] + pub fn type_name(&self) -> String { + match self { + AnyValueSpec::Map { .. } => "map".to_owned(), + AnyValueSpec::Boolean { .. } => "boolean".to_owned(), + AnyValueSpec::Int { .. } => "int".to_owned(), + AnyValueSpec::Double { .. } => "double".to_owned(), + AnyValueSpec::String { .. } => "string".to_owned(), + AnyValueSpec::Strings { .. } => "string[]".to_owned(), + AnyValueSpec::Ints { .. } => "int[]".to_owned(), + AnyValueSpec::Doubles { .. } => "double[]".to_owned(), + AnyValueSpec::Booleans { .. } => "boolean[]".to_owned(), + AnyValueSpec::Bytes { .. } => "byte[]".to_owned(), + AnyValueSpec::Undefined { .. } => "undefined".to_owned(), + AnyValueSpec::Enum { .. } => "enum".to_owned(), + } + } +} + +/// Specifies the default value for allow_custom_values. +fn default_as_true() -> bool { + true +} + +#[cfg(test)] +mod tests { + use std::fs; + + use crate::attribute::ValueSpec; + + use super::*; + + #[test] + fn test_anyvalue_field_type_display() { + #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] + pub struct BodySpec { + pub body: AnyValueSpec, + } + + let map = AnyValueSpec::Map { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), + deprecated: None, + }, + fields: vec![ + AnyValueSpec::Enum { + common: AnyValueCommonSpec { + id: "id_enum".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + allow_custom_values: true, + members: vec![EnumEntriesSpec { + id: "id".to_owned(), + value: ValueSpec::Int(42), + brief: Some("brief".to_owned()), + note: Some("note".to_owned()), + stability: None, + deprecated: None, + }], + }, + AnyValueSpec::Map { + common: AnyValueCommonSpec { + id: "id_map".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + fields: vec![ + AnyValueSpec::Int { + common: AnyValueCommonSpec { + id: "id_int".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Required, + ), + deprecated: None, + }, + }, + AnyValueSpec::Bytes { + common: AnyValueCommonSpec { + id: "id_bytes".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Required, + ), + deprecated: None, + }, + }, + AnyValueSpec::String { + common: AnyValueCommonSpec { + id: "id_string".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + AnyValueSpec::Boolean { + common: AnyValueCommonSpec { + id: "id_bool".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + AnyValueSpec::Map { + common: AnyValueCommonSpec { + id: "id_nested_map".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + fields: vec![ + AnyValueSpec::Ints { + common: AnyValueCommonSpec { + id: "id_nested_int".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + AnyValueSpec::Doubles { + common: AnyValueCommonSpec { + id: "id_nested_bytes".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + AnyValueSpec::Strings { + common: AnyValueCommonSpec { + id: "id_nested_string".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + AnyValueSpec::Booleans { + common: AnyValueCommonSpec { + id: "id_nested_bool".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + ], + }, + ], + }, + AnyValueSpec::Int { + common: AnyValueCommonSpec { + id: "id_int".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + AnyValueSpec::Bytes { + common: AnyValueCommonSpec { + id: "id_bytes".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + AnyValueSpec::String { + common: AnyValueCommonSpec { + id: "id_string".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Recommended, + ), + deprecated: None, + }, + }, + AnyValueSpec::Boolean { + common: AnyValueCommonSpec { + id: "id_bool".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + AnyValueSpec::Double { + common: AnyValueCommonSpec { + id: "id_double".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + AnyValueSpec::Doubles { + common: AnyValueCommonSpec { + id: "id_doubles".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional, + ), + deprecated: None, + }, + }, + ], + }; + let body = BodySpec { body: map.clone() }; + + let expected_yaml = fs::read_to_string("data/expected/any_value.yaml") + .unwrap() + .replace("\r\n", "\n"); + assert_eq!( + expected_yaml, + format!("{}", serde_yaml::to_string(&body).unwrap()), + "{}", + expected_yaml + ); + + let expected_json = fs::read_to_string("data/expected/any_value.json") + .unwrap() + .replace("\r\n", "\n"); + assert_eq!( + expected_json, + format!("{}", serde_json::to_string(&body).unwrap()), + "{}", + expected_json + ); + + assert_eq!(format!("{}", map.type_name()), "map",); + + assert_eq!( + format!( + "{}", + map + ), + "map{ enum {id}, map{ int, byte[], string, boolean, map{ int[], double[], string[], boolean[] } }, int, byte[], string, boolean, double, double[] }", + ); + + assert_eq!( + format!( + "{}", + AnyValueSpec::Boolean { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + } + } + ), + "boolean" + ); + assert_eq!( + format!( + "{}", + AnyValueSpec::Int { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + } + } + ), + "int" + ); + assert_eq!( + format!( + "{}", + AnyValueSpec::Double { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + } + } + ), + "double" + ); + assert_eq!( + format!( + "{}", + AnyValueSpec::String { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + } + } + ), + "string" + ); + assert_eq!( + format!( + "{}", + AnyValueSpec::Strings { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + } + } + ), + "string[]" + ); + assert_eq!( + format!( + "{}", + AnyValueSpec::Ints { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + } + } + ), + "int[]" + ); + assert_eq!( + format!( + "{}", + AnyValueSpec::Doubles { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + } + } + ), + "double[]" + ); + assert_eq!( + format!( + "{}", + AnyValueSpec::Booleans { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + } + } + ), + "boolean[]" + ); + assert_eq!( + format!( + "{}", + AnyValueSpec::Bytes { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + } + } + ), + "byte[]" + ); + assert_eq!( + format!( + "{}", + AnyValueSpec::Undefined { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + } + } + ), + "undefined" + ); + assert_eq!( + format!( + "{}", + AnyValueSpec::Enum { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + }, + allow_custom_values: true, + members: vec![EnumEntriesSpec { + id: "id".to_owned(), + value: ValueSpec::Int(42), + brief: Some("brief".to_owned()), + note: Some("note".to_owned()), + stability: None, + deprecated: None, + }] + } + .type_name() + ), + "enum" + ); + + assert_eq!( + format!( + "{}", + AnyValueSpec::Enum { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic( + BasicRequirementLevelSpec::Optional + ), + deprecated: None, + }, + allow_custom_values: true, + members: vec![EnumEntriesSpec { + id: "entry1".to_owned(), + value: ValueSpec::Int(42), + brief: Some("brief".to_owned()), + note: Some("note".to_owned()), + stability: None, + deprecated: None, + }] + } + ), + "enum {entry1}" + ); + } +} diff --git a/crates/weaver_semconv/src/body.rs b/crates/weaver_semconv/src/body.rs deleted file mode 100644 index eb6ba229..00000000 --- a/crates/weaver_semconv/src/body.rs +++ /dev/null @@ -1,361 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -#![allow(rustdoc::invalid_html_tags)] - -//! Body Field specification. - -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use std::fmt::{Display, Formatter}; - -use crate::attribute::{AttributeType, BasicRequirementLevelSpec, Examples, RequirementLevel}; -use crate::stability::Stability; - -/// A body specification -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(deny_unknown_fields)] -#[serde(untagged)] -#[serde(rename_all = "snake_case")] -pub enum BodySpec { - /// The collection of body fields associated with a body definition - Fields { - /// Identifies that the type of the body is a map of fields or a string. - r#type: BodyType, - /// A brief description of the body. - #[serde(skip_serializing_if = "String::is_empty")] - #[serde(default)] - brief: String, - /// A more elaborate description of the body. - /// It defaults to an empty string. - #[serde(skip_serializing_if = "String::is_empty")] - #[serde(default)] - note: String, - /// Specifies the stability of the body. - #[serde(skip_serializing_if = "Option::is_none")] - stability: Option, - /// Sequence of example values for the body or single example - /// value. They are required only for string types. Example values - /// must be of the same type of the body. If only a single example is - /// provided, it can directly be reported without encapsulating it - /// into a sequence/dictionary. - #[serde(skip_serializing_if = "Option::is_none")] - examples: Option, - /// Identifies the definition of the "fields" of the body when the body type is "map". - #[serde(skip_serializing_if = "Vec::is_empty")] - fields: Vec, - }, - /// The body will just be a string. - String { - /// Identifies that the type of the body is a string. - r#type: BodyType, - /// A brief description of the body. - #[serde(skip_serializing_if = "String::is_empty")] - #[serde(default)] - brief: String, - /// A more elaborate description of the body. - /// It defaults to an empty string. - #[serde(skip_serializing_if = "String::is_empty")] - #[serde(default)] - note: String, - /// Specifies the stability of the body. - #[serde(skip_serializing_if = "Option::is_none")] - stability: Option, - /// Sequence of example values for the body or single example - /// value. They are required only for string types. Example values - /// must be of the same type of the body. If only a single example is - /// provided, it can directly be reported without encapsulating it - /// into a sequence/dictionary. - #[serde(skip_serializing_if = "Option::is_none")] - examples: Option, - }, -} - -impl BodySpec { - /// Returns true if the body field is required. - #[must_use] - pub fn has_fields(&self) -> bool { - match self { - BodySpec::Fields { fields, .. } => !fields.is_empty(), - BodySpec::String { .. } => false, - } - } -} - -/// Identifies the different types of body (specification). -#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum BodyType { - /// A map body type. - Map, - /// A string body type. - String, -} - -/// Implements a human readable display for PrimitiveOrArrayType. -impl Display for BodyType { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - BodyType::String => write!(f, "string"), - BodyType::Map => write!(f, "map"), - } - } -} - -/// A `BodyField` specification. -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(deny_unknown_fields)] -#[serde(rename_all = "snake_case")] -pub struct BodyFieldSpec { - /// String that uniquely identifies the body field. - pub id: String, - /// Either a string literal denoting the type as a primitive or an - /// array type, a template type or an enum definition. - pub r#type: AttributeType, - /// A brief description of the body field. - pub brief: String, - /// Sequence of example values for the body field or single example - /// value. They are required only for string and string array - /// fields. Example values must be of the same type of the - /// body field. If only a single example is provided, it can directly - /// be reported without encapsulating it into a sequence/dictionary. - #[serde(skip_serializing_if = "Option::is_none")] - pub examples: Option, - /// Specifies if the body field is mandatory. Can be "required", - /// "conditionally_required", "recommended" or "opt_in". When omitted, - /// the body field is "recommended". When set to - /// "conditionally_required", the string provided as MUST - /// specify the conditions under which the body field is required. - #[serde(default)] - pub requirement_level: RequirementLevel, - /// A more elaborate description of the body field. - /// It defaults to an empty string. - #[serde(default)] - pub note: String, - /// Specifies the stability of the body field. - /// Note that, if stability is missing but deprecated is present, it will - /// automatically set the stability to deprecated. If deprecated is - /// present and stability differs from deprecated, this will result in an - /// error. - #[serde(skip_serializing_if = "Option::is_none")] - pub stability: Option, - /// Specifies if the body field is deprecated. The string - /// provided as MUST specify why it's deprecated and/or what - /// to use instead. See also stability. - #[serde(skip_serializing_if = "Option::is_none")] - pub deprecated: Option, -} - -impl BodyFieldSpec { - /// Returns true if the body field is required. - #[must_use] - pub fn is_required(&self) -> bool { - matches!( - self, - BodyFieldSpec { - requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), - .. - } - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::attribute::{ - EnumEntriesSpec, PrimitiveOrArrayTypeSpec, TemplateTypeSpec, ValueSpec, - }; - - #[test] - fn test_body_field_type_display() { - assert_eq!( - format!( - "{}", - AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Boolean) - ), - "boolean" - ); - assert_eq!( - format!( - "{}", - AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Int) - ), - "int" - ); - assert_eq!( - format!( - "{}", - AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Double) - ), - "double" - ); - assert_eq!( - format!( - "{}", - AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::String) - ), - "string" - ); - assert_eq!( - format!( - "{}", - AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Strings) - ), - "string[]" - ); - assert_eq!( - format!( - "{}", - AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Ints) - ), - "int[]" - ); - assert_eq!( - format!( - "{}", - AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Doubles) - ), - "double[]" - ); - assert_eq!( - format!( - "{}", - AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Booleans) - ), - "boolean[]" - ); - assert_eq!( - format!("{}", AttributeType::Template(TemplateTypeSpec::Boolean)), - "template[boolean]" - ); - assert_eq!( - format!("{}", AttributeType::Template(TemplateTypeSpec::Int)), - "template[int]" - ); - assert_eq!( - format!("{}", AttributeType::Template(TemplateTypeSpec::Double)), - "template[double]" - ); - assert_eq!( - format!("{}", AttributeType::Template(TemplateTypeSpec::String)), - "template[string]" - ); - assert_eq!( - format!("{}", AttributeType::Template(TemplateTypeSpec::Strings)), - "template[string[]]" - ); - assert_eq!( - format!("{}", AttributeType::Template(TemplateTypeSpec::Ints)), - "template[int[]]" - ); - assert_eq!( - format!("{}", AttributeType::Template(TemplateTypeSpec::Doubles)), - "template[double[]]" - ); - assert_eq!( - format!("{}", AttributeType::Template(TemplateTypeSpec::Booleans)), - "template[boolean[]]" - ); - assert_eq!( - format!( - "{}", - AttributeType::Enum { - allow_custom_values: true, - members: vec![EnumEntriesSpec { - id: "id".to_owned(), - value: ValueSpec::Int(42), - brief: Some("brief".to_owned()), - note: Some("note".to_owned()), - stability: None, - deprecated: None, - }] - } - ), - "enum {id}" - ); - } - - #[test] - fn test_field_body() { - let body = BodySpec::Fields { - r#type: BodyType::Map, - brief: "brief".to_owned(), - note: "note".to_owned(), - stability: Some(Stability::Stable), - examples: Some(Examples::Int(42)), - fields: vec![BodyFieldSpec { - id: "id".to_owned(), - r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Int), - brief: "brief".to_owned(), - examples: Some(Examples::Int(42)), - requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), - note: "note".to_owned(), - stability: Some(Stability::Stable), - deprecated: Some("deprecated".to_owned()), - }], - }; - - assert!(matches!(body, BodySpec::Fields { .. })); - assert!(!matches!(body, BodySpec::String { .. })); - assert!(body.has_fields()); - - if let BodySpec::Fields { - brief, - note, - fields, - .. - } = body - { - assert_eq!(brief, "brief"); - assert_eq!(note, "note"); - assert!(fields.len() == 1); - } - } - - #[test] - fn test_string_body() { - let body = BodySpec::String { - r#type: BodyType::String, - brief: "brief".to_owned(), - note: "note".to_owned(), - stability: Some(Stability::Stable), - examples: Some(Examples::String("{key: value}".to_owned())), - }; - - assert!(matches!(body, BodySpec::String { .. })); - assert!(!matches!(body, BodySpec::Fields { .. })); - assert!(!body.has_fields()); - - if let BodySpec::String { brief, note, .. } = body { - assert_eq!(brief, "brief"); - assert_eq!(note, "note"); - } - } - - #[test] - fn test_body_field() { - let field = BodyFieldSpec { - id: "id".to_owned(), - r#type: AttributeType::PrimitiveOrArray(PrimitiveOrArrayTypeSpec::Int), - brief: "brief".to_owned(), - examples: Some(Examples::Int(42)), - requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Required), - note: "note".to_owned(), - stability: Some(Stability::Stable), - deprecated: Some("deprecated".to_owned()), - }; - assert_eq!(field.id, "id"); - assert_eq!(field.brief.to_owned(), "brief".to_owned()); - assert_eq!(field.note, "note"); - assert!(field.is_required()); - } -} - -/// A Body Field definition with its provenance (path or URL). -#[derive(Debug, Clone)] -pub struct BodyFieldSpecWithProvenance { - /// The body field definition. - pub body_field: BodyFieldSpec, - /// The provenance of the body field (path or URL). - pub provenance: String, -} diff --git a/crates/weaver_semconv/src/group.rs b/crates/weaver_semconv/src/group.rs index 1724af70..8f870db6 100644 --- a/crates/weaver_semconv/src/group.rs +++ b/crates/weaver_semconv/src/group.rs @@ -9,8 +9,8 @@ use std::fmt::{Display, Formatter}; use serde::{Deserialize, Serialize}; +use crate::any_value::AnyValueSpec; use crate::attribute::{AttributeSpec, AttributeType, PrimitiveOrArrayTypeSpec}; -use crate::body::BodySpec; use crate::group::InstrumentSpec::{Counter, Gauge, Histogram, UpDownCounter}; use crate::stability::Stability; use crate::Error; @@ -90,7 +90,7 @@ pub struct GroupSpec { /// The event body definition /// Note: only valid if type is event #[serde(skip_serializing_if = "Option::is_none")] - pub body: Option, + pub body: Option, } impl GroupSpec { diff --git a/crates/weaver_semconv/src/lib.rs b/crates/weaver_semconv/src/lib.rs index 6131ceb0..3f7a298e 100644 --- a/crates/weaver_semconv/src/lib.rs +++ b/crates/weaver_semconv/src/lib.rs @@ -8,8 +8,8 @@ use serde::Serialize; use weaver_common::diagnostic::{DiagnosticMessage, DiagnosticMessages}; use weaver_common::error::{format_errors, WeaverError}; +pub mod any_value; pub mod attribute; -pub mod body; pub mod group; pub mod metric; pub mod registry; From d836d08cd91818adc2ad97490410066b3668bcc0 Mon Sep 17 00:00:00 2001 From: Nev Wylie <54870357+MSNev@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:00:04 -0700 Subject: [PATCH 6/8] Remove allow_custom_values, deprecated and type_display --- crates/weaver_forge/data/mobile-events.yaml | 2 - .../semconv_jq_fn/semconv_events.json | 2 +- .../weaver_resolved_schema/src/any_value.rs | 14 - .../expected-events.json | 8 - .../expected-registry.json | 44 +-- .../registry/mobile-events.yaml | 2 - crates/weaver_resolver/src/any_value.rs | 23 +- crates/weaver_semconv/data/event.yaml | 2 - .../data/expected/any_value.json | 2 +- .../data/expected/any_value.yaml | 1 - crates/weaver_semconv/src/any_value.rs | 98 +------ crates/weaver_semconv/src/attribute.rs | 68 +++++ crates/weaver_semconv/src/group.rs | 250 +++++++++++++++++- crates/weaver_semconv/src/lib.rs | 14 + schemas/semconv-syntax.md | 136 ++++++---- schemas/semconv.schema.json | 141 +++++----- 16 files changed, 522 insertions(+), 285 deletions(-) diff --git a/crates/weaver_forge/data/mobile-events.yaml b/crates/weaver_forge/data/mobile-events.yaml index a8008d98..503b045d 100644 --- a/crates/weaver_forge/data/mobile-events.yaml +++ b/crates/weaver_forge/data/mobile-events.yaml @@ -24,7 +24,6 @@ groups: brief: > This attribute represents the state the application has transitioned into at the occurrence of the event. type: enum - allow_custom_values: false members: - id: active value: 'active' @@ -58,7 +57,6 @@ groups: The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived. type: enum - allow_custom_values: false members: - id: created value: 'created' diff --git a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json index 2cb781cd..debdb697 100644 --- a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json +++ b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json @@ -1 +1 @@ -[{"attributes":[],"body":{"fields":[{"allow_custom_values":false,"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","members":[{"brief":"The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n","deprecated":null,"id":"active","note":null,"stability":null,"value":"active"},{"brief":"The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n","deprecated":null,"id":"inactive","note":null,"stability":null,"value":"inactive"},{"brief":"The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"brief":"The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"},{"brief":"The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n","deprecated":null,"id":"terminate","note":null,"stability":null,"value":"terminate"}],"name":"ios.state","note":"The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `ios`"},"stability":"experimental","type":"enum","type_display":"enum\u003cios.state\u003e {active, inactive, background, foreground, terminate}"},{"allow_custom_values":false,"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","members":[{"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.\n","deprecated":null,"id":"created","note":null,"stability":null,"value":"created"},{"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.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"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.","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"}],"name":"android.state","note":"The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `android`"},"stability":"experimental","type":"enum","type_display":"enum\u003candroid.state\u003e {created, background, foreground}"}],"name":"device.app.lifecycle.fields","requirement_level":"required","type":"map","type_display":"map\u003cdevice.app.lifecycle.fields\u003e{ enum\u003cios.state\u003e {active, inactive, background, foreground, terminate}, enum\u003candroid.state\u003e {created, background, foreground} }"},"brief":"This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n","event_namespace":"device.app","events":[],"id":"device.app.lifecycle","instrument":null,"lineage":{"source_file":"data/mobile-events.yaml"},"metric_name":null,"name":"device.app.lifecycle","note":"This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n","span_kind":null,"stability":"experimental","type":"event","unit":null},{"attributes":[{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","stability":"stable","type":"string"},{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","stability":"stable","type":"boolean"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":{"conditionally_required":"Required if `exception.message` is not set, recommended otherwise."},"stability":"stable","type":"string"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":{"conditionally_required":"Required if `exception.type` is not set, recommended otherwise."},"stability":"stable","type":"string"}],"brief":"This document defines the attributes used to report a single exception associated with a span.\n","event_namespace":"other","events":[],"id":"trace-exception","instrument":null,"lineage":{"attributes":{"exception.escaped":{"inherited_fields":["brief","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.message":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"},"exception.stacktrace":{"inherited_fields":["brief","examples","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.type":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"}},"source_file":"data/trace-exception.yaml"},"metric_name":null,"name":null,"prefix":"exception","span_kind":null,"type":"event","unit":null}] \ No newline at end of file +[{"attributes":[],"body":{"fields":[{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","members":[{"brief":"The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n","deprecated":null,"id":"active","note":null,"stability":null,"value":"active"},{"brief":"The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n","deprecated":null,"id":"inactive","note":null,"stability":null,"value":"inactive"},{"brief":"The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"brief":"The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"},{"brief":"The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n","deprecated":null,"id":"terminate","note":null,"stability":null,"value":"terminate"}],"name":"ios.state","note":"The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `ios`"},"stability":"experimental","type":"enum {active, inactive, background, foreground, terminate}"},{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","members":[{"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.\n","deprecated":null,"id":"created","note":null,"stability":null,"value":"created"},{"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.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"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.","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"}],"name":"android.state","note":"The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `android`"},"stability":"experimental","type":"enum {created, background, foreground}"}],"name":"device.app.lifecycle.fields","requirement_level":"required","type":"map"},"brief":"This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n","event_namespace":"device.app","events":[],"id":"device.app.lifecycle","instrument":null,"lineage":{"source_file":"data/mobile-events.yaml"},"metric_name":null,"name":"device.app.lifecycle","note":"This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n","span_kind":null,"stability":"experimental","type":"event","unit":null},{"attributes":[{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","stability":"stable","type":"string"},{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","stability":"stable","type":"boolean"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":{"conditionally_required":"Required if `exception.message` is not set, recommended otherwise."},"stability":"stable","type":"string"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":{"conditionally_required":"Required if `exception.type` is not set, recommended otherwise."},"stability":"stable","type":"string"}],"brief":"This document defines the attributes used to report a single exception associated with a span.\n","event_namespace":"other","events":[],"id":"trace-exception","instrument":null,"lineage":{"attributes":{"exception.escaped":{"inherited_fields":["brief","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.message":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"},"exception.stacktrace":{"inherited_fields":["brief","examples","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.type":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"}},"source_file":"data/trace-exception.yaml"},"metric_name":null,"name":null,"prefix":"exception","span_kind":null,"type":"event","unit":null}] \ No newline at end of file diff --git a/crates/weaver_resolved_schema/src/any_value.rs b/crates/weaver_resolved_schema/src/any_value.rs index e3add63c..e995577e 100644 --- a/crates/weaver_resolved_schema/src/any_value.rs +++ b/crates/weaver_resolved_schema/src/any_value.rs @@ -18,10 +18,6 @@ pub struct AnyValue { /// Either a string literal denoting the type as a primitive or an /// array type, a template type or an enum definition. pub r#type: String, - /// A description of the type of the AnyValue - /// e.g. "string", "string[]", "int", "enum", "map{ int, string }" - #[serde(skip_serializing_if = "Option::is_none")] - pub type_display: Option, /// A brief description of the AnyValue. #[serde(skip_serializing_if = "String::is_empty")] #[serde(default)] @@ -51,20 +47,10 @@ pub struct AnyValue { /// error. #[serde(skip_serializing_if = "Option::is_none")] pub stability: Option, - /// Specifies if the value is deprecated. The string - /// provided as MUST specify why it's deprecated and/or what - /// to use instead. See also stability. - #[serde(skip_serializing_if = "Option::is_none")] - pub deprecated: Option, /// Identifies the definition of the "fields" of the value when the type is "map". #[serde(skip_serializing_if = "Option::is_none")] pub fields: Option>, /// Used when the type is "enum". - /// Set to false to not accept values other than the specified members. - /// It defaults to true. - #[serde(skip_serializing_if = "Option::is_none")] - pub allow_custom_values: Option, - /// Used when the type is "enum". /// List of enum entries. #[serde(skip_serializing_if = "Option::is_none")] pub members: Option>, diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-events.json b/crates/weaver_resolver/data/registry-test-4-events/expected-events.json index 2ccc397e..87861a35 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/expected-events.json +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-events.json @@ -16,7 +16,6 @@ "members": [ { "brief": "The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n", - "deprecated": null, "id": "active", "note": null, "stability": null, @@ -24,7 +23,6 @@ }, { "brief": "The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n", - "deprecated": null, "id": "inactive", "note": null, "stability": null, @@ -32,7 +30,6 @@ }, { "brief": "The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n", - "deprecated": null, "id": "background", "note": null, "stability": null, @@ -40,7 +37,6 @@ }, { "brief": "The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n", - "deprecated": null, "id": "foreground", "note": null, "stability": null, @@ -48,7 +44,6 @@ }, { "brief": "The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n", - "deprecated": null, "id": "terminate", "note": null, "stability": null, @@ -70,7 +65,6 @@ "members": [ { "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.\n", - "deprecated": null, "id": "created", "note": null, "stability": null, @@ -78,7 +72,6 @@ }, { "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.\n", - "deprecated": null, "id": "background", "note": null, "stability": null, @@ -86,7 +79,6 @@ }, { "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.", - "deprecated": null, "id": "foreground", "note": null, "stability": null, diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json b/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json index c3d8b4fe..3899cb23 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json @@ -19,13 +19,11 @@ "body": { "name": "browser.test.event_with_body.fields", "type": "map", - "type_display": "map{ string }", "requirement_level": "required", "fields": [ { "name": "some.field", "type": "string", - "type_display": "string", "brief": "A field that is not referenced in the attributes", "examples": [ "some value", @@ -49,7 +47,6 @@ "body": { "name": "browser.test.event_with_body_details.fields", "type": "map", - "type_display": "map{ string }", "brief": "A map of fields that are not referenced in the attributes", "note": "This map is not referenced in the attributes", "stability": "experimental", @@ -61,7 +58,6 @@ { "name": "some.field", "type": "string", - "type_display": "string", "brief": "A field that is not referenced in the attributes", "examples": [ "some value", @@ -87,13 +83,11 @@ "body": { "name": "client.exception.event.fields", "type": "map", - "type_display": "map{ string, string, string, boolean }", "requirement_level": "optional", "fields": [ { "name": "type", "type": "string", - "type_display": "string", "brief": "The type of the exception.\n", "examples": [ "java.net.ConnectException", @@ -104,7 +98,6 @@ { "name": "message", "type": "string", - "type_display": "string", "brief": "The exception message.", "examples": [ "Division by zero", @@ -115,7 +108,6 @@ { "name": "stacktrace", "type": "string", - "type_display": "string", "brief": "A stacktrace.\n", "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)", "requirement_level": "optional" @@ -123,7 +115,6 @@ { "name": "escaped", "type": "boolean", - "type_display": "boolean", "brief": "SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n", "requirement_level": "optional", "note": "An exception is considered to have escaped." @@ -212,54 +203,46 @@ "body": { "name": "device.app.lifecycle.fields", "type": "map", - "type_display": "map{ enum {active, inactive, background, foreground, terminate}, enum {created, background, foreground} }", "requirement_level": "required", "fields": [ { "name": "ios.state", - "type": "enum", - "type_display": "enum {active, inactive, background, foreground, terminate}", - "allow_custom_values": false, + "type": "enum {active, inactive, background, foreground, terminate}", "members": [ { "id": "active", "value": "active", "brief": "The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n", "note": null, - "stability": null, - "deprecated": null + "stability": null }, { "id": "inactive", "value": "inactive", "brief": "The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n", "note": null, - "stability": null, - "deprecated": null + "stability": null }, { "id": "background", "value": "background", "brief": "The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n", "note": null, - "stability": null, - "deprecated": null + "stability": null }, { "id": "foreground", "value": "foreground", "brief": "The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n", "note": null, - "stability": null, - "deprecated": null + "stability": null }, { "id": "terminate", "value": "terminate", "brief": "The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n", "note": null, - "stability": null, - "deprecated": null + "stability": null } ], "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", @@ -271,33 +254,28 @@ }, { "name": "android.state", - "type": "enum", - "type_display": "enum {created, background, foreground}", - "allow_custom_values": false, + "type": "enum {created, background, foreground}", "members": [ { "id": "created", "value": "created", "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.\n", "note": null, - "stability": null, - "deprecated": null + "stability": null }, { "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.\n", "note": null, - "stability": null, - "deprecated": null + "stability": null }, { "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.", "note": null, - "stability": null, - "deprecated": null + "stability": null } ], "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", @@ -472,7 +450,6 @@ "body": { "name": "some.string.body.event.fields", "type": "string", - "type_display": "string", "brief": "This is the body of the event which is a JSON encoded string.\n", "examples": [ "{\"key1\":\"value1\",\"key2\":\"value2\"}" @@ -494,7 +471,6 @@ "body": { "name": "some.string.body.event.fields", "type": "string", - "type_display": "string", "brief": "This is the body of the event which is a JSON encoded string.\n", "note": "This is a detailed note about the body.\n", "stability": "experimental", diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml index f0e0b79e..ae6b3a55 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml @@ -24,7 +24,6 @@ groups: brief: > This attribute represents the state the application has transitioned into at the occurrence of the event. type: enum - allow_custom_values: false members: - id: active value: 'active' @@ -58,7 +57,6 @@ groups: The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived. type: enum - allow_custom_values: false members: - id: created value: 'created' diff --git a/crates/weaver_resolver/src/any_value.rs b/crates/weaver_resolver/src/any_value.rs index a8c97e53..86a751f5 100644 --- a/crates/weaver_resolver/src/any_value.rs +++ b/crates/weaver_resolver/src/any_value.rs @@ -13,19 +13,12 @@ pub fn resolve_any_value_spec(value: &AnyValueSpec) -> AnyValue { let resolved_fields: Vec = fields.iter().map(resolve_any_value_spec).collect(); - construct_any_value_common(value, Some(resolved_fields), None, None) + construct_any_value_common(value, Some(resolved_fields), None) } - AnyValueSpec::Enum { - allow_custom_values, - members, - .. - } => construct_any_value_common( - value, - None, - Some(*allow_custom_values), - Some(members.to_vec()), - ), - _ => construct_any_value_common(value, None, None, None), + AnyValueSpec::Enum { members, .. } => { + construct_any_value_common(value, None, Some(members.to_vec())) + } + _ => construct_any_value_common(value, None, None), } } @@ -33,23 +26,19 @@ pub fn resolve_any_value_spec(value: &AnyValueSpec) -> AnyValue { fn construct_any_value_common( value: &AnyValueSpec, resolved_fields: Option>, - allow_custom_values: Option, members: Option>, ) -> AnyValue { let common = value.common(); AnyValue { name: value.id(), - r#type: value.type_name(), - type_display: Some(value.to_string()), + r#type: value.to_string(), brief: value.brief(), note: value.note(), stability: common.stability.clone(), examples: common.examples.clone(), fields: resolved_fields, requirement_level: common.requirement_level.clone(), - deprecated: common.deprecated.clone(), - allow_custom_values, members, } } diff --git a/crates/weaver_semconv/data/event.yaml b/crates/weaver_semconv/data/event.yaml index d17481a8..244d5fa2 100644 --- a/crates/weaver_semconv/data/event.yaml +++ b/crates/weaver_semconv/data/event.yaml @@ -24,7 +24,6 @@ groups: brief: > This attribute represents the state the application has transitioned into at the occurrence of the event. type: enum - allow_custom_values: false members: - id: active value: 'active' @@ -58,7 +57,6 @@ groups: The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived. type: enum - allow_custom_values: false members: - id: created value: 'created' diff --git a/crates/weaver_semconv/data/expected/any_value.json b/crates/weaver_semconv/data/expected/any_value.json index 97479e72..8684091b 100644 --- a/crates/weaver_semconv/data/expected/any_value.json +++ b/crates/weaver_semconv/data/expected/any_value.json @@ -1 +1 @@ -{"body":{"type":"map","id":"id","brief":"brief","note":"note","requirement_level":"optional","fields":[{"type":"enum","id":"id_enum","brief":"brief","note":"note","requirement_level":"optional","allow_custom_values":true,"members":[{"id":"id","value":42,"brief":"brief","note":"note","stability":null,"deprecated":null}]},{"type":"map","id":"id_map","brief":"brief","note":"note","requirement_level":"optional","fields":[{"type":"int","id":"id_int","brief":"brief","note":"note","requirement_level":"required"},{"type":"bytes","id":"id_bytes","brief":"brief","note":"note","requirement_level":"required"},{"type":"string","id":"id_string","brief":"brief","note":"note","requirement_level":"optional"},{"type":"boolean","id":"id_bool","brief":"brief","note":"note","requirement_level":"optional"},{"type":"map","id":"id_nested_map","brief":"brief","note":"note","requirement_level":"optional","fields":[{"type":"int[]","id":"id_nested_int","brief":"brief","note":"note","requirement_level":"optional"},{"type":"double[]","id":"id_nested_bytes","brief":"brief","note":"note","requirement_level":"optional"},{"type":"string[]","id":"id_nested_string","brief":"brief","note":"note","requirement_level":"optional"},{"type":"boolean[]","id":"id_nested_bool","brief":"brief","note":"note","requirement_level":"optional"}]}]},{"type":"int","id":"id_int","brief":"brief","note":"note","requirement_level":"optional"},{"type":"bytes","id":"id_bytes","brief":"brief","note":"note","requirement_level":"optional"},{"type":"string","id":"id_string","brief":"brief","note":"note","requirement_level":"recommended"},{"type":"boolean","id":"id_bool","brief":"brief","note":"note","requirement_level":"optional"},{"type":"double","id":"id_double","brief":"brief","note":"note","requirement_level":"optional"},{"type":"double[]","id":"id_doubles","brief":"brief","note":"note","requirement_level":"optional"}]}} \ No newline at end of file +{"body":{"type":"map","id":"id","brief":"brief","note":"note","requirement_level":"optional","fields":[{"type":"enum","id":"id_enum","brief":"brief","note":"note","requirement_level":"optional","members":[{"id":"id","value":42,"brief":"brief","note":"note","stability":null,"deprecated":null}]},{"type":"map","id":"id_map","brief":"brief","note":"note","requirement_level":"optional","fields":[{"type":"int","id":"id_int","brief":"brief","note":"note","requirement_level":"required"},{"type":"bytes","id":"id_bytes","brief":"brief","note":"note","requirement_level":"required"},{"type":"string","id":"id_string","brief":"brief","note":"note","requirement_level":"optional"},{"type":"boolean","id":"id_bool","brief":"brief","note":"note","requirement_level":"optional"},{"type":"map","id":"id_nested_map","brief":"brief","note":"note","requirement_level":"optional","fields":[{"type":"int[]","id":"id_nested_int","brief":"brief","note":"note","requirement_level":"optional"},{"type":"double[]","id":"id_nested_bytes","brief":"brief","note":"note","requirement_level":"optional"},{"type":"string[]","id":"id_nested_string","brief":"brief","note":"note","requirement_level":"optional"},{"type":"boolean[]","id":"id_nested_bool","brief":"brief","note":"note","requirement_level":"optional"}]}]},{"type":"int","id":"id_int","brief":"brief","note":"note","requirement_level":"optional"},{"type":"bytes","id":"id_bytes","brief":"brief","note":"note","requirement_level":"optional"},{"type":"string","id":"id_string","brief":"brief","note":"note","requirement_level":"recommended"},{"type":"boolean","id":"id_bool","brief":"brief","note":"note","requirement_level":"optional"},{"type":"double","id":"id_double","brief":"brief","note":"note","requirement_level":"optional"},{"type":"double[]","id":"id_doubles","brief":"brief","note":"note","requirement_level":"optional"}]}} \ No newline at end of file diff --git a/crates/weaver_semconv/data/expected/any_value.yaml b/crates/weaver_semconv/data/expected/any_value.yaml index b3555d79..7e3ac6fc 100644 --- a/crates/weaver_semconv/data/expected/any_value.yaml +++ b/crates/weaver_semconv/data/expected/any_value.yaml @@ -10,7 +10,6 @@ body: brief: brief note: note requirement_level: optional - allow_custom_values: true members: - id: id value: 42 diff --git a/crates/weaver_semconv/src/any_value.rs b/crates/weaver_semconv/src/any_value.rs index 90e3d277..9f750265 100644 --- a/crates/weaver_semconv/src/any_value.rs +++ b/crates/weaver_semconv/src/any_value.rs @@ -106,10 +106,6 @@ pub enum AnyValueSpec { #[serde(flatten)] common: AnyValueCommonSpec, - /// Set to false to not accept values other than the specified members. - /// It defaults to true. - #[serde(default = "default_as_true")] - allow_custom_values: bool, /// List of enum entries. members: Vec, }, @@ -150,25 +146,13 @@ pub struct AnyValueCommonSpec { /// "conditionally_required", the string provided as MUST /// specify the conditions under which the field is required. pub requirement_level: RequirementLevel, - /// Specifies if the body field is deprecated. The string - /// provided as MUST specify why it's deprecated and/or what - /// to use instead. See also stability. - #[serde(skip_serializing_if = "Option::is_none")] - pub deprecated: Option, } -/// Implements a human readable display for AnyValueType, used to populate the type_display field. +/// Implements a human readable display for AnyValueType. impl Display for AnyValueSpec { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - AnyValueSpec::Map { fields, .. } => { - let entries = fields - .iter() - .map(|v| format!("{}", v)) - .collect::>() - .join(", "); - write!(f, "map<{}>{{ {} }}", self.id(), entries) - } + AnyValueSpec::Map { .. } => write!(f, "map"), AnyValueSpec::Boolean { .. } => write!(f, "boolean"), AnyValueSpec::Int { .. } => write!(f, "int"), AnyValueSpec::Double { .. } => write!(f, "double"), @@ -185,7 +169,7 @@ impl Display for AnyValueSpec { .map(|m| m.id.clone()) .collect::>() .join(", "); - write!(f, "enum<{}> {{{}}}", self.id(), entries) + write!(f, "enum {{{}}}", entries) } } } @@ -243,31 +227,6 @@ impl AnyValueSpec { let AnyValueCommonSpec { note, .. } = self.common(); note.clone() } - - /// Provides a string representation of the type of the value, with the id for - /// enum and map types. - #[must_use] - pub fn type_name(&self) -> String { - match self { - AnyValueSpec::Map { .. } => "map".to_owned(), - AnyValueSpec::Boolean { .. } => "boolean".to_owned(), - AnyValueSpec::Int { .. } => "int".to_owned(), - AnyValueSpec::Double { .. } => "double".to_owned(), - AnyValueSpec::String { .. } => "string".to_owned(), - AnyValueSpec::Strings { .. } => "string[]".to_owned(), - AnyValueSpec::Ints { .. } => "int[]".to_owned(), - AnyValueSpec::Doubles { .. } => "double[]".to_owned(), - AnyValueSpec::Booleans { .. } => "boolean[]".to_owned(), - AnyValueSpec::Bytes { .. } => "byte[]".to_owned(), - AnyValueSpec::Undefined { .. } => "undefined".to_owned(), - AnyValueSpec::Enum { .. } => "enum".to_owned(), - } - } -} - -/// Specifies the default value for allow_custom_values. -fn default_as_true() -> bool { - true } #[cfg(test)] @@ -279,7 +238,7 @@ mod tests { use super::*; #[test] - fn test_anyvalue_field_type_display() { + fn test_anyvalue_field_format_type() { #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] pub struct BodySpec { pub body: AnyValueSpec, @@ -293,7 +252,6 @@ mod tests { stability: None, examples: None, requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), - deprecated: None, }, fields: vec![ AnyValueSpec::Enum { @@ -306,9 +264,7 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, - allow_custom_values: true, members: vec![EnumEntriesSpec { id: "id".to_owned(), value: ValueSpec::Int(42), @@ -328,7 +284,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, fields: vec![ AnyValueSpec::Int { @@ -341,7 +296,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Required, ), - deprecated: None, }, }, AnyValueSpec::Bytes { @@ -354,7 +308,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Required, ), - deprecated: None, }, }, AnyValueSpec::String { @@ -367,7 +320,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, AnyValueSpec::Boolean { @@ -380,7 +332,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, AnyValueSpec::Map { @@ -393,7 +344,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, fields: vec![ AnyValueSpec::Ints { @@ -406,7 +356,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, AnyValueSpec::Doubles { @@ -419,7 +368,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, AnyValueSpec::Strings { @@ -432,7 +380,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, AnyValueSpec::Booleans { @@ -445,7 +392,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, ], @@ -462,7 +408,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, AnyValueSpec::Bytes { @@ -475,7 +420,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, AnyValueSpec::String { @@ -488,7 +432,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Recommended, ), - deprecated: None, }, }, AnyValueSpec::Boolean { @@ -501,7 +444,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, AnyValueSpec::Double { @@ -514,7 +456,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, AnyValueSpec::Doubles { @@ -527,7 +468,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional, ), - deprecated: None, }, }, ], @@ -537,6 +477,7 @@ mod tests { let expected_yaml = fs::read_to_string("data/expected/any_value.yaml") .unwrap() .replace("\r\n", "\n"); + assert_eq!( expected_yaml, format!("{}", serde_yaml::to_string(&body).unwrap()), @@ -554,15 +495,7 @@ mod tests { expected_json ); - assert_eq!(format!("{}", map.type_name()), "map",); - - assert_eq!( - format!( - "{}", - map - ), - "map{ enum {id}, map{ int, byte[], string, boolean, map{ int[], double[], string[], boolean[] } }, int, byte[], string, boolean, double, double[] }", - ); + assert_eq!(format!("{}", map), "map",); assert_eq!( format!( @@ -577,7 +510,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, } } ), @@ -596,7 +528,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, } } ), @@ -615,7 +546,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, } } ), @@ -634,7 +564,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, } } ), @@ -653,7 +582,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, } } ), @@ -672,7 +600,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, } } ), @@ -691,7 +618,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, } } ), @@ -710,7 +636,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, } } ), @@ -729,7 +654,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, } } ), @@ -748,7 +672,6 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, } } ), @@ -767,9 +690,7 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, }, - allow_custom_values: true, members: vec![EnumEntriesSpec { id: "id".to_owned(), value: ValueSpec::Int(42), @@ -779,9 +700,8 @@ mod tests { deprecated: None, }] } - .type_name() ), - "enum" + "enum {id}" ); assert_eq!( @@ -797,9 +717,7 @@ mod tests { requirement_level: RequirementLevel::Basic( BasicRequirementLevelSpec::Optional ), - deprecated: None, }, - allow_custom_values: true, members: vec![EnumEntriesSpec { id: "entry1".to_owned(), value: ValueSpec::Int(42), @@ -810,7 +728,7 @@ mod tests { }] } ), - "enum {entry1}" + "enum {entry1}" ); } } diff --git a/crates/weaver_semconv/src/attribute.rs b/crates/weaver_semconv/src/attribute.rs index 324cc8b3..05db77a4 100644 --- a/crates/weaver_semconv/src/attribute.rs +++ b/crates/weaver_semconv/src/attribute.rs @@ -4,6 +4,7 @@ //! Attribute specification. +use crate::any_value::AnyValueSpec; use crate::stability::Stability; use crate::Error; use ordered_float::OrderedFloat; @@ -490,6 +491,73 @@ impl Examples { ), } } + + /// Validation logic for the any_value. + pub(crate) fn validate_any_value( + &self, + any_value: &AnyValueSpec, + group_id: &str, + path_or_url: &str, + ) -> WResult<(), Error> { + match (self, any_value) { + (Examples::Bool(_), AnyValueSpec::Boolean { .. }) + | (Examples::Int(_), AnyValueSpec::Int { .. }) + | (Examples::Double(_), AnyValueSpec::Double { .. }) + | (Examples::String(_), AnyValueSpec::String { .. }) + | (Examples::String(_), AnyValueSpec::Map { .. }) + | (Examples::Ints(_), AnyValueSpec::Int { .. }) + | (Examples::Doubles(_), AnyValueSpec::Double { .. }) + | (Examples::Bools(_), AnyValueSpec::Boolean { .. }) + | (Examples::Strings(_), AnyValueSpec::String { .. }) + | (Examples::Strings(_), AnyValueSpec::Map { .. }) + | (Examples::ListOfInts(_), AnyValueSpec::Ints { .. }) + | (Examples::ListOfDoubles(_), AnyValueSpec::Doubles { .. }) + | (Examples::ListOfBools(_), AnyValueSpec::Booleans { .. }) + | (Examples::ListOfStrings(_), AnyValueSpec::Strings { .. }) + | (Examples::ListOfStrings(_), AnyValueSpec::Map { .. }) => WResult::Ok(()), + (_, AnyValueSpec::Enum { .. }) + | (_, AnyValueSpec::Bytes { .. }) + | (_, AnyValueSpec::Undefined { .. }) => { + // enum, bytes, and undefined types are open so it's not possible to validate the examples + WResult::Ok(()) + } + // Only if future mode is disabled, we allow to have examples following + // the conventions used in semconv 1.27.0 and earlier. + (Examples::Ints(_), AnyValueSpec::Ints { .. }) + | (Examples::Doubles(_), AnyValueSpec::Doubles { .. }) + | (Examples::Bools(_), AnyValueSpec::Booleans { .. }) + | (Examples::Strings(_), AnyValueSpec::Strings { .. }) => WResult::OkWithNFEs( + (), + vec![Error::InvalidAnyValueExampleError { + path_or_url: path_or_url.to_owned(), + group_id: group_id.to_owned(), + value_id: any_value.id(), + error: format!("All examples SHOULD be of type `{}`", any_value), + }], + ), + (_, AnyValueSpec::Map { .. }) => WResult::OkWithNFEs( + (), + vec![Error::InvalidAnyValueExampleError { + path_or_url: path_or_url.to_owned(), + group_id: group_id.to_owned(), + value_id: any_value.id(), + error: format!( + "Examples for `{}` values MUST be a supported string type", + any_value + ), + }], + ), + _ => WResult::OkWithNFEs( + (), + vec![Error::InvalidAnyValueExampleError { + path_or_url: path_or_url.to_owned(), + group_id: group_id.to_owned(), + value_id: any_value.id(), + error: format!("All examples MUST be of type `{}`", any_value), + }], + ), + } + } } /// The different requirement level specifications. diff --git a/crates/weaver_semconv/src/group.rs b/crates/weaver_semconv/src/group.rs index 8f870db6..ffe02fca 100644 --- a/crates/weaver_semconv/src/group.rs +++ b/crates/weaver_semconv/src/group.rs @@ -128,7 +128,8 @@ impl GroupSpec { error: "This group contains an event type with a body definition but the name is not set.".to_owned(), }); } - if self.name.is_none() && self.prefix.is_empty() { + if self.body.is_none() && self.name.is_none() && self.prefix.is_empty() { + // This is ONLY for backward compatibility of span based events. // Must have a name (whether explicit or via a prefix which will derive the name) errors.push(Error::InvalidGroup { path_or_url: path_or_url.to_owned(), @@ -136,6 +137,17 @@ impl GroupSpec { error: "This group contains an event type but the name is not set and no prefix is defined.".to_owned(), }); } + + match validate_any_value_examples( + &mut errors, + self.body.as_ref(), + &self.id, + path_or_url, + ) { + WResult::Ok(_) => {} + WResult::OkWithNFEs(_, errs) => errors.extend(errs), + WResult::FatalErr(err) => return WResult::FatalErr(err), + } } else if self.body.is_some() { // Make sure that body is only used for events errors.push(Error::InvalidGroup { @@ -244,6 +256,62 @@ impl GroupSpec { } } +fn validate_any_value_examples( + errors: &mut Vec, + any_value: Option<&AnyValueSpec>, + group_id: &str, + path_or_url: &str, +) -> WResult<(), Error> { + if let Some(value) = any_value { + let common_examples = &value.common().examples; + if let Some(examples) = common_examples { + match examples.validate_any_value(value, group_id, path_or_url) { + WResult::Ok(_) => {} + WResult::OkWithNFEs(_, errs) => errors.extend(errs), + WResult::FatalErr(err) => return WResult::FatalErr(err), + } + } else { + // No examples are set. + match value { + AnyValueSpec::String { .. } => { + // string values must have examples. + errors.push(Error::InvalidAnyValueExampleError { + path_or_url: path_or_url.to_owned(), + group_id: group_id.to_owned(), + value_id: value.id(), + error: "This value is a string but it does not contain any examples." + .to_owned(), + }); + } + AnyValueSpec::Strings { .. } => { + // string array attributes must have examples. + errors.push(Error::InvalidAnyValueExampleError { + path_or_url: path_or_url.to_owned(), + group_id: group_id.to_owned(), + value_id: value.id(), + error: "This value is a string array but it does not contain any examples." + .to_owned(), + }); + } + _ => {} + } + } + + // Recursively validate the examples for the fields. + if let AnyValueSpec::Map { fields, .. } = value { + for field in fields { + if let WResult::FatalErr(err) = + validate_any_value_examples(errors, Some(field), group_id, path_or_url) + { + return WResult::FatalErr(err); + } + } + } + } + + WResult::Ok(()) +} + /// The different types of groups (specification). #[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Clone, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -336,7 +404,8 @@ impl Display for InstrumentSpec { #[cfg(test)] mod tests { - use crate::attribute::Examples; + use crate::any_value::AnyValueCommonSpec; + use crate::attribute::{BasicRequirementLevelSpec, Examples, RequirementLevel}; use crate::Error::{CompoundError, InvalidExampleWarning, InvalidGroup, InvalidMetric}; use super::*; @@ -534,6 +603,183 @@ mod tests { ); } + #[test] + fn test_validate_event() { + let mut group = GroupSpec { + id: "test".to_owned(), + r#type: GroupType::Event, + name: Some("test_event".to_owned()), + brief: "test".to_owned(), + note: "test".to_owned(), + prefix: "test".to_owned(), + extends: None, + stability: Some(Stability::Deprecated), + deprecated: Some("true".to_owned()), + constraints: vec![], + span_kind: None, + events: vec![], + metric_name: None, + instrument: None, + unit: None, + display_name: None, + attributes: vec![], + body: Some(AnyValueSpec::String { + common: AnyValueCommonSpec { + id: "id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: Some(Examples::String("test".to_owned())), + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), + }, + }), + }; + assert!(group + .validate("") + .into_result_failing_non_fatal() + .is_ok()); + + // Examples are mandatory for string attributes. + group.body = Some(AnyValueSpec::String { + common: AnyValueCommonSpec { + id: "string_id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), + }, + }); + + let result = group.validate("").into_result_failing_non_fatal(); + assert_eq!( + Err(Error::InvalidAnyValueExampleError { + path_or_url: "".to_owned(), + group_id: "test".to_owned(), + value_id: "string_id".to_owned(), + error: "This value is a string but it does not contain any examples.".to_owned(), + },), + result + ); + + // Examples are mandatory for strings attributes. + group.body = Some(AnyValueSpec::Strings { + common: AnyValueCommonSpec { + id: "string_array_id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), + }, + }); + let result = group.validate("").into_result_failing_non_fatal(); + assert_eq!( + Err(Error::InvalidAnyValueExampleError { + path_or_url: "".to_owned(), + group_id: "test".to_owned(), + value_id: "string_array_id".to_owned(), + error: "This value is a string array but it does not contain any examples." + .to_owned(), + },), + result + ); + + // Examples are not required for Maps. + group.body = Some(AnyValueSpec::Map { + common: AnyValueCommonSpec { + id: "map_id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), + }, + fields: vec![AnyValueSpec::String { + common: AnyValueCommonSpec { + id: "string_id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: Some(Examples::String("test".to_owned())), + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), + }, + }], + }); + + assert!(group + .validate("") + .into_result_failing_non_fatal() + .is_ok()); + + // Examples are mandatory for string attributes even if nested + group.body = Some(AnyValueSpec::Map { + common: AnyValueCommonSpec { + id: "map_id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), + }, + fields: vec![AnyValueSpec::String { + common: AnyValueCommonSpec { + id: "nested_string_id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), + }, + }], + }); + + let result = group.validate("").into_result_failing_non_fatal(); + assert_eq!( + Err(Error::InvalidAnyValueExampleError { + path_or_url: "".to_owned(), + group_id: "test".to_owned(), + value_id: "nested_string_id".to_owned(), + error: "This value is a string but it does not contain any examples.".to_owned(), + },), + result + ); + + // Examples are mandatory for strings attributes even if nested + group.body = Some(AnyValueSpec::Map { + common: AnyValueCommonSpec { + id: "map_id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), + }, + fields: vec![AnyValueSpec::Strings { + common: AnyValueCommonSpec { + id: "nested_strings_id".to_owned(), + brief: "brief".to_owned(), + note: "note".to_owned(), + stability: None, + examples: None, + requirement_level: RequirementLevel::Basic(BasicRequirementLevelSpec::Optional), + }, + }], + }); + + let result = group.validate("").into_result_failing_non_fatal(); + assert_eq!( + Err(Error::InvalidAnyValueExampleError { + path_or_url: "".to_owned(), + group_id: "test".to_owned(), + value_id: "nested_strings_id".to_owned(), + error: "This value is a string array but it does not contain any examples." + .to_owned(), + },), + result + ); + } + #[test] fn test_instrumentation_spec() { assert_eq!(Counter.to_string(), "counter"); diff --git a/crates/weaver_semconv/src/lib.rs b/crates/weaver_semconv/src/lib.rs index 3f7a298e..e8c8b0ff 100644 --- a/crates/weaver_semconv/src/lib.rs +++ b/crates/weaver_semconv/src/lib.rs @@ -129,6 +129,20 @@ pub enum Error { error: String, }, + /// This indicates that a semantic convention asset contains an invalid example. + #[error("The value `{value_id}` in the group `{group_id}` contains an invalid example. {error}.\nProvenance: {path_or_url:?}")] + #[diagnostic(severity(Error))] + InvalidAnyValueExampleError { + /// The path or URL of the semantic convention asset. + path_or_url: String, + /// The group id of the attribute. + group_id: String, + /// The id of the any_value + value_id: String, + /// The reason of the error. + error: String, + }, + /// A container for multiple errors. #[error("{:?}", format_errors(.0))] CompoundError(#[related] Vec), diff --git a/schemas/semconv-syntax.md b/schemas/semconv-syntax.md index 221f35f2..878dc813 100644 --- a/schemas/semconv-syntax.md +++ b/schemas/semconv-syntax.md @@ -15,12 +15,11 @@ Then, the semantic of each field is described. - [Semantic Convention](#semantic-convention) - [Span semantic convention](#span-semantic-convention) - [Event semantic convention](#event-semantic-convention) - - [Event Body semantic convention](#event-body-semantic-convention) - - [Event Body Field semantic convention](#event-body-field-semantic-convention) - [Event semantic convention example](#event-semantic-convention-example) - [Metric Group semantic convention](#metric-group-semantic-convention) - [Metric semantic convention](#metric-semantic-convention) - [Attribute group semantic convention](#attribute-group-semantic-convention) + - [Any Value semantic convention](#any-value-semantic-convention) - [Attributes](#attributes) - [Examples (for examples)](#examples-for-examples) - [Ref](#ref) @@ -108,12 +107,24 @@ spanfields ::= [events] [span_kind] eventfields ::= name [body] -body ::= body_type [brief] [examples] [stability] [note] [body_fields] +body ::= any_value -body_type ::= "map" +any_value_type ::= "map" | "string" + | "int" + | "double" + | "boolean" + | "string[]" + | "int[]" + | "double[]" + | "boolean[]" + | "byte[]" + | "enum" + | "undefined" -body_fields ::= id type brief [examples] stability [deprecated] [requirement_level] [note] +any_value ::= id any_value_type brief [examples] stability [deprecated] requirement_level [note] [fields] [members] + +fields ::= any_value {any_value} span_kind ::= "client" | "server" @@ -170,45 +181,9 @@ The following is only valid if `type` is `span` (the default): The following is only valid if `type` is `event`: - `name`, required, string. The name of the event. -- `body`, optional, object. Describes the body of the event. - -#### Event Body semantic convention - -The following is only valid if `type` is `event` and `body` is present: - -- `fields`, required, list of fields that describe the event body. - -#### Event Body Field semantic convention - -The following is only valid if `type` is `event` and `body` is present and `fields` is present: +- `body`, optional, [`any value`](#any-value-semantic-convention). Describes the body of the event as an any_value type. -- `id`, required, string. The name of the field. -- `type`, either a string literal denoting the type as a primitive or an array type, a template type or an enum definition (See later). Required. - The accepted string literals are: - * _primitive and array types as string literals:_ - * `"string"`: String attributes. - * `"int"`: Integer attributes. - * `"double"`: Double attributes. - * `"boolean"`: Boolean attributes. - * `"string[]"`: Array of strings attributes. - * `"int[]"`: Array of integer attributes. - * `"double[]"`: Array of double attributes. - * `"boolean[]"`: Array of boolean attributes. - * _template type as string literal:_ `"template[]"` (See [below](#template-type)) - See the [specification of Attributes](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/common/README.md#attribute) for the definition of the value types. -- `stability`, required, enum. The stability of the field. -- `requirement_level`, optional. Specifies if the field is mandatory. - Can be "required", "conditionally_required", "recommended" or "opt_in". When omitted, the field is "recommended". - When set to "conditionally_required", the string provided as `` MUST specify - the conditions under which the field is required. -- `brief`, `note`, `deprecated`, same meaning as for the whole - [semantic convention](#semantic-convention), but per field. -- `examples`, sequence of example values for the field or single example value. - They are required only for string and string array fields. - Example values must be of the same type of the field. - If only a single example is provided, it can directly be reported without encapsulating it into a sequence/dictionary. See [below](#examples-for-examples). - -#### Event semantic convention example +##### Event semantic convention example ```yaml - id: event.some_event @@ -216,28 +191,58 @@ The following is only valid if `type` is `event` and `body` is present and `fiel type: event brief: "Describes the event." stability: experimental - attributes: # Optional + attributes: # Optional - ref: registry.attribute.id - - ref: registry.some_other.attribute.id # Reference to an existing global attribute - body: # Optional + - ref: registry.some_other.attribute.id # Reference to an existing global attribute + body: # Optional, follows the any_value conventions + id: event_body.some_event.fields type: map - fields: + requirement_level: required + fields: # Unique to this event definition only - id: method type: string stability: experimental brief: "The HTTP method used in the request." examples: ['GET', 'POST'] + requirement_level: required - id: url type: string stability: experimental brief: "The URL of the request." examples: ['http://example.com'] + requirement_level: required - id: status_code type: int stability: experimental brief: "The status code of the response." examples: [200, 404] - ``` + requirement_level: required + - id: nested_map + type: map + stability: experimental + requirement_level: required + fields: + - id: nested_field + type: string # May be any supported any_value type + stability: experimental + requirement_level: required + brief: "A nested field." + examples: ['nested_value'] + - id: nested_enum_state + type: enum + stability: experimental + requirement_level: required + members: + - id: active + value: 'active' + brief: The state became active. + - id: inactive + value: 'inactive' + brief: The state became inactive. + - id: background + value: 'background' + brief: The state is now in the background. +``` #### Metric Group semantic convention @@ -265,6 +270,40 @@ Attribute group (`attribute_group` type) defines a set of attributes that can be declared once and referenced by semantic conventions for different signals, for example spans and logs. Attribute groups don't have any specific fields and follow the general `semconv` semantics. +#### Any Value semantic convention + +Describes the type of the value of an extended (log) attribute or the body of an event. + +- `id`, required, string. The name of the field / any value. +- `type`, either a string literal denoting the type as a primitive or an array type, [an enum definition](#enumeration) or a map of fields. Required. + The accepted string literals are: + * `"string"`: String value. + * `"int"`: Integer value. + * `"double"`: Double value. + * `"boolean"`: Boolean value. + * `"string[]"`: Array of strings value. + * `"int[]"`: Array of integer value. + * `"double[]"`: Array of double value. + * `"boolean[]"`: Array of boolean value. + * `"byte[]"`: Array of bytes value. + * `"map"`: Map of any_value types. + * The `fields` field is required and contains a list of any_value entries that describe each field of the map. + * `"enum"`: Enumerated value. + * The `members` field is required and contains a list of enum entries. + * `"undefined"`: The actually format of the value is not defined. +- `brief`, `note`, `deprecated`, `stability`, same meaning as for the whole + [semantic convention](#semantic-convention), but per field. +- `requirement_level`, required. Specifies if the field is mandatory. + Can be "required", "conditionally_required", "recommended" or "opt_in". When omitted, the field is "recommended". + When set to "conditionally_required", the string provided as `` MUST specify + the conditions under which the field is required. +- `examples`, sequence of example values for the field or single example value. + They are required only for string and string array fields. + Example values must be of the same type of the field or for a map of fields, the type can be of a string type. + If only a single example is provided, it can directly be reported without encapsulating it into a sequence/dictionary. See [below](#examples-for-examples). +- `fields`, required only when the type is `map`, list of any value entries that describe each field of the map. +- `members`, required only when the type is `enum`, list of enum entries. See [below](#enumeration). + ### Attributes An attribute is defined by: @@ -435,3 +474,4 @@ An enum entry has the following fields: - `note`, optional string, longer description. It defaults to an empty string. - `stability`, required stability level. Attributes marked as experimental cannot have stable members. - `deprecated`, optional string, similarly to semantic convention and attribute deprecation, marks specific member as deprecated. + diff --git a/schemas/semconv.schema.json b/schemas/semconv.schema.json index 819ce020..65c7ecd6 100644 --- a/schemas/semconv.schema.json +++ b/schemas/semconv.schema.json @@ -152,7 +152,7 @@ "description": "The name of the event." }, "body": { - "$ref": "#/$defs/BodySemanticConvention" + "$ref": "#/$defs/AnyValueSemanticConvention" } }, "anyOf": [ @@ -163,59 +163,12 @@ } ] }, - "BodySemanticConvention": { + "AnyValueSemanticConvention": { "type": "object", "required": [ - "type" - ], - "properties": { - "type": { - "$ref": "#/$defs/BodyType" - }, - "brief": { - "type": "string", - "description": "a brief description of the field." - }, - "note": { - "type": "string", - "description": "a more elaborate description of the field. It defaults to an empty string." - }, - "stability": { - "allOf": [ - { - "$ref": "#/$defs/StabilityLevel" - } - ] - }, - "examples": { - "anyOf": [ - { - "$ref": "#/$defs/ValueType" - }, - { - "type": "array", - "items": { - "$ref": "#/$defs/ValueType" - } - } - ], - "description": "sequence/dictionary of example values for the field. They are optional for boolean, int, double, and enum attributes. Example values must be of the same type of the field. If only a single example is provided, it can directly be reported without encapsulating it into a sequence/dictionary." - }, - "fields": { - "type": "array", - "items": { - "$ref": "#/$defs/BodyFieldSemanticContention" - } - } - } - }, - "BodyFieldSemanticContention": { - "type": "object", - "required": [ - "id", "type", - "brief", - "stability" + "id", + "requirement_level" ], "properties": { "id": { @@ -223,19 +176,15 @@ "description": "unique string" }, "type": { - "$ref": "#/$defs/AttributeType" + "$ref": "#/$defs/AnyValueType" }, "brief": { "type": "string", - "description": "a brief description of the field." + "description": "a brief description of the value." }, "note": { "type": "string", - "description": "a more elaborate description of the field. It defaults to an empty string." - }, - "deprecated": { - "type": "string", - "description": "specifies if the field is deprecated. The string provided as MUST specify why it's deprecated and/or what to use instead." + "description": "a more elaborate description of the value. It defaults to an empty string." }, "stability": { "allOf": [ @@ -245,7 +194,7 @@ ] }, "requirement_level": { - "description": "specifies the field requirement level. Can be 'required', 'conditionally_required', 'recommended', or 'opt_in'. When omitted, the field is 'recommended'. When set to 'conditionally_required', the string provided MUST specify the conditions under which the field is required.", + "description": "specifies the any value requirement level. Can be 'required', 'conditionally_required', 'recommended', or 'opt_in'. When omitted, the value is 'recommended'. When set to 'conditionally_required', the string provided MUST specify the conditions under which the value is required.", "oneOf": [ { "const": "required" @@ -298,7 +247,63 @@ } } ], - "description": "sequence/dictionary of example values for the field. They are optional for boolean, int, double, and enum attributes. Example values must be of the same type of the field. If only a single example is provided, it can directly be reported without encapsulating it into a sequence/dictionary." + "description": "sequence/dictionary of example values. They are optional for boolean, int, double, and enum attributes. Example values must be of the same type as the value. If only a single example is provided, it can directly be reported without encapsulating it into a sequence/dictionary." + }, + "deprecated": { + "type": "string", + "description": "specifies if the value is deprecated. The string provided as MUST specify why it's deprecated and/or what to use instead." + }, + "fields": { + "type": "array", + "description": "when the type is map, this identifies the child (nested) any values associated with the map.", + "items": { + "$ref": "#/$defs/AnyValueSemanticConvention" + } + }, + "members": { + "type": "array", + "description": "when the type is enum, this identifies the enum members.", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "value", + "stability" + ], + "properties": { + "id": { + "type": "string", + "description": "string unique" + }, + "value": { + "type": [ + "string", + "number" + ], + "description": "string or number, value of the enum entry." + }, + "brief": { + "type": "string", + "description": "brief description of the enum entry value. It defaults to the value of ID." + }, + "note": { + "type": "string", + "description": "longer description. It defaults to an empty string." + }, + "deprecated": { + "type": "string", + "description": "specifies if the attribute is deprecated. The string provided as MUST specify why it's deprecated and/or what to use instead." + }, + "stability": { + "allOf": [ + { + "$ref": "#/$defs/StabilityLevel" + } + ] + } + } + } } } }, @@ -589,14 +594,24 @@ } ] }, - "BodyType": { - "description": "specifies the supported body types.", + "AnyValueType": { + "description": "specifies the supported any value types.", "oneOf": [ { "type": "string", "enum": [ "string", - "map" + "int", + "double", + "boolean", + "string[]", + "int[]", + "double[]", + "boolean[]", + "map", + "byte[]", + "enum", + "undefined" ], "description": "literal denoting the type" } From 15ee5fba7afad382bd464c72d9769c45c0663551 Mon Sep 17 00:00:00 2001 From: Nev Wylie <54870357+MSNev@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:04:20 -0700 Subject: [PATCH 7/8] remove resolved and resolver `any_value.rs` just use AnyValueSpec in resolved schema - simplify validate_any_value_examples - Reduce the test yaml events to smaller set - Removed observed file --- .../semconv_jq_fn/semconv_events.json | 2 +- crates/weaver_forge/src/registry.rs | 4 +- .../weaver_resolved_schema/src/any_value.rs | 57 - crates/weaver_resolved_schema/src/lib.rs | 1 - crates/weaver_resolved_schema/src/registry.rs | 4 +- crates/weaver_resolved_schema/src/signal.rs | 4 +- .../expected-attribute-catalog.json | 1868 +---------------- .../expected-registry.json | 1627 ++------------ .../observed-events.json | 219 -- .../registry/browser-event.yaml | 71 - .../registry/client-exception-event.yaml | 46 - .../registry/log-event.yaml | 7 - .../registry/log-events.yaml | 248 +++ .../registry/log-feature_flag.yaml | 11 - .../registry/mobile-events.yaml | 75 - .../registry/ping-event.yaml | 5 - .../registry/referenced-attributes.yaml | 58 +- .../registry/referenced-client.yaml | 28 - .../registry/referenced-exception.yaml | 55 - .../registry/referenced-gen_ai.yaml | 148 -- .../registry/referenced-network.yaml | 235 --- .../registry/referenced-rpc.yaml | 265 --- .../registry/referenced-server.yaml | 28 - .../registry/stringbody-event.yaml | 35 - ...ce-feature-flag.yaml => trace-events.yaml} | 42 +- .../registry/trace-exception.yaml | 16 - .../registry/trace-gen-ai.yaml | 73 - .../registry/trace-rpc.yaml | 131 -- crates/weaver_resolver/src/any_value.rs | 44 - crates/weaver_resolver/src/lib.rs | 1 - crates/weaver_resolver/src/registry.rs | 3 +- crates/weaver_semconv/src/group.rs | 28 +- 32 files changed, 602 insertions(+), 4837 deletions(-) delete mode 100644 crates/weaver_resolved_schema/src/any_value.rs delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/observed-events.json delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/log-event.yaml create mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/log-events.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/log-feature_flag.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/ping-event.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-client.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-exception.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-gen_ai.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-network.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-rpc.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/referenced-server.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml rename crates/weaver_resolver/data/registry-test-4-events/registry/{trace-feature-flag.yaml => trace-events.yaml} (51%) delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/trace-exception.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/trace-gen-ai.yaml delete mode 100644 crates/weaver_resolver/data/registry-test-4-events/registry/trace-rpc.yaml delete mode 100644 crates/weaver_resolver/src/any_value.rs diff --git a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json index debdb697..190149d8 100644 --- a/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json +++ b/crates/weaver_forge/expected_output/semconv_jq_fn/semconv_events.json @@ -1 +1 @@ -[{"attributes":[],"body":{"fields":[{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","members":[{"brief":"The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n","deprecated":null,"id":"active","note":null,"stability":null,"value":"active"},{"brief":"The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n","deprecated":null,"id":"inactive","note":null,"stability":null,"value":"inactive"},{"brief":"The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"brief":"The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"},{"brief":"The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n","deprecated":null,"id":"terminate","note":null,"stability":null,"value":"terminate"}],"name":"ios.state","note":"The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `ios`"},"stability":"experimental","type":"enum {active, inactive, background, foreground, terminate}"},{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","members":[{"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.\n","deprecated":null,"id":"created","note":null,"stability":null,"value":"created"},{"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.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"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.","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"}],"name":"android.state","note":"The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `android`"},"stability":"experimental","type":"enum {created, background, foreground}"}],"name":"device.app.lifecycle.fields","requirement_level":"required","type":"map"},"brief":"This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n","event_namespace":"device.app","events":[],"id":"device.app.lifecycle","instrument":null,"lineage":{"source_file":"data/mobile-events.yaml"},"metric_name":null,"name":"device.app.lifecycle","note":"This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n","span_kind":null,"stability":"experimental","type":"event","unit":null},{"attributes":[{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","stability":"stable","type":"string"},{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","stability":"stable","type":"boolean"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":{"conditionally_required":"Required if `exception.message` is not set, recommended otherwise."},"stability":"stable","type":"string"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":{"conditionally_required":"Required if `exception.type` is not set, recommended otherwise."},"stability":"stable","type":"string"}],"brief":"This document defines the attributes used to report a single exception associated with a span.\n","event_namespace":"other","events":[],"id":"trace-exception","instrument":null,"lineage":{"attributes":{"exception.escaped":{"inherited_fields":["brief","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.message":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"},"exception.stacktrace":{"inherited_fields":["brief","examples","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.type":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"}},"source_file":"data/trace-exception.yaml"},"metric_name":null,"name":null,"prefix":"exception","span_kind":null,"type":"event","unit":null}] \ No newline at end of file +[{"attributes":[],"body":{"fields":[{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","id":"ios.state","members":[{"brief":"The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n","deprecated":null,"id":"active","note":null,"stability":null,"value":"active"},{"brief":"The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n","deprecated":null,"id":"inactive","note":null,"stability":null,"value":"inactive"},{"brief":"The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"brief":"The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"},{"brief":"The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n","deprecated":null,"id":"terminate","note":null,"stability":null,"value":"terminate"}],"note":"The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `ios`"},"stability":"experimental","type":"enum"},{"brief":"This attribute represents the state the application has transitioned into at the occurrence of the event.\n","id":"android.state","members":[{"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.\n","deprecated":null,"id":"created","note":null,"stability":null,"value":"created"},{"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.\n","deprecated":null,"id":"background","note":null,"stability":null,"value":"background"},{"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.","deprecated":null,"id":"foreground","note":null,"stability":null,"value":"foreground"}],"note":"The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n","requirement_level":{"conditionally_required":"if and only if `os.name` is `android`"},"stability":"experimental","type":"enum"}],"id":"device.app.lifecycle.fields","requirement_level":"required","type":"map"},"brief":"This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n","event_namespace":"device.app","events":[],"id":"device.app.lifecycle","instrument":null,"lineage":{"source_file":"data/mobile-events.yaml"},"metric_name":null,"name":"device.app.lifecycle","note":"This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n","span_kind":null,"stability":"experimental","type":"event","unit":null},{"attributes":[{"brief":"A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n","examples":"Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)","name":"exception.stacktrace","requirement_level":"recommended","stability":"stable","type":"string"},{"brief":"SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n","name":"exception.escaped","note":"An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager\u0027s `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.","requirement_level":"recommended","stability":"stable","type":"boolean"},{"brief":"The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n","examples":["java.net.ConnectException","OSError"],"name":"exception.type","requirement_level":{"conditionally_required":"Required if `exception.message` is not set, recommended otherwise."},"stability":"stable","type":"string"},{"brief":"The exception message.","examples":["Division by zero","Can\u0027t convert \u0027int\u0027 object to str implicitly"],"name":"exception.message","requirement_level":{"conditionally_required":"Required if `exception.type` is not set, recommended otherwise."},"stability":"stable","type":"string"}],"brief":"This document defines the attributes used to report a single exception associated with a span.\n","event_namespace":"other","events":[],"id":"trace-exception","instrument":null,"lineage":{"attributes":{"exception.escaped":{"inherited_fields":["brief","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.message":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"},"exception.stacktrace":{"inherited_fields":["brief","examples","note","requirement_level","stability"],"source_group":"registry.exception"},"exception.type":{"inherited_fields":["brief","examples","note","stability"],"locally_overridden_fields":["requirement_level"],"source_group":"registry.exception"}},"source_file":"data/trace-exception.yaml"},"metric_name":null,"name":null,"prefix":"exception","span_kind":null,"type":"event","unit":null}] \ No newline at end of file diff --git a/crates/weaver_forge/src/registry.rs b/crates/weaver_forge/src/registry.rs index 9ca549a1..5d46ecd7 100644 --- a/crates/weaver_forge/src/registry.rs +++ b/crates/weaver_forge/src/registry.rs @@ -7,11 +7,11 @@ use crate::error::Error; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use weaver_resolved_schema::any_value::AnyValue; use weaver_resolved_schema::attribute::Attribute; use weaver_resolved_schema::catalog::Catalog; use weaver_resolved_schema::lineage::GroupLineage; use weaver_resolved_schema::registry::{Constraint, Group, Registry}; +use weaver_semconv::any_value::AnyValueSpec; use weaver_semconv::group::{GroupType, InstrumentSpec, SpanKindSpec}; use weaver_semconv::stability::Stability; @@ -107,7 +107,7 @@ pub struct ResolvedGroup { pub display_name: Option, /// The body specification used for event semantic conventions. #[serde(skip_serializing_if = "Option::is_none")] - pub body: Option, + pub body: Option, } impl ResolvedGroup { diff --git a/crates/weaver_resolved_schema/src/any_value.rs b/crates/weaver_resolved_schema/src/any_value.rs deleted file mode 100644 index e995577e..00000000 --- a/crates/weaver_resolved_schema/src/any_value.rs +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -#![allow(rustdoc::invalid_html_tags)] - -//! Specification of a resolved `AnyValue`. - -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use weaver_semconv::attribute::{EnumEntriesSpec, Examples, RequirementLevel}; -use weaver_semconv::stability::Stability; - -/// An `AnyValue` definition. -#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, JsonSchema)] -#[serde(deny_unknown_fields)] -pub struct AnyValue { - /// AnyValue name. - pub name: String, - /// Either a string literal denoting the type as a primitive or an - /// array type, a template type or an enum definition. - pub r#type: String, - /// A brief description of the AnyValue. - #[serde(skip_serializing_if = "String::is_empty")] - #[serde(default)] - pub brief: String, - /// Sequence of example values for the AnyValue or single example - /// value. They are required only for primitive and primitive array - /// values. Example values must be of the same type of the type. - /// If only a single example is provided, it can directly be reported - /// without encapsulating it into a sequence/dictionary. - #[serde(skip_serializing_if = "Option::is_none")] - pub examples: Option, - /// Specifies if the value is mandatory. Can be "required", - /// "conditionally_required", "recommended" or "opt_in". When omitted, - /// the value is "recommended". When set to - /// "conditionally_required", the string provided as MUST - /// specify the conditions under which the value is required. - pub requirement_level: RequirementLevel, - /// A more elaborate description of the any value. - /// It defaults to an empty string. - #[serde(skip_serializing_if = "String::is_empty")] - #[serde(default)] - pub note: String, - /// Specifies the stability of the any value. - /// Note that, if stability is missing but deprecated is present, it will - /// automatically set the stability to deprecated. If deprecated is - /// present and stability differs from deprecated, this will result in an - /// error. - #[serde(skip_serializing_if = "Option::is_none")] - pub stability: Option, - /// Identifies the definition of the "fields" of the value when the type is "map". - #[serde(skip_serializing_if = "Option::is_none")] - pub fields: Option>, - /// Used when the type is "enum". - /// List of enum entries. - #[serde(skip_serializing_if = "Option::is_none")] - pub members: Option>, -} diff --git a/crates/weaver_resolved_schema/src/lib.rs b/crates/weaver_resolved_schema/src/lib.rs index 1a0dd865..f7e1793c 100644 --- a/crates/weaver_resolved_schema/src/lib.rs +++ b/crates/weaver_resolved_schema/src/lib.rs @@ -13,7 +13,6 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use weaver_version::Versions; -pub mod any_value; pub mod attribute; pub mod catalog; pub mod error; diff --git a/crates/weaver_resolved_schema/src/registry.rs b/crates/weaver_resolved_schema/src/registry.rs index aa3b7da0..e0d07ef3 100644 --- a/crates/weaver_resolved_schema/src/registry.rs +++ b/crates/weaver_resolved_schema/src/registry.rs @@ -6,13 +6,13 @@ use schemars::JsonSchema; use std::collections::{BTreeMap, HashMap, HashSet}; +use weaver_semconv::any_value::AnyValueSpec; use serde::{Deserialize, Serialize}; use weaver_semconv::group::{GroupType, InstrumentSpec, SpanKindSpec}; use weaver_semconv::stability::Stability; -use crate::any_value::AnyValue; use crate::attribute::{Attribute, AttributeRef}; use crate::catalog::Catalog; use crate::error::{handle_errors, Error}; @@ -130,7 +130,7 @@ pub struct Group { /// The body of the event. /// This fields is only used for event groups. #[serde(skip_serializing_if = "Option::is_none")] - pub body: Option, + pub body: Option, } /// Common statistics for a group. diff --git a/crates/weaver_resolved_schema/src/signal.rs b/crates/weaver_resolved_schema/src/signal.rs index 0f5d3f26..22a39adf 100644 --- a/crates/weaver_resolved_schema/src/signal.rs +++ b/crates/weaver_resolved_schema/src/signal.rs @@ -4,8 +4,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use weaver_semconv::any_value::AnyValueSpec; -use crate::any_value::AnyValue; use crate::attribute::AttributeRef; use crate::metric::MetricRef; use crate::tags::Tags; @@ -64,7 +64,7 @@ pub struct Event { tags: Option, /// The body of the event, not used for Span events. #[serde(skip_serializing_if = "Option::is_none")] - body: Option, + body: Option, } /// A span signal. diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json b/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json index 1050f62e..0454de50 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-attribute-catalog.json @@ -1,4 +1,13 @@ [ + { + "name": "client.name", + "type": "string", + "brief": "The name of the client that reported the exception.\n", + "examples": [ + "myclient" + ], + "requirement_level": "recommended" + }, { "name": "browser.brands", "type": "string[]", @@ -49,16 +58,7 @@ "note": "This value is intended to be taken from the Navigator API `navigator.language`.\n" }, { - "name": "client.name", - "type": "string", - "brief": "The name of the client that reported the exception.\n", - "examples": [ - "myclient" - ], - "requirement_level": "recommended" - }, - { - "name": "browser.platform", + "name": "test_attr.platform", "type": "string", "brief": "The browser platform", "examples": [ @@ -71,7 +71,7 @@ "stability": "stable" }, { - "name": "http.url", + "name": "test_attr.http.url", "type": "string", "brief": "The Url", "examples": [ @@ -82,7 +82,7 @@ "stability": "stable" }, { - "name": "log.event.attr", + "name": "test_attr.event.attr", "type": "string", "brief": "Just making sure the referenced attributes are defined", "examples": "some value", @@ -91,7 +91,7 @@ "stability": "stable" }, { - "name": "session.id", + "name": "test_attr.session.id", "type": "string", "brief": "The session id", "examples": "127836abcdef98", @@ -102,14 +102,14 @@ { "name": "client.address", "type": "string", - "brief": "Client address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name.", + "brief": "Test Client address ....", "examples": [ "client.example.com", "10.1.2.80", "/tmp/my.sock" ], "requirement_level": "recommended", - "note": "When observed from the server side, and when communicating through an intermediary, `client.address` SHOULD represent the client address behind any intermediaries, for example proxies, if it's available.\n", + "note": "Test client address note\n", "stability": "stable" }, { @@ -120,13 +120,13 @@ 65123 ], "requirement_level": "recommended", - "note": "When observed from the server side, and when communicating through an intermediary, `client.port` SHOULD represent the client port behind any intermediaries, for example proxies, if it's available.\n", + "note": "Test client port", "stability": "stable" }, { "name": "exception.type", "type": "string", - "brief": "The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n", + "brief": "The type of the exception (its fully-qualified class name, if applicable).\n", "examples": [ "java.net.ConnectException", "OSError" @@ -148,8 +148,8 @@ { "name": "exception.stacktrace", "type": "string", - "brief": "A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n", - "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)", + "brief": ".", + "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n", "requirement_level": "recommended", "stability": "stable" }, @@ -158,1233 +158,12 @@ "type": "boolean", "brief": "SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n", "requirement_level": "recommended", - "note": "An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager's `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.", - "stability": "stable" - }, - { - "name": "gen_ai.system", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "openai", - "value": "openai", - "brief": "OpenAI", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "vertex_ai", - "value": "vertex_ai", - "brief": "Vertex AI", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "anthropic", - "value": "anthropic", - "brief": "Anthropic", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "cohere", - "value": "cohere", - "brief": "Cohere", - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The Generative AI product as identified by the client or server instrumentation.", - "examples": "openai", - "requirement_level": "recommended", - "note": "The `gen_ai.system` describes a family of GenAI models with specific model identified\nby `gen_ai.request.model` and `gen_ai.response.model` attributes.\n\nThe actual GenAI product may differ from the one identified by the client.\nFor example, when using OpenAI client libraries to communicate with Mistral, the `gen_ai.system`\nis set to `openai` based on the instrumentation's best knowledge.\n\nFor custom model, a custom friendly name SHOULD be used.\nIf none of these options apply, the `gen_ai.system` SHOULD be set to `_OTHER`.\n", - "stability": "experimental" - }, - { - "name": "gen_ai.request.model", - "type": "string", - "brief": "The name of the GenAI model a request is being made to.", - "examples": "gpt-4", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.request.max_tokens", - "type": "int", - "brief": "The maximum number of tokens the model generates for a request.", - "examples": [ - 100 - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.request.temperature", - "type": "double", - "brief": "The temperature setting for the GenAI request.", - "examples": [ - 0.0 - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.request.top_p", - "type": "double", - "brief": "The top_p sampling setting for the GenAI request.", - "examples": [ - 1.0 - ], - "tag": "llm-generic-request", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.request.top_k", - "type": "double", - "brief": "The top_k sampling setting for the GenAI request.", - "examples": [ - 1.0 - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.request.stop_sequences", - "type": "string[]", - "brief": "List of sequences that the model will use to stop generating further tokens.", - "examples": [ - [ - "forest", - "lived" - ] - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.request.frequency_penalty", - "type": "double", - "brief": "The frequency penalty setting for the GenAI request.", - "examples": [ - 0.1 - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.request.presence_penalty", - "type": "double", - "brief": "The presence penalty setting for the GenAI request.", - "examples": [ - 0.1 - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.response.id", - "type": "string", - "brief": "The unique identifier for the completion.", - "examples": [ - "chatcmpl-123" - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.response.model", - "type": "string", - "brief": "The name of the model that generated the response.", - "examples": [ - "gpt-4-0613" - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.response.finish_reasons", - "type": "string[]", - "brief": "Array of reasons the model stopped generating tokens, corresponding to each generation received.", - "examples": [ - [ - "stop" - ] - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.usage.input_tokens", - "type": "int", - "brief": "The number of tokens used in the GenAI input (prompt).", - "examples": [ - 100 - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.usage.output_tokens", - "type": "int", - "brief": "The number of tokens used in the GenAI response (completion).", - "examples": [ - 180 - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.token.type", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "input", - "value": "input", - "brief": "Input tokens (prompt, input, etc.)", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "completion", - "value": "output", - "brief": "Output tokens (completion, response, etc.)", - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The type of token being counted.", - "examples": [ - "input", - "output" - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "gen_ai.prompt", - "type": "string", - "brief": "The full prompt sent to the GenAI model.", - "examples": [ - "[{'role': 'user', 'content': 'What is the capital of France?'}]" - ], - "requirement_level": "recommended", - "note": "It's RECOMMENDED to format prompts as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation)", - "stability": "experimental" - }, - { - "name": "gen_ai.completion", - "type": "string", - "brief": "The full response received from the GenAI model.", - "examples": [ - "[{'role': 'assistant', 'content': 'The capital of France is Paris.'}]" - ], - "requirement_level": "recommended", - "note": "It's RECOMMENDED to format completions as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation)", - "stability": "experimental" - }, - { - "name": "gen_ai.operation.name", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "chat", - "value": "chat", - "brief": "Chat completion operation such as [OpenAI Chat API](https://platform.openai.com/docs/api-reference/chat)", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "text_completion", - "value": "text_completion", - "brief": "Text completions operation such as [OpenAI Completions API (Legacy)](https://platform.openai.com/docs/api-reference/completions)", - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The name of the operation being performed.", - "requirement_level": "recommended", - "note": "If one of the predefined values applies, but specific system uses a different name it's RECOMMENDED to document it in the semantic conventions for specific GenAI system and use system-specific name in the instrumentation. If a different name is not documented, instrumentation libraries SHOULD use applicable predefined value.\n", - "stability": "experimental" - }, - { - "name": "network.carrier.icc", - "type": "string", - "brief": "The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network.", - "examples": "DE", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "network.carrier.mcc", - "type": "string", - "brief": "The mobile carrier country code.", - "examples": "310", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "network.carrier.mnc", - "type": "string", - "brief": "The mobile carrier network code.", - "examples": "001", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "network.carrier.name", - "type": "string", - "brief": "The name of the mobile carrier.", - "examples": "sprint", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "network.connection.subtype", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "gprs", - "value": "gprs", - "brief": "GPRS", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "edge", - "value": "edge", - "brief": "EDGE", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "umts", - "value": "umts", - "brief": "UMTS", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "cdma", - "value": "cdma", - "brief": "CDMA", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "evdo_0", - "value": "evdo_0", - "brief": "EVDO Rel. 0", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "evdo_a", - "value": "evdo_a", - "brief": "EVDO Rev. A", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "cdma2000_1xrtt", - "value": "cdma2000_1xrtt", - "brief": "CDMA2000 1XRTT", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "hsdpa", - "value": "hsdpa", - "brief": "HSDPA", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "hsupa", - "value": "hsupa", - "brief": "HSUPA", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "hspa", - "value": "hspa", - "brief": "HSPA", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "iden", - "value": "iden", - "brief": "IDEN", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "evdo_b", - "value": "evdo_b", - "brief": "EVDO Rev. B", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "lte", - "value": "lte", - "brief": "LTE", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "ehrpd", - "value": "ehrpd", - "brief": "EHRPD", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "hspap", - "value": "hspap", - "brief": "HSPAP", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "gsm", - "value": "gsm", - "brief": "GSM", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "td_scdma", - "value": "td_scdma", - "brief": "TD-SCDMA", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "iwlan", - "value": "iwlan", - "brief": "IWLAN", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "nr", - "value": "nr", - "brief": "5G NR (New Radio)", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "nrnsa", - "value": "nrnsa", - "brief": "5G NRNSA (New Radio Non-Standalone)", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "lte_ca", - "value": "lte_ca", - "brief": "LTE CA", - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.", - "examples": "LTE", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "network.connection.type", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "wifi", - "value": "wifi", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "wired", - "value": "wired", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "cell", - "value": "cell", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unavailable", - "value": "unavailable", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unknown", - "value": "unknown", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The internet connection type.", - "examples": "wifi", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "network.local.address", - "type": "string", - "brief": "Local address of the network connection - IP address or Unix domain socket name.", - "examples": [ - "10.1.2.80", - "/tmp/my.sock" - ], - "requirement_level": "recommended", - "stability": "stable" - }, - { - "name": "network.local.port", - "type": "int", - "brief": "Local port number of the network connection.", - "examples": [ - 65123 - ], - "requirement_level": "recommended", - "stability": "stable" - }, - { - "name": "network.peer.address", - "type": "string", - "brief": "Peer address of the network connection - IP address or Unix domain socket name.", - "examples": [ - "10.1.2.80", - "/tmp/my.sock" - ], - "requirement_level": "recommended", - "stability": "stable" - }, - { - "name": "network.peer.port", - "type": "int", - "brief": "Peer port number of the network connection.", - "examples": [ - 65123 - ], - "requirement_level": "recommended", - "stability": "stable" - }, - { - "name": "network.protocol.name", - "type": "string", - "brief": "[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.", - "examples": [ - "amqp", - "http", - "mqtt" - ], - "requirement_level": "recommended", - "note": "The value SHOULD be normalized to lowercase.", - "stability": "stable" - }, - { - "name": "network.protocol.version", - "type": "string", - "brief": "The actual version of the protocol used for network communication.", - "examples": [ - "1.1", - "2" - ], - "requirement_level": "recommended", - "note": "If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set.\n", - "stability": "stable" - }, - { - "name": "network.transport", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "tcp", - "value": "tcp", - "brief": "TCP", - "note": null, - "stability": "stable", - "deprecated": null - }, - { - "id": "udp", - "value": "udp", - "brief": "UDP", - "note": null, - "stability": "stable", - "deprecated": null - }, - { - "id": "pipe", - "value": "pipe", - "brief": "Named or anonymous pipe.", - "note": null, - "stability": "stable", - "deprecated": null - }, - { - "id": "unix", - "value": "unix", - "brief": "Unix domain socket", - "note": null, - "stability": "stable", - "deprecated": null - } - ] - }, - "brief": "[OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication).\n", - "examples": [ - "tcp", - "udp" - ], - "requirement_level": "recommended", - "note": "The value SHOULD be normalized to lowercase.\n\nConsider always setting the transport when setting a port number, since\na port number is ambiguous without knowing the transport. For example\ndifferent processes could be listening on TCP port 12345 and UDP port 12345.\n", - "stability": "stable" - }, - { - "name": "network.type", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "ipv4", - "value": "ipv4", - "brief": "IPv4", - "note": null, - "stability": "stable", - "deprecated": null - }, - { - "id": "ipv6", - "value": "ipv6", - "brief": "IPv6", - "note": null, - "stability": "stable", - "deprecated": null - } - ] - }, - "brief": "[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.", - "examples": [ - "ipv4", - "ipv6" - ], - "requirement_level": "recommended", - "note": "The value SHOULD be normalized to lowercase.", - "stability": "stable" - }, - { - "name": "network.io.direction", - "type": { - "allow_custom_values": false, - "members": [ - { - "id": "transmit", - "value": "transmit", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "receive", - "value": "receive", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The network IO operation direction.", - "examples": [ - "transmit" - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.connect_rpc.error_code", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "cancelled", - "value": "cancelled", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unknown", - "value": "unknown", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "invalid_argument", - "value": "invalid_argument", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "deadline_exceeded", - "value": "deadline_exceeded", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "not_found", - "value": "not_found", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "already_exists", - "value": "already_exists", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "permission_denied", - "value": "permission_denied", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "resource_exhausted", - "value": "resource_exhausted", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "failed_precondition", - "value": "failed_precondition", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "aborted", - "value": "aborted", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "out_of_range", - "value": "out_of_range", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unimplemented", - "value": "unimplemented", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "internal", - "value": "internal", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unavailable", - "value": "unavailable", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "data_loss", - "value": "data_loss", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unauthenticated", - "value": "unauthenticated", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The [error codes](https://connect.build/docs/protocol/#error-codes) of the Connect request. Error codes are always string values.", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.connect_rpc.request.metadata", - "type": "template[string[]]", - "brief": "Connect request metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values.\n", - "examples": [ - "rpc.request.metadata.my-custom-metadata-attribute=[\"1.2.3.4\", \"1.2.3.5\"]" - ], - "requirement_level": "recommended", - "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", - "stability": "experimental" - }, - { - "name": "rpc.connect_rpc.response.metadata", - "type": "template[string[]]", - "brief": "Connect response metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values.\n", - "examples": [ - "rpc.response.metadata.my-custom-metadata-attribute=[\"attribute_value\"]" - ], - "requirement_level": "recommended", - "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", - "stability": "experimental" - }, - { - "name": "rpc.grpc.status_code", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "ok", - "value": 0, - "brief": "OK", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "cancelled", - "value": 1, - "brief": "CANCELLED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unknown", - "value": 2, - "brief": "UNKNOWN", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "invalid_argument", - "value": 3, - "brief": "INVALID_ARGUMENT", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "deadline_exceeded", - "value": 4, - "brief": "DEADLINE_EXCEEDED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "not_found", - "value": 5, - "brief": "NOT_FOUND", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "already_exists", - "value": 6, - "brief": "ALREADY_EXISTS", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "permission_denied", - "value": 7, - "brief": "PERMISSION_DENIED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "resource_exhausted", - "value": 8, - "brief": "RESOURCE_EXHAUSTED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "failed_precondition", - "value": 9, - "brief": "FAILED_PRECONDITION", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "aborted", - "value": 10, - "brief": "ABORTED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "out_of_range", - "value": 11, - "brief": "OUT_OF_RANGE", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unimplemented", - "value": 12, - "brief": "UNIMPLEMENTED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "internal", - "value": 13, - "brief": "INTERNAL", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unavailable", - "value": 14, - "brief": "UNAVAILABLE", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "data_loss", - "value": 15, - "brief": "DATA_LOSS", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unauthenticated", - "value": 16, - "brief": "UNAUTHENTICATED", - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The [numeric status code](https://github.com/grpc/grpc/blob/v1.33.2/doc/statuscodes.md) of the gRPC request.", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.grpc.request.metadata", - "type": "template[string[]]", - "brief": "gRPC request metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values.\n", - "examples": [ - "rpc.grpc.request.metadata.my-custom-metadata-attribute=[\"1.2.3.4\", \"1.2.3.5\"]" - ], - "requirement_level": "recommended", - "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", - "stability": "experimental" - }, - { - "name": "rpc.grpc.response.metadata", - "type": "template[string[]]", - "brief": "gRPC response metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values.\n", - "examples": [ - "rpc.grpc.response.metadata.my-custom-metadata-attribute=[\"attribute_value\"]" - ], - "requirement_level": "recommended", - "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", - "stability": "experimental" - }, - { - "name": "rpc.jsonrpc.error_code", - "type": "int", - "brief": "`error.code` property of response if it is an error response.", - "examples": [ - -32700, - 100 - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.jsonrpc.error_message", - "type": "string", - "brief": "`error.message` property of response if it is an error response.", - "examples": [ - "Parse error", - "User already exists" - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.jsonrpc.request_id", - "type": "string", - "brief": "`id` property of request or response. Since protocol allows id to be int, string, `null` or missing (for notifications), value is expected to be cast to string for simplicity. Use empty string in case of `null` value. Omit entirely if this is a notification.\n", - "examples": [ - "10", - "request-7", - "" - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.jsonrpc.version", - "type": "string", - "brief": "Protocol version as in `jsonrpc` property of request/response. Since JSON-RPC 1.0 doesn't specify this, the value can be omitted.", - "examples": [ - "2.0", - "1.0" - ], - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.method", - "type": "string", - "brief": "The name of the (logical) method being called, must be equal to the $method part in the span name.", - "examples": "exampleMethod", - "requirement_level": "recommended", - "note": "This is the logical name of the method from the RPC interface perspective, which can be different from the name of any implementing method/function. The `code.function` attribute may be used to store the latter (e.g., method actually executing the call on the server side, RPC client stub method on the client side).\n", - "stability": "experimental" - }, - { - "name": "rpc.service", - "type": "string", - "brief": "The full (logical) name of the service being called, including its package name, if applicable.", - "examples": "myservice.EchoService", - "requirement_level": "recommended", - "note": "This is the logical name of the service from the RPC interface perspective, which can be different from the name of any implementing class. The `code.namespace` attribute may be used to store the latter (despite the attribute name, it may include a class name; e.g., class with method actually executing the call on the server side, RPC client stub class on the client side).\n", - "stability": "experimental" - }, - { - "name": "rpc.system", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "grpc", - "value": "grpc", - "brief": "gRPC", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "java_rmi", - "value": "java_rmi", - "brief": "Java RMI", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "dotnet_wcf", - "value": "dotnet_wcf", - "brief": ".NET WCF", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "apache_dubbo", - "value": "apache_dubbo", - "brief": "Apache Dubbo", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "connect_rpc", - "value": "connect_rpc", - "brief": "Connect RPC", - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "A string identifying the remoting system. See below for a list of well-known identifiers.", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.message.type", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "sent", - "value": "SENT", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "received", - "value": "RECEIVED", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "Whether this is a received or sent message.", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.message.id", - "type": "int", - "brief": "MUST be calculated as two different counters starting from `1` one for sent messages and one for received message.", - "requirement_level": "recommended", - "note": "This way we guarantee that the values will be consistent between different implementations.", - "stability": "experimental" - }, - { - "name": "rpc.message.compressed_size", - "type": "int", - "brief": "Compressed size of the message in bytes.", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.message.uncompressed_size", - "type": "int", - "brief": "Uncompressed size of the message in bytes.", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "server.address", - "type": "string", - "brief": "Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name.", - "examples": [ - "example.com", - "10.1.2.80", - "/tmp/my.sock" - ], - "requirement_level": "recommended", - "note": "When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available.\n", - "stability": "stable" - }, - { - "name": "server.port", - "type": "int", - "brief": "Server port number.", - "examples": [ - 80, - 8080, - 443 - ], - "requirement_level": "recommended", - "note": "When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available.\n", "stability": "stable" }, { "name": "exception.type", "type": "string", - "brief": "The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n", + "brief": "The type of the exception (its fully-qualified class name, if applicable).\n", "examples": [ "java.net.ConnectException", "OSError" @@ -1438,614 +217,25 @@ "note": "A semantic identifier, commonly referred to as a variant, provides a means\nfor referring to a value without including the value itself. This can\nprovide additional context for understanding the meaning behind a value.\nFor example, the variant `red` maybe be used for the value `#c05543`.\n\nA stringified version of the value can be used in situations where a\nsemantic identifier is unavailable. String representation of the value\nshould be determined by the implementer." }, { - "name": "gen_ai.system", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "openai", - "value": "openai", - "brief": "OpenAI", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "vertex_ai", - "value": "vertex_ai", - "brief": "Vertex AI", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "anthropic", - "value": "anthropic", - "brief": "Anthropic", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "cohere", - "value": "cohere", - "brief": "Cohere", - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The Generative AI product as identified by the client or server instrumentation.", - "examples": "openai", - "requirement_level": "required", - "note": "The `gen_ai.system` describes a family of GenAI models with specific model identified\nby `gen_ai.request.model` and `gen_ai.response.model` attributes.\n\nThe actual GenAI product may differ from the one identified by the client.\nFor example, when using OpenAI client libraries to communicate with Mistral, the `gen_ai.system`\nis set to `openai` based on the instrumentation's best knowledge.\n\nFor custom model, a custom friendly name SHOULD be used.\nIf none of these options apply, the `gen_ai.system` SHOULD be set to `_OTHER`.\n", - "stability": "experimental" - }, - { - "name": "gen_ai.request.model", - "type": "string", - "brief": "The name of the GenAI model a request is being made to.", - "examples": "gpt-4", - "requirement_level": "required", - "note": "The name of the GenAI model a request is being made to. If the model is supplied by a vendor, then the value must be the exact name of the model requested. If the model is a fine-tuned custom model, the value should have a more specific name than the base model that's been fine-tuned.\n", - "stability": "experimental" - }, - { - "name": "gen_ai.operation.name", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "chat", - "value": "chat", - "brief": "Chat completion operation such as [OpenAI Chat API](https://platform.openai.com/docs/api-reference/chat)", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "text_completion", - "value": "text_completion", - "brief": "Text completions operation such as [OpenAI Completions API (Legacy)](https://platform.openai.com/docs/api-reference/completions)", - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The name of the operation being performed.", - "requirement_level": "required", - "note": "If one of the predefined values applies, but specific system uses a different name it's RECOMMENDED to document it in the semantic conventions for specific GenAI system and use system-specific name in the instrumentation. If a different name is not documented, instrumentation libraries SHOULD use applicable predefined value.\n", - "stability": "experimental" - }, - { - "name": "gen_ai.response.model", + "name": "test_attr.event.attr", "type": "string", - "brief": "The name of the model that generated the response.", - "examples": [ - "gpt-4-0613" - ], - "requirement_level": "recommended", - "note": "If available. The name of the GenAI model that provided the response. If the model is supplied by a vendor, then the value must be the exact name of the model actually used. If the model is a fine-tuned custom model, the value should have a more specific name than the base model that's been fine-tuned.\n", - "stability": "experimental" - }, - { - "name": "gen_ai.prompt", - "type": "string", - "brief": "The full prompt sent to the GenAI model.", - "examples": [ - "[{'role': 'user', 'content': 'What is the capital of France?'}]" - ], + "brief": "Just making sure the referenced attributes are defined", + "examples": "some value", "requirement_level": { "conditionally_required": "if and only if corresponding event is enabled" }, - "note": "It's RECOMMENDED to format prompts as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation)\n", - "stability": "experimental" + "note": "test attribute\n", + "stability": "stable" }, { - "name": "gen_ai.completion", + "name": "test_attr.session.id", "type": "string", - "brief": "The full response received from the GenAI model.", - "examples": [ - "[{'role': 'assistant', 'content': 'The capital of France is Paris.'}]" - ], + "brief": "The session id", + "examples": "127836abcdef98", "requirement_level": { "conditionally_required": "if and only if corresponding event is enabled" }, - "note": "It's RECOMMENDED to format completions as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation)\n", - "stability": "experimental" - }, - { - "name": "rpc.system", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "grpc", - "value": "grpc", - "brief": "gRPC", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "java_rmi", - "value": "java_rmi", - "brief": "Java RMI", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "dotnet_wcf", - "value": "dotnet_wcf", - "brief": ".NET WCF", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "apache_dubbo", - "value": "apache_dubbo", - "brief": "Apache Dubbo", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "connect_rpc", - "value": "connect_rpc", - "brief": "Connect RPC", - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "A string identifying the remoting system. See below for a list of well-known identifiers.", - "requirement_level": "required", - "stability": "experimental" - }, - { - "name": "server.address", - "type": "string", - "brief": "RPC server [host name](https://grpc.github.io/grpc/core/md_doc_naming.html).\n", - "examples": [ - "example.com", - "10.1.2.80", - "/tmp/my.sock" - ], - "requirement_level": "required", - "note": "May contain server IP address, DNS name, or local socket name. When host component is an IP address, instrumentations SHOULD NOT do a reverse proxy lookup to obtain DNS name and SHOULD set `server.address` to the IP address provided in the host component.\n", + "note": "Another test attribute\n", "stability": "stable" - }, - { - "name": "server.port", - "type": "int", - "brief": "Server port number.", - "examples": [ - 80, - 8080, - 443 - ], - "requirement_level": { - "conditionally_required": "if the port is supported by the network transport used for communication." - }, - "note": "When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available.\n", - "stability": "stable" - }, - { - "name": "network.peer.port", - "type": "int", - "brief": "Peer port number of the network connection.", - "examples": [ - 65123 - ], - "requirement_level": { - "recommended": "If `network.peer.address` is set." - }, - "stability": "stable" - }, - { - "name": "rpc.grpc.request.metadata", - "type": "template[string[]]", - "brief": "gRPC request metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values.\n", - "examples": [ - "rpc.grpc.request.metadata.my-custom-metadata-attribute=[\"1.2.3.4\", \"1.2.3.5\"]" - ], - "tag": "grpc-tech-specific", - "requirement_level": "opt_in", - "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", - "stability": "experimental" - }, - { - "name": "rpc.grpc.response.metadata", - "type": "template[string[]]", - "brief": "gRPC response metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values.\n", - "examples": [ - "rpc.grpc.response.metadata.my-custom-metadata-attribute=[\"attribute_value\"]" - ], - "tag": "grpc-tech-specific", - "requirement_level": "opt_in", - "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", - "stability": "experimental" - }, - { - "name": "rpc.grpc.status_code", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "ok", - "value": 0, - "brief": "OK", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "cancelled", - "value": 1, - "brief": "CANCELLED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unknown", - "value": 2, - "brief": "UNKNOWN", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "invalid_argument", - "value": 3, - "brief": "INVALID_ARGUMENT", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "deadline_exceeded", - "value": 4, - "brief": "DEADLINE_EXCEEDED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "not_found", - "value": 5, - "brief": "NOT_FOUND", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "already_exists", - "value": 6, - "brief": "ALREADY_EXISTS", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "permission_denied", - "value": 7, - "brief": "PERMISSION_DENIED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "resource_exhausted", - "value": 8, - "brief": "RESOURCE_EXHAUSTED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "failed_precondition", - "value": 9, - "brief": "FAILED_PRECONDITION", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "aborted", - "value": 10, - "brief": "ABORTED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "out_of_range", - "value": 11, - "brief": "OUT_OF_RANGE", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unimplemented", - "value": 12, - "brief": "UNIMPLEMENTED", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "internal", - "value": 13, - "brief": "INTERNAL", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unavailable", - "value": 14, - "brief": "UNAVAILABLE", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "data_loss", - "value": 15, - "brief": "DATA_LOSS", - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unauthenticated", - "value": 16, - "brief": "UNAUTHENTICATED", - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The [numeric status code](https://github.com/grpc/grpc/blob/v1.33.2/doc/statuscodes.md) of the gRPC request.", - "tag": "grpc-tech-specific", - "requirement_level": "required", - "stability": "experimental" - }, - { - "name": "rpc.jsonrpc.error_code", - "type": "int", - "brief": "`error.code` property of response if it is an error response.", - "examples": [ - -32700, - 100 - ], - "tag": "jsonrpc-tech-specific", - "requirement_level": { - "conditionally_required": "If response is not successful." - }, - "stability": "experimental" - }, - { - "name": "rpc.jsonrpc.error_message", - "type": "string", - "brief": "`error.message` property of response if it is an error response.", - "examples": [ - "Parse error", - "User already exists" - ], - "tag": "jsonrpc-tech-specific", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.jsonrpc.request_id", - "type": "string", - "brief": "`id` property of request or response. Since protocol allows id to be int, string, `null` or missing (for notifications), value is expected to be cast to string for simplicity. Use empty string in case of `null` value. Omit entirely if this is a notification.\n", - "examples": [ - "10", - "request-7", - "" - ], - "tag": "jsonrpc-tech-specific", - "requirement_level": "recommended", - "stability": "experimental" - }, - { - "name": "rpc.jsonrpc.version", - "type": "string", - "brief": "Protocol version as in `jsonrpc` property of request/response. Since JSON-RPC 1.0 doesn't specify this, the value can be omitted.", - "examples": [ - "2.0", - "1.0" - ], - "tag": "jsonrpc-tech-specific", - "requirement_level": { - "conditionally_required": "If other than the default version (`1.0`)" - }, - "stability": "experimental" - }, - { - "name": "rpc.method", - "type": "string", - "brief": "The name of the (logical) method being called, must be equal to the $method part in the span name.", - "examples": "exampleMethod", - "tag": "jsonrpc-tech-specific", - "requirement_level": "required", - "note": "This is always required for jsonrpc. See the note in the general RPC conventions for more information.\n", - "stability": "experimental" - }, - { - "name": "rpc.connect_rpc.error_code", - "type": { - "allow_custom_values": true, - "members": [ - { - "id": "cancelled", - "value": "cancelled", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unknown", - "value": "unknown", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "invalid_argument", - "value": "invalid_argument", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "deadline_exceeded", - "value": "deadline_exceeded", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "not_found", - "value": "not_found", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "already_exists", - "value": "already_exists", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "permission_denied", - "value": "permission_denied", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "resource_exhausted", - "value": "resource_exhausted", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "failed_precondition", - "value": "failed_precondition", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "aborted", - "value": "aborted", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "out_of_range", - "value": "out_of_range", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unimplemented", - "value": "unimplemented", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "internal", - "value": "internal", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unavailable", - "value": "unavailable", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "data_loss", - "value": "data_loss", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - }, - { - "id": "unauthenticated", - "value": "unauthenticated", - "brief": null, - "note": null, - "stability": "experimental", - "deprecated": null - } - ] - }, - "brief": "The [error codes](https://connect.build/docs/protocol/#error-codes) of the Connect request. Error codes are always string values.", - "tag": "connect_rpc-tech-specific", - "requirement_level": { - "conditionally_required": "If response is not successful and if error code available." - }, - "stability": "experimental" - }, - { - "name": "rpc.connect_rpc.request.metadata", - "type": "template[string[]]", - "brief": "Connect request metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values.\n", - "examples": [ - "rpc.request.metadata.my-custom-metadata-attribute=[\"1.2.3.4\", \"1.2.3.5\"]" - ], - "tag": "connect_rpc-tech-specific", - "requirement_level": "opt_in", - "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", - "stability": "experimental" - }, - { - "name": "rpc.connect_rpc.response.metadata", - "type": "template[string[]]", - "brief": "Connect response metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values.\n", - "examples": [ - "rpc.response.metadata.my-custom-metadata-attribute=[\"attribute_value\"]" - ], - "tag": "connect_rpc-tech-specific", - "requirement_level": "opt_in", - "note": "Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information.\n", - "stability": "experimental" } ] \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json b/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json index 3899cb23..462bfd0a 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json +++ b/crates/weaver_resolver/data/registry-test-4-events/expected-registry.json @@ -1,127 +1,6 @@ { "registry_url": "https://127.0.0.1", "groups": [ - { - "id": "browser.test.event_with_fields", - "type": "event", - "brief": "An event that adds global attributes for reuse.\n", - "prefix": "browser", - "attributes": [ - 0, - 1, - 2, - 3 - ], - "name": "browser.test.event_with_fields", - "lineage": { - "source_file": "data/registry-test-4-events/registry/browser-event.yaml" - }, - "body": { - "name": "browser.test.event_with_body.fields", - "type": "map", - "requirement_level": "required", - "fields": [ - { - "name": "some.field", - "type": "string", - "brief": "A field that is not referenced in the attributes", - "examples": [ - "some value", - "another value" - ], - "requirement_level": "required", - "note": "This field is not referenced in the attributes" - } - ] - } - }, - { - "id": "browser.test.event_with_body_details", - "type": "event", - "brief": "An event that adds global attributes for reuse.\n", - "attributes": [], - "name": "browser.test.event_with_body_details", - "lineage": { - "source_file": "data/registry-test-4-events/registry/browser-event.yaml" - }, - "body": { - "name": "browser.test.event_with_body_details.fields", - "type": "map", - "brief": "A map of fields that are not referenced in the attributes", - "note": "This map is not referenced in the attributes", - "stability": "experimental", - "examples": [ - "{ \"some.field\": \"some value\" }" - ], - "requirement_level": "required", - "fields": [ - { - "name": "some.field", - "type": "string", - "brief": "A field that is not referenced in the attributes", - "examples": [ - "some value", - "another value" - ], - "requirement_level": "optional", - "note": "This field is not referenced in the attributes" - } - ] - } - }, - { - "id": "client.exception.event", - "type": "event", - "brief": "This document defines the log event used to report a client exception.\n", - "attributes": [ - 4 - ], - "name": "client.exception.event", - "lineage": { - "source_file": "data/registry-test-4-events/registry/client-exception-event.yaml" - }, - "body": { - "name": "client.exception.event.fields", - "type": "map", - "requirement_level": "optional", - "fields": [ - { - "name": "type", - "type": "string", - "brief": "The type of the exception.\n", - "examples": [ - "java.net.ConnectException", - "OSError" - ], - "requirement_level": "optional" - }, - { - "name": "message", - "type": "string", - "brief": "The exception message.", - "examples": [ - "Division by zero", - "Can't convert 'int' object to str implicitly" - ], - "requirement_level": "optional" - }, - { - "name": "stacktrace", - "type": "string", - "brief": "A stacktrace.\n", - "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)", - "requirement_level": "optional" - }, - { - "name": "escaped", - "type": "boolean", - "brief": "SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n", - "requirement_level": "optional", - "note": "An exception is considered to have escaped." - } - ] - } - }, { "id": "log_event_attributes_only", "type": "event", @@ -131,9 +10,9 @@ ], "name": "some.event", "lineage": { - "source_file": "data/registry-test-4-events/registry/log-event.yaml", + "source_file": "data/registry-test-4-events/registry/log-events.yaml", "attributes": { - "log.event.attr": { + "test_attr.event.attr": { "source_group": "referenced.attributes", "inherited_fields": [ "brief", @@ -146,18 +25,28 @@ } } }, + { + "id": "log_event_empty", + "type": "event", + "brief": "brief", + "attributes": [], + "name": "empty.event", + "lineage": { + "source_file": "data/registry-test-4-events/registry/log-events.yaml" + } + }, { "id": "log-feature_flag", "type": "event", "brief": "This document defines attributes for feature flag evaluations represented using Log Records.\n", "prefix": "feature_flag", "attributes": [ - 69, - 70, - 71 + 17, + 18, + 19 ], "lineage": { - "source_file": "data/registry-test-4-events/registry/log-feature_flag.yaml", + "source_file": "data/registry-test-4-events/registry/log-events.yaml", "attributes": { "feature_flag.key": { "source_group": "feature_flag", @@ -189,6 +78,50 @@ } } }, + { + "id": "some.string.body.event", + "type": "event", + "brief": "This event represents an occurrence of a something.\n", + "note": "This event transmits the body as a JSON encoded string.\n", + "stability": "experimental", + "attributes": [], + "name": "string.body.event", + "lineage": { + "source_file": "data/registry-test-4-events/registry/log-events.yaml" + }, + "body": { + "id": "some.string.body.event.fields", + "type": "string", + "brief": "This is the body of the event which is a JSON encoded string.\n", + "examples": [ + "{\"key1\":\"value1\",\"key2\":\"value2\"}" + ], + "requirement_level": "required" + } + }, + { + "id": "some.string.body.detailed.event", + "type": "event", + "brief": "This event represents an occurrence of a something.\n", + "note": "This event transmits the body as a JSON encoded string.\n", + "stability": "experimental", + "attributes": [], + "name": "string.body.event", + "lineage": { + "source_file": "data/registry-test-4-events/registry/log-events.yaml" + }, + "body": { + "id": "some.string.body.event.fields", + "type": "string", + "brief": "This is the body of the event which is a JSON encoded string.\n", + "note": "This is a detailed note about the body.\n", + "stability": "experimental", + "examples": [ + "{\"key1\":\"value1\",\"key2\":\"value2\"}" + ], + "requirement_level": "required" + } + }, { "id": "device.app.lifecycle", "type": "event", @@ -198,16 +131,16 @@ "attributes": [], "name": "device.app.lifecycle", "lineage": { - "source_file": "data/registry-test-4-events/registry/mobile-events.yaml" + "source_file": "data/registry-test-4-events/registry/log-events.yaml" }, "body": { - "name": "device.app.lifecycle.fields", + "id": "device.app.lifecycle.fields", "type": "map", "requirement_level": "required", "fields": [ { - "name": "ios.state", - "type": "enum {active, inactive, background, foreground, terminate}", + "id": "ios.state", + "type": "enum", "members": [ { "id": "active", @@ -253,8 +186,8 @@ "stability": "experimental" }, { - "name": "android.state", - "type": "enum {created, background, foreground}", + "id": "android.state", + "type": "enum", "members": [ { "id": "created", @@ -273,7 +206,7 @@ { "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.", + "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.\n", "note": null, "stability": null } @@ -289,195 +222,166 @@ } }, { - "id": "log_event_empty", + "id": "client.exception.event", "type": "event", - "brief": "brief", - "attributes": [], - "name": "ping.event", - "lineage": { - "source_file": "data/registry-test-4-events/registry/ping-event.yaml" - } - }, - { - "id": "referenced.attributes", - "type": "attribute_group", - "brief": "These attributes are used as references for the test below\n", + "brief": "This document defines the log event used to report a client exception.\n", "attributes": [ - 5, - 6, - 7, - 8 + 0 ], + "name": "client.exception.event", "lineage": { - "source_file": "data/registry-test-4-events/registry/referenced-attributes.yaml" + "source_file": "data/registry-test-4-events/registry/log-events.yaml" + }, + "body": { + "id": "client.exception.event.fields", + "type": "map", + "requirement_level": "optional", + "fields": [ + { + "id": "type", + "type": "string", + "brief": "The type of the exception.\n", + "examples": [ + "java.net.ConnectException", + "OSError" + ], + "requirement_level": "optional" + }, + { + "id": "message", + "type": "string", + "brief": "The exception message.", + "examples": [ + "Division by zero", + "Can't convert 'int' object to str implicitly" + ], + "requirement_level": "optional" + }, + { + "id": "stacktrace", + "type": "string", + "brief": "A stacktrace.\n", + "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)", + "requirement_level": "optional" + }, + { + "id": "escaped", + "type": "boolean", + "brief": "SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n", + "requirement_level": "optional", + "note": "An exception is considered to have escaped." + } + ] } }, { - "id": "registry.client", - "type": "attribute_group", - "brief": "These attributes may be used to describe the client in a connection-based network interaction where there is one side that initiates the connection (the client is the side that initiates the connection). This covers all TCP network interactions since TCP is connection-based and one side initiates the connection (an exception is made for peer-to-peer communication over TCP where the \"user-facing\" surface of the protocol / API doesn't expose a clear notion of client and server). This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS.\n", - "prefix": "client", + "id": "browser.test.event_with_fields", + "type": "event", + "brief": "An event that adds global attributes for reuse.\n", + "prefix": "browser", "attributes": [ - 9, - 10 + 1, + 2, + 3, + 4 ], + "name": "browser.test.event_with_fields", "lineage": { - "source_file": "data/registry-test-4-events/registry/referenced-client.yaml" + "source_file": "data/registry-test-4-events/registry/log-events.yaml" + }, + "body": { + "id": "browser.test.event_with_body.fields", + "type": "map", + "requirement_level": "required", + "fields": [ + { + "id": "some.field", + "type": "string", + "brief": "A field that is not referenced in the attributes", + "examples": [ + "some value", + "another value" + ], + "requirement_level": "required", + "note": "This field is not referenced in the attributes" + } + ] } }, { - "id": "registry.exception", - "type": "attribute_group", - "brief": "This document defines the shared attributes used to report a single exception associated with a span or log.\n", - "prefix": "exception", - "attributes": [ - 11, - 12, - 13, - 14 - ], + "id": "browser.test.event_with_body_details", + "type": "event", + "brief": "An event that adds global attributes for reuse.\n", + "attributes": [], + "name": "browser.test.event_with_body_details", "lineage": { - "source_file": "data/registry-test-4-events/registry/referenced-exception.yaml" - } - }, - { - "id": "registry.gen_ai", - "type": "attribute_group", - "brief": "This document defines the attributes used to describe telemetry in the context of Generative Artificial Intelligence (GenAI) Models requests and responses.\n", - "prefix": "gen_ai", - "attributes": [ - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32 - ], - "lineage": { - "source_file": "data/registry-test-4-events/registry/referenced-gen_ai.yaml" + "source_file": "data/registry-test-4-events/registry/log-events.yaml" + }, + "body": { + "id": "browser.test.event_with_body_details.fields", + "type": "map", + "brief": "A map of fields that are not referenced in the attributes", + "note": "This map is not referenced in the attributes", + "stability": "experimental", + "examples": [ + "{ \"some.field\": \"some value\" }" + ], + "requirement_level": "required", + "fields": [ + { + "id": "some.field", + "type": "string", + "brief": "A field that is not referenced in the attributes", + "examples": [ + "some value", + "another value" + ], + "requirement_level": "optional", + "note": "This field is not referenced in the attributes" + } + ] } }, { - "id": "registry.network", + "id": "referenced.attributes", "type": "attribute_group", - "brief": "These attributes may be used for any network related operation.\n", - "prefix": "network", + "brief": "These attributes are used as references for the test below\n", "attributes": [ - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47 + 5, + 6, + 7, + 8 ], "lineage": { - "source_file": "data/registry-test-4-events/registry/referenced-network.yaml" + "source_file": "data/registry-test-4-events/registry/referenced-attributes.yaml" } }, { - "id": "registry.rpc", + "id": "registry.client", "type": "attribute_group", - "brief": "This document defines attributes for remote procedure calls.", - "prefix": "rpc", + "brief": "Client test attributes", + "prefix": "client", "attributes": [ - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64 + 9, + 10 ], "lineage": { - "source_file": "data/registry-test-4-events/registry/referenced-rpc.yaml" + "source_file": "data/registry-test-4-events/registry/referenced-attributes.yaml" } }, { - "id": "registry.server", + "id": "registry.exception", "type": "attribute_group", - "brief": "These attributes may be used to describe the server in a connection-based network interaction where there is one side that initiates the connection (the client is the side that initiates the connection). This covers all TCP network interactions since TCP is connection-based and one side initiates the connection (an exception is made for peer-to-peer communication over TCP where the \"user-facing\" surface of the protocol / API doesn't expose a clear notion of client and server). This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS.\n", - "prefix": "server", + "brief": "This document defines the shared attributes used to report a single exception associated with a span or log.\n", + "prefix": "exception", "attributes": [ - 65, - 66 + 11, + 12, + 13, + 14 ], "lineage": { - "source_file": "data/registry-test-4-events/registry/referenced-server.yaml" - } - }, - { - "id": "some.string.body.event", - "type": "event", - "brief": "This event represents an occurrence of a something.\n", - "note": "This event transmits the body as a JSON encoded string.\n", - "stability": "experimental", - "attributes": [], - "name": "string.body.event", - "lineage": { - "source_file": "data/registry-test-4-events/registry/stringbody-event.yaml" - }, - "body": { - "name": "some.string.body.event.fields", - "type": "string", - "brief": "This is the body of the event which is a JSON encoded string.\n", - "examples": [ - "{\"key1\":\"value1\",\"key2\":\"value2\"}" - ], - "requirement_level": "required" - } - }, - { - "id": "some.string.body.detailed.event", - "type": "event", - "brief": "This event represents an occurrence of a something.\n", - "note": "This event transmits the body as a JSON encoded string.\n", - "stability": "experimental", - "attributes": [], - "name": "string.body.event", - "lineage": { - "source_file": "data/registry-test-4-events/registry/stringbody-event.yaml" - }, - "body": { - "name": "some.string.body.event.fields", - "type": "string", - "brief": "This is the body of the event which is a JSON encoded string.\n", - "note": "This is a detailed note about the body.\n", - "stability": "experimental", - "examples": [ - "{\"key1\":\"value1\",\"key2\":\"value2\"}" - ], - "requirement_level": "required" + "source_file": "data/registry-test-4-events/registry/referenced-attributes.yaml" } }, { @@ -488,11 +392,11 @@ "attributes": [ 13, 14, - 67, - 68 + 15, + 16 ], "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-exception.yaml", + "source_file": "data/registry-test-4-events/registry/trace-events.yaml", "attributes": { "exception.escaped": { "source_group": "registry.exception", @@ -545,239 +449,28 @@ "type": "event", "brief": "This semantic convention defines the attributes used to represent a feature flag evaluation as an event.\n", "prefix": "feature_flag", - "attributes": [ - 69, - 70, - 71 - ], - "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-feature-flag.yaml" - } - }, - { - "id": "trace.gen_ai.client", - "type": "span", - "brief": "Describes GenAI operation span.\n", "attributes": [ 17, 18, - 19, - 20, - 21, - 22, - 23, - 24, - 26, - 27, - 28, - 72, - 73, - 74, - 75 - ], - "events": [ - "gen_ai.content.prompt", - "gen_ai.content.completion" + 19 ], "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-gen-ai.yaml", - "attributes": { - "gen_ai.operation.name": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.request.frequency_penalty": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.request.max_tokens": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.request.model": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "stability" - ], - "locally_overridden_fields": [ - "note", - "requirement_level" - ] - }, - "gen_ai.request.presence_penalty": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.request.stop_sequences": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.request.temperature": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.request.top_k": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.request.top_p": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability", - "tag" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.response.finish_reasons": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.response.id": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.response.model": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "stability" - ], - "locally_overridden_fields": [ - "note", - "requirement_level" - ] - }, - "gen_ai.system": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.usage.input_tokens": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "gen_ai.usage.output_tokens": { - "source_group": "registry.gen_ai", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - } - } + "source_file": "data/registry-test-4-events/registry/trace-events.yaml" } }, { - "id": "gen_ai.content.prompt", + "id": "test_evt.with_attr", "type": "event", - "brief": "In the lifetime of an GenAI span, events for prompts sent and completions received may be created, depending on the configuration of the instrumentation.\n", + "brief": "Simple example span event with an attribute\n", "attributes": [ - 76 + 20 ], - "name": "gen_ai.content.prompt", + "name": "test_evt.with_attr", "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-gen-ai.yaml", + "source_file": "data/registry-test-4-events/registry/trace-events.yaml", "attributes": { - "gen_ai.prompt": { - "source_group": "registry.gen_ai", + "test_attr.event.attr": { + "source_group": "referenced.attributes", "inherited_fields": [ "brief", "examples", @@ -792,18 +485,18 @@ } }, { - "id": "gen_ai.content.completion", + "id": "test_evt.session", "type": "event", - "brief": "In the lifetime of an GenAI span, events for prompts sent and completions received may be created, depending on the configuration of the instrumentation.\n", + "brief": "Another simple span event with another attribute\n", "attributes": [ - 77 + 21 ], - "name": "gen_ai.content.completion", + "name": "test_evt.session", "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-gen-ai.yaml", + "source_file": "data/registry-test-4-events/registry/trace-events.yaml", "attributes": { - "gen_ai.completion": { - "source_group": "registry.gen_ai", + "test_attr.session.id": { + "source_group": "referenced.attributes", "inherited_fields": [ "brief", "examples", @@ -816,902 +509,6 @@ } } } - }, - { - "id": "rpc", - "type": "span", - "brief": "This document defines semantic conventions for remote procedure calls.", - "prefix": "rpc", - "attributes": [ - 45, - 46, - 58, - 59, - 78, - 79, - 80 - ], - "events": [ - "rpc.message" - ], - "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", - "attributes": { - "network.transport": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.type": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.method": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.service": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.system": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "server.address": { - "source_group": "registry.server", - "inherited_fields": [ - "examples", - "stability" - ], - "locally_overridden_fields": [ - "brief", - "note", - "requirement_level" - ] - }, - "server.port": { - "source_group": "registry.server", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - } - } - } - }, - { - "id": "rpc.client", - "type": "span", - "brief": "This document defines semantic conventions for remote procedure call client spans.", - "attributes": [ - 41, - 45, - 46, - 58, - 59, - 78, - 79, - 80, - 81 - ], - "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", - "attributes": { - "network.peer.address": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.peer.port": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.transport": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.type": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.method": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.service": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.system": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "server.address": { - "source_group": "registry.server", - "inherited_fields": [ - "examples", - "stability" - ], - "locally_overridden_fields": [ - "brief", - "note", - "requirement_level" - ] - }, - "server.port": { - "source_group": "registry.server", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - } - } - } - }, - { - "id": "rpc.server", - "type": "span", - "brief": "Semantic Convention for RPC server spans", - "attributes": [ - 9, - 10, - 41, - 45, - 46, - 58, - 59, - 78, - 79, - 80, - 81 - ], - "span_kind": "server", - "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", - "attributes": { - "client.address": { - "source_group": "registry.client", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "client.port": { - "source_group": "registry.client", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.peer.address": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.peer.port": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.transport": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.type": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.method": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.service": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.system": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "server.address": { - "source_group": "registry.server", - "inherited_fields": [ - "examples", - "stability" - ], - "locally_overridden_fields": [ - "brief", - "note", - "requirement_level" - ] - }, - "server.port": { - "source_group": "registry.server", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - } - } - } - }, - { - "id": "rpc.grpc", - "type": "span", - "brief": "Tech-specific attributes for gRPC.", - "attributes": [ - 45, - 46, - 58, - 59, - 78, - 79, - 80, - 82, - 83, - 84 - ], - "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", - "attributes": { - "network.transport": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.type": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.grpc.request.metadata": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level", - "tag" - ] - }, - "rpc.grpc.response.metadata": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level", - "tag" - ] - }, - "rpc.grpc.status_code": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level", - "tag" - ] - }, - "rpc.method": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.service": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.system": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "server.address": { - "source_group": "registry.server", - "inherited_fields": [ - "examples", - "stability" - ], - "locally_overridden_fields": [ - "brief", - "note", - "requirement_level" - ] - }, - "server.port": { - "source_group": "registry.server", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - } - } - } - }, - { - "id": "rpc.jsonrpc", - "type": "span", - "brief": "Tech-specific attributes for [JSON RPC](https://www.jsonrpc.org/).", - "prefix": "rpc.jsonrpc", - "attributes": [ - 45, - 46, - 59, - 78, - 79, - 80, - 85, - 86, - 87, - 88, - 89 - ], - "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", - "attributes": { - "network.transport": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.type": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.jsonrpc.error_code": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level", - "tag" - ] - }, - "rpc.jsonrpc.error_message": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level", - "tag" - ] - }, - "rpc.jsonrpc.request_id": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level", - "tag" - ] - }, - "rpc.jsonrpc.version": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level", - "tag" - ] - }, - "rpc.method": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "stability" - ], - "locally_overridden_fields": [ - "note", - "requirement_level", - "tag" - ] - }, - "rpc.service": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.system": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "server.address": { - "source_group": "registry.server", - "inherited_fields": [ - "examples", - "stability" - ], - "locally_overridden_fields": [ - "brief", - "note", - "requirement_level" - ] - }, - "server.port": { - "source_group": "registry.server", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - } - } - } - }, - { - "id": "rpc.message", - "type": "event", - "brief": "RPC received/sent message.", - "prefix": "rpc.message", - "attributes": [ - 61, - 62, - 63, - 64 - ], - "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", - "attributes": { - "rpc.message.compressed_size": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.message.id": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.message.type": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.message.uncompressed_size": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - } - } - } - }, - { - "id": "rpc.connect_rpc", - "type": "span", - "brief": "Tech-specific attributes for Connect RPC.", - "attributes": [ - 45, - 46, - 58, - 59, - 78, - 79, - 80, - 90, - 91, - 92 - ], - "lineage": { - "source_file": "data/registry-test-4-events/registry/trace-rpc.yaml", - "attributes": { - "network.transport": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "network.type": { - "source_group": "registry.network", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.connect_rpc.error_code": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level", - "tag" - ] - }, - "rpc.connect_rpc.request.metadata": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level", - "tag" - ] - }, - "rpc.connect_rpc.response.metadata": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level", - "tag" - ] - }, - "rpc.method": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.service": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "rpc.system": { - "source_group": "registry.rpc", - "inherited_fields": [ - "brief", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - }, - "server.address": { - "source_group": "registry.server", - "inherited_fields": [ - "examples", - "stability" - ], - "locally_overridden_fields": [ - "brief", - "note", - "requirement_level" - ] - }, - "server.port": { - "source_group": "registry.server", - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ] - } - } - } - } + } ] } \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/observed-events.json b/crates/weaver_resolver/data/registry-test-4-events/observed-events.json deleted file mode 100644 index 4f5390da..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/observed-events.json +++ /dev/null @@ -1,219 +0,0 @@ -[ - { - "attributes": [], - "body": { - "fields": [ - { - "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", - "name": "ios.state", - "note": "The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), and from which the `OS terminology` column values are derived.\n", - "requirement_level": { - "conditionally_required": "if and only if `os.name` is `ios`" - }, - "stability": "experimental", - "type": { - "allow_custom_values": false, - "members": [ - { - "brief": "The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`.\n", - "deprecated": null, - "id": "active", - "note": null, - "stability": null, - "value": "active" - }, - { - "brief": "The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`.\n", - "deprecated": null, - "id": "inactive", - "note": null, - "stability": null, - "value": "inactive" - }, - { - "brief": "The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`.\n", - "deprecated": null, - "id": "background", - "note": null, - "stability": null, - "value": "background" - }, - { - "brief": "The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`.\n", - "deprecated": null, - "id": "foreground", - "note": null, - "stability": null, - "value": "foreground" - }, - { - "brief": "The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`.\n", - "deprecated": null, - "id": "terminate", - "note": null, - "stability": null, - "value": "terminate" - } - ] - } - }, - { - "brief": "This attribute represents the state the application has transitioned into at the occurrence of the event.\n", - "name": "android.state", - "note": "The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), and from which the `OS identifiers` are derived.\n", - "requirement_level": { - "conditionally_required": "if and only if `os.name` is `android`" - }, - "stability": "experimental", - "type": { - "allow_custom_values": false, - "members": [ - { - "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.\n", - "deprecated": null, - "id": "created", - "note": null, - "stability": null, - "value": "created" - }, - { - "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.\n", - "deprecated": null, - "id": "background", - "note": null, - "stability": null, - "value": "background" - }, - { - "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.", - "deprecated": null, - "id": "foreground", - "note": null, - "stability": null, - "value": "foreground" - } - ] - } - } - ] - }, - "brief": "This event represents an occurrence of a lifecycle transition on Android or iOS platform.\n", - "events": [], - "id": "device.app.lifecycle", - "instrument": null, - "lineage": { - "source_file": "data/mobile-events.yaml" - }, - "metric_name": null, - "name": "device.app.lifecycle", - "note": "This event identifies the fields that are common to all lifecycle events for android and iOS using the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are mutually exclusive.\n", - "span_kind": null, - "stability": "experimental", - "type": "event", - "unit": null - }, - { - "attributes": [ - { - "brief": "A stacktrace as a string in the natural representation for the language runtime. The representation is to be determined and documented by each language SIG.\n", - "examples": "Exception in thread \"main\" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)", - "name": "exception.stacktrace", - "requirement_level": "recommended", - "stability": "stable", - "type": "string" - }, - { - "brief": "SHOULD be set to true if the exception event is recorded at a point where it is known that the exception is escaping the scope of the span.\n", - "name": "exception.escaped", - "note": "An exception is considered to have escaped (or left) the scope of a span,\nif that span is ended while the exception is still logically \"in flight\".\nThis may be actually \"in flight\" in some languages (e.g. if the exception\nis passed to a Context manager's `__exit__` method in Python) but will\nusually be caught at the point of recording the exception in most languages.\n\nIt is usually not possible to determine at the point where an exception is thrown\nwhether it will escape the scope of a span.\nHowever, it is trivial to know that an exception\nwill escape, if one checks for an active exception just before ending the span,\nas done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception).\n\nIt follows that an exception may still escape the scope of the span\neven if the `exception.escaped` attribute was not set or set to false,\nsince the event might have been recorded at a time where it was not\nclear whether the exception will escape.", - "requirement_level": "recommended", - "stability": "stable", - "type": "boolean" - }, - { - "brief": "The type of the exception (its fully-qualified class name, if applicable). The dynamic type of the exception should be preferred over the static type in languages that support it.\n", - "examples": [ - "java.net.ConnectException", - "OSError" - ], - "name": "exception.type", - "requirement_level": { - "conditionally_required": "Required if `exception.message` is not set, recommended otherwise." - }, - "stability": "stable", - "type": "string" - }, - { - "brief": "The exception message.", - "examples": [ - "Division by zero", - "Can't convert 'int' object to str implicitly" - ], - "name": "exception.message", - "requirement_level": { - "conditionally_required": "Required if `exception.type` is not set, recommended otherwise." - }, - "stability": "stable", - "type": "string" - } - ], - "brief": "This document defines the attributes used to report a single exception associated with a span.\n", - "events": [], - "id": "trace-exception", - "instrument": null, - "lineage": { - "attributes": { - "exception.escaped": { - "inherited_fields": [ - "brief", - "note", - "requirement_level", - "stability" - ], - "source_group": "registry.exception" - }, - "exception.message": { - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ], - "source_group": "registry.exception" - }, - "exception.stacktrace": { - "inherited_fields": [ - "brief", - "examples", - "note", - "requirement_level", - "stability" - ], - "source_group": "registry.exception" - }, - "exception.type": { - "inherited_fields": [ - "brief", - "examples", - "note", - "stability" - ], - "locally_overridden_fields": [ - "requirement_level" - ], - "source_group": "registry.exception" - } - }, - "source_file": "data/trace-exception.yaml" - }, - "metric_name": null, - "name": null, - "prefix": "exception", - "span_kind": null, - "type": "event", - "unit": null - } -] \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml deleted file mode 100644 index 2575c9c3..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/browser-event.yaml +++ /dev/null @@ -1,71 +0,0 @@ -groups: - - id: browser.test.event_with_fields - name: browser.test.event_with_fields - prefix: browser - type: event - brief: > - An event that adds global attributes for reuse. - attributes: - - id: brands - type: string[] - brief: 'Array of brand name and version separated by a space' - note: > - This value is intended to be taken from the - [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) - (`navigator.userAgentData.brands`). - examples: [ [ " Not A;Brand 99", "Chromium 99", "Chrome 99" ] ] - - id: platform - type: string - brief: 'The platform on which the browser is running' - note: > - This value is intended to be taken from the - [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) - (`navigator.userAgentData.platform`). - examples: [ "Windows", "macOS", "Android", "iOS", "Linux" ] - - id: mobile - type: boolean - brief: 'A boolean that is true if the browser is running on a mobile device' - note: > - This value is intended to be taken from the - [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) - (`navigator.userAgentData.mobile`). If unavailable, this attribute - SHOULD be left unset. - - id: language - type: string - brief: 'Preferred language of the user using the browser' - note: > - This value is intended to be taken from the Navigator API - `navigator.language`. - examples: [ "en", "en-US", "en-AU", "fr", "fr-FR" ] - body: - id: browser.test.event_with_body.fields - type: map - requirement_level: required - fields: - - id: some.field - type: string - brief: 'A field that is not referenced in the attributes' - note: 'This field is not referenced in the attributes' - examples: [ "some value", "another value" ] - requirement_level: required - - - id: browser.test.event_with_body_details - name: browser.test.event_with_body_details - type: event - brief: > - An event that adds global attributes for reuse. - body: - id: browser.test.event_with_body_details.fields - type: map - brief: A map of fields that are not referenced in the attributes - note: This map is not referenced in the attributes - stability: experimental - examples: [ '{ "some.field": "some value" }' ] - requirement_level: required - fields: - - id: some.field - type: string - brief: 'A field that is not referenced in the attributes' - note: 'This field is not referenced in the attributes' - examples: [ "some value", "another value" ] - requirement_level: optional \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml deleted file mode 100644 index 1c686939..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/client-exception-event.yaml +++ /dev/null @@ -1,46 +0,0 @@ -groups: - - id: client.exception.event - name: client.exception.event - type: event - brief: > - This document defines the log event used to - report a client exception. - body: - id: client.exception.event.fields - type: map - requirement_level: optional - fields: - - id: type - type: string - brief: > - The type of the exception. - examples: ["java.net.ConnectException","OSError"] - requirement_level: optional - - id: message - type: string - brief: The exception message. - examples: ["Division by zero","Can't convert 'int' object to str implicitly"] - requirement_level: optional - - id: stacktrace - type: string - brief: > - A stacktrace. - examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n - at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n - at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n - at com.example.GenerateTrace.main(GenerateTrace.java:5)' - requirement_level: optional - - id: escaped - type: boolean - brief: > - SHOULD be set to true if the exception event is recorded at a point where - it is known that the exception is escaping the scope of the span. - note: |- - An exception is considered to have escaped. - requirement_level: optional - attributes: - - id: client.name - type: string - brief: > - The name of the client that reported the exception. - examples: ["myclient"] \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/log-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/log-event.yaml deleted file mode 100644 index e2556e1b..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/log-event.yaml +++ /dev/null @@ -1,7 +0,0 @@ -groups: - - id: log_event_attributes_only - name: some.event - type: event - brief: brief - attributes: - - ref: log.event.attr diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/log-events.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/log-events.yaml new file mode 100644 index 00000000..b6966da7 --- /dev/null +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/log-events.yaml @@ -0,0 +1,248 @@ +groups: + - id: log_event_attributes_only + name: some.event + type: event + brief: brief + attributes: + - ref: test_attr.event.attr + + - id: log_event_empty + name: empty.event + type: event + brief: brief + + - id: log-feature_flag + type: event + prefix: feature_flag + brief: > + This document defines attributes for feature flag evaluations + represented using Log Records. + attributes: + - ref: feature_flag.key + - ref: feature_flag.provider_name + - ref: feature_flag.variant + + - id: some.string.body.event + stability: experimental + type: event + name: string.body.event + brief: > + This event represents an occurrence of a something. + note: > + This event transmits the body as a JSON encoded string. + body: + id: some.string.body.event.fields + type: string + requirement_level: required + brief: > + This is the body of the event which is a JSON encoded string. + examples: ['{"key1":"value1","key2":"value2"}'] + + - id: some.string.body.detailed.event + stability: experimental + type: event + name: string.body.event + brief: > + This event represents an occurrence of a something. + note: > + This event transmits the body as a JSON encoded string. + body: + id: some.string.body.event.fields + type: string + requirement_level: required + brief: > + This is the body of the event which is a JSON encoded string. + note: > + This is a detailed note about the body. + stability: experimental + examples: ['{"key1":"value1","key2":"value2"}'] + + - id: device.app.lifecycle + stability: experimental + type: event + name: device.app.lifecycle + brief: > + This event represents an occurrence of a lifecycle transition on Android or iOS platform. + note: > + This event identifies the fields that are common to all lifecycle events for android and iOS using + the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are + mutually exclusive. + body: + id: device.app.lifecycle.fields + type: map + requirement_level: required + fields: + - id: ios.state + stability: experimental + requirement_level: + conditionally_required: if and only if `os.name` is `ios` + note: > + The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), + and from which the `OS terminology` column values are derived. + brief: > + This attribute represents the state the application has transitioned into at the occurrence of the event. + type: enum + members: + - id: active + value: 'active' + brief: > + The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. + - id: inactive + value: 'inactive' + brief: > + The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. + - id: background + value: 'background' + brief: > + The app is now in the background. + This value is associated with UIKit notification `applicationDidEnterBackground`. + - id: foreground + value: 'foreground' + brief: > + The app is now in the foreground. + This value is associated with UIKit notification `applicationWillEnterForeground`. + - id: terminate + value: 'terminate' + brief: > + The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. + - id: android.state + stability: experimental + requirement_level: + conditionally_required: if and only if `os.name` is `android` + brief: > + This attribute represents the state the application has transitioned into at the occurrence of the event. + note: > + The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), + and from which the `OS identifiers` are derived. + type: enum + members: + - id: created + value: 'created' + 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. + - 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. + - 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. + - id: client.exception.event + name: client.exception.event + type: event + brief: > + This document defines the log event used to + report a client exception. + body: + id: client.exception.event.fields + type: map + requirement_level: optional + fields: + - id: type + type: string + brief: > + The type of the exception. + examples: ["java.net.ConnectException","OSError"] + requirement_level: optional + - id: message + type: string + brief: The exception message. + examples: ["Division by zero","Can't convert 'int' object to str implicitly"] + requirement_level: optional + - id: stacktrace + type: string + brief: > + A stacktrace. + examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n + at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n + at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n + at com.example.GenerateTrace.main(GenerateTrace.java:5)' + requirement_level: optional + - id: escaped + type: boolean + brief: > + SHOULD be set to true if the exception event is recorded at a point where + it is known that the exception is escaping the scope of the span. + note: |- + An exception is considered to have escaped. + requirement_level: optional + attributes: + - id: client.name + type: string + brief: > + The name of the client that reported the exception. + examples: ["myclient"] + - id: browser.test.event_with_fields + name: browser.test.event_with_fields + prefix: browser + type: event + brief: > + An event that adds global attributes for reuse. + attributes: + - id: brands + type: string[] + brief: 'Array of brand name and version separated by a space' + note: > + This value is intended to be taken from the + [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) + (`navigator.userAgentData.brands`). + examples: [ [ " Not A;Brand 99", "Chromium 99", "Chrome 99" ] ] + - id: platform + type: string + brief: 'The platform on which the browser is running' + note: > + This value is intended to be taken from the + [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) + (`navigator.userAgentData.platform`). + examples: [ "Windows", "macOS", "Android", "iOS", "Linux" ] + - id: mobile + type: boolean + brief: 'A boolean that is true if the browser is running on a mobile device' + note: > + This value is intended to be taken from the + [UA client hints API](https://wicg.github.io/ua-client-hints/#interface) + (`navigator.userAgentData.mobile`). If unavailable, this attribute + SHOULD be left unset. + - id: language + type: string + brief: 'Preferred language of the user using the browser' + note: > + This value is intended to be taken from the Navigator API + `navigator.language`. + examples: [ "en", "en-US", "en-AU", "fr", "fr-FR" ] + body: + id: browser.test.event_with_body.fields + type: map + requirement_level: required + fields: + - id: some.field + type: string + brief: 'A field that is not referenced in the attributes' + note: 'This field is not referenced in the attributes' + examples: [ "some value", "another value" ] + requirement_level: required + + - id: browser.test.event_with_body_details + name: browser.test.event_with_body_details + type: event + brief: > + An event that adds global attributes for reuse. + body: + id: browser.test.event_with_body_details.fields + type: map + brief: A map of fields that are not referenced in the attributes + note: This map is not referenced in the attributes + stability: experimental + examples: [ '{ "some.field": "some value" }' ] + requirement_level: required + fields: + - id: some.field + type: string + brief: 'A field that is not referenced in the attributes' + note: 'This field is not referenced in the attributes' + examples: [ "some value", "another value" ] + requirement_level: optional \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/log-feature_flag.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/log-feature_flag.yaml deleted file mode 100644 index 081125bf..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/log-feature_flag.yaml +++ /dev/null @@ -1,11 +0,0 @@ -groups: - - id: log-feature_flag - type: event - prefix: feature_flag - brief: > - This document defines attributes for feature flag evaluations - represented using Log Records. - attributes: - - ref: feature_flag.key - - ref: feature_flag.provider_name - - ref: feature_flag.variant \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml deleted file mode 100644 index ae6b3a55..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/mobile-events.yaml +++ /dev/null @@ -1,75 +0,0 @@ -groups: - - id: device.app.lifecycle - stability: experimental - type: event - name: device.app.lifecycle - brief: > - This event represents an occurrence of a lifecycle transition on Android or iOS platform. - note: > - This event identifies the fields that are common to all lifecycle events for android and iOS using - the `android.state` and `ios.state` fields. The `android.state` and `ios.state` attributes are - mutually exclusive. - body: - id: device.app.lifecycle.fields - type: map - requirement_level: required - fields: - - id: ios.state - stability: experimental - requirement_level: - conditionally_required: if and only if `os.name` is `ios` - note: > - The iOS lifecycle states are defined in the [UIApplicationDelegate documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902), - and from which the `OS terminology` column values are derived. - brief: > - This attribute represents the state the application has transitioned into at the occurrence of the event. - type: enum - members: - - id: active - value: 'active' - brief: > - The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`. - - id: inactive - value: 'inactive' - brief: > - The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`. - - id: background - value: 'background' - brief: > - The app is now in the background. - This value is associated with UIKit notification `applicationDidEnterBackground`. - - id: foreground - value: 'foreground' - brief: > - The app is now in the foreground. - This value is associated with UIKit notification `applicationWillEnterForeground`. - - id: terminate - value: 'terminate' - brief: > - The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`. - - id: android.state - stability: experimental - requirement_level: - conditionally_required: if and only if `os.name` is `android` - brief: > - This attribute represents the state the application has transitioned into at the occurrence of the event. - note: > - The Android lifecycle states are defined in [Activity lifecycle callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc), - and from which the `OS identifiers` are derived. - type: enum - members: - - id: created - value: 'created' - 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. - - 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. - - 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. \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/ping-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/ping-event.yaml deleted file mode 100644 index a9ea856e..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/ping-event.yaml +++ /dev/null @@ -1,5 +0,0 @@ -groups: - - id: log_event_empty - name: ping.event - type: event - brief: brief \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-attributes.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-attributes.yaml index 8dad8dd0..8662f9a3 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-attributes.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-attributes.yaml @@ -6,27 +6,77 @@ groups: brief: > These attributes are used as references for the test below attributes: - - id: browser.platform + - id: test_attr.platform stability: stable type: string brief: 'The browser platform' note: Test value. examples: ['Windows', 'macOS', 'Android'] - - id: http.url + - id: test_attr.http.url stability: stable type: string brief: 'The Url' note: Test url value. examples: ['https://example.com'] - - id: log.event.attr + - id: test_attr.event.attr stability: stable type: string brief: 'Just making sure the referenced attributes are defined' note: Test value. examples: some value - - id: session.id + - id: test_attr.session.id stability: stable type: string brief: 'The session id' note: Test value. examples: 127836abcdef98 + + - id: registry.client + prefix: client + type: attribute_group + brief: Client test attributes + attributes: + - id: address + stability: stable + type: string + brief: "Test Client address ...." + note: > + Test client address note + examples: ['client.example.com', '10.1.2.80', '/tmp/my.sock'] + - id: port + stability: stable + type: int + brief: Client port number. + examples: [65123] + note: Test client port + + - id: registry.exception + type: attribute_group + prefix: exception + brief: > + This document defines the shared attributes used to + report a single exception associated with a span or log. + attributes: + - id: type + type: string + stability: stable + brief: > + The type of the exception (its fully-qualified class name, if applicable). + examples: ["java.net.ConnectException", "OSError"] + - id: message + type: string + stability: stable + brief: The exception message. + examples: ["Division by zero", "Can't convert 'int' object to str implicitly"] + - id: stacktrace + type: string + stability: stable + brief: . + examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n' + - id: escaped + type: boolean + stability: stable + brief: > + SHOULD be set to true if the exception event is recorded at a point where + it is known that the exception is escaping the scope of the span. + diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-client.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-client.yaml deleted file mode 100644 index 3b17ed8b..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-client.yaml +++ /dev/null @@ -1,28 +0,0 @@ -groups: - - id: registry.client - prefix: client - type: attribute_group - brief: > - These attributes may be used to describe the client in a connection-based network interaction - where there is one side that initiates the connection (the client is the side that initiates the connection). - This covers all TCP network interactions since TCP is connection-based and one side initiates the - connection (an exception is made for peer-to-peer communication over TCP where the "user-facing" surface of the - protocol / API doesn't expose a clear notion of client and server). - This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS. - attributes: - - id: address - stability: stable - type: string - brief: "Client address - domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name." - note: > - When observed from the server side, and when communicating through an intermediary, `client.address` SHOULD represent - the client address behind any intermediaries, for example proxies, if it's available. - examples: ['client.example.com', '10.1.2.80', '/tmp/my.sock'] - - id: port - stability: stable - type: int - brief: Client port number. - examples: [65123] - note: > - When observed from the server side, and when communicating through an intermediary, `client.port` SHOULD represent - the client port behind any intermediaries, for example proxies, if it's available. diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-exception.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-exception.yaml deleted file mode 100644 index 3044fe69..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-exception.yaml +++ /dev/null @@ -1,55 +0,0 @@ -groups: - - id: registry.exception - type: attribute_group - prefix: exception - brief: > - This document defines the shared attributes used to - report a single exception associated with a span or log. - attributes: - - id: type - type: string - stability: stable - brief: > - The type of the exception (its fully-qualified class name, if applicable). - The dynamic type of the exception should be preferred over the static type - in languages that support it. - examples: ["java.net.ConnectException", "OSError"] - - id: message - type: string - stability: stable - brief: The exception message. - examples: ["Division by zero", "Can't convert 'int' object to str implicitly"] - - id: stacktrace - type: string - stability: stable - brief: > - A stacktrace as a string in the natural representation for the language runtime. - The representation is to be determined and documented by each language SIG. - examples: 'Exception in thread "main" java.lang.RuntimeException: Test exception\n - at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\n - at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\n - at com.example.GenerateTrace.main(GenerateTrace.java:5)' - - id: escaped - type: boolean - stability: stable - brief: > - SHOULD be set to true if the exception event is recorded at a point where - it is known that the exception is escaping the scope of the span. - note: |- - An exception is considered to have escaped (or left) the scope of a span, - if that span is ended while the exception is still logically "in flight". - This may be actually "in flight" in some languages (e.g. if the exception - is passed to a Context manager's `__exit__` method in Python) but will - usually be caught at the point of recording the exception in most languages. - - It is usually not possible to determine at the point where an exception is thrown - whether it will escape the scope of a span. - However, it is trivial to know that an exception - will escape, if one checks for an active exception just before ending the span, - as done in the [example for recording span exceptions](https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-spans/#recording-an-exception). - - It follows that an exception may still escape the scope of the span - even if the `exception.escaped` attribute was not set or set to false, - since the event might have been recorded at a time where it was not - clear whether the exception will escape. - diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-gen_ai.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-gen_ai.yaml deleted file mode 100644 index d05e09ea..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-gen_ai.yaml +++ /dev/null @@ -1,148 +0,0 @@ -groups: - - id: registry.gen_ai - prefix: gen_ai - type: attribute_group - brief: > - This document defines the attributes used to describe telemetry in the context of Generative Artificial Intelligence (GenAI) Models requests and responses. - attributes: - - id: system - stability: experimental - type: - members: - - id: openai - stability: experimental - value: "openai" - brief: 'OpenAI' - - id: vertex_ai - stability: experimental - value: "vertex_ai" - brief: 'Vertex AI' - - id: anthropic - stability: experimental - value: "anthropic" - brief: 'Anthropic' - - id: cohere - stability: experimental - value: "cohere" - brief: 'Cohere' - brief: The Generative AI product as identified by the client or server instrumentation. - note: | - The `gen_ai.system` describes a family of GenAI models with specific model identified - by `gen_ai.request.model` and `gen_ai.response.model` attributes. - - The actual GenAI product may differ from the one identified by the client. - For example, when using OpenAI client libraries to communicate with Mistral, the `gen_ai.system` - is set to `openai` based on the instrumentation's best knowledge. - - For custom model, a custom friendly name SHOULD be used. - If none of these options apply, the `gen_ai.system` SHOULD be set to `_OTHER`. - examples: 'openai' - - id: request.model - stability: experimental - type: string - brief: The name of the GenAI model a request is being made to. - examples: 'gpt-4' - - id: request.max_tokens - stability: experimental - type: int - brief: The maximum number of tokens the model generates for a request. - examples: [100] - - id: request.temperature - stability: experimental - type: double - brief: The temperature setting for the GenAI request. - examples: [0.0] - - id: request.top_p - stability: experimental - type: double - brief: The top_p sampling setting for the GenAI request. - examples: [1.0] - tag: llm-generic-request - - id: request.top_k - stability: experimental - type: double - brief: The top_k sampling setting for the GenAI request. - examples: [1.0] - - id: request.stop_sequences - stability: experimental - type: string[] - brief: List of sequences that the model will use to stop generating further tokens. - examples: [ [ 'forest', 'lived' ]] - - id: request.frequency_penalty - stability: experimental - type: double - brief: The frequency penalty setting for the GenAI request. - examples: [0.1] - - id: request.presence_penalty - stability: experimental - type: double - brief: The presence penalty setting for the GenAI request. - examples: [0.1] - - id: response.id - stability: experimental - type: string - brief: The unique identifier for the completion. - examples: ['chatcmpl-123'] - - id: response.model - stability: experimental - type: string - brief: The name of the model that generated the response. - examples: ['gpt-4-0613'] - - id: response.finish_reasons - stability: experimental - type: string[] - brief: Array of reasons the model stopped generating tokens, corresponding to each generation received. - examples: [ [ 'stop' ] ] - - id: usage.input_tokens - stability: experimental - type: int - brief: The number of tokens used in the GenAI input (prompt). - examples: [100] - - id: usage.output_tokens - stability: experimental - type: int - brief: The number of tokens used in the GenAI response (completion). - examples: [180] - - id: token.type - stability: experimental - type: - members: - - id: input - stability: experimental - value: "input" - brief: 'Input tokens (prompt, input, etc.)' - - id: completion - stability: experimental - value: "output" - brief: 'Output tokens (completion, response, etc.)' - brief: The type of token being counted. - examples: ['input', 'output'] - - id: prompt - stability: experimental - type: string - brief: The full prompt sent to the GenAI model. - note: It's RECOMMENDED to format prompts as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation) - examples: ["[{'role': 'user', 'content': 'What is the capital of France?'}]"] - - id: completion - stability: experimental - type: string - brief: The full response received from the GenAI model. - note: It's RECOMMENDED to format completions as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation) - examples: ["[{'role': 'assistant', 'content': 'The capital of France is Paris.'}]"] - - id: operation.name - stability: experimental - type: - members: - - id: chat - value: "chat" - brief: 'Chat completion operation such as [OpenAI Chat API](https://platform.openai.com/docs/api-reference/chat)' - stability: experimental - - id: text_completion - value: "text_completion" - brief: 'Text completions operation such as [OpenAI Completions API (Legacy)](https://platform.openai.com/docs/api-reference/completions)' - stability: experimental - brief: The name of the operation being performed. - note: > - If one of the predefined values applies, but specific system uses a different name it's RECOMMENDED to document it in the semantic - conventions for specific GenAI system and use system-specific name in the instrumentation. - If a different name is not documented, instrumentation libraries SHOULD use applicable predefined value. diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-network.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-network.yaml deleted file mode 100644 index 2f3f1957..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-network.yaml +++ /dev/null @@ -1,235 +0,0 @@ -groups: - - id: registry.network - prefix: network - type: attribute_group - brief: > - These attributes may be used for any network related operation. - attributes: - - id: carrier.icc - type: string - stability: experimental - brief: "The ISO 3166-1 alpha-2 2-character country code associated with the mobile carrier network." - examples: "DE" - - id: carrier.mcc - type: string - stability: experimental - brief: "The mobile carrier country code." - examples: "310" - - id: carrier.mnc - type: string - stability: experimental - brief: "The mobile carrier network code." - examples: "001" - - id: carrier.name - type: string - stability: experimental - brief: "The name of the mobile carrier." - examples: "sprint" - - id: connection.subtype - type: - allow_custom_values: true - members: - - id: gprs - brief: GPRS - value: "gprs" - stability: experimental - - id: edge - brief: EDGE - value: "edge" - stability: experimental - - id: umts - brief: UMTS - value: "umts" - stability: experimental - - id: cdma - brief: CDMA - value: "cdma" - stability: experimental - - id: evdo_0 - brief: EVDO Rel. 0 - value: "evdo_0" - stability: experimental - - id: evdo_a - brief: "EVDO Rev. A" - value: "evdo_a" - stability: experimental - - id: cdma2000_1xrtt - brief: CDMA2000 1XRTT - value: "cdma2000_1xrtt" - stability: experimental - - id: hsdpa - brief: HSDPA - value: "hsdpa" - stability: experimental - - id: hsupa - brief: HSUPA - value: "hsupa" - stability: experimental - - id: hspa - brief: HSPA - value: "hspa" - stability: experimental - - id: iden - brief: IDEN - value: "iden" - stability: experimental - - id: evdo_b - brief: "EVDO Rev. B" - value: "evdo_b" - stability: experimental - - id: lte - brief: LTE - value: "lte" - stability: experimental - - id: ehrpd - brief: EHRPD - value: "ehrpd" - stability: experimental - - id: hspap - brief: HSPAP - value: "hspap" - stability: experimental - - id: gsm - brief: GSM - value: "gsm" - stability: experimental - - id: td_scdma - brief: TD-SCDMA - value: "td_scdma" - stability: experimental - - id: iwlan - brief: IWLAN - value: "iwlan" - stability: experimental - - id: nr - brief: "5G NR (New Radio)" - value: "nr" - stability: experimental - - id: nrnsa - brief: "5G NRNSA (New Radio Non-Standalone)" - value: "nrnsa" - stability: experimental - - id: lte_ca - brief: LTE CA - value: "lte_ca" - stability: experimental - stability: experimental - brief: 'This describes more details regarding the connection.type. It may be the type of cell technology connection, but it could be used for describing details about a wifi connection.' - examples: 'LTE' - - id: connection.type - type: - allow_custom_values: true - members: - - id: wifi - value: "wifi" - stability: experimental - - id: wired - value: "wired" - stability: experimental - - id: cell - value: "cell" - stability: experimental - - id: unavailable - value: "unavailable" - stability: experimental - - id: unknown - value: "unknown" - stability: experimental - stability: experimental - brief: 'The internet connection type.' - examples: 'wifi' - - id: local.address - stability: stable - type: string - brief: Local address of the network connection - IP address or Unix domain socket name. - examples: ['10.1.2.80', '/tmp/my.sock'] - - id: local.port - stability: stable - type: int - brief: Local port number of the network connection. - examples: [65123] - - id: peer.address - stability: stable - type: string - brief: Peer address of the network connection - IP address or Unix domain socket name. - examples: ['10.1.2.80', '/tmp/my.sock'] - - id: peer.port - stability: stable - type: int - brief: Peer port number of the network connection. - examples: [65123] - - id: protocol.name - stability: stable - type: string - brief: '[OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent.' - note: The value SHOULD be normalized to lowercase. - examples: ['amqp', 'http', 'mqtt'] - - id: protocol.version - stability: stable - type: string - brief: The actual version of the protocol used for network communication. - examples: ['1.1', '2'] - note: > - If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), - this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, - this attribute SHOULD NOT be set. - - id: transport - stability: stable - type: - allow_custom_values: true - members: - - id: tcp - value: 'tcp' - brief: "TCP" - stability: stable - - id: udp - value: 'udp' - brief: "UDP" - stability: stable - - id: pipe - value: "pipe" - brief: 'Named or anonymous pipe.' - stability: stable - - id: unix - value: 'unix' - brief: "Unix domain socket" - stability: stable - brief: > - [OSI transport layer](https://osi-model.com/transport-layer/) or - [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). - note: | - The value SHOULD be normalized to lowercase. - - Consider always setting the transport when setting a port number, since - a port number is ambiguous without knowing the transport. For example - different processes could be listening on TCP port 12345 and UDP port 12345. - examples: ['tcp', 'udp'] - - id: type - stability: stable - type: - allow_custom_values: true - members: - - id: ipv4 - value: 'ipv4' - brief: "IPv4" - stability: stable - - id: ipv6 - value: 'ipv6' - brief: "IPv6" - stability: stable - brief: '[OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent.' - note: The value SHOULD be normalized to lowercase. - examples: ['ipv4', 'ipv6'] - - id: io.direction - type: - allow_custom_values: false - members: - - id: transmit - value: 'transmit' - stability: experimental - - id: receive - value: 'receive' - stability: experimental - stability: experimental - brief: "The network IO operation direction." - examples: ["transmit"] diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-rpc.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-rpc.yaml deleted file mode 100644 index d1e0aa05..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-rpc.yaml +++ /dev/null @@ -1,265 +0,0 @@ -groups: - - id: registry.rpc - prefix: rpc - type: attribute_group - brief: 'This document defines attributes for remote procedure calls.' - attributes: - - id: connect_rpc.error_code - type: - members: - - id: cancelled - value: cancelled - stability: experimental - - id: unknown - value: unknown - stability: experimental - - id: invalid_argument - value: invalid_argument - stability: experimental - - id: deadline_exceeded - value: deadline_exceeded - stability: experimental - - id: not_found - value: not_found - stability: experimental - - id: already_exists - value: already_exists - stability: experimental - - id: permission_denied - value: permission_denied - stability: experimental - - id: resource_exhausted - value: resource_exhausted - stability: experimental - - id: failed_precondition - value: failed_precondition - stability: experimental - - id: aborted - value: aborted - stability: experimental - - id: out_of_range - value: out_of_range - stability: experimental - - id: unimplemented - value: unimplemented - stability: experimental - - id: internal - value: internal - stability: experimental - - id: unavailable - value: unavailable - stability: experimental - - id: data_loss - value: data_loss - stability: experimental - - id: unauthenticated - value: unauthenticated - stability: experimental - stability: experimental - brief: "The [error codes](https://connect.build/docs/protocol/#error-codes) of the Connect request. Error codes are always string values." - - id: connect_rpc.request.metadata - type: template[string[]] - stability: experimental - brief: > - Connect request metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values. - note: > - Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. - Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information. - examples: ['rpc.request.metadata.my-custom-metadata-attribute=["1.2.3.4", "1.2.3.5"]'] - - id: connect_rpc.response.metadata - type: template[string[]] - stability: experimental - brief: > - Connect response metadata, `` being the normalized Connect Metadata key (lowercase), the value being the metadata values. - note: > - Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. - Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information. - examples: ['rpc.response.metadata.my-custom-metadata-attribute=["attribute_value"]'] - - id: grpc.status_code - type: - members: - - id: ok - brief: OK - stability: experimental - value: 0 - - id: cancelled - brief: CANCELLED - stability: experimental - value: 1 - - id: unknown - brief: UNKNOWN - stability: experimental - value: 2 - - id: invalid_argument - brief: INVALID_ARGUMENT - stability: experimental - value: 3 - - id: deadline_exceeded - brief: DEADLINE_EXCEEDED - stability: experimental - value: 4 - - id: not_found - brief: NOT_FOUND - stability: experimental - value: 5 - - id: already_exists - brief: ALREADY_EXISTS - stability: experimental - value: 6 - - id: permission_denied - brief: PERMISSION_DENIED - stability: experimental - value: 7 - - id: resource_exhausted - brief: RESOURCE_EXHAUSTED - stability: experimental - value: 8 - - id: failed_precondition - brief: FAILED_PRECONDITION - stability: experimental - value: 9 - - id: aborted - brief: ABORTED - stability: experimental - value: 10 - - id: out_of_range - brief: OUT_OF_RANGE - stability: experimental - value: 11 - - id: unimplemented - brief: UNIMPLEMENTED - stability: experimental - value: 12 - - id: internal - brief: INTERNAL - stability: experimental - value: 13 - - id: unavailable - brief: UNAVAILABLE - stability: experimental - value: 14 - - id: data_loss - brief: DATA_LOSS - stability: experimental - value: 15 - - id: unauthenticated - brief: UNAUTHENTICATED - stability: experimental - value: 16 - stability: experimental - brief: "The [numeric status code](https://github.com/grpc/grpc/blob/v1.33.2/doc/statuscodes.md) of the gRPC request." - - id: grpc.request.metadata - type: template[string[]] - stability: experimental - brief: > - gRPC request metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values. - note: > - Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. - Including all request metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information. - examples: ['rpc.grpc.request.metadata.my-custom-metadata-attribute=["1.2.3.4", "1.2.3.5"]'] - - id: grpc.response.metadata - type: template[string[]] - stability: experimental - brief: > - gRPC response metadata, `` being the normalized gRPC Metadata key (lowercase), the value being the metadata values. - note: > - Instrumentations SHOULD require an explicit configuration of which metadata values are to be captured. - Including all response metadata values can be a security risk - explicit configuration helps avoid leaking sensitive information. - examples: ['rpc.grpc.response.metadata.my-custom-metadata-attribute=["attribute_value"]'] - - id: jsonrpc.error_code - type: int - stability: experimental - brief: "`error.code` property of response if it is an error response." - examples: [-32700, 100] - - id: jsonrpc.error_message - type: string - stability: experimental - brief: "`error.message` property of response if it is an error response." - examples: ['Parse error', 'User already exists'] - - id: jsonrpc.request_id - type: string - stability: experimental - brief: > - `id` property of request or response. - Since protocol allows id to be int, string, `null` or missing (for notifications), - value is expected to be cast to string for simplicity. - Use empty string in case of `null` value. Omit entirely if this is a notification. - examples: ['10', 'request-7', ''] - - id: jsonrpc.version - type: string - stability: experimental - brief: "Protocol version as in `jsonrpc` property of request/response. Since JSON-RPC 1.0 doesn't specify this, the value can be omitted." - examples: ['2.0', '1.0'] - - id: method - type: string - stability: experimental - brief: 'The name of the (logical) method being called, must be equal to the $method part in the span name.' - note: > - This is the logical name of the method from the RPC interface perspective, - which can be different from the name of any implementing method/function. - The `code.function` attribute may be used to store the latter - (e.g., method actually executing the call on the server side, - RPC client stub method on the client side). - examples: "exampleMethod" - - id: service - type: string - stability: experimental - brief: 'The full (logical) name of the service being called, including its package name, if applicable.' - note: > - This is the logical name of the service from the RPC interface perspective, - which can be different from the name of any implementing class. - The `code.namespace` attribute may be used to store the latter - (despite the attribute name, it may include a class name; - e.g., class with method actually executing the call on the server side, - RPC client stub class on the client side). - examples: "myservice.EchoService" - - id: system - brief: 'A string identifying the remoting system. See below for a list of well-known identifiers.' - type: - allow_custom_values: true - members: - - id: grpc - value: 'grpc' - brief: 'gRPC' - stability: experimental - - id: java_rmi - value: 'java_rmi' - brief: 'Java RMI' - stability: experimental - - id: dotnet_wcf - value: 'dotnet_wcf' - brief: '.NET WCF' - stability: experimental - - id: apache_dubbo - value: 'apache_dubbo' - brief: 'Apache Dubbo' - stability: experimental - - id: connect_rpc - value: 'connect_rpc' - brief: 'Connect RPC' - stability: experimental - stability: experimental - - id: message.type - type: - members: - - id: sent - value: "SENT" - stability: experimental - - id: received - value: "RECEIVED" - stability: experimental - stability: experimental - brief: "Whether this is a received or sent message." - - id: message.id - type: int - stability: experimental - brief: "MUST be calculated as two different counters starting from `1` one for sent messages and one for received message." - note: "This way we guarantee that the values will be consistent between different implementations." - - id: message.compressed_size - type: int - stability: experimental - brief: "Compressed size of the message in bytes." - - id: message.uncompressed_size - type: int - stability: experimental - brief: "Uncompressed size of the message in bytes." diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-server.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-server.yaml deleted file mode 100644 index d6927fe9..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/referenced-server.yaml +++ /dev/null @@ -1,28 +0,0 @@ -groups: - - id: registry.server - prefix: server - type: attribute_group - brief: > - These attributes may be used to describe the server in a connection-based network interaction - where there is one side that initiates the connection (the client is the side that initiates the connection). - This covers all TCP network interactions since TCP is connection-based and one side initiates the - connection (an exception is made for peer-to-peer communication over TCP where the "user-facing" surface of the - protocol / API doesn't expose a clear notion of client and server). - This also covers UDP network interactions where one side initiates the interaction, e.g. QUIC (HTTP/3) and DNS. - attributes: - - id: address - stability: stable - type: string - brief: "Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name." - note: > - When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent - the server address behind any intermediaries, for example proxies, if it's available. - examples: ['example.com', '10.1.2.80', '/tmp/my.sock'] - - id: port - stability: stable - type: int - brief: Server port number. - note: > - When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent - the server port behind any intermediaries, for example proxies, if it's available. - examples: [80, 8080, 443] diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml deleted file mode 100644 index 4cfdf06a..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/stringbody-event.yaml +++ /dev/null @@ -1,35 +0,0 @@ -groups: - - id: some.string.body.event - stability: experimental - type: event - name: string.body.event - brief: > - This event represents an occurrence of a something. - note: > - This event transmits the body as a JSON encoded string. - body: - id: some.string.body.event.fields - type: string - requirement_level: required - brief: > - This is the body of the event which is a JSON encoded string. - examples: ['{"key1":"value1","key2":"value2"}'] - - - id: some.string.body.detailed.event - stability: experimental - type: event - name: string.body.event - brief: > - This event represents an occurrence of a something. - note: > - This event transmits the body as a JSON encoded string. - body: - id: some.string.body.event.fields - type: string - requirement_level: required - brief: > - This is the body of the event which is a JSON encoded string. - note: > - This is a detailed note about the body. - stability: experimental - examples: ['{"key1":"value1","key2":"value2"}'] \ No newline at end of file diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-feature-flag.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-events.yaml similarity index 51% rename from crates/weaver_resolver/data/registry-test-4-events/registry/trace-feature-flag.yaml rename to crates/weaver_resolver/data/registry-test-4-events/registry/trace-events.yaml index fa4c8816..08c8cb13 100644 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-feature-flag.yaml +++ b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-events.yaml @@ -1,4 +1,20 @@ groups: + - id: trace-exception + prefix: exception + type: event + brief: > + This document defines the attributes used to + report a single exception associated with a span. + attributes: + - ref: exception.type + requirement_level: + conditionally_required: Required if `exception.message` is not set, recommended otherwise. + - ref: exception.message + requirement_level: + conditionally_required: Required if `exception.type` is not set, recommended otherwise. + - ref: exception.stacktrace + - ref: exception.escaped + - id: feature_flag prefix: feature_flag type: event @@ -31,4 +47,28 @@ groups: A stringified version of the value can be used in situations where a semantic identifier is unavailable. String representation of the value - should be determined by the implementer. \ No newline at end of file + should be determined by the implementer. + + - id: test_evt.with_attr + name: test_evt.with_attr + type: event + brief: > + Simple example span event with an attribute + attributes: + - ref: test_attr.event.attr + requirement_level: + conditionally_required: if and only if corresponding event is enabled + note: > + test attribute + + - id: test_evt.session + name: test_evt.session + type: event + brief: > + Another simple span event with another attribute + attributes: + - ref: test_attr.session.id + requirement_level: + conditionally_required: if and only if corresponding event is enabled + note: > + Another test attribute diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-exception.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-exception.yaml deleted file mode 100644 index 32c53f4b..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-exception.yaml +++ /dev/null @@ -1,16 +0,0 @@ -groups: - - id: trace-exception - prefix: exception - type: event - brief: > - This document defines the attributes used to - report a single exception associated with a span. - attributes: - - ref: exception.type - requirement_level: - conditionally_required: Required if `exception.message` is not set, recommended otherwise. - - ref: exception.message - requirement_level: - conditionally_required: Required if `exception.type` is not set, recommended otherwise. - - ref: exception.stacktrace - - ref: exception.escaped diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-gen-ai.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-gen-ai.yaml deleted file mode 100644 index d036c197..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-gen-ai.yaml +++ /dev/null @@ -1,73 +0,0 @@ -groups: - - id: trace.gen_ai.client - type: span - brief: > - Describes GenAI operation span. - attributes: - - ref: gen_ai.system - requirement_level: required - - ref: gen_ai.request.model - requirement_level: required - note: > - The name of the GenAI model a request is being made to. If the model is supplied by a vendor, - then the value must be the exact name of the model requested. If the model is a fine-tuned - custom model, the value should have a more specific name than the base model that's been fine-tuned. - - ref: gen_ai.operation.name - requirement_level: required - - ref: gen_ai.request.max_tokens - requirement_level: recommended - - ref: gen_ai.request.temperature - requirement_level: recommended - - ref: gen_ai.request.top_p - requirement_level: recommended - - ref: gen_ai.request.top_k - requirement_level: recommended - - ref: gen_ai.request.stop_sequences - requirement_level: recommended - - ref: gen_ai.request.frequency_penalty - requirement_level: recommended - - ref: gen_ai.request.presence_penalty - requirement_level: recommended - - ref: gen_ai.response.id - requirement_level: recommended - - ref: gen_ai.response.model - requirement_level: recommended - note: > - If available. The name of the GenAI model that provided the response. If the model is supplied by a vendor, - then the value must be the exact name of the model actually used. If the model is a - fine-tuned custom model, the value should have a more specific name than the base model that's been fine-tuned. - - ref: gen_ai.response.finish_reasons - requirement_level: recommended - - ref: gen_ai.usage.input_tokens - requirement_level: recommended - - ref: gen_ai.usage.output_tokens - requirement_level: recommended - events: - - gen_ai.content.prompt - - gen_ai.content.completion - - - id: gen_ai.content.prompt - name: gen_ai.content.prompt - type: event - brief: > - In the lifetime of an GenAI span, events for prompts sent and completions received - may be created, depending on the configuration of the instrumentation. - attributes: - - ref: gen_ai.prompt - requirement_level: - conditionally_required: if and only if corresponding event is enabled - note: > - It's RECOMMENDED to format prompts as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation) - - - id: gen_ai.content.completion - name: gen_ai.content.completion - type: event - brief: > - In the lifetime of an GenAI span, events for prompts sent and completions received - may be created, depending on the configuration of the instrumentation. - attributes: - - ref: gen_ai.completion - requirement_level: - conditionally_required: if and only if corresponding event is enabled - note: > - It's RECOMMENDED to format completions as JSON string matching [OpenAI messages format](https://platform.openai.com/docs/guides/text-generation) diff --git a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-rpc.yaml b/crates/weaver_resolver/data/registry-test-4-events/registry/trace-rpc.yaml deleted file mode 100644 index d578c6ba..00000000 --- a/crates/weaver_resolver/data/registry-test-4-events/registry/trace-rpc.yaml +++ /dev/null @@ -1,131 +0,0 @@ -groups: - - id: rpc - prefix: rpc - type: span - brief: 'This document defines semantic conventions for remote procedure calls.' - events: [rpc.message] - attributes: - - ref: rpc.system - requirement_level: required - - ref: rpc.service - requirement_level: recommended - - ref: rpc.method - requirement_level: recommended - - ref: network.transport - requirement_level: recommended - - ref: network.type - requirement_level: recommended - - ref: server.address - requirement_level: required - brief: > - RPC server [host name](https://grpc.github.io/grpc/core/md_doc_naming.html). - note: > - May contain server IP address, DNS name, or local socket name. When host component is an IP address, - instrumentations SHOULD NOT do a reverse proxy lookup to obtain DNS name and SHOULD set - `server.address` to the IP address provided in the host component. - - ref: server.port - requirement_level: - conditionally_required: if the port is supported by the network transport used for communication. - - - id: rpc.client - type: span - brief: 'This document defines semantic conventions for remote procedure call client spans.' - extends: rpc - attributes: - - ref: network.peer.address - requirement_level: recommended - - ref: network.peer.port - requirement_level: - recommended: If `network.peer.address` is set. - - - id: rpc.server - type: span - extends: rpc - span_kind: server - brief: 'Semantic Convention for RPC server spans' - attributes: - - ref: client.address - requirement_level: recommended - - ref: client.port - requirement_level: recommended - - ref: network.peer.address - requirement_level: recommended - - ref: network.peer.port - requirement_level: - recommended: If `network.peer.address` is set. - - ref: network.transport - requirement_level: recommended - - ref: network.type - requirement_level: recommended - - - id: rpc.grpc - type: span - extends: rpc - brief: 'Tech-specific attributes for gRPC.' - attributes: - - ref: rpc.grpc.status_code - tag: grpc-tech-specific - requirement_level: required - - ref: rpc.grpc.request.metadata - tag: grpc-tech-specific - requirement_level: opt_in - - ref: rpc.grpc.response.metadata - tag: grpc-tech-specific - requirement_level: opt_in - - - id: rpc.jsonrpc - prefix: rpc.jsonrpc - type: span - extends: rpc - brief: 'Tech-specific attributes for [JSON RPC](https://www.jsonrpc.org/).' - attributes: - - ref: rpc.jsonrpc.version - tag: jsonrpc-tech-specific - requirement_level: - conditionally_required: If other than the default version (`1.0`) - - ref: rpc.jsonrpc.request_id - tag: jsonrpc-tech-specific - requirement_level: recommended - - ref: rpc.jsonrpc.error_code - tag: jsonrpc-tech-specific - requirement_level: - conditionally_required: If response is not successful. - - ref: rpc.jsonrpc.error_message - tag: jsonrpc-tech-specific - requirement_level: recommended - - ref: rpc.method - tag: jsonrpc-tech-specific - requirement_level: required - note: > - This is always required for jsonrpc. See the note in the general - RPC conventions for more information. - - - id: rpc.message - prefix: rpc.message - type: event - brief: "RPC received/sent message." - attributes: - - ref: rpc.message.type - requirement_level: recommended - - ref: rpc.message.id - requirement_level: recommended - - ref: rpc.message.compressed_size - requirement_level: recommended - - ref: rpc.message.uncompressed_size - requirement_level: recommended - - - id: rpc.connect_rpc - type: span - extends: rpc - brief: 'Tech-specific attributes for Connect RPC.' - attributes: - - ref: rpc.connect_rpc.error_code - tag: connect_rpc-tech-specific - requirement_level: - conditionally_required: If response is not successful and if error code available. - - ref: rpc.connect_rpc.request.metadata - tag: connect_rpc-tech-specific - requirement_level: opt_in - - ref: rpc.connect_rpc.response.metadata - tag: connect_rpc-tech-specific - requirement_level: opt_in diff --git a/crates/weaver_resolver/src/any_value.rs b/crates/weaver_resolver/src/any_value.rs deleted file mode 100644 index 86a751f5..00000000 --- a/crates/weaver_resolver/src/any_value.rs +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Functions to resolve a semantic convention body. - -use weaver_resolved_schema::any_value::AnyValue; -use weaver_semconv::{any_value::AnyValueSpec, attribute::EnumEntriesSpec}; - -/// Resolve a `Body` specification into a resolved `Body`. -#[must_use] -pub fn resolve_any_value_spec(value: &AnyValueSpec) -> AnyValue { - match value { - AnyValueSpec::Map { fields, .. } => { - let resolved_fields: Vec = - fields.iter().map(resolve_any_value_spec).collect(); - - construct_any_value_common(value, Some(resolved_fields), None) - } - AnyValueSpec::Enum { members, .. } => { - construct_any_value_common(value, None, Some(members.to_vec())) - } - _ => construct_any_value_common(value, None, None), - } -} - -/// Construct an AnyValue with common fields. -fn construct_any_value_common( - value: &AnyValueSpec, - resolved_fields: Option>, - members: Option>, -) -> AnyValue { - let common = value.common(); - - AnyValue { - name: value.id(), - r#type: value.to_string(), - brief: value.brief(), - note: value.note(), - stability: common.stability.clone(), - examples: common.examples.clone(), - fields: resolved_fields, - requirement_level: common.requirement_level.clone(), - members, - } -} diff --git a/crates/weaver_resolver/src/lib.rs b/crates/weaver_resolver/src/lib.rs index 40b1a545..34b69e4f 100644 --- a/crates/weaver_resolver/src/lib.rs +++ b/crates/weaver_resolver/src/lib.rs @@ -25,7 +25,6 @@ use weaver_semconv::semconv::SemConvSpec; use crate::attribute::AttributeCatalog; use crate::registry::resolve_semconv_registry; -pub mod any_value; pub mod attribute; mod constraint; pub mod registry; diff --git a/crates/weaver_resolver/src/registry.rs b/crates/weaver_resolver/src/registry.rs index 53d95e1a..8ea341c4 100644 --- a/crates/weaver_resolver/src/registry.rs +++ b/crates/weaver_resolver/src/registry.rs @@ -14,7 +14,6 @@ use weaver_semconv::attribute::AttributeSpec; use weaver_semconv::group::GroupSpecWithProvenance; use weaver_semconv::registry::SemConvRegistry; -use crate::any_value::resolve_any_value_spec; use crate::attribute::AttributeCatalog; use crate::constraint::resolve_constraints; use crate::{Error, UnsatisfiedAnyOfConstraint}; @@ -331,7 +330,7 @@ fn group_from_spec(group: GroupSpecWithProvenance) -> UnresolvedGroup { name: group.spec.name, lineage: Some(GroupLineage::new(&group.provenance)), display_name: group.spec.display_name, - body: group.spec.body.map(|body| resolve_any_value_spec(&body)), + body: group.spec.body, }, attributes: attrs, provenance: group.provenance, diff --git a/crates/weaver_semconv/src/group.rs b/crates/weaver_semconv/src/group.rs index ffe02fca..d0b64684 100644 --- a/crates/weaver_semconv/src/group.rs +++ b/crates/weaver_semconv/src/group.rs @@ -263,41 +263,33 @@ fn validate_any_value_examples( path_or_url: &str, ) -> WResult<(), Error> { if let Some(value) = any_value { - let common_examples = &value.common().examples; - if let Some(examples) = common_examples { + if let Some(examples) = &value.common().examples { match examples.validate_any_value(value, group_id, path_or_url) { WResult::Ok(_) => {} WResult::OkWithNFEs(_, errs) => errors.extend(errs), WResult::FatalErr(err) => return WResult::FatalErr(err), } } else { - // No examples are set. match value { - AnyValueSpec::String { .. } => { - // string values must have examples. + AnyValueSpec::String { .. } | AnyValueSpec::Strings { .. } => { errors.push(Error::InvalidAnyValueExampleError { path_or_url: path_or_url.to_owned(), group_id: group_id.to_owned(), value_id: value.id(), - error: "This value is a string but it does not contain any examples." - .to_owned(), - }); - } - AnyValueSpec::Strings { .. } => { - // string array attributes must have examples. - errors.push(Error::InvalidAnyValueExampleError { - path_or_url: path_or_url.to_owned(), - group_id: group_id.to_owned(), - value_id: value.id(), - error: "This value is a string array but it does not contain any examples." - .to_owned(), + error: format!( + "This value is a {} but it does not contain any examples.", + if let AnyValueSpec::String { .. } = value { + "string" + } else { + "string array" + } + ), }); } _ => {} } } - // Recursively validate the examples for the fields. if let AnyValueSpec::Map { fields, .. } = value { for field in fields { if let WResult::FatalErr(err) = From a6ac3c1893f373fa8f3ad07fad091a499673e5dd Mon Sep 17 00:00:00 2001 From: Nev Wylie <54870357+MSNev@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:33:53 -0700 Subject: [PATCH 8/8] remove UnresolvedBody error and update ChangeLog.md --- CHANGELOG.md | 1 + crates/weaver_resolver/src/lib.rs | 11 ----------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c7af8d3..6edd1e38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ What's changed * Add `enforce_trailing_dots` into the `comment_formats` configuration. ([#XXX](...) by lquerel). * Add support for `indent_type` in both the comment filter and the `comment_formats` configuration. ([#XXX](...) by lquerel). * Add `regex_replace` filter to support replacing text using regex. ([#XXX](...) by lquerel). +* Add support log based `event` definitions with a `body` of new `AnyValue` type. ([#XXX](...) by MSNev). ## [0.9.2] - 2024-09-09 diff --git a/crates/weaver_resolver/src/lib.rs b/crates/weaver_resolver/src/lib.rs index 34b69e4f..5ce6e280 100644 --- a/crates/weaver_resolver/src/lib.rs +++ b/crates/weaver_resolver/src/lib.rs @@ -145,17 +145,6 @@ pub enum Error { /// A container for multiple errors. #[error("{:?}", format_errors(.0))] CompoundError(#[related] Vec), - - /// An error indicating that the Body references are not resolved. - #[error("The following body reference is not resolved.\nBody reference: {group_id}\nProvenance: {provenance}\nError: {error}")] - UnresolvedBody { - /// The unresolved body reference. - group_id: String, - /// The provenance of the reference (URL or path). - provenance: String, - /// The errors that occurred. - error: weaver_resolved_schema::error::Error, - }, } impl WeaverError for Error {