/** Get metrics data for this service node (self) for current interval. */ public MetricsData getMyMetrics(String clusterId, String serviceId) { String key = clusterId + "/" + serviceId + "/" + getContext().getZkNodeId().getPathToken(); ExportMeta exportMeta = exportPathMap.get(key); if (exportMeta == null) { logger.trace( "MetricsData not found: data has not been exported: clusterId={}; serviceId={}; exportMeta={}", clusterId, serviceId, exportMeta); return null; } if (exportMeta.dataPath == null) { logger.trace( "MetricsData not found: waiting for data to be reported in ZK: clusterId={}; serviceId={}; exportMeta.dataPath={}", clusterId, serviceId, exportMeta.dataPath); synchronized (exportMeta) { try { exportMeta.wait(); } catch (InterruptedException e) { logger.warn("Interrupted while waiting: " + e, e); } } } try { logger.debug("Retrieving metrics: path={}", exportMeta.dataPath); Stat stat = new Stat(); byte[] bytes = getContext().getZkClient().getData(exportMeta.dataPath, true, stat); MetricsData metricsData = JacksonUtil.getObjectMapper().readValue(bytes, MetricsData.class); metricsData.setClusterId(clusterId); metricsData.setServiceId(serviceId); metricsData.setLastUpdatedTimestamp(stat.getMtime()); return metricsData; } catch (KeeperException e) { if (e.code() == KeeperException.Code.NONODE) { return null; } throw new ReignException(e); } catch (Exception e) { throw new ReignException(e); } }
@Override public void run() { try { for (Entry<String, ExportMeta> mapEntry : exportPathMap.entrySet()) { ExportMeta exportMeta = mapEntry.getValue(); // rotate as necessary synchronized (exportMeta) { MetricRegistryManager registryManager = exportMeta.registryManager; if (registryManager == null) { continue; } long oldLastRotatedTimestamp = registryManager.getLastRotatedTimestamp(); MetricRegistry currentMetricRegistry = registryManager.rotateAsNecessary(); MetricRegistry workingMetricRegistry = registryManager.get(); if (currentMetricRegistry != null && currentMetricRegistry != workingMetricRegistry) { if (exportMeta.dataPath != null) { try { // write out stats for old metric registry StringBuilder sb = new StringBuilder(); sb = exportMeta.metricsReporter.report( currentMetricRegistry, oldLastRotatedTimestamp, registryManager.getRotationInterval(), registryManager.getRotationTimeUnit(), sb); if (logger.isDebugEnabled()) { logger.debug( "Flushing to old data node after rotation: currentMetricRegistry={}; workingMetricRegistry={}; path={}; data={}", currentMetricRegistry, workingMetricRegistry, exportMeta.dataPath, sb.toString().replace("\n", "")); } zkClientUtil.updatePath( getContext().getZkClient(), getContext().getPathScheme(), exportMeta.dataPath, sb.toString().getBytes(UTF_8), getContext().getDefaultZkAclList(), CreateMode.PERSISTENT, -1); } catch (Exception e) { logger.error( "Could not export update metrics data after rotation: path=" + exportMeta.dataPath, e); } } // set to null to force creation of new node in ZK exportMeta.dataPath = null; } } } } catch (Exception e) { logger.error("Unexpected exception: " + e, e); } } // run
void scheduleExport( final String clusterId, final String serviceId, final String nodeId, final MetricRegistryManager registryManager, long updateInterval, TimeUnit updateIntervalTimeUnit) { final String key = exportPathMapKey(clusterId, serviceId, nodeId); synchronized (exportPathMap) { if (!exportPathMap.containsKey(key)) { exportPathMap.put(key, new ExportMeta(null, registryManager, null)); } else { logger.info("Metrics export already scheduled: {}", key); return; } } final ZkMetricsReporter reporter = ZkMetricsReporter.builder() .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) .build(); // determine runnable interval long updateIntervalSeconds = updateIntervalTimeUnit.toSeconds(updateInterval); updateIntervalSeconds = Math.min( updateIntervalSeconds / 2, registryManager.getRotationTimeUnit().toSeconds(registryManager.getRotationInterval()) / 2); if (updateIntervalSeconds < 1) { updateIntervalSeconds = 1; } // get export metadata for this key final ExportMeta exportMeta = exportPathMap.get(key); if (exportMeta.future != null) { // cancel existing job if there is one exportMeta.future.cancel(false); } exportMeta.metricsReporter = reporter; // create future exportMeta.future = executorService.scheduleAtFixedRate( new Runnable() { @Override public void run() { // export to zk try { synchronized (exportMeta) { MetricRegistry currentMetricRegistry = registryManager.get(); // logger.trace("EXPORTING METRICS..."); StringBuilder sb = new StringBuilder(); sb = reporter.report( currentMetricRegistry, registryManager.getLastRotatedTimestamp(), registryManager.getRotationInterval(), registryManager.getRotationTimeUnit(), sb); // logger.trace("EXPORTING METRICS: clusterId={}; serviceId={}; data=\n{}", // clusterId, // serviceId, // sb); if (exportMeta.dataPath == null) { PathScheme pathScheme = getContext().getPathScheme(); String dataPathPrefix = pathScheme .getAbsolutePath( PathType.METRICS, pathScheme.joinTokens(clusterId, serviceId, nodeId)) .replace("\"", "'"); // update node and get new path exportMeta.dataPath = zkClientUtil.updatePath( getContext().getZkClient(), getContext().getPathScheme(), dataPathPrefix + "-", sb.toString().getBytes(UTF_8), getContext().getDefaultZkAclList(), CreateMode.PERSISTENT_SEQUENTIAL, -1); logger.debug("New data path: path={}", exportMeta.dataPath); // put in again to update data exportPathMap.put(key, exportMeta); } else { logger.debug("Updating data path: path={}", exportMeta.dataPath); // update node zkClientUtil.updatePath( getContext().getZkClient(), getContext().getPathScheme(), exportMeta.dataPath, sb.toString().getBytes(UTF_8), getContext().getDefaultZkAclList(), CreateMode.PERSISTENT, -1); } exportMeta.notifyAll(); } logger.debug("Updated metrics data: dataPath={}", exportMeta.dataPath); } catch (Exception e) { logger.error( "Could not export metrics data: clusterId=" + clusterId + "; serviceId=" + serviceId + "; nodeId=" + nodeId + "; dataPath=" + exportMeta.dataPath, e); } } }, 0, updateIntervalSeconds, TimeUnit.SECONDS); }