Skip to content

Commit

Permalink
Extended jinja template to generate template-type semantic attributes.
Browse files Browse the repository at this point in the history
Signed-off-by: Alexander Wert <alexander.wert@elastic.co>
  • Loading branch information
AlexanderWert committed Oct 29, 2023
1 parent 8bbebbc commit e58f9eb
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 0 deletions.
25 changes: 25 additions & 0 deletions buildscripts/templates/SemanticAttributes.java.j2
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ import static io.opentelemetry.api.common.AttributeKey.longKey;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;

import static io.opentelemetry.semconv.AttributeKeyTemplate.stringArrayKeyTemplate;
import static io.opentelemetry.semconv.AttributeKeyTemplate.stringKeyTemplate;

import io.opentelemetry.api.common.AttributeKey;
import java.util.List;

Expand Down Expand Up @@ -84,6 +87,28 @@ public final class {{class}} {
{%- endif %}
public static final AttributeKey<{{upFirst(to_java_return_type(attribute.attr_type | string))}}> {{attribute.fqn | to_const_name}} = {{to_java_key_type(attribute.attr_type | string)}}("{{attribute.fqn}}");
{%- endfor %}
{%- for attribute_template in attribute_templates if attribute_template.is_local and not attribute_template.ref %}

/**
* {{attribute_template.brief | render_markdown(code="{{@code {0}}}", paragraph="{0}")}}
{%- if attribute_template.note %}
*
* <p>Notes:
{# NOTE: replace("> ", "") removes the following problematic characters which produce mangled javadoc: #}
{# https://github.com/open-telemetry/semantic-conventions/blob/c83a10a9c33c18a769835e959200d0e24dc708fe/model/resource/k8s.yaml#L34-L38 #}
<ul> {{attribute_template.note | replace("> ", "") | render_markdown(code="{{@code {0}}}", paragraph="<li>{0}</li>", list="{0}")}} </ul>

{%- endif %}
{%- if (attribute_template.stability | string()) == "StabilityLevel.DEPRECATED" %}
*
* @deprecated {{attribute_template.brief | to_doc_brief}}.
{%- endif %}
*/
{%- if (attribute_template.stability | string()) == "StabilityLevel.DEPRECATED" %}
@Deprecated
{%- endif %}
public static final AttributeKeyTemplate<{{upFirst(to_java_return_type(attribute_template.instantiated_type | string))}}> {{attribute_template.fqn | to_const_name}} = {{to_java_key_type(attribute_template.instantiated_type | string)}}Template("{{attribute_template.fqn}}");
{%- endfor %}

// Enum definitions
{%- for attribute in attributes if attribute.is_local and not attribute.ref %}
Expand Down
66 changes: 66 additions & 0 deletions src/main/java/io/opentelemetry/semconv/AttributeKeyTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.semconv;

import io.opentelemetry.api.common.AttributeKey;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;

public final class AttributeKeyTemplate<T> {

private final ConcurrentMap<String, AttributeKey<T>> keysCache = new ConcurrentHashMap<>();
private final String prefix;
private final Function<String, AttributeKey<T>> keyBuilder;

AttributeKeyTemplate(String prefix, Function<String, AttributeKey<T>> keyBuilder) {
this.prefix = prefix;
this.keyBuilder = keyBuilder;
}

static AttributeKeyTemplate<String> stringKeyTemplate(String prefix) {
return new AttributeKeyTemplate<String>(prefix, AttributeKey::stringKey);
}

static AttributeKeyTemplate<List<String>> stringArrayKeyTemplate(String prefix) {
return new AttributeKeyTemplate<List<String>>(prefix, AttributeKey::stringArrayKey);
}

static AttributeKeyTemplate<Boolean> booleanKeyTemplate(String prefix) {
return new AttributeKeyTemplate<Boolean>(prefix, AttributeKey::booleanKey);
}

static AttributeKeyTemplate<List<Boolean>> booleanArrayKeyTemplate(String prefix) {
return new AttributeKeyTemplate<List<Boolean>>(prefix, AttributeKey::booleanArrayKey);
}

static AttributeKeyTemplate<Long> longKeyTemplate(String prefix) {
return new AttributeKeyTemplate<Long>(prefix, AttributeKey::longKey);
}

static AttributeKeyTemplate<List<Long>> longArrayKeyTemplate(String prefix) {
return new AttributeKeyTemplate<List<Long>>(prefix, AttributeKey::longArrayKey);
}

static AttributeKeyTemplate<Double> doubleKeyTemplate(String prefix) {
return new AttributeKeyTemplate<Double>(prefix, AttributeKey::doubleKey);
}

static AttributeKeyTemplate<List<Double>> doubleArrayKeyTemplate(String prefix) {
return new AttributeKeyTemplate<List<Double>>(prefix, AttributeKey::doubleArrayKey);
}

private AttributeKey<T> createAttributeKey(String keyName) {
String key = prefix + "." + keyName.toLowerCase(Locale.ROOT).replace('-', '_');
return keyBuilder.apply(key);
}

public AttributeKey<T> getAttributeKey(String key) {
return keysCache.computeIfAbsent(key, this::createAttributeKey);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static io.opentelemetry.api.common.AttributeKey.longKey;
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import static io.opentelemetry.semconv.AttributeKeyTemplate.stringKeyTemplate;

import io.opentelemetry.api.common.AttributeKey;
import java.util.List;
Expand Down Expand Up @@ -918,6 +919,10 @@ public final class ResourceAttributes {
@Deprecated
public static final AttributeKey<String> OTEL_LIBRARY_VERSION = stringKey("otel.library.version");

/** Container labels, {@code <key>} being the label name, the value being the label value. */
public static final AttributeKeyTemplate<String> CONTAINER_LABELS =
stringKeyTemplate("container.labels");

// Enum definitions
public static final class CloudPlatformValues {
/** Alibaba Cloud Elastic Compute Service. */
Expand Down
117 changes: 117 additions & 0 deletions src/main/java/io/opentelemetry/semconv/SemanticAttributes.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import static io.opentelemetry.api.common.AttributeKey.longKey;
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import static io.opentelemetry.semconv.AttributeKeyTemplate.stringArrayKeyTemplate;
import static io.opentelemetry.semconv.AttributeKeyTemplate.stringKeyTemplate;

import io.opentelemetry.api.common.AttributeKey;
import java.util.List;
Expand Down Expand Up @@ -1688,6 +1690,121 @@ public final class SemanticAttributes {
*/
public static final AttributeKey<String> USER_AGENT_ORIGINAL = stringKey("user_agent.original");

/**
* HTTP request headers, {@code <key>} being the normalized HTTP Header name (lowercase, with
* {@code -} characters replaced by {@code _}), the value being the header values.
*
* <p>Notes:
*
* <ul>
* <li>Instrumentations SHOULD require an explicit configuration of which headers are to be
* captured. Including all request headers can be a security risk - explicit configuration
* helps avoid leaking sensitive information. The {@code User-Agent} header is already
* captured in the {@code user_agent.original} attribute. Users MAY explicitly configure
* instrumentations to capture them even though it is not recommended. The attribute value
* MUST consist of either multiple header values as an array of strings or a single-item
* array containing a possibly comma-concatenated string, depending on the way the HTTP
* library provides access to headers.
* </ul>
*/
public static final AttributeKeyTemplate<List<String>> HTTP_REQUEST_HEADER =
stringArrayKeyTemplate("http.request.header");

/**
* HTTP response headers, {@code <key>} being the normalized HTTP Header name (lowercase, with
* {@code -} characters replaced by {@code _}), the value being the header values.
*
* <p>Notes:
*
* <ul>
* <li>Instrumentations SHOULD require an explicit configuration of which headers are to be
* captured. Including all response headers can be a security risk - explicit configuration
* helps avoid leaking sensitive information. Users MAY explicitly configure
* instrumentations to capture them even though it is not recommended. The attribute value
* MUST consist of either multiple header values as an array of strings or a single-item
* array containing a possibly comma-concatenated string, depending on the way the HTTP
* library provides access to headers.
* </ul>
*/
public static final AttributeKeyTemplate<List<String>> HTTP_RESPONSE_HEADER =
stringArrayKeyTemplate("http.response.header");

/**
* A dynamic value in the url path.
*
* <p>Notes:
*
* <ul>
* <li>Many Elasticsearch url paths allow dynamic values. These SHOULD be recorded in span
* attributes in the format {@code db.elasticsearch.path_parts.<key>}, where {@code <key>}
* is the url path part name. The implementation SHOULD reference the <a
* href="https://raw.githubusercontent.com/elastic/elasticsearch-specification/main/output/schema/schema.json">elasticsearch
* schema</a> in order to map the path part values to their names.
* </ul>
*/
public static final AttributeKeyTemplate<String> DB_ELASTICSEARCH_PATH_PARTS =
stringKeyTemplate("db.elasticsearch.path_parts");

/**
* gRPC request metadata, {@code <key>} being the normalized gRPC Metadata key (lowercase, with
* {@code -} characters replaced by {@code _}), the value being the metadata values.
*
* <p>Notes:
*
* <ul>
* <li>Instrumentations SHOULD require an explicit configuration of which metadata values are to
* be captured. Including all request metadata values can be a security risk - explicit
* configuration helps avoid leaking sensitive information.
* </ul>
*/
public static final AttributeKeyTemplate<List<String>> RPC_GRPC_REQUEST_METADATA =
stringArrayKeyTemplate("rpc.grpc.request.metadata");

/**
* gRPC response metadata, {@code <key>} being the normalized gRPC Metadata key (lowercase, with
* {@code -} characters replaced by {@code _}), the value being the metadata values.
*
* <p>Notes:
*
* <ul>
* <li>Instrumentations SHOULD require an explicit configuration of which metadata values are to
* be captured. Including all response metadata values can be a security risk - explicit
* configuration helps avoid leaking sensitive information.
* </ul>
*/
public static final AttributeKeyTemplate<List<String>> RPC_GRPC_RESPONSE_METADATA =
stringArrayKeyTemplate("rpc.grpc.response.metadata");

/**
* Connect request metadata, {@code <key>} being the normalized Connect Metadata key (lowercase,
* with {@code -} characters replaced by {@code _}), the value being the metadata values.
*
* <p>Notes:
*
* <ul>
* <li>Instrumentations SHOULD require an explicit configuration of which metadata values are to
* be captured. Including all request metadata values can be a security risk - explicit
* configuration helps avoid leaking sensitive information.
* </ul>
*/
public static final AttributeKeyTemplate<List<String>> RPC_CONNECT_RPC_REQUEST_METADATA =
stringArrayKeyTemplate("rpc.connect_rpc.request.metadata");

/**
* Connect response metadata, {@code <key>} being the normalized Connect Metadata key (lowercase,
* with {@code -} characters replaced by {@code _}), the value being the metadata values.
*
* <p>Notes:
*
* <ul>
* <li>Instrumentations SHOULD require an explicit configuration of which metadata values are to
* be captured. Including all response metadata values can be a security risk - explicit
* configuration helps avoid leaking sensitive information.
* </ul>
*/
public static final AttributeKeyTemplate<List<String>> RPC_CONNECT_RPC_RESPONSE_METADATA =
stringArrayKeyTemplate("rpc.connect_rpc.response.metadata");

// Enum definitions
public static final class NetSockFamilyValues {
/** IPv4 address. */
Expand Down

0 comments on commit e58f9eb

Please # to comment.