如何让HikariCP指标在NewRelic中按实体正常显示?
问题描述
我们有一个基于HikariCP的自定义Web应用,打包成Jar后在Docker容器中运行。根据环境差异,启动webapp.jar时会通过-javaagent参数加载newrelic-agent.jar。
HikariCP配置如下:
private DataSource createDataSource() { final HikariConfig config = new HikariConfig(); config.setJdbcUrl(...); config.setUsername(...); config.setPassword(...); config.setSchema(...); config.setConnectionTimeout(...); config.setMinimumIdle(...); config.setMaximumPoolSize(...); config.setIdleTimeout(...); config.setLeakDetectionThreshold(...); config.setMaxLifetime(...); config.addDataSourceProperty("cachePrepStmts", "true"); config.addDataSourceProperty("prepStmtCacheSize", "250"); config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); config.setMetricRegistry(metricsRegistry.getRegistry()); return new HikariDataSource(config); }
我们实现了NewRelicMetricsService,在应用启动时检测NewRelic类是否存在,存在则启动上报器并复用newrelic.yaml配置:
public class NewRelicMetricsService { private static final Logger logger = LoggerFactory.getLogger(NewRelicMetricsService.class); private final NewRelicReporter reporter; @Inject public NewRelicMetricsService(ApplicationMetricsRegistry metricRegistry) { NewRelicReporter tmpReporter = null; // 检查NewRelic Java Agent是否加载 try { Class.forName("com.newrelic.api.agent.NewRelic"); Config config = NewRelic.getAgent().getConfig(); SenderConfiguration sender = MetricBatchSender.configurationBuilder() .apiKey(config.getValue("license_key")) .useLicenseKey(true) .httpPoster(new OkHttpPoster(Duration.ofSeconds(2))) .build(); MetricBatchSender metricBatchSender = MetricBatchSender.create(sender); // 定义APM和服务中可见的自定义属性 Attributes commonAttributes = new Attributes(); tmpReporter = NewRelicReporter.build(metricRegistry.getRegistry(), metricBatchSender) .commonAttributes(commonAttributes) .build(); } catch (ClassNotFoundException e) { logger.info("New Relic Java Agent未加载,指标不会上报到New Relic。"); } this.reporter = tmpReporter; // 启动上报 start(); } public void start() { if (reporter == null) { return; } reporter.start(1, TimeUnit.SECONDS); } public void stop() { if (reporter == null) { return; } reporter.stop(); } }
当前代码能正常上报指标到NewRelic,但无法通过实体过滤找到这些指标,疑似指标被归类到「所有指标」的根实体中。需要解决如何让指标关联到对应的APM实体。
解决方案
问题出在上报指标时没有关联到NewRelic的实体标识属性,导致NewRelic无法将指标归属到对应的APM服务实体。需要在commonAttributes中添加实体关联的核心属性,常用方案如下:
1. 添加实体GUID与服务名称
从NewRelic Agent的API和配置中直接获取当前应用的唯一标识,添加到公共属性:
// 定义APM和服务中可见的自定义属性 Attributes commonAttributes = new Attributes(); // 添加实体唯一GUID,直接从Agent获取当前应用实体标识 commonAttributes.put("entity.guid", NewRelic.getAgent().getEntity().getGuid()); // 添加服务名称,对应newrelic.yaml中的app_name配置 commonAttributes.put("service.name", config.getValue("app_name"));
2. 备选:添加实体类型与名称
若无法获取实体GUID,可通过实体类型+名称的组合来关联:
commonAttributes.put("entity.type", "SERVICE"); commonAttributes.put("entity.name", config.getValue("app_name"));
修改后的NewRelicMetricsService核心代码片段:
try { Class.forName("com.newrelic.api.agent.NewRelic"); Config config = NewRelic.getAgent().getConfig(); SenderConfiguration sender = MetricBatchSender.configurationBuilder() .apiKey(config.getValue("license_key")) .useLicenseKey(true) .httpPoster(new OkHttpPoster(Duration.ofSeconds(2))) .build(); MetricBatchSender metricBatchSender = MetricBatchSender.create(sender); // 定义APM和服务中可见的自定义属性 Attributes commonAttributes = new Attributes(); // 关联到当前APM实体的关键属性 commonAttributes.put("entity.guid", NewRelic.getAgent().getEntity().getGuid()); commonAttributes.put("service.name", config.getValue("app_name")); tmpReporter = NewRelicReporter.build(metricRegistry.getRegistry(), metricBatchSender) .commonAttributes(commonAttributes) .build(); } catch (ClassNotFoundException e) { logger.info("New Relic Java Agent未加载,指标不会上报到New Relic。"); }
原理说明
NewRelic的指标系统通过entity.guid、service.name这类属性识别指标所属实体。如果缺少这些属性,上报的指标会被默认归类到根级别的「所有指标」中,无法关联到具体的APM服务实体。添加这些属性后,NewRelic就能自动将指标映射到对应的应用实体,你就可以在实体过滤中找到这些指标了。
内容的提问来源于stack exchange,提问作者tftd
相关产品推荐
相关产品推荐

