Skip to content

Commit

Permalink
Feature/start ping (#1)
Browse files Browse the repository at this point in the history
* setup project

* add start notification via HTTP

* add tests

* add connectionManager

* implement suggestions

* update README

* add comments

* fix workflow

* fix workflow

* add NotificationCallback

* update README

* close HTTP client

* add default service name
  • Loading branch information
EddeCCC authored Jul 2, 2024
1 parent 2fb6034 commit cd1c1c7
Show file tree
Hide file tree
Showing 19 changed files with 626 additions and 119 deletions.
7 changes: 7 additions & 0 deletions .github/scripts/update-sdk-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash -e
# script to update the OpenTelemetry SDK version

# version, which should be used for the SDK
version=$1

sed -Ei "s/(opentelemetrySdk *: )\"[^\"]*\"/\1\"$version\"/" build.gradle
18 changes: 18 additions & 0 deletions .github/scripts/update-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash -e
# script to update the OpenTelemetry Java agent version


# version, which should be used for the java agent
version=$1

if [[ $version == *-SNAPSHOT ]]; then
alpha_version=${version//-SNAPSHOT/-alpha-SNAPSHOT}
else
alpha_version=${version}-alpha
fi

sed -Ei "s/(opentelemetryJavaagent *: )\"[^\"]*\"/\1\"$version\"/" build.gradle
sed -Ei "s/(opentelemetryJavaagentAlpha *: )\"[^\"]*\"/\1\"$alpha_version\"/" build.gradle

sed -Ei "s/(io.opentelemetry.instrumentation.muzzle-generation\" version )\"[^\"]*\"/\1\"$alpha_version\"/" build.gradle
sed -Ei "s/(io.opentelemetry.instrumentation.muzzle-check\" version )\"[^\"]*\"/\1\"$alpha_version\"/" build.gradle
19 changes: 12 additions & 7 deletions .github/workflows/ci-feature.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ name: Feature Branch Continous Integration

on:
push:
branches: [ "feature/**" ]

branches:
- "feature/**"
- master

jobs:
build-and-test:
name: "Build and test extension"
runs-on: ubuntu-latest
permissions:
contents: read
Expand All @@ -21,25 +24,27 @@ jobs:
# See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
- name: Setup Gradle
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
with:
build-scan-publish: true
build-scan-terms-of-service-url: 'https://gradle.com/terms-of-service'
build-scan-terms-of-service-agree: 'yes'

- name: Test
run: ./gradlew test

- name: Build
run: ./gradlew extendAgent
run: ./gradlew extendedAgent

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: Package
path: build/libs

dependency-submission:

dependency-submission:
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
Expand Down
105 changes: 29 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,15 @@
# Extension
This extension is used as a showcase for VHV in order to demonstrate that we can move inspectit's
agent logic to opentelemetry agent enhanced via an extension.
# inspectIT Gepard Extension

Use `./gradlew extendAgent` (no tests) or `./gradlew build` to build an agent jar with your current
changes.
Extension for the OpenTelemetry Java agent.

## TODOs / next steps
* otel agent wants to export spans.
* Find out where otel wants to report spans to. Jaeger? Something else?
* Do we want to use that? Do we want to disable it?
* Is it easy to change it to an url provided by the config server?
* this extension sends an additional http header named `X-OCELOT-AGENT-TYPE` to the config server. Use it over there to display a different icon in the config server's UI
* tests do not work
* Probably not that important
inspectIT Gepard is the further development of [inspectIT Ocelot](https://github.com/inspectIT/inspectit-ocelot).
While the inspectIT Ocelot Java agent is self-made, inspectIT Gepard uses the OpenTelemetry Java agent as basis
and extends it with features from inspectIT Ocelot.

# Documentation
This extension calls the agent configuration endpoint of the configuration server. For your local
installation this is typically available at http://localhost:8090/v1/api/agent/configuration. The
endpoint of the server is defined in class `rocks.inspectit.ocelot.rest.agent.AgentController` of inspectit-ocelot.
## Installation

Calling that endpoint serves the following purposes:
* First call registers Agent with configuration server
* uses query parameter `service` to display something meaningful in the UI. Currently, hardcoded to `otel-extension`
* Regularly polls configuration server to fetch potentially updated configurations
* Transmits by each call the health state of the agent
* Send an `X-OCELOT-AGENT-TYPE` to distinguish inspectit-ocelot-agent and this agent

Currently, you can influence the target url via SystemProperty named `inspectit.config.http.url`.

Polling of configuration is handled in classes `ConfigurationPolling` and `HttpConfiguration`.

# Original Readme
The following is the original content from which this work is derived.
Source: https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/examples/extension
## Introduction

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](#sample-use-cases)).

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 build this extension project, run `./gradlew build` or `./gradlew extendedAgent` (no tests).
You can find the resulting jar file in `build/libs/`.

To add the extension to the instrumentation agent:

Expand All @@ -52,52 +18,39 @@ To add the extension to the instrumentation agent:

```bash
java -javaagent:path/to/opentelemetry-javaagent.jar \
-Dotel.javaagent.extensions=build/libs/opentelemetry-java-instrumentation-extension-demo-1.0-all.jar
-Dotel.javaagent.extensions=build/libs/opentelemetry-javaagent.jar \
-Dotel.service.name="my-service"
-jar myapp.jar
```

Note: to load multiple extensions, you can specify a comma-separated list of extension jars or directories (that
contain extension jars) for the `otel.javaagent.extensions` value.

## 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.extensions` command line option.

For more information, see the `extendedAgent` task in [build.gradle](build.gradle).
## Network communication

## Extensions examples
The extension contains a client, who is able to communicate with other servers via HTTPS.
To configure TLS

* Custom `IdGenerator`: [DemoIdGenerator](src/main/java/com/example/javaagent/DemoIdGenerator.java)
* Custom `TextMapPropagator`: [DemoPropagator](src/main/java/com/example/javaagent/DemoPropagator.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)
1. Provide a local keystore, which contains the certificate of your server
2. Modify the startup command to add the path to the keystore as well as the password. For example:

## 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"

Create an extension to disable selected instrumentation by providing new default settings.

### "I want to edit some attributes that don't depend on any db connection instance"

Create an extension that provide a custom `SpanProcessor`.

### "I want to edit some attributes and their values depend on a specific db connection instance"
```bash
java -javaagent:path/to/opentelemetry-javaagent.jar \
-Dotel.javaagent.extensions=build/libs/opentelemetry-javaagent.jar \
-Dotel.service.name="my-service" \
-Djavax.net.ssl.trustStore="path\to\keystore\agent-keystore.jks" \
-Djavax.net.ssl.trustStorePassword="password"
-jar myapp.jar
```

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.
## Further Information

For example, see [DemoServlet3InstrumentationModule](src/main/java/com/example/javaagent/instrumentation/DemoServlet3InstrumentationModule.java).
The repository was build upon this example project: https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/examples/extension

### "I want to remove some attributes"
### Why Gepard?
Gepard is the German name for the animal cheetah as well as an acronym for:

Create an extension with a custom exporter or use the attribute filtering functionality in the OpenTelemetry Collector.
"**G**anzheitliche, **e**ffizienz-orientierte, **P**erformance **A**nwendungsüberwachung mit **R**eporting und **D**iagnose"

### "I don't like the OTel spans. I want to modify them and their lifecycle"
meaning: holistic, efficiency-orientated, performance application monitoring with reporting and diagnostics.

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.
70 changes: 35 additions & 35 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,35 @@ plugins {
See https://imperceptiblethoughts.com/shadow/ for more details about Shadow plugin.
*/
id "com.github.johnrengelman.shadow" version "8.1.1"
id "com.diffplug.spotless" version "6.17.0"
id "com.diffplug.spotless" version "6.25.0"

id "io.opentelemetry.instrumentation.muzzle-generation" version "1.31.0-alpha"
id "io.opentelemetry.instrumentation.muzzle-check" version "1.31.0-alpha"
id "io.opentelemetry.instrumentation.muzzle-generation" version "2.5.0-alpha"
id "io.opentelemetry.instrumentation.muzzle-check" version "2.5.0-alpha"

id "pl.allegro.tech.build.axion-release" version "1.11.0"
id "pl.allegro.tech.build.axion-release" version "1.17.2"

}

group 'rocks.inspectit.gepard.agent'
version = scmVersion.version
version = "0.0.1-SNAPSHOT"

sourceCompatibility = "17"
targetCompatibility = "17"

ext {
versions = [
// this line is managed by .github/scripts/update-sdk-version.sh
opentelemetrySdk : "1.38.0",
opentelemetrySdk : "1.39.0",

// these lines are managed by .github/scripts/update-version.sh
opentelemetryJavaagent : "2.3.0",
opentelemetryJavaagentAlpha: "2.3.0-alpha",
opentelemetryJavaagent : "2.5.0",
opentelemetryJavaagentAlpha: "2.5.0-alpha",

junit : "5.9.2"
junit : "5.10.2"
]

deps = [
autoservice: dependencies.create(group: 'com.google.auto.service', name: 'auto-service', version: '1.0.1')
autoservice: dependencies.create(group: 'com.google.auto.service', name: 'auto-service', version: '1.1.1')
]
}

Expand Down Expand Up @@ -73,13 +73,14 @@ dependencies {
// these serve as a test of the instrumentation boms
implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:${versions.opentelemetryJavaagent}"))
implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:${versions.opentelemetryJavaagentAlpha}"))
implementation("org.apache.httpcomponents:httpclient:4.5.14")
implementation("commons-codec:commons-codec:1.15")
implementation("ch.qos.logback:logback-classic:1.3.6")
implementation("org.slf4j:jcl-over-slf4j:2.0.4")

// For instrumentation, same version as OpenTelemetry
implementation("net.bytebuddy:byte-buddy:1.14.12")
// inspectit-gepard dependencies
implementation("net.bytebuddy:byte-buddy:1.14.15")
implementation("ch.qos.logback:logback-classic:1.5.6")
implementation("org.slf4j:jcl-over-slf4j:2.0.13")
// http client for server notification
implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1")
implementation("com.fasterxml.jackson.core:jackson-databind:2.17.1")

/*
Interfaces and SPIs that we implement. We use `compileOnly` dependency because during
Expand All @@ -90,35 +91,34 @@ dependencies {
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api")
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-tooling")
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-bootstrap")
//Provides @AutoService annotation that makes registration of our SPI implementations much easier

// Provides @AutoService annotation that makes registration of our SPI implementations much easier
compileOnly deps.autoservice
annotationProcessor deps.autoservice


//All dependencies below are only for tests
testImplementation("org.testcontainers:testcontainers:1.17.6")
testImplementation("com.fasterxml.jackson.core:jackson-databind:2.14.2")
testImplementation("com.google.protobuf:protobuf-java-util:3.22.2")
testImplementation("com.squareup.okhttp3:okhttp:4.10.0")
testImplementation("io.opentelemetry:opentelemetry-api")
testImplementation("io.opentelemetry.proto:opentelemetry-proto:0.19.0-alpha")
// All dependencies below are only for tests
testImplementation("org.mock-server:mockserver-junit-jupiter:5.15.0")
testImplementation("org.mockito:mockito-core:5.12.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
testImplementation("io.opentelemetry.javaagent:opentelemetry-javaagent-tooling")
testCompileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api")
testCompileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")

testImplementation("org.junit.jupiter:junit-jupiter-api:${versions.junit}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${versions.junit}")
testRuntimeOnly("ch.qos.logback:logback-classic:1.4.6")

//Otel Java instrumentation that we use and extend during integration tests
// Otel Java instrumentation that we use and extend during integration tests
otel("io.opentelemetry.javaagent:opentelemetry-javaagent:${versions.opentelemetryJavaagent}")

//TODO remove when start using io.opentelemetry.instrumentation.javaagent-instrumentation plugin
// TODO remove when start using io.opentelemetry.instrumentation.javaagent-instrumentation plugin
add("codegen", "io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:${versions.opentelemetryJavaagentAlpha}")
add("muzzleBootstrap", "io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations-support:${versions.opentelemetryJavaagentAlpha}")
add("muzzleTooling", "io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api:${versions.opentelemetryJavaagentAlpha}")
add("muzzleTooling", "io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:${versions.opentelemetryJavaagentAlpha}")
}

//Produces a copy of upstream javaagent with this extension jar included inside it
//The location of extension directory inside agent jar is hard-coded in the agent source code
// Produces a copy of upstream javaagent with this extension jar included inside it
// The location of extension directory inside agent jar is hard-coded in the agent source code
tasks.register('extendedAgent', Jar) {
dependsOn(configurations.otel)
archiveFileName = "opentelemetry-javaagent.jar"
Expand All @@ -127,12 +127,12 @@ tasks.register('extendedAgent', Jar) {
into "extensions"
}

//Preserve MANIFEST.MF file from the upstream javaagent
// Preserve MANIFEST.MF file from the upstream javaagent
doFirst {
manifest.from(
zipTree(configurations.otel.singleFile).matching {
include 'META-INF/MANIFEST.MF'
}.singleFile
zipTree(configurations.otel.singleFile).matching {
include 'META-INF/MANIFEST.MF'
}.singleFile
)
}
}
Expand All @@ -150,7 +150,7 @@ tasks {
}

compileJava {
options.release.set(8)
options.release.set(17)
}

assemble.dependsOn(shadowJar)
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading

0 comments on commit cd1c1c7

Please sign in to comment.