Skip to content

Latest commit

 

History

History
314 lines (255 loc) · 11.4 KB

File metadata and controls

314 lines (255 loc) · 11.4 KB

Doc Generator

Runs analysis on instrumentation modules in order to generate documentation.

How to use

Run the analysis to update the instrumentation-list.yaml:

./gradlew :instrumentation-docs:runAnalysis

Telemetry collection

Until this process is ready for all instrumentations, each module will be modified to include a system property feature flag configured for when the tests run. By enabling the following flag you will enable metric and span collection:

tasks {
  test {
    systemProperty("collectMetadata", findProperty("collectMetadata"))
    ...
  }
}

Sometimes instrumentation will behave differently based on configuration options, and we can differentiate between these configurations by using the metadataConfig system property. When the telemetry is written to a file, the value of this property will be included, or it will default to a default attribution.

For example, to collect and write metadata for the otel.semconv-stability.opt-in=database option set for an instrumentation:

val collectMetadata = findProperty("collectMetadata")?.toString() ?: "false"

tasks {
  val testStableSemconv by registering(Test::class) {
    jvmArgs("-Dotel.semconv-stability.opt-in=database")

    systemProperty("collectMetadata", collectMetadata)
    systemProperty("metadataConfig", "otel.semconv-stability.opt-in=database")
  }

  test {
    systemProperty("collectMetadata", collectMetadata)
  }

  check {
    dependsOn(testStableSemconv)
  }
}

Then, prior to running the analyzer, run the following command to generate .telemetry files:

./gradlew test -PcollectMetadata=true

Then run the doc generator

./gradlew :instrumentation-docs:runAnalysis

or use the helper script that will run only the currently supported tests (recommended):

./instrumentation-docs/collect.sh

Instrumentation Hierarchy

An "InstrumentationModule" represents a module that targets specific code in a framework/library/technology. Each module will have a name, a namespace, and a group.

Using these structures as examples:

├── instrumentation
│   ├── clickhouse-client-05
│   ├── jaxrs
│   │   ├── jaxrs-1.0
│   │   ├── jaxrs-2.0
│   ├── spring
│   │   ├── spring-cloud-gateway
│   │   │   ├── spring-cloud-gateway-2.0
│   │   │   ├── spring-cloud-gateway-2.2
│   │   │   └── spring-cloud-gateway-common

Results in the following:

  • Name - the full name of the instrumentation module
    • clickhouse-client-05, jaxrs-1.0, spring-cloud-gateway-2.0
  • Namespace - direct parent. if none, use name and strip version
    • clickhouse-client, jaxrs, spring-cloud-gateway
  • Group - top most parent
    • clickhouse-client, jaxrs, spring

This information is also referenced in InstrumentationModule code for each module:

public class SpringWebInstrumentationModule extends InstrumentationModule
    implements ExperimentalInstrumentationModule {
  public SpringWebInstrumentationModule() {
    super("spring-web", "spring-web-3.1");
  }

Instrumentation metadata

  • classification
    • library - Instrumentation that targets a library
    • internal - Instrumentation that is used internally by the OpenTelemetry Java Agent
    • custom - Utilities that are used to create custom instrumentation
  • name
    • Identifier for instrumentation module, used to enable/disable
    • Configured in InstrumentationModule code for each module
  • semantic_conventions
    • The semantic conventions that the instrumentation module adheres to
    • Options are:
      • HTTP_CLIENT_SPANS
      • HTTP_CLIENT_METRICS
      • HTTP_SERVER_SPANS
      • HTTP_SERVER_METRICS
      • RPC_CLIENT_SPANS
      • RPC_CLIENT_METRICS
      • RPC_SERVER_SPANS
      • RPC_SERVER_METRICS
      • MESSAGING_SPANS
      • DATABASE_CLIENT_SPANS
      • DATABASE_CLIENT_METRICS
      • DATABASE_POOL_METRICS
      • JVM_RUNTIME_METRICS
      • GRAPHQL_SERVER_SPANS
      • FAAS_SERVER_SPANS
      • GENAI_CLIENT_SPANS
      • GENAI_CLIENT_METRIC
  • features
    • The specific functionality that the instrumentation provides
    • Options are:
      • HTTP_ROUTE
      • CONTEXT_PROPAGATION
      • AUTO_INSTRUMENTATION_SHIM
      • CONTROLLER_SPANS
      • VIEW_SPANS
      • LOGGING_BRIDGE
      • RESOURCE_DETECTOR
  • library_link
    • URL to the library or framework's main website or documentation, or if those don't exist, the GitHub repository.
  • source_path
    • Path to the source code of the instrumentation module
  • minimum_java_version
    • Minimum Java version required by the instrumentation module. If not specified, it is assumed to be Java 8
  • description
    • Short description of what the instrumentation does
  • has_standalone_library
    • Whether the instrumentation module has a standalone library that can be used outside of the agent
  • has_javaagent
    • Whether the instrumentation module has a javaagent component that can be used with the OpenTelemetry Java Agent
  • target_versions
    • List of supported versions by the module, broken down by library or javaagent support
  • scope (See instrumentation-scope docs)
    • name: The scope name of the instrumentation, io.opentelemetry.{instrumentation name}
    • schema_url: Location of the telemetry schema that the instrumentation’s emitted telemetry conforms to. (See telemetry schema docs)
    • attributes: The instrumentation scope’s optional attributes provide additional information about the scope.
  • configuration settings
    • List of settings that are available for the instrumentation module
    • Each setting has a name (flat property format), optional declarative_name (YAML path format), description, type, default value, and optional examples
  • metrics
    • List of metrics that the instrumentation module collects, including the metric name, description, type, and attributes.
    • Separate lists for the metrics emitted by default vs via configuration options.
  • spans
    • List of spans kinds the instrumentation module generates, including the attributes and their types.
    • Separate lists for the spans emitted by default vs via configuration options.

Methodology

metadata.yaml file

Within each instrumentation source directory, a metadata.yaml file can be created to provide additional information about the instrumentation module.

As of now, the following fields are supported, all of which are optional:

description: "This instrumentation enables..."    # Description of the instrumentation module
semantic_conventions:                             # List of semantic conventions the instrumentation adheres to
  - HTTP_CLIENT_SPANS
  - DATABASE_CLIENT_SPANS
  - JVM_RUNTIME_METRICS
features:                                        # List of features this instrumentation provides
  - HTTP_ROUTE
  - CONTEXT_PROPAGATION
disabled_by_default: true                         # Defaults to `false`
classification: internal                          # instrumentation classification: library | internal | custom
library_link: https://...                         # URL to the library or framework's main website or documentation
configurations:
  - name: otel.instrumentation.common.db.query-sanitization.enabled
    declarative_name: java.common.db.query_sanitization.enabled    # Optional: YAML config path
    description: Enables query sanitization for database queries.
    type: boolean               # boolean | string | list | map
    default: true
    examples:                   # Optional: Example values for this configuration
      - "true"
      - "false"
override_telemetry: false                         # Set to true to ignore auto-generated .telemetry files
additional_telemetry:                             # Manually document telemetry metadata
  - when: "default"
    metrics:
      - name: "metric.name"
        description: "Metric description"
        type: "COUNTER"
        unit: "1"
        attributes:
          - name: "attribute.name"
            type: "STRING"
    spans:
      - span_kind: "CLIENT"
        attributes:
          - name: "span.attribute"
            type: "STRING"

Gradle File Derived Information

We parse gradle files in order to determine several pieces of metadata:

  • Javaagent versions are determined by the muzzle plugin configurations
  • Standalone Library versions are identified, but we do not try and parse version ranges
  • Minimum Java version is determined by the otelJava configurations

Scope

For now, the scope name is the only value that is implemented in our instrumentations. The scope name is determined by the instrumentation module name: io.opentelemetry.{instrumentation name}

We will implement gatherers for the schemaUrl and scope attributes when instrumentations start implementing them.

Spans and Metrics

In order to identify what telemetry is emitted from instrumentations, we can hook into the InstrumentationTestRunner class and collect the metrics and spans generated during runs. We can then leverage the afterTestClass() in the Agent and library test runners to then write this information into temporary files. When we analyze the instrumentation modules, we can read these files and generate the telemetry section of the instrumentation-list.yaml file.

The data is written into a .telemetry directory in the root of each instrumentation module. This data will be excluded from git and just generated on demand.

Each file has a when value along with the list of metrics that indicates whether the telemetry is emitted by default or via a configuration option.

Manual Telemetry Documentation

In addition to auto-generated telemetry data from test runs, you can manually document telemetry metadata directly in the metadata.yaml file. This is useful for:

  • Documenting telemetry that may not be captured during test runs
  • Overriding auto-generated telemetry data when it's incomplete or incorrect
  • Adding additional telemetry documentation that complements the auto-generated data

You can add manual telemetry documentation using the additional_telemetry field:

additional_telemetry:
  - when: "default"  # or any configuration condition
    metrics:
      - name: "my.custom.metric"
        description: "Description of the metric"
        type: "COUNTER"
        unit: "1"
        attributes:
          - name: "attribute.name"
            type: "STRING"
    spans:
      - span_kind: "CLIENT"
        attributes:
          - name: "span.attribute"
            type: "STRING"

To completely replace auto-generated telemetry data (ignoring .telemetry files), set override_telemetry: true:

override_telemetry: true
additional_telemetry:
  - when: "default"
    metrics:
      - name: "documented.metric"
        description: "This replaces all auto-generated metrics"
        type: "GAUGE"
        unit: "ms"

When both manual and auto-generated telemetry exist for the same when condition, they are merged with manual entries taking precedence in case of conflicts (same metric name or span kind).

Doc Synchronization

The documentation site has a section that lists all the instrumentations in the context of documenting how to disable them.

We have a class DocSynchronization that runs a check against our instrumentation-list.yaml file to identify when we have missing entries, so we know to go update them.

You can run this via:

./gradlew :instrumentation-docs:docSiteAudit

This is setup to run nightly in a github action.