diff --git a/README.md b/README.md index 53c58e34eb2c..a965ac3c6d06 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ * [Getting Started](#getting-started) * [Configuring the Agent](#configuring-the-agent) * [Supported libraries, frameworks, and application servers](#supported-libraries-frameworks-and-application-servers) +* [Creating agent extensions](#creating-agent-extensions) * [Manually instrumenting](#manually-instrumenting) * [Logger MDC auto-instrumentation](#logger-mdc-mapped-diagnostic-context-auto-instrumentation) * [Troubleshooting](#troubleshooting) @@ -108,6 +109,10 @@ a majority of the most popular [application servers](docs/supported-libraries.md [disabled instrumentation](docs/supported-libraries.md#disabled-instrumentations) and how to [suppress unwanted instrumentation](docs/suppressing-instrumentation.md). +## Creating agent extensions + +[Extensions](examples/extension/README.md) add new features and capabilities to the agent without having to create a separate distribution or to fork this repository. For example, you can create custom samplers or span exporters, set new defaults, and embed it all in the agent to obtain a single jar file. + ## Manually instrumenting For most users, the out-of-the-box instrumentation is completely sufficient and nothing more has to diff --git a/docs/agent-config.md b/docs/agent-config.md index c347c63ed7da..81a87591509e 100644 --- a/docs/agent-config.md +++ b/docs/agent-config.md @@ -52,6 +52,13 @@ You can provide a path to agent configuration file by setting the corresponding |--------------------------------------|--------------------------------------|----------------------------------------------------------------------------------| | `otel.javaagent.configuration-file` | `OTEL_JAVAAGENT_CONFIGURATION_FILE` | Path to valid Java properties file which contains the javaagent configuration.| +### Extensions + +You can enable [extensions](../examples/extension/README.md) by setting the corresponding property. + +| System property | Environment variable | Description | +|--------------------------------------|--------------------------------------|----------------------------------------------------------------------------------| +| `otel.javaagent.experimental.extensions` | `OTEL_JAVAAGENT_EXPERIMENTAL_EXTENSIONS` | Path to a an extension jar file or folder, containing jar files. If pointing to a folder, every jar file in that folder will be treated as separate, independent extension| ## Peer service name diff --git a/examples/extension/README.md b/examples/extension/README.md index 8c47e5d26cd0..76f32f560794 100644 --- a/examples/extension/README.md +++ b/examples/extension/README.md @@ -1,84 +1,64 @@ ## Introduction -This repository demonstrates how to create an extension archive to use with `otel.javaagent.experimental.extensions` -configuration option of the OpenTelemetry Java instrumentation agent. - -For every extension point provided by OpenTelemetry Java instrumentation, this repository contains an example of -its usage. - -Please carefully read both the source code and Gradle build script file `build.gradle`. -They contain a lot of documentation and comments explaining the purpose of all major pieces. - -## How to use extension archive - -When you build this project by running `./gradlew build` you will get a jar file in -`build/libs/opentelemetry-java-instrumentation-extension-demo-1.0-all.jar`. -Copy this jar file to a machine running the application that you are monitoring with -OpenTelemetry Java instrumentation agent. - -Assuming that your command line looks similar to this: -``` -java -javaagent:path/to/opentelemetry-javaagent-all.jar \ - -jar myapp.jar -``` -change it to this: -``` -java -javaagent:path/to/opentelemetry-javaagent-all.jar \ - -Dotel.javaagent.experimental.extensions=path/to/extension.jar - -jar myapp.jar -``` -specifying the full path and the correct name of your extensions jar. - -## Embedded extensions - -It is also possible to embedded you extension archive right inside OpenTelemetry Java Agent. -This produces a single jar file thus simplifying deployment. -Please consult `extendedAgent` task in [build.gradle](build.gradle) file for more information. -When using Java Agent with embedded extension, the `-Dotel.javaagent.experimental.extensions` -command line option is not needed anymore. -Just `-javaagent` is sufficient. +Extensions add new features and capabilities to the agent without having to create a separate distribution (for examples and ideas, see [Use cases for extensions](#use-cases-for-extensions)). +The contents in this folder demonstrate how to create an extension for the OpenTelemetry Java instrumentation agent, with examples for every extension point. + +> Read both the source code and the Gradle build script, as they contain documentation that explains the purpose of all the major components. + +## Build and add extensions + +To build this extension project, run `./gradlew build`. You can find the resulting jar file in `build/libs/`. + +To add the extension to the instrumentation agent: + +1. Copy the jar file to a host that is running an application to which you've attached the OpenTelemetry Java instrumentation. +2. Modify the startup command to add the full path to the extension file. For example: + + ```bash + java -javaagent:path/to/opentelemetry-javaagent-all.jar \ + -Dotel.javaagent.experimental.extensions=build/libs/opentelemetry-java-instrumentation-extension-demo-1.0-all.jar + -jar myapp.jar + ``` +## Embed extensions in the OpenTelemetry Agent + +To simplify deployment, you can embed extensions into the OpenTelemetry Java Agent to produce a single jar file. With an integrated extension, you no longer need the `-Dotel.javaagent.experimental.extensions` command line option. + +For more information, see the `extendedAgent` task in [build.gradle](build.gradle). ## Extensions examples -* [DemoIdGenerator](src/main/java/com/example/javaagent/DemoIdGenerator.java) - custom `IdGenerator` -* [DemoPropagator](src/main/java/com/example/javaagent/DemoPropagator.java) - custom `TextMapPropagator` -* [DemoPropertySource](src/main/java/com/example/javaagent/DemoPropertySource.java) - default configuration -* [DemoSampler](src/main/java/com/example/javaagent/DemoSampler.java) - custom `Sampler` -* [DemoSpanProcessor](src/main/java/com/example/javaagent/DemoSpanProcessor.java) - custom `SpanProcessor` -* [DemoSpanExporter](src/main/java/com/example/javaagent/DemoSpanExporter.java) - custom `SpanExporter` -* [DemoServlet3InstrumentationModule](src/main/java/com/example/javaagent/instrumentation/DemoServlet3InstrumentationModule.java) - additional instrumentation +* Custom `IdGenerator`: [DemoIdGenerator](src/main/java/com/example/javaagent/DemoIdGenerator.java) +* Custom `TextMapPropagator`: [DemoPropagator](src/main/java/com/example/javaagent/DemoPropagator.java) +* New default configuration: [DemoPropertySource](src/main/java/com/example/javaagent/DemoPropertySource.java) +* Custom `Sampler`: [DemoSampler](src/main/java/com/example/javaagent/DemoSampler.java) +* Custom `SpanProcessor`: [DemoSpanProcessor](src/main/java/com/example/javaagent/DemoSpanProcessor.java) +* Custom `SpanExporter`: [DemoSpanExporter](src/main/java/com/example/javaagent/DemoSpanExporter.java) +* Additional instrumentation: [DemoServlet3InstrumentationModule](src/main/java/com/example/javaagent/instrumentation/DemoServlet3InstrumentationModule.java) + +## Sample use cases + +Extensions are designed to override or customize the instrumentation provided by the upstream agent without having to create a new OpenTelemetry distribution or alter the agent code in any way. + +Consider an instrumented database client that creates a span per database call and extracts data from the database connection to provide span attributes. The following are sample use cases for that scenario that can be solved by using extensions. + +### "I don't want this span at all" -## Instrumentation customisation +Create an extension to disable selected instrumentation by providing new default settings. -There are several options to override or customise instrumentation provided by the upstream agent. -The following description follows one specific use-case: +### "I want to edit some attributes that don't depend on any db connection instance" -> Instrumentation X from OpenTelemetry distribution creates span that I don't like and I want to change it. +Create an extension that provide a custom `SpanProcessor`. -As an example, let us take some database client instrumentation that creates a span for database call -and extracts data from db connection to provide attributes for that span. +### "I want to edit some attributes and their values depend on a specific db connection instance" -### I don't want this span at all -The easiest case. You can just pre-configure the agent in your extension and disable given instrumentation. +Create an extension with new instrumentation which injects its own advice into the same method as the original one. You can use the `order` method to ensure it runs after the original instrumentation and augment the current span with new information. -### I want to add/modify some attributes and their values does NOT depend on a specific db connection instance. -E.g. you want to add some data from call stack as span attribute. -In this case just provide your custom `SpanProcessor`. -No need for touching instrumentation itself. +For example, see [DemoServlet3InstrumentationModule](src/main/java/com/example/javaagent/instrumentation/DemoServlet3InstrumentationModule.java). -### I want to add/modify some attributes and their values depend on a specific db connection instance. -Write a _new_ instrumentation which injects its own advice into the same method as the original one. -Use `order` method to ensure it is run after the original instrumentation. -Now you can augment current span with new information. +### "I want to remove some attributes" -See [DemoServlet3InstrumentationModule](src/main/java/com/example/javaagent/instrumentation/DemoServlet3InstrumentationModule.java). +Create an extension with a custom exporter or use the attribute filtering functionality in the OpenTelemetry Collector. -### I want to remove some attributes -Write custom exporter or use attribute filtering functionality in Collector. +### "I don't like the OTel spans. I want to modify them and their lifecycle" -### I don't like Otel span at all. I want to significantly modify it and its lifecycle -Disable existing instrumentation. -Write a new one, which injects `Advice` into the same (or better) method as the original instrumentation. -Write your own `Advice` for this. -Use existing `Tracer` directly or extend it. -As you have your own `Advice`, you can control which `Tracer` you use. +Create an extension that disables existing instrumentation and replace it with new one that injects `Advice` into the same (or a better) method as the original instrumentation. You can write your `Advice` for this and use the existing `Tracer` directly or extend it. As you have your own `Advice`, you can control which `Tracer` you use.