Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,31 @@ jobs:
key: ${{ runner.os }}-gradle-wrapper-cache-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}

- name: Build and test
run: ./gradlew build -x :smoke-tests:test --scan --no-daemon
run: ./gradlew build --scan --no-daemon

- name: Build scan
if: ${{ !cancelled() && hashFiles('build-scan.txt') != '' }}
run: cat build-scan.txt

test-latest-deps:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6.0.2

- name: Set up JDK 17 for running Gradle
uses: actions/setup-java@v5.2.0
with:
distribution: temurin
java-version: 17

- name: Cache Gradle Wrapper
uses: actions/cache@v5.0.3
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-cache-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}

- name: Build and test
run: ./gradlew check -x spotlessCheck -PtestLatestDeps=true --scan --no-daemon

- name: Build scan
if: ${{ !cancelled() && hashFiles('build-scan.txt') != '' }}
Expand Down
26 changes: 25 additions & 1 deletion .github/workflows/nightly.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,31 @@ jobs:
key: ${{ runner.os }}-gradle-wrapper-cache-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}

- name: Build and test
run: ./gradlew build -x :smoke-tests:test --scan --no-daemon
run: ./gradlew build --scan --no-daemon

- name: Build scan
if: ${{ !cancelled() && hashFiles('build-scan.txt') != '' }}
run: cat build-scan.txt

test-latest-deps:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6.0.2

- name: Set up JDK 17 for running Gradle
uses: actions/setup-java@v5.2.0
with:
distribution: temurin
java-version: 17

- name: Cache Gradle Wrapper
uses: actions/cache@v5.0.3
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-cache-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}

- name: Build and test
run: ./gradlew check -x spotlessCheck -PtestLatestDeps=true --scan --no-daemon

- name: Build scan
if: ${{ !cancelled() && hashFiles('build-scan.txt') != '' }}
Expand Down
26 changes: 25 additions & 1 deletion .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,31 @@ jobs:
key: ${{ runner.os }}-gradle-wrapper-cache-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}

- name: Build and test
run: ./gradlew build -x :smoke-tests:test --scan --no-daemon
run: ./gradlew build --scan --no-daemon

- name: Build scan
if: ${{ !cancelled() && hashFiles('build-scan.txt') != '' }}
run: cat build-scan.txt

test-latest-deps:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6.0.2

- name: Set up JDK 17 for running Gradle
uses: actions/setup-java@v5.2.0
with:
distribution: temurin
java-version: 17

- name: Cache Gradle Wrapper
uses: actions/cache@v5.0.3
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-cache-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}

- name: Build and test
run: ./gradlew check -x spotlessCheck -PtestLatestDeps=true --scan --no-daemon

- name: Build scan
if: ${{ !cancelled() && hashFiles('build-scan.txt') != '' }}
Expand Down
23 changes: 23 additions & 0 deletions instrumentation/jdbc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ muzzle {
module.set("mssql-jdbc")
versions.set("(,)")
}
pass {
group.set("com.oracle.database.jdbc")
module.set("ojdbc8")
versions.set("(,)")
}
pass {
group.set("com.mysql")
module.set("mysql-connector-j")
versions.set("(,)")
}
pass {
group.set("org.mariadb.jdbc")
module.set("mariadb-java-client")
versions.set("(,)")
}
}

dependencies {
Expand All @@ -32,6 +47,14 @@ dependencies {
// PostgreSQL
testLibrary("org.postgresql:postgresql:42.1.1")
testImplementation("org.testcontainers:testcontainers-postgresql")

// MySQL
testLibrary("com.mysql:mysql-connector-j:8.0.31")
testImplementation("org.testcontainers:testcontainers-mysql")

// MariaDB
testLibrary("org.mariadb.jdbc:mariadb-java-client:2.0.1")
testImplementation("org.testcontainers:testcontainers-mariadb")
}

tasks.withType<Test>().configureEach {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright Splunk Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.splunk.opentelemetry.instrumentation.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.annotation.Nullable;

public class AbstractMySqlDbContextPropagator extends AbstractDbContextPropagator {

@Override
protected void setContext(Connection connection, @Nullable String contextInfo)
throws SQLException {
PreparedStatement statement = connection.prepareStatement("set @traceparent=?");
statement.setString(1, contextInfo);
statement.executeUpdate();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright Splunk Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.splunk.opentelemetry.instrumentation.jdbc.mariadb;

import com.splunk.opentelemetry.instrumentation.jdbc.AbstractMySqlDbContextPropagator;

public final class MariaDbContextPropagator extends AbstractMySqlDbContextPropagator {
public static final MariaDbContextPropagator INSTANCE = new MariaDbContextPropagator();

private MariaDbContextPropagator() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright Splunk Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.splunk.opentelemetry.instrumentation.jdbc.mariadb;

import static java.util.Collections.singletonList;

import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.List;

@AutoService(InstrumentationModule.class)
public class MariaDbInstrumentationModule extends InstrumentationModule {

public MariaDbInstrumentationModule() {
super("splunk-jdbc", "splunk-jdbc-mariadb");
}

@Override
public int order() {
// run after jdbc instrumentation
return 1;
}

@Override
public boolean defaultEnabled() {
return false;
}

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new MariaDbStatementInstrumentation());
}

@Override
public boolean isHelperClass(String className) {
return className.startsWith("com.splunk.opentelemetry.instrumentation");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation is already repeated few times in our repo. Maybe className.startsWith("com.splunk.opentelemetry.instrumentation") could go to some helper class or an interface as a static method and be called from here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could introduce SplunkInstrumentationModule and put that method there and use that class in our instrumentations instead of InstrumentationModule

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright Splunk Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.splunk.opentelemetry.instrumentation.jdbc.mariadb;

import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments;

import io.opentelemetry.javaagent.bootstrap.CallDepth;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.sql.Statement;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

public class MariaDbStatementInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
// class names change between maridb driver versions
return extendsClass(
namedOneOf("org.mariadb.jdbc.Statement", "org.mariadb.jdbc.MariaDbStatement"));
}

@Override
public ElementMatcher<ClassLoader> classLoaderOptimization() {
return hasClassesNamed("org.mariadb.jdbc.Statement")
.or(hasClassesNamed("org.mariadb.jdbc.MariaDbStatement"));
}

@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isPublic()
.and(
nameStartsWith("execute")
.and(takesNoArguments().or(takesArgument(0, String.class)))),
this.getClass().getName() + "$SetContextAdvice");
}

@SuppressWarnings("unused")
public static class SetContextAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(
@Advice.This Statement statement, @Advice.Local("splunkCallDepth") CallDepth callDepth)
throws Exception {
callDepth = CallDepth.forClass(MariaDbContextPropagator.class);
if (callDepth.getAndIncrement() > 0) {
return;
}

MariaDbContextPropagator.INSTANCE.propagateContext(statement.getConnection());
}

@Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit(@Advice.Local("splunkCallDepth") CallDepth callDepth) {
callDepth.decrementAndGet();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright Splunk Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.splunk.opentelemetry.instrumentation.jdbc.mysql;

import com.splunk.opentelemetry.instrumentation.jdbc.AbstractMySqlDbContextPropagator;

public final class MySqlContextPropagator extends AbstractMySqlDbContextPropagator {
public static final MySqlContextPropagator INSTANCE = new MySqlContextPropagator();

private MySqlContextPropagator() {}
}
Loading
Loading