Skip to content

Commit

Permalink
Add link to requirement levels on Markdown table headers (#222)
Browse files Browse the repository at this point in the history
Co-authored-by: Joao Grassi <[email protected]>
  • Loading branch information
lmolkova and joaopgrassi authored Feb 26, 2024
1 parent 1325b9c commit e966e83
Show file tree
Hide file tree
Showing 42 changed files with 317 additions and 282 deletions.
2 changes: 2 additions & 0 deletions semantic-conventions/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Please update the changelog as part of any significant pull request.
([#244](https://github.com/open-telemetry/build-tools/pull/244))
- Add backward-compatibility check mode.
([#271](https://github.com/open-telemetry/build-tools/pull/271))
- Add link to requirement levels definition from Markdown table title.
([#222](https://github.com/open-telemetry/build-tools/pull/222))

## v0.23.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
from opentelemetry.semconv.model.utils import ID_RE
from opentelemetry.semconv.templating.markdown.options import MarkdownOptions

_REQUIREMENT_LEVEL_URL = (
"https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/"
)


class RenderContext:
def __init__(self):
Expand Down Expand Up @@ -80,10 +84,6 @@ class MarkdownRenderer:
]

prelude = "<!-- semconv {} -->\n"
table_headers = "| Attribute | Type | Description | Examples | Requirement Level |\n|---|---|---|---|---|\n"
table_headers_omitting_req_level = (
"| Attribute | Type | Description | Examples |\n|---|---|---|---|\n"
)

def __init__(
self, md_folder, semconvset: SemanticConventionSet, options=MarkdownOptions()
Expand All @@ -100,6 +100,16 @@ def __init__(
# that contains it
self.filename_for_attr_fqn = self._create_attribute_location_dict()

req_level = f"[Requirement Level]({_REQUIREMENT_LEVEL_URL})"

self.table_headers = (
f"| Attribute | Type | Description | Examples | {req_level} |"
"\n|---|---|---|---|---|\n"
)
self.table_headers_omitting_req_level = (
"| Attribute | Type | Description | Examples |\n|---|---|---|---|\n"
)

def to_markdown_attr(
self,
attribute: SemanticAttribute,
Expand Down Expand Up @@ -169,14 +179,14 @@ def to_markdown_attr(

def derive_requirement_level(self, attribute: SemanticAttribute):
if attribute.requirement_level == RequirementLevel.REQUIRED:
required = "Required"
required = "`Required`"
elif attribute.requirement_level == RequirementLevel.CONDITIONALLY_REQUIRED:
if len(attribute.requirement_level_msg) < self.options.break_count:
required = "Conditionally Required: " + attribute.requirement_level_msg
required = "`Conditionally Required` " + attribute.requirement_level_msg
else:
# We put the condition in the notes after the table
self.render_ctx.add_note(attribute.requirement_level_msg)
required = f"Conditionally Required: [{len(self.render_ctx.notes)}]"
required = f"`Conditionally Required` [{len(self.render_ctx.notes)}]"
elif attribute.requirement_level == RequirementLevel.OPT_IN:
required = "Opt-In"
else: # attribute.requirement_level == Required.RECOMMENDED or None
Expand All @@ -188,20 +198,20 @@ def derive_requirement_level(self, attribute: SemanticAttribute):
required = "See below"
else:
if not attribute.requirement_level_msg:
required = "Recommended"
required = "`Recommended`"
elif len(attribute.requirement_level_msg) < self.options.break_count:
required = "Recommended: " + attribute.requirement_level_msg
required = "`Recommended` " + attribute.requirement_level_msg
else:
# We put the condition in the notes after the table
self.render_ctx.add_note(attribute.requirement_level_msg)
required = f"Recommended: [{len(self.render_ctx.notes)}]"
required = f"`Recommended` [{len(self.render_ctx.notes)}]"
return required

def write_table_header(self, output: io.StringIO):
if self.render_ctx.is_omit_requirement_level:
output.write(MarkdownRenderer.table_headers_omitting_req_level)
output.write(self.table_headers_omitting_req_level)
else:
output.write(MarkdownRenderer.table_headers)
output.write(self.table_headers)

def to_markdown_attribute_table(
self, semconv: BaseSemanticConvention, output: io.StringIO
Expand Down Expand Up @@ -322,8 +332,8 @@ def to_markdown_enum(self, output: io.StringIO):
if enum.custom_values:
output.write(
"has the following list of well-known values."
+ " If one of them applies, then the respective value MUST be used,"
+ " otherwise a custom value MAY be used."
+ " If one of them applies, then the respective value MUST be used;"
+ " otherwise, a custom value MAY be used."
)
else:
output.write("MUST be one of the following:")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Attribute Group Example

<!-- semconv span_attribute_group -->
| Attribute | Type | Description | Examples | Requirement Level |
| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) |
|---|---|---|---|---|
| `foo.bar` | string | Attribute 1 | `baz` | Recommended: if available |
| `foo.qux` | int | Attribute 2 | `42` | Conditionally Required: if available |
| `foo.bar` | string | Attribute 1 | `baz` | `Recommended` if available |
| `foo.qux` | int | Attribute 2 | `42` | `Conditionally Required` if available |
<!-- endsemconv -->
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Custom HTTP Semantic Conventions

<!-- semconv custom_http(full) -->
| Attribute | Type | Description | Examples | Requirement Level |
| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) |
|---|---|---|---|---|
| `custom_http.request.header.<key>` | string[] | HTTP request headers, `<key>` being the normalized HTTP Header name (lowercase, with - characters replaced by _), the value being the header values. | ``http.request.header.content_type=["application/json"]`` | Recommended |
| `custom_http.request.method` | string | HTTP request method. | `GET`; `POST`; `HEAD` | Required |
| `general.some_general_attribute.<key>` | string | This is a general attribute. | ``some_general_attribute.some_key="abc"`` | Recommended |
| `referenced_http.request.referenced.header.<key>` | string[] | This is a referenced attribute. | ``http.request.header.content_type=["application/json"]`` | Recommended |
| `custom_http.request.header.<key>` | string[] | HTTP request headers, `<key>` being the normalized HTTP Header name (lowercase, with - characters replaced by _), the value being the header values. | ``http.request.header.content_type=["application/json"]`` | `Recommended` |
| `custom_http.request.method` | string | HTTP request method. | `GET`; `POST`; `HEAD` | `Required` |
| `general.some_general_attribute.<key>` | string | This is a general attribute. | ``some_general_attribute.some_key="abc"`` | `Recommended` |
| `referenced_http.request.referenced.header.<key>` | string[] | This is a referenced attribute. | ``http.request.header.content_type=["application/json"]`` | `Recommended` |
<!-- endsemconv -->
22 changes: 11 additions & 11 deletions semantic-conventions/src/tests/data/markdown/deprecated/expected.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@

<!-- Re-generate TOC with `TODO: ADD cmd` -->
<!-- semconv http -->
| Attribute | Type | Description | Examples | Requirement Level |
| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) |
|---|---|---|---|---|
| `http.flavor` | string | **Deprecated. Use attribute `flavor_new` instead.**<br>Kind of HTTP protocol used [1] | `1.0` | Recommended |
| `http.host` | string | The value of the [HTTP host header](https://tools.ietf.org/html/rfc7230#section-5.4). When the header is empty or not present, this attribute should be the same. | `www.example.org` | Recommended |
| `http.method` | string | HTTP request method. | `GET`; `POST`; `HEAD` | Required |
| `http.scheme` | string | The URI scheme identifying the used protocol. | `http`; `https` | Recommended |
| `http.status_code` | int | [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). | `200` | Conditionally Required: if and only if one was received/sent |
| `http.status_text` | string | **Deprecated: Use attribute `status_description` instead.**<br>[HTTP reason phrase](https://tools.ietf.org/html/rfc7230#section-3.1.2). | `OK` | Recommended |
| `http.target` | string | The full request target as passed in a HTTP request line or equivalent. | `/path/12314/?q=ddds#123` | Recommended |
| `http.url` | string | 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. | `https://www.foo.bar/search?q=OpenTelemetry#SemConv` | Recommended |
| `http.user_agent` | string | Value of the [HTTP User-Agent](https://tools.ietf.org/html/rfc7231#section-5.5.3) header sent by the client. | `CERN-LineMode/2.15 libwww/2.17b3` | Recommended |
| `http.flavor` | string | **Deprecated. Use attribute `flavor_new` instead.**<br>Kind of HTTP protocol used [1] | `1.0` | `Recommended` |
| `http.host` | string | The value of the [HTTP host header](https://tools.ietf.org/html/rfc7230#section-5.4). When the header is empty or not present, this attribute should be the same. | `www.example.org` | `Recommended` |
| `http.method` | string | HTTP request method. | `GET`; `POST`; `HEAD` | `Required` |
| `http.scheme` | string | The URI scheme identifying the used protocol. | `http`; `https` | `Recommended` |
| `http.status_code` | int | [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). | `200` | `Conditionally Required` if and only if one was received/sent |
| `http.status_text` | string | **Deprecated: Use attribute `status_description` instead.**<br>[HTTP reason phrase](https://tools.ietf.org/html/rfc7230#section-3.1.2). | `OK` | `Recommended` |
| `http.target` | string | The full request target as passed in a HTTP request line or equivalent. | `/path/12314/?q=ddds#123` | `Recommended` |
| `http.url` | string | 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. | `https://www.foo.bar/search?q=OpenTelemetry#SemConv` | `Recommended` |
| `http.user_agent` | string | Value of the [HTTP User-Agent](https://tools.ietf.org/html/rfc7231#section-5.5.3) header sent by the client. | `CERN-LineMode/2.15 libwww/2.17b3` | `Recommended` |

**[1]:** 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.

`http.flavor` has the following list of well-known values. If one of them applies, then the respective value MUST be used, otherwise a custom value MAY be used.
`http.flavor` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used.

| Value | Description |
|---|---|
Expand Down
10 changes: 5 additions & 5 deletions semantic-conventions/src/tests/data/markdown/deprecated/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
<!-- Re-generate TOC with `TODO: ADD cmd` -->
<!-- semconv http -->

| Attribute name | Notes and examples | Required? |
| Attribute name | Notes and examples | `Required`? |
| :------------- | :----------------------------------------------------------- | --------- |
| `http.method` | HTTP request method. E.g. `"GET"`. | Required |
| `http.method` | HTTP request method. E.g. `"GET"`. | `Required` |
| `http.url` | 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. | Defined later. |
| `http.target` | The full request target as passed in a [HTTP request line][] or equivalent, e.g. `"/path/12314/?q=ddds#123"`. | Defined later. |
| `http.host` | The value of the [HTTP host header][]. When the header is empty or not present, this attribute should be the same. | Defined later. |
| `http.scheme` | The URI scheme identifying the used protocol: `"http"` or `"https"` | Defined later. |
| `http.status_code` | [HTTP response status code][]. E.g. `200` (integer) | Conditionally Required: if and only if one was received/sent. |
| `http.status_text` | [HTTP reason phrase][]. E.g. `"OK"` | Recommended |
| `http.status_code` | [HTTP response status code][]. E.g. `200` (integer) | `Conditionally Required` if and only if one was received/sent. |
| `http.status_text` | [HTTP reason phrase][]. E.g. `"OK"` | `Recommended` |
| `http.flavor` | Kind of HTTP protocol used: `"1.0"`, `"1.1"`, `"2"`, `"SPDY"` or `"QUIC"`. | No |
| `http.user_agent` | Value of the HTTP [User-Agent][] header sent by the client. | Recommended |
| `http.user_agent` | Value of the HTTP [User-Agent][] header sent by the client. | `Recommended` |

<!-- endsemconv -->

Expand Down
16 changes: 8 additions & 8 deletions semantic-conventions/src/tests/data/markdown/empty/expected.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,17 @@ Note that the items marked with [1] are different from the mapping defined in th

<!-- Re-generate TOC with `TODO: ADD cmd` -->

| Attribute name | Notes and examples | Required? |
| Attribute name | Notes and examples | `Required`? |
| :------------- | :----------------------------------------------------------- | --------- |
| `http.method` | HTTP request method. E.g. `"GET"`. | Required |
| `http.method` | HTTP request method. E.g. `"GET"`. | `Required` |
| `http.url` | 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. | Defined later. |
| `http.target` | The full request target as passed in a [HTTP request line][] or equivalent, e.g. `"/path/12314/?q=ddds#123"`. | Defined later. |
| `http.host` | The value of the [HTTP host header][]. When the header is empty or not present, this attribute should be the same. | Defined later. |
| `http.scheme` | The URI scheme identifying the used protocol: `"http"` or `"https"` | Defined later. |
| `http.status_code` | [HTTP response status code][]. E.g. `200` (integer) | Conditionally Required: if and only if one was received/sent. |
| `http.status_text` | [HTTP reason phrase][]. E.g. `"OK"` | Recommended |
| `http.status_code` | [HTTP response status code][]. E.g. `200` (integer) | `Conditionally Required` if and only if one was received/sent. |
| `http.status_text` | [HTTP reason phrase][]. E.g. `"OK"` | `Recommended` |
| `http.flavor` | Kind of HTTP protocol used: `"1.0"`, `"1.1"`, `"2"`, `"SPDY"` or `"QUIC"`. | Opt-In |
| `http.user_agent` | Value of the HTTP [User-Agent][] header sent by the client. | Recommended |
| `http.user_agent` | Value of the HTTP [User-Agent][] header sent by the client. | `Recommended` |

It is recommended to also use the general [network attributes][], especially `net.peer.ip`. 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.

Expand Down Expand Up @@ -183,11 +183,11 @@ If the route does not include the application root, it SHOULD be prepended to th

If the route cannot be determined, the `name` attribute MUST be set as defined in the general semantic conventions for HTTP.

| Attribute name | Notes and examples | Required? |
| Attribute name | Notes and examples | `Required`? |
| :------------- | :----------------------------------------------------------- | --------- |
| `http.server_name` | 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). | [1] |
| `http.route` | The matched route (path template). (TODO: Define whether to prepend application root) E.g. `"/users/:userID?"`. | Recommended |
| `http.client_ip` | The IP address of the original client behind all proxies, if known (e.g. from [X-Forwarded-For][]). Note that this is not necessarily the same as `net.peer.ip`, which would identify the network-level peer, which may be a proxy. | Recommended |
| `http.route` | The matched route (path template). (TODO: Define whether to prepend application root) E.g. `"/users/:userID?"`. | `Recommended` |
| `http.client_ip` | The IP address of the original client behind all proxies, if known (e.g. from [X-Forwarded-For][]). Note that this is not necessarily the same as `net.peer.ip`, which would identify the network-level peer, which may be a proxy. | `Recommended` |

[HTTP request line]: https://tools.ietf.org/html/rfc7230#section-3.1.1
[HTTP host header]: https://tools.ietf.org/html/rfc7230#section-5.4
Expand Down
Loading

0 comments on commit e966e83

Please sign in to comment.