You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Quarkus中用DataSource方式实现JDBC的OpenTelemetry埋点?

在Quarkus中通过DataSource方式实现OpenTelemetry JDBC埋点

步骤1:添加必要依赖

在项目的构建文件中引入OpenTelemetry JDBC instrumentation依赖:

  • Maven(pom.xml):
<dependency>
    <groupId>io.opentelemetry.instrumentation</groupId>
    <artifactId>opentelemetry-jdbc</artifactId>
    <version>最新稳定版</version>
</dependency>
  • Gradle(build.gradle):
implementation 'io.opentelemetry.instrumentation:opentelemetry-jdbc:最新稳定版'

步骤2:修改LiquibaseRunner代码

你当前的代码直接通过URL打开数据库连接,需要调整为先创建原生DataSource,再用OpenTelemetry包装,最后从包装后的数据源获取连接。修改后的完整代码如下:

package .....infrastructure.data;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.sql.DataSource;

import io.quarkus.runtime.LaunchMode;
import org.eclipse.microprofile.config.inject.ConfigProperty;

import io.quarkus.runtime.StartupEvent;
import io.quarkus.runtime.util.ExceptionUtil;
import liquibase.Contexts;
import liquibase.LabelExpression;
import liquibase.Liquibase;
import liquibase.database.DatabaseConnection;
import liquibase.database.DatabaseFactory;
import liquibase.exception.LiquibaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
import liquibase.resource.ResourceAccessor;
import io.quarkus.logging.Log;
import io.opentelemetry.instrumentation.jdbc.datasource.OpenTelemetryDataSource;
import com.zaxxer.hikari.HikariDataSource;

@ApplicationScoped
public class LiquibaseRunner {

    @ConfigProperty(name = "quarkus.datasource.jdbc.url")
    String datasourceUrl;

    @ConfigProperty(name = "quarkus.datasource.username")
    String datasourceUsername;

    @ConfigProperty(name = "quarkus.datasource.password")
    String datasourcePassword;

    @ConfigProperty(name = "quarkus.datasource.jdbc.driver")
    String datasourceDriver;

    @ConfigProperty(name = "quarkus.liquibase.change-log")
    String changeLogLocation;

    public void onApplicationStart(@Observes StartupEvent even) {
        LaunchMode mode = io.quarkus.runtime.LaunchMode.current();
        if(mode != LaunchMode.TEST) {
            this.runMigration();
        } else {
            Log.info("测试模式下跳过数据库迁移");
        }
    }

    public void runMigration() {
        Log.info("开始迁移数据库:" + datasourceUrl);
        Liquibase liquibase = null;
        DataSource originalDataSource = null;
        DataSource otelDataSource = null;

        try {
            // 创建原生Hikari数据源(Quarkus默认连接池)
            originalDataSource = createOriginalDataSource();
            // 用OpenTelemetry包装数据源,实现JDBC埋点
            otelDataSource = new OpenTelemetryDataSource(originalDataSource);

            ResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor(Thread.currentThread().getContextClassLoader());
            // 从包装后的数据源获取连接
            DatabaseConnection conn = DatabaseFactory.getInstance().openConnection(
                    otelDataSource.getConnection(),
                    resourceAccessor
            );

            liquibase = new Liquibase(changeLogLocation, resourceAccessor, conn);
            liquibase.update(new Contexts(), new LabelExpression());
            Log.info("数据库迁移完成");
        } catch (Exception e) {
            Log.error("Liquibase迁移异常:" + ExceptionUtil.generateStackTrace(e));
            throw new RuntimeException("数据库迁移失败", e);
        } finally {
            // 依次关闭资源
            if(liquibase != null) {
                try {
                    liquibase.close();
                } catch (LiquibaseException e) {
                    Log.info("关闭Liquibase时出错:" + e.getMessage());
                }
            }
            if(originalDataSource instanceof AutoCloseable) {
                try {
                    ((AutoCloseable) originalDataSource).close();
                } catch (Exception e) {
                    Log.info("关闭数据源时出错:" + e.getMessage());
                }
            }
        }
    }

    private DataSource createOriginalDataSource() {
        HikariDataSource hikariDataSource = new HikariDataSource();
        hikariDataSource.setJdbcUrl(datasourceUrl);
        hikariDataSource.setUsername(datasourceUsername);
        hikariDataSource.setPassword(datasourcePassword);
        hikariDataSource.setDriverClassName(datasourceDriver);
        // 可根据需求添加连接池配置,如最大连接数、超时时间等
        return hikariDataSource;
    }
}

步骤3:配置与验证

  1. 驱动配置:确保application.properties中存在quarkus.datasource.jdbc.driver配置,例如MySQL填com.mysql.cj.jdbc.Driver,PostgreSQL填org.postgresql.Driver。
  2. 自定义OpenTelemetry实例:如果项目需要自定义埋点规则(如自定义Tracer、导出器),可以手动创建OpenTelemetry实例并传入包装类:
OpenTelemetry customOtel = OpenTelemetrySdk.builder()
        .setTracerProvider(...)
        .buildAndRegisterGlobal();
otelDataSource = new OpenTelemetryDataSource(customOtel, originalDataSource);
  1. 验证埋点:启动应用执行数据库迁移,检查OpenTelemetry导出目标(如Jaeger、Zipkin)是否生成jdbc.query类型的Span,包含SQL语句、连接信息等埋点数据。

内容的提问来源于stack exchange,提问作者Kavishka Madhushan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 14:54:58