From fdb84e233d28621e11b5770c8c68e60efd0682b8 Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Wed, 12 Apr 2023 11:19:59 +1000 Subject: [PATCH 1/7] update semantic conventions to v1.19 --- script/semantic-conventions/semconv.sh | 25 +- src/SemConv/ResourceAttributeValues.php | 37 +- src/SemConv/ResourceAttributes.php | 144 +++-- src/SemConv/TraceAttributeValues.php | 253 +++++++-- src/SemConv/TraceAttributes.php | 716 ++++++++++++++++-------- 5 files changed, 847 insertions(+), 328 deletions(-) diff --git a/script/semantic-conventions/semconv.sh b/script/semantic-conventions/semconv.sh index 8058b0e66..731154122 100755 --- a/script/semantic-conventions/semconv.sh +++ b/script/semantic-conventions/semconv.sh @@ -12,10 +12,10 @@ SPEC_DIR="${ROOT_DIR}/var/opentelemetry-specification" CODE_DIR="${ROOT_DIR}/src/SemConv" # freeze the spec & generator tools versions to make SemanticAttributes generation reproducible -SEMCONV_VERSION=${SEMCONV_VERSION:=1.12.0} +SEMCONV_VERSION=${SEMCONV_VERSION:=1.19.0} SPEC_VERSION=v$SEMCONV_VERSION SCHEMA_URL=https://opentelemetry.io/schemas/$SEMCONV_VERSION -GENERATOR_VERSION=0.11.0 +GENERATOR_VERSION=0.18.0 cd "${SCRIPT_DIR}" || exit @@ -23,24 +23,25 @@ rm -rf "${SPEC_DIR}" || true mkdir "${SPEC_DIR}" cd "${SPEC_DIR}" || exit -git init +git init -b main git remote add origin https://github.com/open-telemetry/opentelemetry-specification.git git fetch origin "$SPEC_VERSION" git reset --hard FETCH_HEAD cd "${SCRIPT_DIR}" || exit -rm -rf "${CODE_DIR}" || true +rm -rf "${CODE_DIR}/*.php" || true mkdir -p "${CODE_DIR}" git checkout HEAD "${CODE_DIR}/composer.json" # Trace docker run --rm \ - -v "${SPEC_DIR}/semantic_conventions/trace:/source" \ + -v "${SPEC_DIR}/semantic_conventions:/source" \ -v "${SCRIPT_DIR}/templates:/templates" \ -v "${CODE_DIR}:/output" \ -u "${UID}" \ otel/semconvgen:$GENERATOR_VERSION \ + --only span,event,attribute_group,scope \ -f /source code \ --template /templates/Attributes.php.j2 \ --output "/output/TraceAttributes.php" \ @@ -49,11 +50,12 @@ docker run --rm \ -DschemaUrl=$SCHEMA_URL docker run --rm \ - -v "${SPEC_DIR}/semantic_conventions/trace:/source" \ + -v "${SPEC_DIR}/semantic_conventions:/source" \ -v "${SCRIPT_DIR}/templates:/templates" \ - -v "${CODE_DIR}:/"output \ + -v "${CODE_DIR}:/output" \ -u "${UID}" \ otel/semconvgen:$GENERATOR_VERSION \ + --only span,event,attribute_group,scope \ -f /source code \ --template /templates/AttributeValues.php.j2 \ --output "/output/TraceAttributeValues.php" \ @@ -61,14 +63,14 @@ docker run --rm \ -Dclass="Trace" \ -DschemaUrl=$SCHEMA_URL - # Resource docker run --rm \ - -v "${SPEC_DIR}/semantic_conventions/resource:/source" \ + -v "${SPEC_DIR}/semantic_conventions:/source" \ -v "${SCRIPT_DIR}/templates:/templates" \ -v "${CODE_DIR}:/output" \ -u "${UID}" \ otel/semconvgen:$GENERATOR_VERSION \ + --only resource \ -f /source code \ --template /templates/Attributes.php.j2 \ --output "/output/ResourceAttributes.php" \ @@ -77,11 +79,12 @@ docker run --rm \ -DschemaUrl=$SCHEMA_URL docker run --rm \ - -v "${SPEC_DIR}/semantic_conventions/resource:/source" \ + -v "${SPEC_DIR}/semantic_conventions:/source" \ -v "${SCRIPT_DIR}/templates:/templates" \ -v "${CODE_DIR}:/output" \ -u "${UID}" \ otel/semconvgen:$GENERATOR_VERSION \ + --only resource \ -f /source code \ --template /templates/AttributeValues.php.j2 \ --output "/output/ResourceAttributeValues.php" \ @@ -89,4 +92,4 @@ docker run --rm \ -Dclass="Resource" \ -DschemaUrl=$SCHEMA_URL -rm -rf "${SPEC_DIR}" || true +rm -rf "${SPEC_DIR}" || true \ No newline at end of file diff --git a/src/SemConv/ResourceAttributeValues.php b/src/SemConv/ResourceAttributeValues.php index 4148734be..9178f6e5d 100644 --- a/src/SemConv/ResourceAttributeValues.php +++ b/src/SemConv/ResourceAttributeValues.php @@ -11,7 +11,7 @@ interface ResourceAttributeValues /** * The URL of the OpenTelemetry schema for these keys and values. */ - public const SCHEMA_URL = 'https://opentelemetry.io/schemas/1.12.0'; + public const SCHEMA_URL = 'https://opentelemetry.io/schemas/1.19.0'; /** * @see ResourceAttributes::CLOUD_PROVIDER Alibaba Cloud */ @@ -32,6 +32,16 @@ interface ResourceAttributeValues */ public const CLOUD_PROVIDER_GCP = 'gcp'; + /** + * @see ResourceAttributes::CLOUD_PROVIDER Heroku Platform as a Service + */ + public const CLOUD_PROVIDER_HEROKU = 'heroku'; + + /** + * @see ResourceAttributes::CLOUD_PROVIDER IBM Cloud + */ + public const CLOUD_PROVIDER_IBM_CLOUD = 'ibm_cloud'; + /** * @see ResourceAttributes::CLOUD_PROVIDER Tencent Cloud */ @@ -47,6 +57,11 @@ interface ResourceAttributeValues */ public const CLOUD_PLATFORM_ALIBABA_CLOUD_FC = 'alibaba_cloud_fc'; + /** + * @see ResourceAttributes::CLOUD_PLATFORM Red Hat OpenShift on Alibaba Cloud + */ + public const CLOUD_PLATFORM_ALIBABA_CLOUD_OPENSHIFT = 'alibaba_cloud_openshift'; + /** * @see ResourceAttributes::CLOUD_PLATFORM AWS Elastic Compute Cloud */ @@ -77,6 +92,11 @@ interface ResourceAttributeValues */ public const CLOUD_PLATFORM_AWS_APP_RUNNER = 'aws_app_runner'; + /** + * @see ResourceAttributes::CLOUD_PLATFORM Red Hat OpenShift on AWS (ROSA) + */ + public const CLOUD_PLATFORM_AWS_OPENSHIFT = 'aws_openshift'; + /** * @see ResourceAttributes::CLOUD_PLATFORM Azure Virtual Machines */ @@ -102,6 +122,11 @@ interface ResourceAttributeValues */ public const CLOUD_PLATFORM_AZURE_APP_SERVICE = 'azure_app_service'; + /** + * @see ResourceAttributes::CLOUD_PLATFORM Azure Red Hat OpenShift + */ + public const CLOUD_PLATFORM_AZURE_OPENSHIFT = 'azure_openshift'; + /** * @see ResourceAttributes::CLOUD_PLATFORM Google Cloud Compute Engine (GCE) */ @@ -127,6 +152,16 @@ interface ResourceAttributeValues */ public const CLOUD_PLATFORM_GCP_APP_ENGINE = 'gcp_app_engine'; + /** + * @see ResourceAttributes::CLOUD_PLATFORM Red Hat OpenShift on Google Cloud + */ + public const CLOUD_PLATFORM_GCP_OPENSHIFT = 'gcp_openshift'; + + /** + * @see ResourceAttributes::CLOUD_PLATFORM Red Hat OpenShift on IBM Cloud + */ + public const CLOUD_PLATFORM_IBM_CLOUD_OPENSHIFT = 'ibm_cloud_openshift'; + /** * @see ResourceAttributes::CLOUD_PLATFORM Tencent Cloud Cloud Virtual Machine (CVM) */ diff --git a/src/SemConv/ResourceAttributes.php b/src/SemConv/ResourceAttributes.php index 35df77dcf..591c9dca8 100644 --- a/src/SemConv/ResourceAttributes.php +++ b/src/SemConv/ResourceAttributes.php @@ -11,12 +11,12 @@ interface ResourceAttributes /** * The URL of the OpenTelemetry schema for these keys and values. */ - public const SCHEMA_URL = 'https://opentelemetry.io/schemas/1.12.0'; + public const SCHEMA_URL = 'https://opentelemetry.io/schemas/1.19.0'; /** * Array of brand name and version separated by a space. * - * This value is intended to be taken from the UA client hints API (navigator.userAgentData.brands). + * This value is intended to be taken from the UA client hints API (`navigator.userAgentData.brands`). * * @example Not A;Brand 99 * @example Chromium 99 @@ -27,8 +27,8 @@ interface ResourceAttributes /** * The platform on which the browser is running. * - * This value is intended to be taken from the UA client hints API (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. Note that some (but not all) of these values can overlap with values in the os.type and os.name attributes. However, for consistency, the values in the `browser.platform` attribute should capture the exact value that the user agent provides. + * This value is intended to be taken from the UA client hints API (`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. Note that some (but not all) of these values can overlap with values in the `os.type` and `os.name` attributes. However, for consistency, the values in the `browser.platform` attribute should capture the exact value that the user agent provides. * * @example Windows * @example macOS @@ -36,6 +36,25 @@ interface ResourceAttributes */ public const BROWSER_PLATFORM = 'browser.platform'; + /** + * A boolean that is true if the browser is running on a mobile device. + * + * This value is intended to be taken from the UA client hints API (`navigator.userAgentData.mobile`). If unavailable, this attribute SHOULD be left unset. + */ + public const BROWSER_MOBILE = 'browser.mobile'; + + /** + * Preferred language of the user using the browser. + * + * This value is intended to be taken from the Navigator API `navigator.language`. + * + * @example en + * @example en-US + * @example fr + * @example fr-FR + */ + public const BROWSER_LANGUAGE = 'browser.language'; + /** * Full user-agent string provided by the browser. * @@ -43,7 +62,7 @@ interface ResourceAttributes * * @example Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 */ - public const BROWSER_USER_AGENT = 'browser.user_agent'; + public const USER_AGENT_ORIGINAL = 'user_agent.original'; /** * Name of the cloud provider. @@ -68,6 +87,31 @@ interface ResourceAttributes */ public const CLOUD_REGION = 'cloud.region'; + /** + * Cloud provider-specific native identifier of the monitored cloud resource (e.g. an ARN on AWS, a fully qualified resource ID on Azure, a full resource name on GCP). + * + * On some cloud providers, it may not be possible to determine the full ID at startup, + * so it may be necessary to set `cloud.resource_id` as a span attribute instead.The exact value to use for `cloud.resource_id` depends on the cloud provider. + * The following well-known definitions MUST be used if you set this attribute and they apply: + * + * @example arn:aws:lambda:REGION:ACCOUNT_ID:function:my-function + * @example //run.googleapis.com/projects/PROJECT_ID/locations/LOCATION_ID/services/SERVICE_ID + * @example /subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions/ + */ + public const CLOUD_RESOURCE_ID = 'cloud.resource_id'; + /** * Cloud regions often have multiple, isolated locations known as zones to increase availability. Availability zone represents the zone where the resource is running. * @@ -167,6 +211,27 @@ interface ResourceAttributes */ public const AWS_LOG_STREAM_ARNS = 'aws.log.stream.arns'; + /** + * Time and date the release was created. + * + * @example 2022-10-23T18:00:42Z + */ + public const HEROKU_RELEASE_CREATION_TIMESTAMP = 'heroku.release.creation_timestamp'; + + /** + * Commit hash for the current release. + * + * @example e6134959463efd8966b20e75b913cafe3f5ec + */ + public const HEROKU_RELEASE_COMMIT = 'heroku.release.commit'; + + /** + * Unique identifier for the application. + * + * @example 2daa2797-e42b-4624-9322-ec3f968df4da + */ + public const HEROKU_APP_ID = 'heroku.app.id'; + /** * Container name used by container runtime. * @@ -266,7 +331,7 @@ interface ResourceAttributes * can also be seen in the resource JSON for the function). * This means that a span attribute MUST be used, as an Azure function * app can host multiple functions that would usually share - * a TracerProvider (see also the `faas.id` attribute). + * a TracerProvider (see also the `cloud.resource_id` attribute). * * * @example my-function @@ -274,28 +339,6 @@ interface ResourceAttributes */ public const FAAS_NAME = 'faas.name'; - /** - * The unique ID of the single function that this runtime instance executes. - * - * On some cloud providers, it may not be possible to determine the full ID at startup, - * so consider setting `faas.id` as a span attribute instead.The exact value to use for `faas.id` depends on the cloud provider:
    - *
  • AWS Lambda: The function ARN. - * Take care not to use the "invoked ARN" directly but replace any - * alias suffix - * with the resolved function version, as the same runtime instance may be invokable with - * multiple different aliases.
  • - *
  • GCP: The URI of the resource
  • - *
  • Azure: The Fully Qualified Resource ID of the invoked function, - * not the function app, having the form - * `/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions/`. - * This means that a span attribute MUST be used, as an Azure function app can host multiple functions that would usually share - * a TracerProvider.
  • - *
- * - * @example arn:aws:lambda:us-west-2:123456789012:function:my-function - */ - public const FAAS_ID = 'faas.id'; - /** * The immutable version of the function being executed. * @@ -326,18 +369,18 @@ interface ResourceAttributes public const FAAS_INSTANCE = 'faas.instance'; /** - * The amount of memory available to the serverless function in MiB. + * The amount of memory available to the serverless function converted to Bytes. * - * It's recommended to set this attribute since e.g. too little memory can easily stop a Java AWS Lambda function from working correctly. On AWS Lambda, the environment variable `AWS_LAMBDA_FUNCTION_MEMORY_SIZE` provides this information. + * It's recommended to set this attribute since e.g. too little memory can easily stop a Java AWS Lambda function from working correctly. On AWS Lambda, the environment variable `AWS_LAMBDA_FUNCTION_MEMORY_SIZE` provides this information (which must be multiplied by 1,048,576). * - * @example 128 + * @example 134217728 */ public const FAAS_MAX_MEMORY = 'faas.max_memory'; /** - * Unique host ID. For Cloud, this must be the instance_id assigned by the cloud provider. + * Unique host ID. For Cloud, this must be the instance_id assigned by the cloud provider. For non-containerized systems, this should be the `machine-id`. See the table below for the sources to use to determine the `machine-id` based on operating system. * - * @example opentelemetry-test + * @example fdbf79e8af94cb7f9e8df36789187052 */ public const HOST_ID = 'host.id'; @@ -559,6 +602,13 @@ interface ResourceAttributes */ public const PROCESS_PID = 'process.pid'; + /** + * Parent Process identifier (PID). + * + * @example 111 + */ + public const PROCESS_PARENT_PID = 'process.parent_pid'; + /** * The name of the process executable. On Linux based systems, can be set to the `Name` in `proc/[pid]/status`. On Windows, can be set to the base name of `GetProcessImageFileNameW`. * @@ -703,4 +753,32 @@ interface ResourceAttributes * @example WildFly Full 21.0.0.Final (WildFly Core 13.0.1.Final) - 2.2.2.Final */ public const WEBENGINE_DESCRIPTION = 'webengine.description'; + + /** + * The name of the instrumentation scope - (`InstrumentationScope.Name` in OTLP). + * + * @example io.opentelemetry.contrib.mongodb + */ + public const OTEL_SCOPE_NAME = 'otel.scope.name'; + + /** + * The version of the instrumentation scope - (`InstrumentationScope.Version` in OTLP). + * + * @example 1.0.0 + */ + public const OTEL_SCOPE_VERSION = 'otel.scope.version'; + + /** + * Deprecated, use the `otel.scope.name` attribute. + * + * @example io.opentelemetry.contrib.mongodb + */ + public const OTEL_LIBRARY_NAME = 'otel.library.name'; + + /** + * Deprecated, use the `otel.scope.version` attribute. + * + * @example 1.0.0 + */ + public const OTEL_LIBRARY_VERSION = 'otel.library.version'; } diff --git a/src/SemConv/TraceAttributeValues.php b/src/SemConv/TraceAttributeValues.php index 81c0b7468..682df9ef6 100644 --- a/src/SemConv/TraceAttributeValues.php +++ b/src/SemConv/TraceAttributeValues.php @@ -11,7 +11,52 @@ interface TraceAttributeValues /** * The URL of the OpenTelemetry schema for these keys and values. */ - public const SCHEMA_URL = 'https://opentelemetry.io/schemas/1.12.0'; + public const SCHEMA_URL = 'https://opentelemetry.io/schemas/1.19.0'; + /** + * @see TraceAttributes::HTTP_FLAVOR HTTP/1.0 + */ + public const HTTP_FLAVOR_HTTP_1_0 = '1.0'; + + /** + * @see TraceAttributes::HTTP_FLAVOR HTTP/1.1 + */ + public const HTTP_FLAVOR_HTTP_1_1 = '1.1'; + + /** + * @see TraceAttributes::HTTP_FLAVOR HTTP/2 + */ + public const HTTP_FLAVOR_HTTP_2_0 = '2.0'; + + /** + * @see TraceAttributes::HTTP_FLAVOR HTTP/3 + */ + public const HTTP_FLAVOR_HTTP_3_0 = '3.0'; + + /** + * @see TraceAttributes::HTTP_FLAVOR SPDY protocol + */ + public const HTTP_FLAVOR_SPDY = 'SPDY'; + + /** + * @see TraceAttributes::HTTP_FLAVOR QUIC protocol + */ + public const HTTP_FLAVOR_QUIC = 'QUIC'; + + /** + * @see TraceAttributes::EVENT_DOMAIN Events from browser apps + */ + public const EVENT_DOMAIN_BROWSER = 'browser'; + + /** + * @see TraceAttributes::EVENT_DOMAIN Events from mobile apps + */ + public const EVENT_DOMAIN_DEVICE = 'device'; + + /** + * @see TraceAttributes::EVENT_DOMAIN Events from Kubernetes + */ + public const EVENT_DOMAIN_K8S = 'k8s'; + /** * @see TraceAttributes::OPENTRACING_REF_TYPE The parent Span depends on the child Span in some capacity */ @@ -32,6 +77,11 @@ interface TraceAttributeValues */ public const DB_SYSTEM_MSSQL = 'mssql'; + /** + * @see TraceAttributes::DB_SYSTEM Microsoft SQL Server Compact + */ + public const DB_SYSTEM_MSSQLCOMPACT = 'mssqlcompact'; + /** * @see TraceAttributes::DB_SYSTEM MySQL */ @@ -258,24 +308,44 @@ interface TraceAttributeValues public const DB_SYSTEM_COCKROACHDB = 'cockroachdb'; /** - * @see TraceAttributes::NET_TRANSPORT ip_tcp + * @see TraceAttributes::DB_SYSTEM OpenSearch */ - public const NET_TRANSPORT_IP_TCP = 'ip_tcp'; + public const DB_SYSTEM_OPENSEARCH = 'opensearch'; /** - * @see TraceAttributes::NET_TRANSPORT ip_udp + * @see TraceAttributes::DB_SYSTEM ClickHouse */ - public const NET_TRANSPORT_IP_UDP = 'ip_udp'; + public const DB_SYSTEM_CLICKHOUSE = 'clickhouse'; + + /** + * @see TraceAttributes::DB_SYSTEM Cloud Spanner + */ + public const DB_SYSTEM_SPANNER = 'spanner'; + + /** + * @see TraceAttributes::NET_SOCK_FAMILY IPv4 address + */ + public const NET_SOCK_FAMILY_INET = 'inet'; + + /** + * @see TraceAttributes::NET_SOCK_FAMILY IPv6 address + */ + public const NET_SOCK_FAMILY_INET6 = 'inet6'; + + /** + * @see TraceAttributes::NET_SOCK_FAMILY Unix domain socket path + */ + public const NET_SOCK_FAMILY_UNIX = 'unix'; /** - * @see TraceAttributes::NET_TRANSPORT Another IP-based protocol + * @see TraceAttributes::NET_TRANSPORT ip_tcp */ - public const NET_TRANSPORT_IP = 'ip'; + public const NET_TRANSPORT_IP_TCP = 'ip_tcp'; /** - * @see TraceAttributes::NET_TRANSPORT Unix Domain socket. See below + * @see TraceAttributes::NET_TRANSPORT ip_udp */ - public const NET_TRANSPORT_UNIX = 'unix'; + public const NET_TRANSPORT_IP_UDP = 'ip_udp'; /** * @see TraceAttributes::NET_TRANSPORT Named or anonymous pipe. See note below @@ -349,6 +419,16 @@ interface TraceAttributeValues */ public const DB_CASSANDRA_CONSISTENCY_LEVEL_LOCAL_SERIAL = 'local_serial'; + /** + * @see TraceAttributes::OTEL_STATUS_CODE The operation has been validated by an Application developer or Operator to have completed successfully + */ + public const OTEL_STATUS_CODE_OK = 'OK'; + + /** + * @see TraceAttributes::OTEL_STATUS_CODE The operation contains an error + */ + public const OTEL_STATUS_CODE_ERROR = 'ERROR'; + /** * @see TraceAttributes::FAAS_TRIGGER A response to some data source operation such as a database or filesystem read/write */ @@ -390,34 +470,19 @@ interface TraceAttributeValues public const FAAS_DOCUMENT_OPERATION_DELETE = 'delete'; /** - * @see TraceAttributes::HTTP_FLAVOR HTTP/1.0 - */ - public const HTTP_FLAVOR_HTTP_1_0 = '1.0'; - - /** - * @see TraceAttributes::HTTP_FLAVOR HTTP/1.1 - */ - public const HTTP_FLAVOR_HTTP_1_1 = '1.1'; - - /** - * @see TraceAttributes::HTTP_FLAVOR HTTP/2 + * @see TraceAttributes::MESSAGING_OPERATION publish */ - public const HTTP_FLAVOR_HTTP_2_0 = '2.0'; + public const MESSAGING_OPERATION_PUBLISH = 'publish'; /** - * @see TraceAttributes::HTTP_FLAVOR HTTP/3 - */ - public const HTTP_FLAVOR_HTTP_3_0 = '3.0'; - - /** - * @see TraceAttributes::HTTP_FLAVOR SPDY protocol + * @see TraceAttributes::MESSAGING_OPERATION receive */ - public const HTTP_FLAVOR_SPDY = 'SPDY'; + public const MESSAGING_OPERATION_RECEIVE = 'receive'; /** - * @see TraceAttributes::HTTP_FLAVOR QUIC protocol + * @see TraceAttributes::MESSAGING_OPERATION process */ - public const HTTP_FLAVOR_QUIC = 'QUIC'; + public const MESSAGING_OPERATION_PROCESS = 'process'; /** * @see TraceAttributes::NET_HOST_CONNECTION_TYPE wifi @@ -549,16 +614,6 @@ interface TraceAttributeValues */ public const NET_HOST_CONNECTION_SUBTYPE_LTE_CA = 'lte_ca'; - /** - * @see TraceAttributes::MESSAGING_DESTINATION_KIND A message sent to a queue - */ - public const MESSAGING_DESTINATION_KIND_QUEUE = 'queue'; - - /** - * @see TraceAttributes::MESSAGING_DESTINATION_KIND A message sent to a topic - */ - public const MESSAGING_DESTINATION_KIND_TOPIC = 'topic'; - /** * @see TraceAttributes::FAAS_INVOKED_PROVIDER Alibaba Cloud */ @@ -605,14 +660,44 @@ interface TraceAttributeValues public const RPC_SYSTEM_APACHE_DUBBO = 'apache_dubbo'; /** - * @see TraceAttributes::MESSAGING_OPERATION receive + * @see TraceAttributes::RPC_SYSTEM Connect RPC */ - public const MESSAGING_OPERATION_RECEIVE = 'receive'; + public const RPC_SYSTEM_CONNECT_RPC = 'connect_rpc'; /** - * @see TraceAttributes::MESSAGING_OPERATION process + * @see TraceAttributes::GRAPHQL_OPERATION_TYPE GraphQL query */ - public const MESSAGING_OPERATION_PROCESS = 'process'; + public const GRAPHQL_OPERATION_TYPE_QUERY = 'query'; + + /** + * @see TraceAttributes::GRAPHQL_OPERATION_TYPE GraphQL mutation + */ + public const GRAPHQL_OPERATION_TYPE_MUTATION = 'mutation'; + + /** + * @see TraceAttributes::GRAPHQL_OPERATION_TYPE GraphQL subscription + */ + public const GRAPHQL_OPERATION_TYPE_SUBSCRIPTION = 'subscription'; + + /** + * @see TraceAttributes::MESSAGING_DESTINATION_KIND A message sent to a queue + */ + public const MESSAGING_DESTINATION_KIND_QUEUE = 'queue'; + + /** + * @see TraceAttributes::MESSAGING_DESTINATION_KIND A message sent to a topic + */ + public const MESSAGING_DESTINATION_KIND_TOPIC = 'topic'; + + /** + * @see TraceAttributes::MESSAGING_SOURCE_KIND A message received from a queue + */ + public const MESSAGING_SOURCE_KIND_QUEUE = 'queue'; + + /** + * @see TraceAttributes::MESSAGING_SOURCE_KIND A message received from a topic + */ + public const MESSAGING_SOURCE_KIND_TOPIC = 'topic'; /** * @see TraceAttributes::MESSAGING_ROCKETMQ_MESSAGE_TYPE Normal message @@ -738,4 +823,84 @@ interface TraceAttributeValues * @see TraceAttributes::MESSAGE_TYPE received */ public const MESSAGE_TYPE_RECEIVED = 'RECEIVED'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE cancelled + */ + public const RPC_CONNECT_RPC_ERROR_CODE_CANCELLED = 'cancelled'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE unknown + */ + public const RPC_CONNECT_RPC_ERROR_CODE_UNKNOWN = 'unknown'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE invalid_argument + */ + public const RPC_CONNECT_RPC_ERROR_CODE_INVALID_ARGUMENT = 'invalid_argument'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE deadline_exceeded + */ + public const RPC_CONNECT_RPC_ERROR_CODE_DEADLINE_EXCEEDED = 'deadline_exceeded'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE not_found + */ + public const RPC_CONNECT_RPC_ERROR_CODE_NOT_FOUND = 'not_found'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE already_exists + */ + public const RPC_CONNECT_RPC_ERROR_CODE_ALREADY_EXISTS = 'already_exists'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE permission_denied + */ + public const RPC_CONNECT_RPC_ERROR_CODE_PERMISSION_DENIED = 'permission_denied'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE resource_exhausted + */ + public const RPC_CONNECT_RPC_ERROR_CODE_RESOURCE_EXHAUSTED = 'resource_exhausted'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE failed_precondition + */ + public const RPC_CONNECT_RPC_ERROR_CODE_FAILED_PRECONDITION = 'failed_precondition'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE aborted + */ + public const RPC_CONNECT_RPC_ERROR_CODE_ABORTED = 'aborted'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE out_of_range + */ + public const RPC_CONNECT_RPC_ERROR_CODE_OUT_OF_RANGE = 'out_of_range'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE unimplemented + */ + public const RPC_CONNECT_RPC_ERROR_CODE_UNIMPLEMENTED = 'unimplemented'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE internal + */ + public const RPC_CONNECT_RPC_ERROR_CODE_INTERNAL = 'internal'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE unavailable + */ + public const RPC_CONNECT_RPC_ERROR_CODE_UNAVAILABLE = 'unavailable'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE data_loss + */ + public const RPC_CONNECT_RPC_ERROR_CODE_DATA_LOSS = 'data_loss'; + + /** + * @see TraceAttributes::RPC_CONNECT_RPC_ERROR_CODE unauthenticated + */ + public const RPC_CONNECT_RPC_ERROR_CODE_UNAUTHENTICATED = 'unauthenticated'; } diff --git a/src/SemConv/TraceAttributes.php b/src/SemConv/TraceAttributes.php index e929697ab..7e4973233 100644 --- a/src/SemConv/TraceAttributes.php +++ b/src/SemConv/TraceAttributes.php @@ -11,12 +11,176 @@ interface TraceAttributes /** * The URL of the OpenTelemetry schema for these keys and values. */ - public const SCHEMA_URL = 'https://opentelemetry.io/schemas/1.12.0'; + public const SCHEMA_URL = 'https://opentelemetry.io/schemas/1.19.0'; + + /** + * 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. + * + * @example java.net.ConnectException + * @example OSError + */ + public const EXCEPTION_TYPE = 'exception.type'; + + /** + * The exception message. + * + * @example Division by zero + * @example Can't convert 'int' object to str implicitly + */ + public const EXCEPTION_MESSAGE = 'exception.message'; + + /** + * 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. + * + * @example 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) + */ + public const EXCEPTION_STACKTRACE = 'exception.stacktrace'; + + /** + * HTTP request method. + * + * @example GET + * @example POST + * @example HEAD + */ + public const HTTP_METHOD = 'http.method'; + + /** + * HTTP response status code. + * + * @example 200 + */ + public const HTTP_STATUS_CODE = 'http.status_code'; + + /** + * Kind of HTTP protocol used. + */ + public const HTTP_FLAVOR = 'http.flavor'; + + /** + * Host identifier of the "URI origin" HTTP request is sent to. + * + * Determined by using the first of the following that applies
    + *
  • Host identifier of the request target + * if it's sent in absolute-form
  • + *
  • Host identifier of the `Host` header
  • + *
+ * SHOULD NOT be set if capturing it would require an extra DNS lookup. + * + * @example example.com + */ + public const NET_PEER_NAME = 'net.peer.name'; + + /** + * Port identifier of the "URI origin" HTTP request is sent to. + * + * When request target is absolute URI, `net.peer.name` MUST match URI port identifier, otherwise it MUST match `Host` header port identifier. + * + * @example 80 + * @example 8080 + * @example 443 + */ + public const NET_PEER_PORT = 'net.peer.port'; + + /** + * The URI scheme identifying the used protocol. + * + * @example http + * @example https + */ + public const HTTP_SCHEME = 'http.scheme'; + + /** + * The matched route (path template in the format used by the respective server framework). See note below. + * + * 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. + * SHOULD include the application root if there is one. + * + * @example /users/:userID? + * @example {controller}/{action}/{id?} + */ + public const HTTP_ROUTE = 'http.route'; + + /** + * Name of the local HTTP server that received the request. + * + * Determined by using the first of the following that applies
    + *
  • The primary server name of the matched virtual host. MUST only + * include host identifier.
  • + *
  • Host identifier of the request target + * if it's sent in absolute-form.
  • + *
  • Host identifier of the `Host` header
  • + *
+ * SHOULD NOT be set if only IP address is available and capturing name would require a reverse DNS lookup. + * + * @example localhost + */ + public const NET_HOST_NAME = 'net.host.name'; + + /** + * Port of the local HTTP server that received the request. + * + * Determined by using the first of the following that applies
    + *
  • Port identifier of the primary server host of the matched virtual host.
  • + *
  • Port identifier of the request target + * if it's sent in absolute-form.
  • + *
  • Port identifier of the `Host` header
  • + *
+ * + * @example 8080 + */ + public const NET_HOST_PORT = 'net.host.port'; + + /** + * The name identifies the event. + * + * @example click + * @example exception + */ + public const EVENT_NAME = 'event.name'; + + /** + * The domain identifies the business context for the events. + * + * Events across different domains may have same `event.name`, yet be + * unrelated events. + */ + public const EVENT_DOMAIN = 'event.domain'; + + /** + * The unique identifier of the feature flag. + * + * @example logo-color + */ + public const FEATURE_FLAG_KEY = 'feature_flag.key'; + + /** + * The name of the service provider that performs the flag evaluation. + * + * @example Flag Manager + */ + public const FEATURE_FLAG_PROVIDER_NAME = 'feature_flag.provider_name'; + + /** + * SHOULD be a semantic identifier for a value. If one is unavailable, a stringified version of the value can be used. + * + * A semantic identifier, commonly referred to as a variant, provides a means + * for referring to a value without including the value itself. This can + * provide additional context for understanding the meaning behind a value. + * For example, the variant `red` maybe be used for the value `#c05543`.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. + * + * @example red + * @example true + * @example on + */ + public const FEATURE_FLAG_VARIANT = 'feature_flag.variant'; /** * The full invoked ARN as provided on the `Context` passed to the function (`Lambda-Runtime-Invoked-Function-Arn` header on the `/runtime/invocation/next` applicable). * - * This may be different from `faas.id` if an alias is involved. + * This may be different from `cloud.resource_id` if an alias is involved. * * @example arn:aws:lambda:us-east-1:123456:function:myfunction:myalias */ @@ -128,29 +292,34 @@ interface TraceAttributes public const DB_OPERATION = 'db.operation'; /** - * Remote hostname or similar, see note below. + * Remote socket peer address: IPv4 or IPv6 for internet protocols, path for local communication, etc. * - * `net.peer.name` SHOULD NOT be set if capturing it would require an extra DNS lookup. + * @example 127.0.0.1 + * @example /tmp/mysql.sock + */ + public const NET_SOCK_PEER_ADDR = 'net.sock.peer.addr'; + + /** + * Remote socket peer port. * - * @example example.com + * @example 16456 */ - public const NET_PEER_NAME = 'net.peer.name'; + public const NET_SOCK_PEER_PORT = 'net.sock.peer.port'; /** - * Remote address of the peer (dotted decimal for IPv4 or RFC5952 for IPv6). + * Protocol address family which is used for communication. * - * @example 127.0.0.1 + * @example inet6 + * @example bluetooth */ - public const NET_PEER_IP = 'net.peer.ip'; + public const NET_SOCK_FAMILY = 'net.sock.family'; /** - * Remote port number. + * Remote socket peer name. * - * @example 80 - * @example 8080 - * @example 443 + * @example proxy.example.com */ - public const NET_PEER_PORT = 'net.peer.port'; + public const NET_SOCK_PEER_NAME = 'net.sock.peer.name'; /** * Transport protocol used. See note below. @@ -240,48 +409,19 @@ interface TraceAttributes public const DB_SQL_TABLE = 'db.sql.table'; /** - * 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. - * - * @example java.net.ConnectException - * @example OSError + * Name of the code, either "OK" or "ERROR". MUST NOT be set if the status code is UNSET. */ - public const EXCEPTION_TYPE = 'exception.type'; + public const OTEL_STATUS_CODE = 'otel.status_code'; /** - * The exception message. + * Description of the Status if it has a value, otherwise not set. * - * @example Division by zero - * @example Can't convert 'int' object to str implicitly - */ - public const EXCEPTION_MESSAGE = 'exception.message'; - - /** - * 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. - * - * @example 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) + * @example resource not found */ - public const EXCEPTION_STACKTRACE = 'exception.stacktrace'; + public const OTEL_STATUS_DESCRIPTION = 'otel.status_description'; /** - * 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 above.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. - */ - public const EXCEPTION_ESCAPED = 'exception.escaped'; - - /** - * Type of the trigger which caused this function execution. + * Type of the trigger which caused this function invocation. * * For the server/consumer span on the incoming side, * `faas.trigger` MUST be set.Clients invoking FaaS instances usually cannot set `faas.trigger`, @@ -294,11 +434,36 @@ interface TraceAttributes public const FAAS_TRIGGER = 'faas.trigger'; /** - * The execution ID of the current function execution. + * The invocation ID of the current function invocation. * * @example af9d5aa4-a685-4c5f-a22b-444f80b3cc28 */ - public const FAAS_EXECUTION = 'faas.execution'; + public const FAAS_INVOCATION_ID = 'faas.invocation_id'; + + /** + * Cloud provider-specific native identifier of the monitored cloud resource (e.g. an ARN on AWS, a fully qualified resource ID on Azure, a full resource name on GCP). + * + * On some cloud providers, it may not be possible to determine the full ID at startup, + * so it may be necessary to set `cloud.resource_id` as a span attribute instead.The exact value to use for `cloud.resource_id` depends on the cloud provider. + * The following well-known definitions MUST be used if you set this attribute and they apply:
    + *
  • AWS Lambda: The function ARN. + * Take care not to use the "invoked ARN" directly but replace any + * alias suffix + * with the resolved function version, as the same runtime instance may be invokable with + * multiple different aliases.
  • + *
  • GCP: The URI of the resource
  • + *
  • Azure: The Fully Qualified Resource ID of the invoked function, + * not the function app, having the form + * `/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions/`. + * This means that a span attribute MUST be used, as an Azure function app can host multiple functions that would usually share + * a TracerProvider.
  • + *
+ * + * @example arn:aws:lambda:REGION:ACCOUNT_ID:function:my-function + * @example //run.googleapis.com/projects/PROJECT_ID/locations/LOCATION_ID/services/SERVICE_ID + * @example /subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions/ + */ + public const CLOUD_RESOURCE_ID = 'cloud.resource_id'; /** * The name of the source on which the triggering operation was performed. For example, in Cloud Storage or S3 corresponds to the bucket name, and in Cosmos DB to the database name. @@ -328,157 +493,116 @@ interface TraceAttributes */ public const FAAS_DOCUMENT_NAME = 'faas.document.name'; - /** - * HTTP request method. - * - * @example GET - * @example POST - * @example HEAD - */ - public const HTTP_METHOD = 'http.method'; - - /** - * Full HTTP request URL in the form `scheme://host[:port]/path?query[#fragment]`. Usually the fragment is not transmitted over HTTP, but if it is known, it should be included nevertheless. - * - * `http.url` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case the attribute's value should be `https://www.example.com/`. - * - * @example https://www.foo.bar/search?q=OpenTelemetry#SemConv - */ - public const HTTP_URL = 'http.url'; - /** * The full request target as passed in a HTTP request line or equivalent. * - * @example /path/12314/?q=ddds#123 + * @example /path/12314/?q=ddds */ public const HTTP_TARGET = 'http.target'; /** - * The value of the HTTP host header. An empty Host header should also be reported, see note. - * - * When the header is present but empty the attribute SHOULD be set to the empty string. Note that this is a valid situation that is expected in certain cases, according the aforementioned section of RFC 7230. When the header is not set the attribute MUST NOT be set. - * - * @example www.example.org - */ - public const HTTP_HOST = 'http.host'; - - /** - * The URI scheme identifying the used protocol. + * The IP address of the original client behind all proxies, if known (e.g. from X-Forwarded-For). * - * @example http - * @example https - */ - public const HTTP_SCHEME = 'http.scheme'; - - /** - * HTTP response status code. + * This is not necessarily the same as `net.sock.peer.addr`, which would + * identify the network-level peer, which may be a proxy.This attribute should be set when a source of information different + * from the one used for `net.sock.peer.addr`, is available even if that other + * source just confirms the same value as `net.sock.peer.addr`. + * Rationale: For `net.sock.peer.addr`, one typically does not know if it + * comes from a proxy, reverse proxy, or the actual client. Setting + * `http.client_ip` when it's the same as `net.sock.peer.addr` means that + * one is at least somewhat confident that the address is not that of + * the closest proxy. * - * @example 200 + * @example 83.164.160.102 */ - public const HTTP_STATUS_CODE = 'http.status_code'; + public const HTTP_CLIENT_IP = 'http.client_ip'; /** - * Kind of HTTP protocol used. + * Local socket address. Useful in case of a multi-IP host. * - * If `net.transport` is not specified, it can be assumed to be `IP.TCP` except if `http.flavor` is `QUIC`, in which case `IP.UDP` is assumed. + * @example 192.168.0.1 */ - public const HTTP_FLAVOR = 'http.flavor'; + public const NET_SOCK_HOST_ADDR = 'net.sock.host.addr'; /** - * Value of the HTTP User-Agent header sent by the client. + * Local socket port number. * - * @example CERN-LineMode/2.15 libwww/2.17b3 + * @example 35555 */ - public const HTTP_USER_AGENT = 'http.user_agent'; + public const NET_SOCK_HOST_PORT = 'net.sock.host.port'; /** - * 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 header. For requests using transport encoding, this should be the compressed size. + * A string identifying the messaging system. * - * @example 3495 + * @example kafka + * @example rabbitmq + * @example rocketmq + * @example activemq + * @example AmazonSQS */ - public const HTTP_REQUEST_CONTENT_LENGTH = 'http.request_content_length'; + public const MESSAGING_SYSTEM = 'messaging.system'; /** - * The size of the uncompressed request payload body after transport decoding. Not set if transport encoding not used. + * A string identifying the kind of messaging operation as defined in the Operation names section above. * - * @example 5493 + * If a custom value is used, it MUST be of low cardinality. */ - public const HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED = 'http.request_content_length_uncompressed'; + public const MESSAGING_OPERATION = 'messaging.operation'; /** - * 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 header. For requests using transport encoding, this should be the compressed size. + * The number of messages sent, received, or processed in the scope of the batching operation. * - * @example 3495 - */ - public const HTTP_RESPONSE_CONTENT_LENGTH = 'http.response_content_length'; - - /** - * The size of the uncompressed response payload body after transport decoding. Not set if transport encoding not used. + * Instrumentations SHOULD NOT set `messaging.batch.message_count` on spans that operate with a single message. When a messaging client library supports both batch and single-message API for the same operation, instrumentations SHOULD use `messaging.batch.message_count` for batching APIs and SHOULD NOT use it for single-message APIs. * - * @example 5493 + * @example 1 + * @example 2 */ - public const HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED = 'http.response_content_length_uncompressed'; + public const MESSAGING_BATCH_MESSAGE_COUNT = 'messaging.batch.message_count'; /** - * The ordinal number of request re-sending attempt. + * A value used by the messaging system as an identifier for the message, represented as a string. * - * @example 3 + * @example 452a7c7c7c7048c2f887f61572b18fc2 */ - public const HTTP_RETRY_COUNT = 'http.retry_count'; + public const MESSAGING_MESSAGE_ID = 'messaging.message.id'; /** - * The primary server name of the matched virtual host. This should be obtained via configuration. If no such configuration can be obtained, this attribute MUST NOT be set ( `net.host.name` should be used instead). - * - * `http.url` is usually not readily available on the server side but would have to be assembled in a cumbersome and sometimes lossy process from other information (see e.g. open-telemetry/opentelemetry-python/pull/148). It is thus preferred to supply the raw data that is available. + * The conversation ID identifying the conversation to which the message belongs, represented as a string. Sometimes called "Correlation ID". * - * @example example.com + * @example MyConversationId */ - public const HTTP_SERVER_NAME = 'http.server_name'; + public const MESSAGING_MESSAGE_CONVERSATION_ID = 'messaging.message.conversation_id'; /** - * The matched route (path template). + * The (uncompressed) size of the message payload in bytes. Also use this attribute if it is unknown whether the compressed or uncompressed payload size is reported. * - * @example /users/:userID? + * @example 2738 */ - public const HTTP_ROUTE = 'http.route'; + public const MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES = 'messaging.message.payload_size_bytes'; /** - * The IP address of the original client behind all proxies, if known (e.g. from X-Forwarded-For). - * - * This is not necessarily the same as `net.peer.ip`, which would - * identify the network-level peer, which may be a proxy.This attribute should be set when a source of information different - * from the one used for `net.peer.ip`, is available even if that other - * source just confirms the same value as `net.peer.ip`. - * Rationale: For `net.peer.ip`, one typically does not know if it - * comes from a proxy, reverse proxy, or the actual client. Setting - * `http.client_ip` when it's the same as `net.peer.ip` means that - * one is at least somewhat confident that the address is not that of - * the closest proxy. + * The compressed size of the message payload in bytes. * - * @example 83.164.160.102 + * @example 2048 */ - public const HTTP_CLIENT_IP = 'http.client_ip'; + public const MESSAGING_MESSAGE_PAYLOAD_COMPRESSED_SIZE_BYTES = 'messaging.message.payload_compressed_size_bytes'; /** - * Like `net.peer.ip` but for the host IP. Useful in case of a multi-IP host. + * Application layer protocol used. The value SHOULD be normalized to lowercase. * - * @example 192.168.0.1 + * @example amqp + * @example mqtt */ - public const NET_HOST_IP = 'net.host.ip'; + public const NET_APP_PROTOCOL_NAME = 'net.app.protocol.name'; /** - * Like `net.peer.port` but for the host port. + * Version of the application layer protocol used. See note below. * - * @example 35555 - */ - public const NET_HOST_PORT = 'net.host.port'; - - /** - * Local hostname or similar, see note below. + * `net.app.protocol.version` refers to the version of the protocol used and might be different from the protocol client's version. If the HTTP client used has a version of `0.27.2`, but sends HTTP version `1.1`, this attribute should be set to `1.1`. * - * @example localhost + * @example 3.1.1 */ - public const NET_HOST_NAME = 'net.host.name'; + public const NET_APP_PROTOCOL_VERSION = 'net.app.protocol.version'; /** * The internet connection type currently being used by the host. @@ -522,86 +646,6 @@ interface TraceAttributes */ public const NET_HOST_CARRIER_ICC = 'net.host.carrier.icc'; - /** - * A string identifying the messaging system. - * - * @example kafka - * @example rabbitmq - * @example rocketmq - * @example activemq - * @example AmazonSQS - */ - public const MESSAGING_SYSTEM = 'messaging.system'; - - /** - * The message destination name. This might be equal to the span name but is required nevertheless. - * - * @example MyQueue - * @example MyTopic - */ - public const MESSAGING_DESTINATION = 'messaging.destination'; - - /** - * The kind of message destination. - */ - public const MESSAGING_DESTINATION_KIND = 'messaging.destination_kind'; - - /** - * A boolean that is true if the message destination is temporary. - */ - public const MESSAGING_TEMP_DESTINATION = 'messaging.temp_destination'; - - /** - * The name of the transport protocol. - * - * @example AMQP - * @example MQTT - */ - public const MESSAGING_PROTOCOL = 'messaging.protocol'; - - /** - * The version of the transport protocol. - * - * @example 0.9.1 - */ - public const MESSAGING_PROTOCOL_VERSION = 'messaging.protocol_version'; - - /** - * Connection string. - * - * @example tibjmsnaming://localhost:7222 - * @example https://queue.amazonaws.com/80398EXAMPLE/MyQueue - */ - public const MESSAGING_URL = 'messaging.url'; - - /** - * A value used by the messaging system as an identifier for the message, represented as a string. - * - * @example 452a7c7c7c7048c2f887f61572b18fc2 - */ - public const MESSAGING_MESSAGE_ID = 'messaging.message_id'; - - /** - * The conversation ID identifying the conversation to which the message belongs, represented as a string. Sometimes called "Correlation ID". - * - * @example MyConversationId - */ - public const MESSAGING_CONVERSATION_ID = 'messaging.conversation_id'; - - /** - * The (uncompressed) size of the message payload in bytes. Also use this attribute if it is unknown whether the compressed or uncompressed payload size is reported. - * - * @example 2738 - */ - public const MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES = 'messaging.message_payload_size_bytes'; - - /** - * The compressed size of the message payload in bytes. - * - * @example 2048 - */ - public const MESSAGING_MESSAGE_PAYLOAD_COMPRESSED_SIZE_BYTES = 'messaging.message_payload_compressed_size_bytes'; - /** * A string containing the function invocation time in the ISO 8601 format expressed in UTC. * @@ -716,6 +760,52 @@ interface TraceAttributes */ public const CODE_LINENO = 'code.lineno'; + /** + * The column number in `code.filepath` best representing the operation. It SHOULD point within the code unit named in `code.function`. + * + * @example 16 + */ + public const CODE_COLUMN = 'code.column'; + + /** + * 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 header. For requests using transport encoding, this should be the compressed size. + * + * @example 3495 + */ + public const HTTP_REQUEST_CONTENT_LENGTH = 'http.request_content_length'; + + /** + * 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 header. For requests using transport encoding, this should be the compressed size. + * + * @example 3495 + */ + public const HTTP_RESPONSE_CONTENT_LENGTH = 'http.response_content_length'; + + /** + * Value of the HTTP User-Agent header sent by the client. + * + * @example CERN-LineMode/2.15 libwww/2.17b3 + */ + public const USER_AGENT_ORIGINAL = 'user_agent.original'; + + /** + * Full HTTP request URL in the form `scheme://host[:port]/path?query[#fragment]`. Usually the fragment is not transmitted over HTTP, but if it is known, it should be included nevertheless. + * + * `http.url` MUST NOT contain credentials passed via URL in form of `https://username:password@www.example.com/`. In such case the attribute's value should be `https://www.example.com/`. + * + * @example https://www.foo.bar/search?q=OpenTelemetry#SemConv + */ + public const HTTP_URL = 'http.url'; + + /** + * The ordinal number of request resending attempt (for any reason, including redirects). + * + * 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). + * + * @example 3 + */ + public const HTTP_RESEND_COUNT = 'http.resend_count'; + /** * The value `aws-api`. * @@ -902,39 +992,129 @@ interface TraceAttributes public const AWS_DYNAMODB_GLOBAL_SECONDARY_INDEX_UPDATES = 'aws.dynamodb.global_secondary_index_updates'; /** - * A string identifying the kind of message consumption as defined in the Operation names section above. If the operation is "send", this attribute MUST NOT be set, since the operation can be inferred from the span kind in that case. + * The name of the operation being executed. + * + * @example findBookById */ - public const MESSAGING_OPERATION = 'messaging.operation'; + public const GRAPHQL_OPERATION_NAME = 'graphql.operation.name'; + + /** + * The type of the operation being executed. + * + * @example query + * @example mutation + * @example subscription + */ + public const GRAPHQL_OPERATION_TYPE = 'graphql.operation.type'; + + /** + * The GraphQL document being executed. + * + * The value may be sanitized to exclude sensitive information. + * + * @example query findBookById { bookById(id: ?) { name } } + */ + public const GRAPHQL_DOCUMENT = 'graphql.document'; /** - * The identifier for the consumer receiving a message. For Kafka, set it to `{messaging.kafka.consumer_group} - {messaging.kafka.client_id}`, if both are present, or only `messaging.kafka.consumer_group`. For brokers, such as RabbitMQ and Artemis, set it to the `client_id` of the client consuming the message. + * The message destination name. + * + * Destination name SHOULD uniquely identify a specific queue, topic or other entity within the broker. If + * the broker does not have such notion, the destination name SHOULD uniquely identify the broker. + * + * @example MyQueue + * @example MyTopic + */ + public const MESSAGING_DESTINATION_NAME = 'messaging.destination.name'; + + /** + * The message source name. + * + * Source name SHOULD uniquely identify a specific queue, topic, or other entity within the broker. If + * the broker does not have such notion, the source name SHOULD uniquely identify the broker. + * + * @example MyQueue + * @example MyTopic + */ + public const MESSAGING_SOURCE_NAME = 'messaging.source.name'; + + /** + * The kind of message destination. + */ + public const MESSAGING_DESTINATION_KIND = 'messaging.destination.kind'; + + /** + * Low cardinality representation of the messaging destination name. + * + * Destination names could be constructed from templates. An example would be a destination name involving a user name or product id. Although the destination name in this case is of high cardinality, the underlying template is of low cardinality and can be effectively used for grouping and aggregation. + * + * @example /customers/{customerId} + */ + public const MESSAGING_DESTINATION_TEMPLATE = 'messaging.destination.template'; + + /** + * A boolean that is true if the message destination is temporary and might not exist anymore after messages are processed. + */ + public const MESSAGING_DESTINATION_TEMPORARY = 'messaging.destination.temporary'; + + /** + * A boolean that is true if the message destination is anonymous (could be unnamed or have auto-generated name). + */ + public const MESSAGING_DESTINATION_ANONYMOUS = 'messaging.destination.anonymous'; + + /** + * The kind of message source. + */ + public const MESSAGING_SOURCE_KIND = 'messaging.source.kind'; + + /** + * Low cardinality representation of the messaging source name. + * + * Source names could be constructed from templates. An example would be a source name involving a user name or product id. Although the source name in this case is of high cardinality, the underlying template is of low cardinality and can be effectively used for grouping and aggregation. + * + * @example /customers/{customerId} + */ + public const MESSAGING_SOURCE_TEMPLATE = 'messaging.source.template'; + + /** + * A boolean that is true if the message source is temporary and might not exist anymore after messages are processed. + */ + public const MESSAGING_SOURCE_TEMPORARY = 'messaging.source.temporary'; + + /** + * A boolean that is true if the message source is anonymous (could be unnamed or have auto-generated name). + */ + public const MESSAGING_SOURCE_ANONYMOUS = 'messaging.source.anonymous'; + + /** + * The identifier for the consumer receiving a message. For Kafka, set it to `{messaging.kafka.consumer.group} - {messaging.kafka.client_id}`, if both are present, or only `messaging.kafka.consumer.group`. For brokers, such as RabbitMQ and Artemis, set it to the `client_id` of the client consuming the message. * * @example mygroup - client-6 */ - public const MESSAGING_CONSUMER_ID = 'messaging.consumer_id'; + public const MESSAGING_CONSUMER_ID = 'messaging.consumer.id'; /** * RabbitMQ message routing key. * * @example myKey */ - public const MESSAGING_RABBITMQ_ROUTING_KEY = 'messaging.rabbitmq.routing_key'; + public const MESSAGING_RABBITMQ_DESTINATION_ROUTING_KEY = 'messaging.rabbitmq.destination.routing_key'; /** - * Message keys in Kafka are used for grouping alike messages to ensure they're processed on the same partition. They differ from `messaging.message_id` in that they're not unique. If the key is `null`, the attribute MUST NOT be set. + * Message keys in Kafka are used for grouping alike messages to ensure they're processed on the same partition. They differ from `messaging.message.id` in that they're not unique. If the key is `null`, the attribute MUST NOT be set. * * If the key type is not string, it's string representation has to be supplied for the attribute. If the key has no unambiguous, canonical string form, don't include its value. * * @example myKey */ - public const MESSAGING_KAFKA_MESSAGE_KEY = 'messaging.kafka.message_key'; + public const MESSAGING_KAFKA_MESSAGE_KEY = 'messaging.kafka.message.key'; /** * Name of the Kafka Consumer Group that is handling the message. Only applies to consumers, not producers. * * @example my-group */ - public const MESSAGING_KAFKA_CONSUMER_GROUP = 'messaging.kafka.consumer_group'; + public const MESSAGING_KAFKA_CONSUMER_GROUP = 'messaging.kafka.consumer.group'; /** * Client Id for the Consumer or Producer that is handling the message. @@ -948,12 +1128,26 @@ interface TraceAttributes * * @example 2 */ - public const MESSAGING_KAFKA_PARTITION = 'messaging.kafka.partition'; + public const MESSAGING_KAFKA_DESTINATION_PARTITION = 'messaging.kafka.destination.partition'; + + /** + * Partition the message is received from. + * + * @example 2 + */ + public const MESSAGING_KAFKA_SOURCE_PARTITION = 'messaging.kafka.source.partition'; + + /** + * The offset of a record in the corresponding Kafka partition. + * + * @example 42 + */ + public const MESSAGING_KAFKA_MESSAGE_OFFSET = 'messaging.kafka.message.offset'; /** * A boolean that is true if the message is a tombstone. */ - public const MESSAGING_KAFKA_TOMBSTONE = 'messaging.kafka.tombstone'; + public const MESSAGING_KAFKA_MESSAGE_TOMBSTONE = 'messaging.kafka.message.tombstone'; /** * Namespace of RocketMQ resources, resources in different namespaces are individual. @@ -976,17 +1170,38 @@ interface TraceAttributes */ public const MESSAGING_ROCKETMQ_CLIENT_ID = 'messaging.rocketmq.client_id'; + /** + * The timestamp in milliseconds that the delay message is expected to be delivered to consumer. + * + * @example 1665987217045 + */ + public const MESSAGING_ROCKETMQ_MESSAGE_DELIVERY_TIMESTAMP = 'messaging.rocketmq.message.delivery_timestamp'; + + /** + * The delay time level for delay message, which determines the message delay time. + * + * @example 3 + */ + public const MESSAGING_ROCKETMQ_MESSAGE_DELAY_TIME_LEVEL = 'messaging.rocketmq.message.delay_time_level'; + + /** + * It is essential for FIFO message. Messages that belong to the same message group are always processed one by one within the same consumer group. + * + * @example myMessageGroup + */ + public const MESSAGING_ROCKETMQ_MESSAGE_GROUP = 'messaging.rocketmq.message.group'; + /** * Type of message. */ - public const MESSAGING_ROCKETMQ_MESSAGE_TYPE = 'messaging.rocketmq.message_type'; + public const MESSAGING_ROCKETMQ_MESSAGE_TYPE = 'messaging.rocketmq.message.type'; /** * The secondary classifier of message besides topic. * * @example tagA */ - public const MESSAGING_ROCKETMQ_MESSAGE_TAG = 'messaging.rocketmq.message_tag'; + public const MESSAGING_ROCKETMQ_MESSAGE_TAG = 'messaging.rocketmq.message.tag'; /** * Key(s) of message, another way to mark message besides message id. @@ -994,7 +1209,7 @@ interface TraceAttributes * @example keyA * @example keyB */ - public const MESSAGING_ROCKETMQ_MESSAGE_KEYS = 'messaging.rocketmq.message_keys'; + public const MESSAGING_ROCKETMQ_MESSAGE_KEYS = 'messaging.rocketmq.message.keys'; /** * Model of message consumption. This only applies to consumer spans. @@ -1059,4 +1274,27 @@ interface TraceAttributes * Uncompressed size of the message in bytes. */ public const MESSAGE_UNCOMPRESSED_SIZE = 'message.uncompressed_size'; + + /** + * The error codes of the Connect request. Error codes are always string values. + */ + public const RPC_CONNECT_RPC_ERROR_CODE = 'rpc.connect_rpc.error_code'; + + /** + * 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 above.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. + */ + public const EXCEPTION_ESCAPED = 'exception.escaped'; } From d71b6aa410694b65204d21732a2a3c232bae053c Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Wed, 12 Apr 2023 14:35:23 +1000 Subject: [PATCH 2/7] updating semconv readme --- src/SemConv/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/SemConv/README.md b/src/SemConv/README.md index c3de7a4b4..fe30b2f4f 100644 --- a/src/SemConv/README.md +++ b/src/SemConv/README.md @@ -1 +1,11 @@ # OpenTelemetry Semantic Conventions + +Common semantic conventions used by OpenTelemetry implementations across all languages. + +See https://opentelemetry.io/docs/concepts/semantic-conventions/. + +## Installation + +```shell +composer require open-telemetry/sem-conv +``` From bbeb695cc912acbbf7d47e8cb817b3a74252853f Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Wed, 12 Apr 2023 16:23:08 +1000 Subject: [PATCH 3/7] adding more semantic attributes, dropping attribute values taking a lead from the go SIG, who seem to be using semconv the most, I've split semantic conventions up into smaller files representing top-level semconvs. I can't find any usage of the various AttributeValues being used, and other SIGs no longer generate them, so removing them --- script/semantic-conventions/semconv.sh | 25 +- src/SemConv/EventAttributes.php | 108 +++ src/SemConv/MetricAttributes.php | 118 +++ src/SemConv/ResourceAttributeValues.php | 339 --------- src/SemConv/TraceAttributeValues.php | 906 ------------------------ src/SemConv/TraceAttributes.php | 424 +++-------- 6 files changed, 322 insertions(+), 1598 deletions(-) create mode 100644 src/SemConv/EventAttributes.php create mode 100644 src/SemConv/MetricAttributes.php delete mode 100644 src/SemConv/ResourceAttributeValues.php delete mode 100644 src/SemConv/TraceAttributeValues.php diff --git a/script/semantic-conventions/semconv.sh b/script/semantic-conventions/semconv.sh index 731154122..86bc302e8 100755 --- a/script/semantic-conventions/semconv.sh +++ b/script/semantic-conventions/semconv.sh @@ -30,9 +30,8 @@ git reset --hard FETCH_HEAD cd "${SCRIPT_DIR}" || exit -rm -rf "${CODE_DIR}/*.php" || true mkdir -p "${CODE_DIR}" -git checkout HEAD "${CODE_DIR}/composer.json" +find "${CODE_DIR}" -name "*.php" -exec rm -f {} \; # Trace docker run --rm \ @@ -41,7 +40,7 @@ docker run --rm \ -v "${CODE_DIR}:/output" \ -u "${UID}" \ otel/semconvgen:$GENERATOR_VERSION \ - --only span,event,attribute_group,scope \ + --only span \ -f /source code \ --template /templates/Attributes.php.j2 \ --output "/output/TraceAttributes.php" \ @@ -49,18 +48,19 @@ docker run --rm \ -Dclass="Trace" \ -DschemaUrl=$SCHEMA_URL +# Event docker run --rm \ -v "${SPEC_DIR}/semantic_conventions:/source" \ -v "${SCRIPT_DIR}/templates:/templates" \ -v "${CODE_DIR}:/output" \ -u "${UID}" \ otel/semconvgen:$GENERATOR_VERSION \ - --only span,event,attribute_group,scope \ + --only event \ -f /source code \ - --template /templates/AttributeValues.php.j2 \ - --output "/output/TraceAttributeValues.php" \ + --template /templates/Attributes.php.j2 \ + --output "/output/EventAttributes.php" \ -Dnamespace="OpenTelemetry\\SemConv" \ - -Dclass="Trace" \ + -Dclass="Event" \ -DschemaUrl=$SCHEMA_URL # Resource @@ -78,18 +78,19 @@ docker run --rm \ -Dclass="Resource" \ -DschemaUrl=$SCHEMA_URL +# Metric docker run --rm \ -v "${SPEC_DIR}/semantic_conventions:/source" \ -v "${SCRIPT_DIR}/templates:/templates" \ -v "${CODE_DIR}:/output" \ -u "${UID}" \ otel/semconvgen:$GENERATOR_VERSION \ - --only resource \ + --only metric \ -f /source code \ - --template /templates/AttributeValues.php.j2 \ - --output "/output/ResourceAttributeValues.php" \ + --template /templates/Attributes.php.j2 \ + --output "/output/MetricAttributes.php" \ -Dnamespace="OpenTelemetry\\SemConv" \ - -Dclass="Resource" \ + -Dclass="Metric" \ -DschemaUrl=$SCHEMA_URL -rm -rf "${SPEC_DIR}" || true \ No newline at end of file +rm -rf "${SPEC_DIR}" || true diff --git a/src/SemConv/EventAttributes.php b/src/SemConv/EventAttributes.php new file mode 100644 index 000000000..abaf30eb6 --- /dev/null +++ b/src/SemConv/EventAttributes.php @@ -0,0 +1,108 @@ + + *
  • The primary server name of the matched virtual host. MUST only + * include host identifier.
  • + *
  • Host identifier of the request target + * if it's sent in absolute-form.
  • + *
  • Host identifier of the `Host` header
  • + * + * SHOULD NOT be set if only IP address is available and capturing name would require a reverse DNS lookup. + * + * @example localhost + */ + public const NET_HOST_NAME = 'net.host.name'; + + /** + * Port of the local HTTP server that received the request. + * + * Determined by using the first of the following that applies
      + *
    • Port identifier of the primary server host of the matched virtual host.
    • + *
    • Port identifier of the request target + * if it's sent in absolute-form.
    • + *
    • Port identifier of the `Host` header
    • + *
    + * + * @example 8080 + */ + public const NET_HOST_PORT = 'net.host.port'; + + /** + * HTTP request method. + * + * @example GET + * @example POST + * @example HEAD + */ + public const HTTP_METHOD = 'http.method'; + + /** + * HTTP response status code. + * + * @example 200 + */ + public const HTTP_STATUS_CODE = 'http.status_code'; + + /** + * Kind of HTTP protocol used. + */ + public const HTTP_FLAVOR = 'http.flavor'; + + /** + * Host identifier of the "URI origin" HTTP request is sent to. + * + * Determined by using the first of the following that applies
      + *
    • Host identifier of the request target + * if it's sent in absolute-form
    • + *
    • Host identifier of the `Host` header
    • + *
    + * SHOULD NOT be set if capturing it would require an extra DNS lookup. + * + * @example example.com + */ + public const NET_PEER_NAME = 'net.peer.name'; + + /** + * Port identifier of the "URI origin" HTTP request is sent to. + * + * When request target is absolute URI, `net.peer.name` MUST match URI port identifier, otherwise it MUST match `Host` header port identifier. + * + * @example 80 + * @example 8080 + * @example 443 + */ + public const NET_PEER_PORT = 'net.peer.port'; + + /** + * Remote socket peer address: IPv4 or IPv6 for internet protocols, path for local communication, etc. + * + * @example 127.0.0.1 + * @example /tmp/mysql.sock + */ + public const NET_SOCK_PEER_ADDR = 'net.sock.peer.addr'; +} diff --git a/src/SemConv/ResourceAttributeValues.php b/src/SemConv/ResourceAttributeValues.php deleted file mode 100644 index 9178f6e5d..000000000 --- a/src/SemConv/ResourceAttributeValues.php +++ /dev/null @@ -1,339 +0,0 @@ - - *
  • Host identifier of the request target - * if it's sent in absolute-form
  • - *
  • Host identifier of the `Host` header
  • - * - * SHOULD NOT be set if capturing it would require an extra DNS lookup. - * - * @example example.com - */ - public const NET_PEER_NAME = 'net.peer.name'; - - /** - * Port identifier of the "URI origin" HTTP request is sent to. - * - * When request target is absolute URI, `net.peer.name` MUST match URI port identifier, otherwise it MUST match `Host` header port identifier. - * - * @example 80 - * @example 8080 - * @example 443 - */ - public const NET_PEER_PORT = 'net.peer.port'; - - /** - * The URI scheme identifying the used protocol. - * - * @example http - * @example https - */ - public const HTTP_SCHEME = 'http.scheme'; - - /** - * The matched route (path template in the format used by the respective server framework). See note below. - * - * 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. - * SHOULD include the application root if there is one. - * - * @example /users/:userID? - * @example {controller}/{action}/{id?} - */ - public const HTTP_ROUTE = 'http.route'; - - /** - * Name of the local HTTP server that received the request. - * - * Determined by using the first of the following that applies
      - *
    • The primary server name of the matched virtual host. MUST only - * include host identifier.
    • - *
    • Host identifier of the request target - * if it's sent in absolute-form.
    • - *
    • Host identifier of the `Host` header
    • - *
    - * SHOULD NOT be set if only IP address is available and capturing name would require a reverse DNS lookup. - * - * @example localhost - */ - public const NET_HOST_NAME = 'net.host.name'; - - /** - * Port of the local HTTP server that received the request. - * - * Determined by using the first of the following that applies
      - *
    • Port identifier of the primary server host of the matched virtual host.
    • - *
    • Port identifier of the request target - * if it's sent in absolute-form.
    • - *
    • Port identifier of the `Host` header
    • - *
    - * - * @example 8080 - */ - public const NET_HOST_PORT = 'net.host.port'; - - /** - * The name identifies the event. - * - * @example click - * @example exception - */ - public const EVENT_NAME = 'event.name'; - - /** - * The domain identifies the business context for the events. - * - * Events across different domains may have same `event.name`, yet be - * unrelated events. - */ - public const EVENT_DOMAIN = 'event.domain'; - - /** - * The unique identifier of the feature flag. - * - * @example logo-color - */ - public const FEATURE_FLAG_KEY = 'feature_flag.key'; - - /** - * The name of the service provider that performs the flag evaluation. - * - * @example Flag Manager - */ - public const FEATURE_FLAG_PROVIDER_NAME = 'feature_flag.provider_name'; - - /** - * SHOULD be a semantic identifier for a value. If one is unavailable, a stringified version of the value can be used. - * - * A semantic identifier, commonly referred to as a variant, provides a means - * for referring to a value without including the value itself. This can - * provide additional context for understanding the meaning behind a value. - * For example, the variant `red` maybe be used for the value `#c05543`.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. - * - * @example red - * @example true - * @example on - */ - public const FEATURE_FLAG_VARIANT = 'feature_flag.variant'; - /** * The full invoked ARN as provided on the `Context` passed to the function (`Lambda-Runtime-Invoked-Function-Arn` header on the `/runtime/invocation/next` applicable). * @@ -291,6 +150,24 @@ interface TraceAttributes */ public const DB_OPERATION = 'db.operation'; + /** + * Name of the database host. + * + * `net.peer.name` SHOULD NOT be set if capturing it would require an extra DNS lookup. + * + * @example example.com + */ + public const NET_PEER_NAME = 'net.peer.name'; + + /** + * Logical remote port number. + * + * @example 80 + * @example 8080 + * @example 443 + */ + public const NET_PEER_PORT = 'net.peer.port'; + /** * Remote socket peer address: IPv4 or IPv6 for internet protocols, path for local communication, etc. * @@ -493,6 +370,55 @@ interface TraceAttributes */ public const FAAS_DOCUMENT_NAME = 'faas.document.name'; + /** + * The URI scheme identifying the used protocol. + * + * @example http + * @example https + */ + public const HTTP_SCHEME = 'http.scheme'; + + /** + * The matched route (path template in the format used by the respective server framework). See note below. + * + * 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. + * SHOULD include the application root if there is one. + * + * @example /users/:userID? + * @example {controller}/{action}/{id?} + */ + public const HTTP_ROUTE = 'http.route'; + + /** + * Name of the local HTTP server that received the request. + * + * Determined by using the first of the following that applies
      + *
    • The primary server name of the matched virtual host. MUST only + * include host identifier.
    • + *
    • Host identifier of the request target + * if it's sent in absolute-form.
    • + *
    • Host identifier of the `Host` header
    • + *
    + * SHOULD NOT be set if only IP address is available and capturing name would require a reverse DNS lookup. + * + * @example localhost + */ + public const NET_HOST_NAME = 'net.host.name'; + + /** + * Port of the local HTTP server that received the request. + * + * Determined by using the first of the following that applies
      + *
    • Port identifier of the primary server host of the matched virtual host.
    • + *
    • Port identifier of the request target + * if it's sent in absolute-form.
    • + *
    • Port identifier of the `Host` header
    • + *
    + * + * @example 8080 + */ + public const NET_HOST_PORT = 'net.host.port'; + /** * The full request target as passed in a HTTP request line or equivalent. * @@ -767,27 +693,6 @@ interface TraceAttributes */ public const CODE_COLUMN = 'code.column'; - /** - * 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 header. For requests using transport encoding, this should be the compressed size. - * - * @example 3495 - */ - public const HTTP_REQUEST_CONTENT_LENGTH = 'http.request_content_length'; - - /** - * 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 header. For requests using transport encoding, this should be the compressed size. - * - * @example 3495 - */ - public const HTTP_RESPONSE_CONTENT_LENGTH = 'http.response_content_length'; - - /** - * Value of the HTTP User-Agent header sent by the client. - * - * @example CERN-LineMode/2.15 libwww/2.17b3 - */ - public const USER_AGENT_ORIGINAL = 'user_agent.original'; - /** * Full HTTP request URL in the form `scheme://host[:port]/path?query[#fragment]`. Usually the fragment is not transmitted over HTTP, but if it is known, it should be included nevertheless. * @@ -1027,17 +932,6 @@ interface TraceAttributes */ public const MESSAGING_DESTINATION_NAME = 'messaging.destination.name'; - /** - * The message source name. - * - * Source name SHOULD uniquely identify a specific queue, topic, or other entity within the broker. If - * the broker does not have such notion, the source name SHOULD uniquely identify the broker. - * - * @example MyQueue - * @example MyTopic - */ - public const MESSAGING_SOURCE_NAME = 'messaging.source.name'; - /** * The kind of message destination. */ @@ -1062,30 +956,6 @@ interface TraceAttributes */ public const MESSAGING_DESTINATION_ANONYMOUS = 'messaging.destination.anonymous'; - /** - * The kind of message source. - */ - public const MESSAGING_SOURCE_KIND = 'messaging.source.kind'; - - /** - * Low cardinality representation of the messaging source name. - * - * Source names could be constructed from templates. An example would be a source name involving a user name or product id. Although the source name in this case is of high cardinality, the underlying template is of low cardinality and can be effectively used for grouping and aggregation. - * - * @example /customers/{customerId} - */ - public const MESSAGING_SOURCE_TEMPLATE = 'messaging.source.template'; - - /** - * A boolean that is true if the message source is temporary and might not exist anymore after messages are processed. - */ - public const MESSAGING_SOURCE_TEMPORARY = 'messaging.source.temporary'; - - /** - * A boolean that is true if the message source is anonymous (could be unnamed or have auto-generated name). - */ - public const MESSAGING_SOURCE_ANONYMOUS = 'messaging.source.anonymous'; - /** * The identifier for the consumer receiving a message. For Kafka, set it to `{messaging.kafka.consumer.group} - {messaging.kafka.client_id}`, if both are present, or only `messaging.kafka.consumer.group`. For brokers, such as RabbitMQ and Artemis, set it to the `client_id` of the client consuming the message. * @@ -1094,127 +964,39 @@ interface TraceAttributes public const MESSAGING_CONSUMER_ID = 'messaging.consumer.id'; /** - * RabbitMQ message routing key. - * - * @example myKey - */ - public const MESSAGING_RABBITMQ_DESTINATION_ROUTING_KEY = 'messaging.rabbitmq.destination.routing_key'; - - /** - * Message keys in Kafka are used for grouping alike messages to ensure they're processed on the same partition. They differ from `messaging.message.id` in that they're not unique. If the key is `null`, the attribute MUST NOT be set. - * - * If the key type is not string, it's string representation has to be supplied for the attribute. If the key has no unambiguous, canonical string form, don't include its value. - * - * @example myKey - */ - public const MESSAGING_KAFKA_MESSAGE_KEY = 'messaging.kafka.message.key'; - - /** - * Name of the Kafka Consumer Group that is handling the message. Only applies to consumers, not producers. - * - * @example my-group - */ - public const MESSAGING_KAFKA_CONSUMER_GROUP = 'messaging.kafka.consumer.group'; - - /** - * Client Id for the Consumer or Producer that is handling the message. - * - * @example client-5 - */ - public const MESSAGING_KAFKA_CLIENT_ID = 'messaging.kafka.client_id'; - - /** - * Partition the message is sent to. - * - * @example 2 - */ - public const MESSAGING_KAFKA_DESTINATION_PARTITION = 'messaging.kafka.destination.partition'; - - /** - * Partition the message is received from. - * - * @example 2 - */ - public const MESSAGING_KAFKA_SOURCE_PARTITION = 'messaging.kafka.source.partition'; - - /** - * The offset of a record in the corresponding Kafka partition. - * - * @example 42 - */ - public const MESSAGING_KAFKA_MESSAGE_OFFSET = 'messaging.kafka.message.offset'; - - /** - * A boolean that is true if the message is a tombstone. - */ - public const MESSAGING_KAFKA_MESSAGE_TOMBSTONE = 'messaging.kafka.message.tombstone'; - - /** - * Namespace of RocketMQ resources, resources in different namespaces are individual. - * - * @example myNamespace - */ - public const MESSAGING_ROCKETMQ_NAMESPACE = 'messaging.rocketmq.namespace'; - - /** - * Name of the RocketMQ producer/consumer group that is handling the message. The client type is identified by the SpanKind. - * - * @example myConsumerGroup - */ - public const MESSAGING_ROCKETMQ_CLIENT_GROUP = 'messaging.rocketmq.client_group'; - - /** - * The unique identifier for each client. + * The message source name. * - * @example myhost@8742@s8083jm - */ - public const MESSAGING_ROCKETMQ_CLIENT_ID = 'messaging.rocketmq.client_id'; - - /** - * The timestamp in milliseconds that the delay message is expected to be delivered to consumer. + * Source name SHOULD uniquely identify a specific queue, topic, or other entity within the broker. If + * the broker does not have such notion, the source name SHOULD uniquely identify the broker. * - * @example 1665987217045 + * @example MyQueue + * @example MyTopic */ - public const MESSAGING_ROCKETMQ_MESSAGE_DELIVERY_TIMESTAMP = 'messaging.rocketmq.message.delivery_timestamp'; + public const MESSAGING_SOURCE_NAME = 'messaging.source.name'; /** - * The delay time level for delay message, which determines the message delay time. - * - * @example 3 + * The kind of message source. */ - public const MESSAGING_ROCKETMQ_MESSAGE_DELAY_TIME_LEVEL = 'messaging.rocketmq.message.delay_time_level'; + public const MESSAGING_SOURCE_KIND = 'messaging.source.kind'; /** - * It is essential for FIFO message. Messages that belong to the same message group are always processed one by one within the same consumer group. + * Low cardinality representation of the messaging source name. * - * @example myMessageGroup - */ - public const MESSAGING_ROCKETMQ_MESSAGE_GROUP = 'messaging.rocketmq.message.group'; - - /** - * Type of message. - */ - public const MESSAGING_ROCKETMQ_MESSAGE_TYPE = 'messaging.rocketmq.message.type'; - - /** - * The secondary classifier of message besides topic. + * Source names could be constructed from templates. An example would be a source name involving a user name or product id. Although the source name in this case is of high cardinality, the underlying template is of low cardinality and can be effectively used for grouping and aggregation. * - * @example tagA + * @example /customers/{customerId} */ - public const MESSAGING_ROCKETMQ_MESSAGE_TAG = 'messaging.rocketmq.message.tag'; + public const MESSAGING_SOURCE_TEMPLATE = 'messaging.source.template'; /** - * Key(s) of message, another way to mark message besides message id. - * - * @example keyA - * @example keyB + * A boolean that is true if the message source is temporary and might not exist anymore after messages are processed. */ - public const MESSAGING_ROCKETMQ_MESSAGE_KEYS = 'messaging.rocketmq.message.keys'; + public const MESSAGING_SOURCE_TEMPORARY = 'messaging.source.temporary'; /** - * Model of message consumption. This only applies to consumer spans. + * A boolean that is true if the message source is anonymous (could be unnamed or have auto-generated name). */ - public const MESSAGING_ROCKETMQ_CONSUMPTION_MODEL = 'messaging.rocketmq.consumption_model'; + public const MESSAGING_SOURCE_ANONYMOUS = 'messaging.source.anonymous'; /** * The numeric status code of the gRPC request. @@ -1253,48 +1035,8 @@ interface TraceAttributes */ public const RPC_JSONRPC_ERROR_MESSAGE = 'rpc.jsonrpc.error_message'; - /** - * Whether this is a received or sent message. - */ - public const MESSAGE_TYPE = 'message.type'; - - /** - * MUST be calculated as two different counters starting from `1` one for sent messages and one for received message. - * - * This way we guarantee that the values will be consistent between different implementations. - */ - public const MESSAGE_ID = 'message.id'; - - /** - * Compressed size of the message in bytes. - */ - public const MESSAGE_COMPRESSED_SIZE = 'message.compressed_size'; - - /** - * Uncompressed size of the message in bytes. - */ - public const MESSAGE_UNCOMPRESSED_SIZE = 'message.uncompressed_size'; - /** * The error codes of the Connect request. Error codes are always string values. */ public const RPC_CONNECT_RPC_ERROR_CODE = 'rpc.connect_rpc.error_code'; - - /** - * 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 above.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. - */ - public const EXCEPTION_ESCAPED = 'exception.escaped'; } From 21880e8774d2c0b3bcc0a5cb82db10b3e2b1d246 Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Wed, 12 Apr 2023 16:53:48 +1000 Subject: [PATCH 4/7] exception semconv's have moved from trace to event --- src/API/Trace/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/API/Trace/functions.php b/src/API/Trace/functions.php index 33f129a4b..02a1a145c 100644 --- a/src/API/Trace/functions.php +++ b/src/API/Trace/functions.php @@ -5,7 +5,7 @@ namespace OpenTelemetry\API\Trace; use Closure; -use OpenTelemetry\SemConv\TraceAttributes; +use OpenTelemetry\SemConv\EventAttributes; use Throwable; /** @@ -35,7 +35,7 @@ function trace(SpanInterface $span, Closure $closure, iterable $args = []) return $c(...$a, ...($a = [])); } catch (Throwable $e) { $s->setStatus(StatusCode::STATUS_ERROR, $e->getMessage()); - $s->recordException($e, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $s->recordException($e, [EventAttributes::EXCEPTION_ESCAPED => true]); throw $e; } finally { From 229462d3f436cffbe6b9e90ef8bd968554aa9ba0 Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Tue, 18 Apr 2023 13:26:01 +1000 Subject: [PATCH 5/7] removing semconv usage from API --- src/API/Trace/functions.php | 3 +-- src/API/composer.json | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/API/Trace/functions.php b/src/API/Trace/functions.php index 02a1a145c..79f730717 100644 --- a/src/API/Trace/functions.php +++ b/src/API/Trace/functions.php @@ -5,7 +5,6 @@ namespace OpenTelemetry\API\Trace; use Closure; -use OpenTelemetry\SemConv\EventAttributes; use Throwable; /** @@ -35,7 +34,7 @@ function trace(SpanInterface $span, Closure $closure, iterable $args = []) return $c(...$a, ...($a = [])); } catch (Throwable $e) { $s->setStatus(StatusCode::STATUS_ERROR, $e->getMessage()); - $s->recordException($e, [EventAttributes::EXCEPTION_ESCAPED => true]); + $s->recordException($e, ['exception.escaped' => true]); throw $e; } finally { diff --git a/src/API/composer.json b/src/API/composer.json index 0ac612e89..0867f12d5 100644 --- a/src/API/composer.json +++ b/src/API/composer.json @@ -13,7 +13,6 @@ "require": { "php": "^7.4 || ^8.0", "open-telemetry/context": "^1.0", - "open-telemetry/sem-conv": "^1.0", "psr/log": "^1.1|^2.0|^3.0", "symfony/polyfill-php80": "^1.26", "symfony/polyfill-php81": "^1.26", From 477c45ec81f2ec500d6e4aa9fd184ec982650a24 Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Fri, 21 Apr 2023 14:37:46 +1000 Subject: [PATCH 6/7] removing event + metric attributes java has not progressed with these yet, so I think we should wait until we see what they do :) allow deprecations of moved/removed attributes so that we don't break things across different semconv versions (similar to how java does it, except I moved them into a file which is imported --- script/semantic-conventions/README.md | 26 + script/semantic-conventions/semconv.sh | 32 +- .../templates/Attributes.php.j2 | 8 +- .../resource_deprecations.php.partial | 9 + .../templates/trace_deprecations.php.partial | 90 +++ src/SemConv/EventAttributes.php | 108 ---- src/SemConv/MetricAttributes.php | 118 ---- src/SemConv/ResourceAttributes.php | 12 + src/SemConv/TraceAttributes.php | 515 +++++++++++++++--- 9 files changed, 575 insertions(+), 343 deletions(-) create mode 100644 script/semantic-conventions/README.md create mode 100644 script/semantic-conventions/templates/resource_deprecations.php.partial create mode 100644 script/semantic-conventions/templates/trace_deprecations.php.partial delete mode 100644 src/SemConv/EventAttributes.php delete mode 100644 src/SemConv/MetricAttributes.php diff --git a/script/semantic-conventions/README.md b/script/semantic-conventions/README.md new file mode 100644 index 000000000..ff230d8cd --- /dev/null +++ b/script/semantic-conventions/README.md @@ -0,0 +1,26 @@ +# Semantic Convention generation script and templates + +## Usage + +To update semantic conventions, modify `semconv.sh`'s `SEMCONV_VERSION` and `GENERATOR_VERSION` values, then run: + +```shell +./semconv.sh +``` + +## Backwards compatibility + +If attributes have been removed in an update, you can add them back in via `templates/_deprecations.php.partial` files, +the contents will be included in the generated output. Please remember to mark them as deprecated to discourage their future +use. + +After generating new sementic conventions, you can locate removed attributes via: + +```shell +diff <(grep "public const" src/SemConv/ResourceAttributes.php | sort -u) \ + <(git show main:src/SemConv/ResourceAttributes.php | grep "public const" | sort -u) \ + | grep '^>' \ + | grep -v SCHEMA_URL +``` + +Use this output as a basis for updating the relevant deprecations file and generate a second time to include them in the final output. diff --git a/script/semantic-conventions/semconv.sh b/script/semantic-conventions/semconv.sh index 86bc302e8..225e9d070 100755 --- a/script/semantic-conventions/semconv.sh +++ b/script/semantic-conventions/semconv.sh @@ -40,7 +40,7 @@ docker run --rm \ -v "${CODE_DIR}:/output" \ -u "${UID}" \ otel/semconvgen:$GENERATOR_VERSION \ - --only span \ + --only span,event,attribute_group,scope \ -f /source code \ --template /templates/Attributes.php.j2 \ --output "/output/TraceAttributes.php" \ @@ -48,21 +48,6 @@ docker run --rm \ -Dclass="Trace" \ -DschemaUrl=$SCHEMA_URL -# Event -docker run --rm \ - -v "${SPEC_DIR}/semantic_conventions:/source" \ - -v "${SCRIPT_DIR}/templates:/templates" \ - -v "${CODE_DIR}:/output" \ - -u "${UID}" \ - otel/semconvgen:$GENERATOR_VERSION \ - --only event \ - -f /source code \ - --template /templates/Attributes.php.j2 \ - --output "/output/EventAttributes.php" \ - -Dnamespace="OpenTelemetry\\SemConv" \ - -Dclass="Event" \ - -DschemaUrl=$SCHEMA_URL - # Resource docker run --rm \ -v "${SPEC_DIR}/semantic_conventions:/source" \ @@ -78,19 +63,4 @@ docker run --rm \ -Dclass="Resource" \ -DschemaUrl=$SCHEMA_URL -# Metric -docker run --rm \ - -v "${SPEC_DIR}/semantic_conventions:/source" \ - -v "${SCRIPT_DIR}/templates:/templates" \ - -v "${CODE_DIR}:/output" \ - -u "${UID}" \ - otel/semconvgen:$GENERATOR_VERSION \ - --only metric \ - -f /source code \ - --template /templates/Attributes.php.j2 \ - --output "/output/MetricAttributes.php" \ - -Dnamespace="OpenTelemetry\\SemConv" \ - -Dclass="Metric" \ - -DschemaUrl=$SCHEMA_URL - rm -rf "${SPEC_DIR}" || true diff --git a/script/semantic-conventions/templates/Attributes.php.j2 b/script/semantic-conventions/templates/Attributes.php.j2 index 17ed33cc6..67a45a7f1 100644 --- a/script/semantic-conventions/templates/Attributes.php.j2 +++ b/script/semantic-conventions/templates/Attributes.php.j2 @@ -19,10 +19,10 @@ interface {{ class }}Attributes * * {{ attribute.note | render_markdown(code="`{0}`", paragraph="{0}", link="{1}") | trim("\n")| regex_replace(pattern="\n", replace="\n * ") }} {%- endif %} - {%- if attribute.examples or attribute.deprecated %} + {%- if attribute.examples or attribute.stability == "deprecated" %} * - {%- if attribute.deprecated %} - * @deprecated {{ attribute.deprecated | render_markdown(code="`{0}`", paragraph="{0}", link="{{@link {0} {1}}}") | regex_replace(pattern="\n", replace="\n * ") }} + {%- if (attribute.stability | string()) == "StabilityLevel.DEPRECATED" %} + * @deprecated {{attribute.brief}}. {%- endif %} {%- for example in attribute.examples if example %} * @example {{ example }} @@ -32,5 +32,7 @@ interface {{ class }}Attributes public const {{ attribute.fqn | to_const_name }} = '{{ attribute.fqn }}'; {% if not loop.last %}{# blank line #}{% endif %} {%- endfor -%} +{# add our own deprecations for moved/removed attributes, so we don't break things #} +{% include class|lower + "_deprecations.php.partial" ignore missing without context %} } {# blank line #} diff --git a/script/semantic-conventions/templates/resource_deprecations.php.partial b/script/semantic-conventions/templates/resource_deprecations.php.partial new file mode 100644 index 000000000..2f24bb0b9 --- /dev/null +++ b/script/semantic-conventions/templates/resource_deprecations.php.partial @@ -0,0 +1,9 @@ + /** + * @deprecated + */ + public const BROWSER_USER_AGENT = 'browser.user_agent'; + + /** + * @deprecated + */ + public const FAAS_ID = 'faas.id'; diff --git a/script/semantic-conventions/templates/trace_deprecations.php.partial b/script/semantic-conventions/templates/trace_deprecations.php.partial new file mode 100644 index 000000000..d73b0e17e --- /dev/null +++ b/script/semantic-conventions/templates/trace_deprecations.php.partial @@ -0,0 +1,90 @@ + /** + * @deprecated + */ + public const FAAS_EXECUTION = 'faas.execution'; + + /** + * @deprecated + */ + public const HTTP_HOST = 'http.host'; + + /** + * @deprecated + */ + public const HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED = 'http.request_content_length_uncompressed'; + + /** + * @deprecated + */ + public const HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED = 'http.response_content_length_uncompressed'; + + /** + * @deprecated + */ + public const HTTP_RETRY_COUNT = 'http.retry_count'; + + /** + * @deprecated + */ + public const HTTP_SERVER_NAME = 'http.server_name'; + + /** + * @deprecated + */ + public const HTTP_USER_AGENT = 'http.user_agent'; + + /** + * @deprecated + */ + public const MESSAGING_CONVERSATION_ID = 'messaging.conversation_id'; + + /** + * @deprecated + */ + public const MESSAGING_DESTINATION = 'messaging.destination'; + + + /** + * @deprecated + */ + public const MESSAGING_KAFKA_PARTITION = 'messaging.kafka.partition'; + + /** + * @deprecated + */ + public const MESSAGING_KAFKA_TOMBSTONE = 'messaging.kafka.tombstone'; + + /** + * @deprecated + */ + public const MESSAGING_PROTOCOL = 'messaging.protocol'; + + /** + * @deprecated + */ + public const MESSAGING_PROTOCOL_VERSION = 'messaging.protocol_version'; + + /** + * @deprecated + */ + public const MESSAGING_RABBITMQ_ROUTING_KEY = 'messaging.rabbitmq.routing_key'; + + /** + * @deprecated + */ + public const MESSAGING_TEMP_DESTINATION = 'messaging.temp_destination'; + + /** + * @deprecated + */ + public const MESSAGING_URL = 'messaging.url'; + + /** + * @deprecated + */ + public const NET_HOST_IP = 'net.host.ip'; + + /** + * @deprecated + */ + public const NET_PEER_IP = 'net.peer.ip'; \ No newline at end of file diff --git a/src/SemConv/EventAttributes.php b/src/SemConv/EventAttributes.php deleted file mode 100644 index abaf30eb6..000000000 --- a/src/SemConv/EventAttributes.php +++ /dev/null @@ -1,108 +0,0 @@ - - *
  • The primary server name of the matched virtual host. MUST only - * include host identifier.
  • - *
  • Host identifier of the request target - * if it's sent in absolute-form.
  • - *
  • Host identifier of the `Host` header
  • - * - * SHOULD NOT be set if only IP address is available and capturing name would require a reverse DNS lookup. - * - * @example localhost - */ - public const NET_HOST_NAME = 'net.host.name'; - - /** - * Port of the local HTTP server that received the request. - * - * Determined by using the first of the following that applies
      - *
    • Port identifier of the primary server host of the matched virtual host.
    • - *
    • Port identifier of the request target - * if it's sent in absolute-form.
    • - *
    • Port identifier of the `Host` header
    • - *
    - * - * @example 8080 - */ - public const NET_HOST_PORT = 'net.host.port'; - - /** - * HTTP request method. - * - * @example GET - * @example POST - * @example HEAD - */ - public const HTTP_METHOD = 'http.method'; - - /** - * HTTP response status code. - * - * @example 200 - */ - public const HTTP_STATUS_CODE = 'http.status_code'; - - /** - * Kind of HTTP protocol used. - */ - public const HTTP_FLAVOR = 'http.flavor'; - - /** - * Host identifier of the "URI origin" HTTP request is sent to. - * - * Determined by using the first of the following that applies
      - *
    • Host identifier of the request target - * if it's sent in absolute-form
    • - *
    • Host identifier of the `Host` header
    • - *
    - * SHOULD NOT be set if capturing it would require an extra DNS lookup. - * - * @example example.com - */ - public const NET_PEER_NAME = 'net.peer.name'; - - /** - * Port identifier of the "URI origin" HTTP request is sent to. - * - * When request target is absolute URI, `net.peer.name` MUST match URI port identifier, otherwise it MUST match `Host` header port identifier. - * - * @example 80 - * @example 8080 - * @example 443 - */ - public const NET_PEER_PORT = 'net.peer.port'; - - /** - * Remote socket peer address: IPv4 or IPv6 for internet protocols, path for local communication, etc. - * - * @example 127.0.0.1 - * @example /tmp/mysql.sock - */ - public const NET_SOCK_PEER_ADDR = 'net.sock.peer.addr'; -} diff --git a/src/SemConv/ResourceAttributes.php b/src/SemConv/ResourceAttributes.php index 591c9dca8..126c488df 100644 --- a/src/SemConv/ResourceAttributes.php +++ b/src/SemConv/ResourceAttributes.php @@ -771,6 +771,7 @@ interface ResourceAttributes /** * Deprecated, use the `otel.scope.name` attribute. * + * @deprecated Deprecated, use the `otel.scope.name` attribute.. * @example io.opentelemetry.contrib.mongodb */ public const OTEL_LIBRARY_NAME = 'otel.library.name'; @@ -778,7 +779,18 @@ interface ResourceAttributes /** * Deprecated, use the `otel.scope.version` attribute. * + * @deprecated Deprecated, use the `otel.scope.version` attribute.. * @example 1.0.0 */ public const OTEL_LIBRARY_VERSION = 'otel.library.version'; + + /** + * @deprecated + */ + public const BROWSER_USER_AGENT = 'browser.user_agent'; + + /** + * @deprecated + */ + public const FAAS_ID = 'faas.id'; } diff --git a/src/SemConv/TraceAttributes.php b/src/SemConv/TraceAttributes.php index ad76c03ef..72b45785b 100644 --- a/src/SemConv/TraceAttributes.php +++ b/src/SemConv/TraceAttributes.php @@ -36,6 +36,147 @@ interface TraceAttributes */ public const EXCEPTION_STACKTRACE = 'exception.stacktrace'; + /** + * HTTP request method. + * + * @example GET + * @example POST + * @example HEAD + */ + public const HTTP_METHOD = 'http.method'; + + /** + * HTTP response status code. + * + * @example 200 + */ + public const HTTP_STATUS_CODE = 'http.status_code'; + + /** + * Kind of HTTP protocol used. + */ + public const HTTP_FLAVOR = 'http.flavor'; + + /** + * Host identifier of the "URI origin" HTTP request is sent to. + * + * Determined by using the first of the following that applies
      + *
    • Host identifier of the request target + * if it's sent in absolute-form
    • + *
    • Host identifier of the `Host` header
    • + *
    + * SHOULD NOT be set if capturing it would require an extra DNS lookup. + * + * @example example.com + */ + public const NET_PEER_NAME = 'net.peer.name'; + + /** + * Port identifier of the "URI origin" HTTP request is sent to. + * + * When request target is absolute URI, `net.peer.name` MUST match URI port identifier, otherwise it MUST match `Host` header port identifier. + * + * @example 80 + * @example 8080 + * @example 443 + */ + public const NET_PEER_PORT = 'net.peer.port'; + + /** + * The URI scheme identifying the used protocol. + * + * @example http + * @example https + */ + public const HTTP_SCHEME = 'http.scheme'; + + /** + * The matched route (path template in the format used by the respective server framework). See note below. + * + * 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. + * SHOULD include the application root if there is one. + * + * @example /users/:userID? + * @example {controller}/{action}/{id?} + */ + public const HTTP_ROUTE = 'http.route'; + + /** + * Name of the local HTTP server that received the request. + * + * Determined by using the first of the following that applies
      + *
    • The primary server name of the matched virtual host. MUST only + * include host identifier.
    • + *
    • Host identifier of the request target + * if it's sent in absolute-form.
    • + *
    • Host identifier of the `Host` header
    • + *
    + * SHOULD NOT be set if only IP address is available and capturing name would require a reverse DNS lookup. + * + * @example localhost + */ + public const NET_HOST_NAME = 'net.host.name'; + + /** + * Port of the local HTTP server that received the request. + * + * Determined by using the first of the following that applies
      + *
    • Port identifier of the primary server host of the matched virtual host.
    • + *
    • Port identifier of the request target + * if it's sent in absolute-form.
    • + *
    • Port identifier of the `Host` header
    • + *
    + * + * @example 8080 + */ + public const NET_HOST_PORT = 'net.host.port'; + + /** + * The name identifies the event. + * + * @example click + * @example exception + */ + public const EVENT_NAME = 'event.name'; + + /** + * The domain identifies the business context for the events. + * + * Events across different domains may have same `event.name`, yet be + * unrelated events. + */ + public const EVENT_DOMAIN = 'event.domain'; + + /** + * The unique identifier of the feature flag. + * + * @example logo-color + */ + public const FEATURE_FLAG_KEY = 'feature_flag.key'; + + /** + * The name of the service provider that performs the flag evaluation. + * + * @example Flag Manager + */ + public const FEATURE_FLAG_PROVIDER_NAME = 'feature_flag.provider_name'; + + /** + * SHOULD be a semantic identifier for a value. If one is unavailable, a stringified version of the value can be used. + * + * A semantic identifier, commonly referred to as a variant, provides a means + * for referring to a value without including the value itself. This can + * provide additional context for understanding the meaning behind a value. + * For example, the variant `red` maybe be used for the value `#c05543`.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. + * + * @example red + * @example true + * @example on + */ + public const FEATURE_FLAG_VARIANT = 'feature_flag.variant'; + /** * The full invoked ARN as provided on the `Context` passed to the function (`Lambda-Runtime-Invoked-Function-Arn` header on the `/runtime/invocation/next` applicable). * @@ -150,24 +291,6 @@ interface TraceAttributes */ public const DB_OPERATION = 'db.operation'; - /** - * Name of the database host. - * - * `net.peer.name` SHOULD NOT be set if capturing it would require an extra DNS lookup. - * - * @example example.com - */ - public const NET_PEER_NAME = 'net.peer.name'; - - /** - * Logical remote port number. - * - * @example 80 - * @example 8080 - * @example 443 - */ - public const NET_PEER_PORT = 'net.peer.port'; - /** * Remote socket peer address: IPv4 or IPv6 for internet protocols, path for local communication, etc. * @@ -370,55 +493,6 @@ interface TraceAttributes */ public const FAAS_DOCUMENT_NAME = 'faas.document.name'; - /** - * The URI scheme identifying the used protocol. - * - * @example http - * @example https - */ - public const HTTP_SCHEME = 'http.scheme'; - - /** - * The matched route (path template in the format used by the respective server framework). See note below. - * - * 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. - * SHOULD include the application root if there is one. - * - * @example /users/:userID? - * @example {controller}/{action}/{id?} - */ - public const HTTP_ROUTE = 'http.route'; - - /** - * Name of the local HTTP server that received the request. - * - * Determined by using the first of the following that applies
      - *
    • The primary server name of the matched virtual host. MUST only - * include host identifier.
    • - *
    • Host identifier of the request target - * if it's sent in absolute-form.
    • - *
    • Host identifier of the `Host` header
    • - *
    - * SHOULD NOT be set if only IP address is available and capturing name would require a reverse DNS lookup. - * - * @example localhost - */ - public const NET_HOST_NAME = 'net.host.name'; - - /** - * Port of the local HTTP server that received the request. - * - * Determined by using the first of the following that applies
      - *
    • Port identifier of the primary server host of the matched virtual host.
    • - *
    • Port identifier of the request target - * if it's sent in absolute-form.
    • - *
    • Port identifier of the `Host` header
    • - *
    - * - * @example 8080 - */ - public const NET_HOST_PORT = 'net.host.port'; - /** * The full request target as passed in a HTTP request line or equivalent. * @@ -693,6 +767,27 @@ interface TraceAttributes */ public const CODE_COLUMN = 'code.column'; + /** + * 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 header. For requests using transport encoding, this should be the compressed size. + * + * @example 3495 + */ + public const HTTP_REQUEST_CONTENT_LENGTH = 'http.request_content_length'; + + /** + * 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 header. For requests using transport encoding, this should be the compressed size. + * + * @example 3495 + */ + public const HTTP_RESPONSE_CONTENT_LENGTH = 'http.response_content_length'; + + /** + * Value of the HTTP User-Agent header sent by the client. + * + * @example CERN-LineMode/2.15 libwww/2.17b3 + */ + public const USER_AGENT_ORIGINAL = 'user_agent.original'; + /** * Full HTTP request URL in the form `scheme://host[:port]/path?query[#fragment]`. Usually the fragment is not transmitted over HTTP, but if it is known, it should be included nevertheless. * @@ -932,6 +1027,17 @@ interface TraceAttributes */ public const MESSAGING_DESTINATION_NAME = 'messaging.destination.name'; + /** + * The message source name. + * + * Source name SHOULD uniquely identify a specific queue, topic, or other entity within the broker. If + * the broker does not have such notion, the source name SHOULD uniquely identify the broker. + * + * @example MyQueue + * @example MyTopic + */ + public const MESSAGING_SOURCE_NAME = 'messaging.source.name'; + /** * The kind of message destination. */ @@ -956,6 +1062,30 @@ interface TraceAttributes */ public const MESSAGING_DESTINATION_ANONYMOUS = 'messaging.destination.anonymous'; + /** + * The kind of message source. + */ + public const MESSAGING_SOURCE_KIND = 'messaging.source.kind'; + + /** + * Low cardinality representation of the messaging source name. + * + * Source names could be constructed from templates. An example would be a source name involving a user name or product id. Although the source name in this case is of high cardinality, the underlying template is of low cardinality and can be effectively used for grouping and aggregation. + * + * @example /customers/{customerId} + */ + public const MESSAGING_SOURCE_TEMPLATE = 'messaging.source.template'; + + /** + * A boolean that is true if the message source is temporary and might not exist anymore after messages are processed. + */ + public const MESSAGING_SOURCE_TEMPORARY = 'messaging.source.temporary'; + + /** + * A boolean that is true if the message source is anonymous (could be unnamed or have auto-generated name). + */ + public const MESSAGING_SOURCE_ANONYMOUS = 'messaging.source.anonymous'; + /** * The identifier for the consumer receiving a message. For Kafka, set it to `{messaging.kafka.consumer.group} - {messaging.kafka.client_id}`, if both are present, or only `messaging.kafka.consumer.group`. For brokers, such as RabbitMQ and Artemis, set it to the `client_id` of the client consuming the message. * @@ -964,39 +1094,127 @@ interface TraceAttributes public const MESSAGING_CONSUMER_ID = 'messaging.consumer.id'; /** - * The message source name. + * RabbitMQ message routing key. * - * Source name SHOULD uniquely identify a specific queue, topic, or other entity within the broker. If - * the broker does not have such notion, the source name SHOULD uniquely identify the broker. + * @example myKey + */ + public const MESSAGING_RABBITMQ_DESTINATION_ROUTING_KEY = 'messaging.rabbitmq.destination.routing_key'; + + /** + * Message keys in Kafka are used for grouping alike messages to ensure they're processed on the same partition. They differ from `messaging.message.id` in that they're not unique. If the key is `null`, the attribute MUST NOT be set. * - * @example MyQueue - * @example MyTopic + * If the key type is not string, it's string representation has to be supplied for the attribute. If the key has no unambiguous, canonical string form, don't include its value. + * + * @example myKey */ - public const MESSAGING_SOURCE_NAME = 'messaging.source.name'; + public const MESSAGING_KAFKA_MESSAGE_KEY = 'messaging.kafka.message.key'; /** - * The kind of message source. + * Name of the Kafka Consumer Group that is handling the message. Only applies to consumers, not producers. + * + * @example my-group */ - public const MESSAGING_SOURCE_KIND = 'messaging.source.kind'; + public const MESSAGING_KAFKA_CONSUMER_GROUP = 'messaging.kafka.consumer.group'; /** - * Low cardinality representation of the messaging source name. + * Client Id for the Consumer or Producer that is handling the message. * - * Source names could be constructed from templates. An example would be a source name involving a user name or product id. Although the source name in this case is of high cardinality, the underlying template is of low cardinality and can be effectively used for grouping and aggregation. + * @example client-5 + */ + public const MESSAGING_KAFKA_CLIENT_ID = 'messaging.kafka.client_id'; + + /** + * Partition the message is sent to. * - * @example /customers/{customerId} + * @example 2 */ - public const MESSAGING_SOURCE_TEMPLATE = 'messaging.source.template'; + public const MESSAGING_KAFKA_DESTINATION_PARTITION = 'messaging.kafka.destination.partition'; /** - * A boolean that is true if the message source is temporary and might not exist anymore after messages are processed. + * Partition the message is received from. + * + * @example 2 */ - public const MESSAGING_SOURCE_TEMPORARY = 'messaging.source.temporary'; + public const MESSAGING_KAFKA_SOURCE_PARTITION = 'messaging.kafka.source.partition'; /** - * A boolean that is true if the message source is anonymous (could be unnamed or have auto-generated name). + * The offset of a record in the corresponding Kafka partition. + * + * @example 42 */ - public const MESSAGING_SOURCE_ANONYMOUS = 'messaging.source.anonymous'; + public const MESSAGING_KAFKA_MESSAGE_OFFSET = 'messaging.kafka.message.offset'; + + /** + * A boolean that is true if the message is a tombstone. + */ + public const MESSAGING_KAFKA_MESSAGE_TOMBSTONE = 'messaging.kafka.message.tombstone'; + + /** + * Namespace of RocketMQ resources, resources in different namespaces are individual. + * + * @example myNamespace + */ + public const MESSAGING_ROCKETMQ_NAMESPACE = 'messaging.rocketmq.namespace'; + + /** + * Name of the RocketMQ producer/consumer group that is handling the message. The client type is identified by the SpanKind. + * + * @example myConsumerGroup + */ + public const MESSAGING_ROCKETMQ_CLIENT_GROUP = 'messaging.rocketmq.client_group'; + + /** + * The unique identifier for each client. + * + * @example myhost@8742@s8083jm + */ + public const MESSAGING_ROCKETMQ_CLIENT_ID = 'messaging.rocketmq.client_id'; + + /** + * The timestamp in milliseconds that the delay message is expected to be delivered to consumer. + * + * @example 1665987217045 + */ + public const MESSAGING_ROCKETMQ_MESSAGE_DELIVERY_TIMESTAMP = 'messaging.rocketmq.message.delivery_timestamp'; + + /** + * The delay time level for delay message, which determines the message delay time. + * + * @example 3 + */ + public const MESSAGING_ROCKETMQ_MESSAGE_DELAY_TIME_LEVEL = 'messaging.rocketmq.message.delay_time_level'; + + /** + * It is essential for FIFO message. Messages that belong to the same message group are always processed one by one within the same consumer group. + * + * @example myMessageGroup + */ + public const MESSAGING_ROCKETMQ_MESSAGE_GROUP = 'messaging.rocketmq.message.group'; + + /** + * Type of message. + */ + public const MESSAGING_ROCKETMQ_MESSAGE_TYPE = 'messaging.rocketmq.message.type'; + + /** + * The secondary classifier of message besides topic. + * + * @example tagA + */ + public const MESSAGING_ROCKETMQ_MESSAGE_TAG = 'messaging.rocketmq.message.tag'; + + /** + * Key(s) of message, another way to mark message besides message id. + * + * @example keyA + * @example keyB + */ + public const MESSAGING_ROCKETMQ_MESSAGE_KEYS = 'messaging.rocketmq.message.keys'; + + /** + * Model of message consumption. This only applies to consumer spans. + */ + public const MESSAGING_ROCKETMQ_CONSUMPTION_MODEL = 'messaging.rocketmq.consumption_model'; /** * The numeric status code of the gRPC request. @@ -1035,8 +1253,139 @@ interface TraceAttributes */ public const RPC_JSONRPC_ERROR_MESSAGE = 'rpc.jsonrpc.error_message'; + /** + * Whether this is a received or sent message. + */ + public const MESSAGE_TYPE = 'message.type'; + + /** + * MUST be calculated as two different counters starting from `1` one for sent messages and one for received message. + * + * This way we guarantee that the values will be consistent between different implementations. + */ + public const MESSAGE_ID = 'message.id'; + + /** + * Compressed size of the message in bytes. + */ + public const MESSAGE_COMPRESSED_SIZE = 'message.compressed_size'; + + /** + * Uncompressed size of the message in bytes. + */ + public const MESSAGE_UNCOMPRESSED_SIZE = 'message.uncompressed_size'; + /** * The error codes of the Connect request. Error codes are always string values. */ public const RPC_CONNECT_RPC_ERROR_CODE = 'rpc.connect_rpc.error_code'; + + /** + * 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 above.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. + */ + public const EXCEPTION_ESCAPED = 'exception.escaped'; + + /** + * @deprecated + */ + public const FAAS_EXECUTION = 'faas.execution'; + + /** + * @deprecated + */ + public const HTTP_HOST = 'http.host'; + + /** + * @deprecated + */ + public const HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED = 'http.request_content_length_uncompressed'; + + /** + * @deprecated + */ + public const HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED = 'http.response_content_length_uncompressed'; + + /** + * @deprecated + */ + public const HTTP_RETRY_COUNT = 'http.retry_count'; + + /** + * @deprecated + */ + public const HTTP_SERVER_NAME = 'http.server_name'; + + /** + * @deprecated + */ + public const HTTP_USER_AGENT = 'http.user_agent'; + + /** + * @deprecated + */ + public const MESSAGING_CONVERSATION_ID = 'messaging.conversation_id'; + + /** + * @deprecated + */ + public const MESSAGING_DESTINATION = 'messaging.destination'; + + + /** + * @deprecated + */ + public const MESSAGING_KAFKA_PARTITION = 'messaging.kafka.partition'; + + /** + * @deprecated + */ + public const MESSAGING_KAFKA_TOMBSTONE = 'messaging.kafka.tombstone'; + + /** + * @deprecated + */ + public const MESSAGING_PROTOCOL = 'messaging.protocol'; + + /** + * @deprecated + */ + public const MESSAGING_PROTOCOL_VERSION = 'messaging.protocol_version'; + + /** + * @deprecated + */ + public const MESSAGING_RABBITMQ_ROUTING_KEY = 'messaging.rabbitmq.routing_key'; + + /** + * @deprecated + */ + public const MESSAGING_TEMP_DESTINATION = 'messaging.temp_destination'; + + /** + * @deprecated + */ + public const MESSAGING_URL = 'messaging.url'; + + /** + * @deprecated + */ + public const NET_HOST_IP = 'net.host.ip'; + + /** + * @deprecated + */ + public const NET_PEER_IP = 'net.peer.ip'; } From c217edbbba3015887b345ea992ad6ed954224a81 Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Fri, 21 Apr 2023 17:57:27 +1000 Subject: [PATCH 7/7] style --- .../templates/trace_deprecations.php.partial | 1 - src/SemConv/TraceAttributes.php | 1 - 2 files changed, 2 deletions(-) diff --git a/script/semantic-conventions/templates/trace_deprecations.php.partial b/script/semantic-conventions/templates/trace_deprecations.php.partial index d73b0e17e..f350f1673 100644 --- a/script/semantic-conventions/templates/trace_deprecations.php.partial +++ b/script/semantic-conventions/templates/trace_deprecations.php.partial @@ -43,7 +43,6 @@ */ public const MESSAGING_DESTINATION = 'messaging.destination'; - /** * @deprecated */ diff --git a/src/SemConv/TraceAttributes.php b/src/SemConv/TraceAttributes.php index 72b45785b..0eeca05ab 100644 --- a/src/SemConv/TraceAttributes.php +++ b/src/SemConv/TraceAttributes.php @@ -1343,7 +1343,6 @@ interface TraceAttributes */ public const MESSAGING_DESTINATION = 'messaging.destination'; - /** * @deprecated */