TT Lab
Get started
Learn Learning paths Courses

OTCA — OpenTelemetry Certified Associate

SDK Configuration and Resource Attributes

Continue in TT Lab

Goal

Configure the SDK with environment variables, fix the resource attributes according to the semantic conventions, and inject an instance identifier in Kubernetes with the Downward API. Finally, build a linter yourself that checks span name cardinality.

Why it matters

The hardest decision to reverse in instrumentation is the resource attributes. Code can be fixed at any time, but the moment you change service.name, the connections to dashboards, alerts, the service graph, and past data are all cut. So you settle these before adding more spans. The naming convention matters for the same reason. deployment.environment and deployment.environment.name look the same to a person, but to the system they are two completely different attributes, and a dashboard variable reads only one of them. The same goes for span names. If IDs get mixed into names, the backend's aggregated view collapses entirely, and this accident is discovered not right after deployment but weeks later, in the form of "the service graph looks odd." So it should be CI that blocks it, not human memory.

Steps

  1. Create /root/otca-sdk/otel.env and write OTEL_SERVICE_NAME=checkout-api, OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector.observability.svc:4317, and OTEL_EXPORTER_OTLP_PROTOCOL=grpc. Put one per line, in the 키=값 form (key=value).
  2. In the same file, add OTEL_RESOURCE_ATTRIBUTES. Its value is service.version=2.7.1, deployment.environment.name=prod, and service.namespace=commerce joined with commas. Do not use the old name deployment.environment.
  3. In the same file, add OTEL_TRACES_SAMPLER=parentbased_traceidratio, OTEL_TRACES_SAMPLER_ARG=0.1, and OTEL_PROPAGATORS=tracecontext,baggage.
  4. In the same file, add four limits: OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=64, OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=2048, OTEL_BSP_MAX_QUEUE_SIZE=4096, and OTEL_BSP_MAX_EXPORT_BATCH_SIZE=512.
  5. In /root/otca-sdk/deployment.yaml, write a Deployment. Set metadata.name: checkout-api and metadata.namespace: otca-sdk. In the env of the first container, add POD_NAME (fieldRef metadata.name), POD_NAMESPACE (fieldRef metadata.namespace), OTEL_SERVICE_NAME=checkout-api, OTEL_EXPORTER_OTLP_ENDPOINT (including 4317), and OTEL_RESOURCE_ATTRIBUTES, whose value must contain deployment.environment.name=prod, service.instance.id=$(POD_NAME), and k8s.namespace.name=$(POD_NAMESPACE).
  6. Create the namespace otca-sdk and apply the manifest from step 5 to the cluster.
  7. In /root/otca-sdk/span-names.txt, write at least 6 lines of span names. At least 4 of them must start with an HTTP method, like GET /..., and at least 3 must contain an :id placeholder. No line may contain a run of three or more digits or a UUID.
  8. Write /root/otca-sdk/lint-span-names.sh. If the file passed as the first argument contains a run of three or more digits or a UUID-like string, print that line and exit with a non-zero code; otherwise exit with 0.

Notes

Service name and endpoint

Create /root/otca-sdk/otel.env and write OTEL_SERVICE_NAME=checkout-api, OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector.observability.svc:4317, and OTEL_EXPORTER_OTLP_PROTOCOL=grpc. Put one per line, in the 키=값 form (key=value).

The SDK can be controlled with environment variables alone. That is why the instrumentation settings live in the deployment manifest rather than in code, and changing the endpoint needs no code review. The port and protocol must always be a matching pair.

Fix the resource attributes

In the same file, add OTEL_RESOURCE_ATTRIBUTES. Its value is service.version=2.7.1, deployment.environment.name=prod, and service.namespace=commerce joined with commas. Do not use the old name deployment.environment.

Resource attributes are attached to every signal this process emits. Join several with commas, each in the form key=value. The name of the environment attribute was changed in a recent convention, so take care not to use the old name.

Sampler and propagators

In the same file, add OTEL_TRACES_SAMPLER=parentbased_traceidratio, OTEL_TRACES_SAMPLER_ARG=0.1, and OTEL_PROPAGATORS=tracecontext,baggage.

The sampler name must have parentbased in it to follow the parent's decision. Without it, each service makes its own independent probability decision and traces get cut off midway. You can specify several propagators separated by commas.

Span size and queue limits

In the same file, add four limits: OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=64, OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=2048, OTEL_BSP_MAX_QUEUE_SIZE=4096, and OTEL_BSP_MAX_EXPORT_BATCH_SIZE=512.

The number of attributes has a default limit, but the value length does not. If a request body goes in whole, a single span becomes hundreds of KB. Also set the queue size and batch size of the batch span processor.

Inject the instance identifier with the Downward API

In /root/otca-sdk/deployment.yaml, write a Deployment. Set metadata.name: checkout-api and metadata.namespace: otca-sdk. In the env of the first container, add POD_NAME (fieldRef metadata.name), POD_NAMESPACE (fieldRef metadata.namespace), OTEL_SERVICE_NAME=checkout-api, OTEL_EXPORTER_OTLP_ENDPOINT (including 4317), and OTEL_RESOURCE_ATTRIBUTES, whose value must contain deployment.environment.name=prod, service.instance.id=$(POD_NAME), and k8s.namespace.name=$(POD_NAMESPACE).

If you hardcode the Pod name, a wrong value remains after every restart. Receive metadata.name and metadata.namespace as environment variables with fieldRef, then reference them inside another environment variable with the parenthesis notation, and the kubelet substitutes them. A multi-line value reads better as a folded block.

Apply to the cluster

Create the namespace otca-sdk and apply the manifest from step 5 to the cluster.

Create the namespace first, then apply the manifest. Grading reads the Pod template that actually entered the cluster, so it does not pass if you only edit the file without applying it.

A low-cardinality list of span names

In /root/otca-sdk/span-names.txt, write at least 6 lines of span names. At least 4 of them must start with an HTTP method, like GET /..., and at least 3 must contain an :id placeholder. No line may contain a run of three or more digits or a UUID.

The backend groups by span name to build latency statistics and the service graph. If an order number or UUID goes into the name, you get as many groups as there are requests. Write routes as templates and send concrete values as attributes.

Span name linter

Write /root/otca-sdk/lint-span-names.sh. If the file passed as the first argument contains a run of three or more digits or a UUID-like string, print that line and exit with a non-zero code; otherwise exit with 0.

The script takes the list file as its first argument. If it contains a run of three or more digits or a UUID-like string, print that line and end with failure. The list you made in the earlier step must pass.