OpenTelemetry Java agent extension
The HCL OpenTelemetry extension extends the standard OpenTelemetry Java agent with a set of features for serviceablity.
Capabilities of the Java agent include
- traceresponse: Enables a
traceresponseresponse header. - passthrough: Propagates selected request headers across services.
- threadMonitor: Automatic threaddump generation when conditions such as number of active spans, or slow spans are met.
- spanLogger: Configurable logger of spans.
Enabling the extension
The HCL extension is enabled by default with the OpenTelemetry agent, as described in
OpenTelemetry support. The
extension binary is available in containers under
/SETUP/otel/opentelemetry-hcl-agent.jar. This Jar is
registered using the otel.javaagent.extensions configuration.
otel.javaagent.logging=application must be set for logging to
occur.
When exporterOtlpEndpointEnabled is true, the extension is
registered along with the other agent configurations in the configuration map.
configMap:
otel_config_properties: |-
otel.exporter.otlp.endpoint=
otel.collector.namespace=YOUR-OTEL-NAMESPACE
otel.exporter.otlp.metrics.temporality.preference=cumulative
otel.exporter.otlp.protocol=http/protobuf
otel.service.name=${OTEL_SERVICE_NAME}
otel.resource.attributes=deployment.environment=${TENANT}${ENVIRONMENT}${ENVTYPE}
otel.javaagent.extensions=/SETUP/otel/opentelemetry-hcl-agent.jar
otel.javaagent.logging=application
If exporterOtlpEndpointEnabled is false, the extension is enabled by
default in /SETUP/otel/otel_noexporters.properties.
In Commerce+, by default, sampling is not enabled in the agent
configuration. If you decide to enable sampling in the agent configuration (using
the otel.traces.sampler configuration), not all spans will be
reported to the HCL extension.
Customizing configuration values
The extension configuration file hcl_otel_agent_config.yaml
supports configurable values. When a value is specified with format
${key_name:default_value}, the system uses the default value if
the key is not declared as a configuration file entry, environment variable, or
system property. The extension follows the OpenTelemetry configuration rules as the
OpenTelemetry agent.
For example, threadMonitor triggers a threaddump if
the current number of active spans is higher than the configured value, which
defaults to 20.
spans:
activeLargerThan: ${otel.javaagent.extensions.hcl.threadmonitor.active-larger-than:20}
If exporterOtlpEndpointEnabled is true, this value can be
overwritten in otel_config_properties, as defined in the Helm
Chart. The change will apply to all containers.
configMap:
otel_config_properties: |-
...
otel.javaagent.extensions=/SETUP/otel/opentelemetry-hcl-agent.jar
otel.javaagent.logging=application
otel.javaagent.extensions.hcl.threadmonitor.active-larger-than=20
Configurations can also be defined as environment variables to apply to a single container.
- name: OTEL_JAVAAGENT_EXTENSIONS_HCL_THREADMONITOR_ACTIVE_LARGER_THAN
value: 20
You can customize the image for extended container-specific configurations with a new
otel_config_properties configuration map. For ad-hoc testing,
such as tracing, changes made to the file will be reloaded by the extension in
runtime.
Available features
Following are some of the features currently provided by the HCL extension.
traceresponseresponse header- Appends the
traceresponseresponse header to the response, which includes thetrace_idused by the request.traceresponse: 00-3857f023970fb38eb4b098826d31fd21-d17d97455bb26a4d-00 - Passthrough
- Enables the automatic propagation of specified headers across pods, such as
X-Log-Level.Edit /SETUP/otel/hcl_otel_agent_config.yaml.
passthrough: enabled: ${otel.javaagent.extensions.hcl.passthrough.enabled:true} headers: - name: X-Log-Level # Optional regex validation regex: TRACE|DEBUGIn addition to enabling the feature in hcl_otel_agent_config.yaml, the
hclpassthroughmust be registered with the OpenTelemetry configuration:otel.propagators: tracecontext,baggage,hclpassthrough - Thread Monitor
- This version replaces the original implementation of
threadMonitorin Commerce+. It automates thread dump generation based on criteria such as active or slow spans, and it includes OpenTelemetry details with each thread."Default Executor-thread-1", id: 34, state:RUNNABLE ACTIVE: "name": "GET", "kind": "SERVER", "tracer": "io.opentelemetry.servlet-5.0:2.7.0-alpha", "traceId": "fd7870132f4c8447ab617d68fec1e6aa-d9fc60c4f8542815", "parent.traceId": "00000000000000000000000000000000-0000000000000000", "thread": "Default Executor-thread-1", "client.address": "10.128.0.132", "server.address": "www.perfcluster9qalive.svt.commerce.com, www.perfcluster9qalive.svt.commerce.com", "user_agent.original": "curl/7.81.0", "url.query": "store=Emerald&partNumber=SKU190164&fulfillmentCenter=13001&limit=1&availableToPromise=false", "url.path": "/inventory/api/v1/item-inventories", "http.request.method": "GET", "url.scheme": "https", "thread.id": "52", "startTime": "2024-12-13T14:14:29.0304Z", "elapsedMs": 202,351, "ended": "false" ACTIVE: "name": "SELECT inventory.items", "kind": "CLIENT", "tracer": "io.opentelemetry.jdbc:2.7.0-alpha", "traceId": "fd7870132f4c8447ab617d68fec1e6aa-3b1374671c827cc7", "parent.traceId": "fd7870132f4c8447ab617d68fec1e6aa-d9fc60c4f8542815", "thread": "Default Executor-thread-1", "server.address": "perfcluster9qalivepostgres.commerce.svc.cluster.local", "db.connection_string": "postgresql://perfcluster9qalivepostgres.commerce.svc.cluster.local:5432", "db.user": "inventory", "db.statement": "select i1_0.partnumber,i1_0.backorder_limit,i1_0.hasexpectedinventory,i1_0.inventorysystem,i1_0.lagtimeoffset,i1_0.maxbooffset,i1_0.max_threshold,i1_0.min_threshold,i1_0.product_desc,i1_0.reservetimeoffset,i1_0.trackinventory,i1_0.quantitymeasure from inventory.items i1_0 where i1_0.partnumber=?", "db.system": "postgresql", "db.sql.table": "inventory.items", "server.port": "5432", "db.operation": "SELECT", "db.name": "inventorydb", "thread.id": "52", "startTime": "2024-12-13T14:14:29.0310Z", "elapsedMs": 202,345, "ended": "false" ENDED: "Transaction.commit": 1ms/3 , "FulfillmentCenterRepository.findActiveNonDeletedIds": 2ms/1 , "SELECT inventory.availableinventory": 1ms/3 , "inventorydb": 0ms/1 , "SELECT inventory.fulfilmentcenter": 0ms/1 , "SELECT com.hcl.inventory.entity.AvailableInventory": 2ms/3 , "AvailableInventoryRepository.findDistinctPartNumbersByStoreAndPartNumberAndFfmCenter": 2ms/1 , "AvailableInventoryRepository.findByStoreInAndPartNumberInAndFfmCenterIdIn": 1ms/1 , "SELECT com.hcl.inventory.entity.FulfillmentCenter": 0ms/1 Java callstack: at ... at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:517) at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:434) at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:194) - SpanLogger
- Logs span
onStartandonEndevents that match the configured criteria.