diff --git a/src/OpenTelemetry.SemanticConventions/Resource/ResourceSemanticConventions.cs b/src/OpenTelemetry.SemanticConventions/Resource/ResourceSemanticConventions.cs
index 98c68233e74..deb31c02bd2 100644
--- a/src/OpenTelemetry.SemanticConventions/Resource/ResourceSemanticConventions.cs
+++ b/src/OpenTelemetry.SemanticConventions/Resource/ResourceSemanticConventions.cs
@@ -47,7 +47,7 @@ public static class ResourceSemanticConventions
/// Cloud regions often have multiple, isolated locations known as zones to increase availability. Availability zone represents the zone where the resource is running.
///
///
- /// Availability zones are called "zones" on Google Cloud.
+ /// Availability zones are called "zones" on Google Cloud.
///
public const string AttributeCloudAvailabilityZone = "cloud.availability_zone";
@@ -165,7 +165,7 @@ public static class ResourceSemanticConventions
/// The model identifier for the device.
///
///
- /// It's recommended this value represents a machine readable version of the model identifier rather than the market or consumer-friendly name of the device.
+ /// It's recommended this value represents a machine readable version of the model identifier rather than the market or consumer-friendly name of the device.
///
public const string AttributeDeviceModelIdentifier = "device.model.identifier";
@@ -173,7 +173,7 @@ public static class ResourceSemanticConventions
/// The marketing name for the device model.
///
///
- /// It's recommended this value represents a human readable version of the device model rather than a machine readable alternative.
+ /// It's recommended this value represents a human readable version of the device model rather than a machine readable alternative.
///
public const string AttributeDeviceModelName = "device.model.name";
@@ -189,7 +189,7 @@ public static class ResourceSemanticConventions
/// The unique ID of the single function that this runtime instance executes.
///
///
- /// Depending on the cloud provider, use: * **AWS Lambda:** The function [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html). Take care not to use the "invoked ARN" directly but replace any [alias suffix](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) with the resolved function version, as the same runtime instance may be invokable with multiple different aliases. * **GCP:** The [URI of the resource](https://cloud.google.com/iam/docs/full-resource-names) * **Azure:** The [Fully Qualified Resource ID](https://docs.microsoft.com/en-us/rest/api/resources/resources/get-by-id). On some providers, it may not be possible to determine the full ID at startup, which is why this field cannot be made required. For example, on AWS the account ID part of the ARN is not available without calling another AWS API which may be deemed too slow for a short-running lambda function. As an alternative, consider setting `faas.id` as a span attribute instead.
+ /// Depending on the cloud provider, use: * **AWS Lambda:** The function [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html). Take care not to use the "invoked ARN" directly but replace any [alias suffix](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) with the resolved function version, as the same runtime instance may be invokable with multiple different aliases. * **GCP:** The [URI of the resource](https://cloud.google.com/iam/docs/full-resource-names) * **Azure:** The [Fully Qualified Resource ID](https://docs.microsoft.com/en-us/rest/api/resources/resources/get-by-id). On some providers, it may not be possible to determine the full ID at startup, which is why this field cannot be made required. For example, on AWS the account ID part of the ARN is not available without calling another AWS API which may be deemed too slow for a short-running lambda function. As an alternative, consider setting `faas.id` as a span attribute instead.
///
public const string AttributeFaasId = "faas.id";
@@ -213,7 +213,7 @@ public static class ResourceSemanticConventions
/// The amount of memory available to the serverless function in MiB.
///
///
- /// 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.
///
public const string AttributeFaasMaxMemory = "faas.max_memory";
diff --git a/src/OpenTelemetry.SemanticConventions/Trace/TraceSemanticConventions.cs b/src/OpenTelemetry.SemanticConventions/Trace/TraceSemanticConventions.cs
index 1ade54fb490..fcff20825f3 100644
--- a/src/OpenTelemetry.SemanticConventions/Trace/TraceSemanticConventions.cs
+++ b/src/OpenTelemetry.SemanticConventions/Trace/TraceSemanticConventions.cs
@@ -60,7 +60,7 @@ public static class TraceSemanticConventions
/// If no tech-specific attribute is defined, this attribute is used to report the name of the database being accessed. For commands that switch the database, this should be set to the target database (even if the command fails).
///
///
- /// In some SQL databases, the database name to be used is called "schema name".
+ /// In some SQL databases, the database name to be used is called "schema name".
///
public const string AttributeDbName = "db.name";
@@ -173,7 +173,7 @@ public static class TraceSemanticConventions
/// 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](#exception-end-example). 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.
+ /// 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](#exception-end-example). 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 string AttributeExceptionEscaped = "exception.escaped";
@@ -340,7 +340,7 @@ public static class TraceSemanticConventions
/// 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/`.
+ /// `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/`.
///
public const string AttributeHttpUrl = "http.url";
@@ -597,7 +597,7 @@ public static class TraceSemanticConventions
/// 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.
+ /// 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.
///
public const string AttributeMessagingKafkaMessageKey = "messaging.kafka.message_key";
@@ -760,7 +760,7 @@ public static class DbSystemValues
public const string Edb = "edb";
///
- /// InterSystems Caché.
+ /// InterSystems Caché.
///
public const string Cache = "cache";
diff --git a/src/OpenTelemetry.SemanticConventions/scripts/semantic-convetion/templates/SemanticConventions.cs.j2 b/src/OpenTelemetry.SemanticConventions/scripts/semantic-convetion/templates/SemanticConventions.cs.j2
index 321dad29b40..060ec84fb17 100644
--- a/src/OpenTelemetry.SemanticConventions/scripts/semantic-convetion/templates/SemanticConventions.cs.j2
+++ b/src/OpenTelemetry.SemanticConventions/scripts/semantic-convetion/templates/SemanticConventions.cs.j2
@@ -1,16 +1,18 @@
{%- macro print_value(type, value) -%}
{{ "\"" if type == "string"}}{{value}}{{ "\"" if type == "string"}}
{%- endmacro %}
+
{%- macro formatRemarks(text) -%}
-{%- set notes = ' '.join(text.splitlines()) -%}
-{% filter escape %}{{notes}}{% endfilter %}
+{%- set notes = ' '.join(text.splitlines()).encode('ascii', 'xmlcharrefreplace').decode() -%}
+{{notes}}
{%- endmacro -%}
-{%- macro addMissingEndPeriod(text) -%}
- {%- if not text.endswith('.')-%}
- {{text + '.'}}
+{%- macro formatXmlDoc(text) -%}
+{%- set escaped = text.encode('ascii', 'xmlcharrefreplace').decode() -%}
+ {%- if not escaped.endswith('.')-%}
+ {{escaped + '.'}}
{%- else -%}
- {{text}}
+ {{escaped}}
{%- endif -%}
{%- endmacro -%}
@@ -46,7 +48,7 @@ namespace {{pkg | trim}}
{
{%- for attribute in attributes if attribute.is_local and not attribute.ref %}
///
- /// {{addMissingEndPeriod(attribute.brief | render_markdown(code="{0}", paragraph="{0}"))}}
+ /// {{formatXmlDoc(attribute.brief | render_markdown(code="{0}", paragraph="{0}"))}}
///
{%- if attribute.note %}
///
@@ -73,13 +75,13 @@ namespace {{pkg | trim}}
{%- set type = attribute.attr_type.enum_type %}
{%- if not loop.first -%} {{"\n"}} {%- endif %}
///
- /// {{addMissingEndPeriod(attribute.brief | render_markdown(code="{0}", paragraph="{0}"))}}
+ /// {{formatXmlDoc(attribute.brief | render_markdown(code="{0}", paragraph="{0}"))}}
///
public static class {{class_name}}
{
{%- for member in attribute.attr_type.members %}
///
- /// {{addMissingEndPeriod(member.brief | render_markdown(code="{0}", paragraph="{0}"))}}
+ /// {{formatXmlDoc(member.brief | render_markdown(code="{0}", paragraph="{0}"))}}
///
public const {{ type }} {{ member.member_id | to_camelcase(True) }} = {{ print_value(type, member.value) }};
{%- if not loop.last -%} {{"\n"}} {%- endif %}