/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.nifi.reporting.datadog.metrics;
import com.yammer.metrics.core.VirtualMachineMetrics;
import org.apache.nifi.controller.status.ConnectionStatus;
import org.apache.nifi.controller.status.PortStatus;
import org.apache.nifi.controller.status.ProcessGroupStatus;
import org.apache.nifi.controller.status.ProcessorStatus;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* A service used to produce key/value metrics based on a given input.
*/
public class MetricsService {
//processor - specific metrics
public Map<String, Double> getProcessorMetrics(ProcessorStatus status) {
final Map<String, Double> metrics = new HashMap<>();
metrics.put(MetricNames.FLOW_FILES_RECEIVED, new Double(status.getInputCount()));
metrics.put(MetricNames.FLOW_FILES_SENT, new Double(status.getOutputCount()));
metrics.put(MetricNames.BYTES_READ, new Double(status.getInputBytes()));
metrics.put(MetricNames.BYTES_WRITTEN, new Double(status.getOutputBytes()));
metrics.put(MetricNames.ACTIVE_THREADS, new Double(status.getActiveThreadCount()));
metrics.put(MetricNames.TOTAL_TASK_DURATION, new Double(status.getProcessingNanos()));
return metrics;
}
public Map<String, Double> getPortStatusMetrics(PortStatus status){
final Map<String, Double> metrics = new HashMap<>();
metrics.put(MetricNames.ACTIVE_THREADS, new Double(status.getActiveThreadCount()));
metrics.put(MetricNames.INPUT_COUNT, new Double(status.getInputCount()));
metrics.put(MetricNames.OUTPUT_COUNT, new Double(status.getOutputCount()));
metrics.put(MetricNames.INPUT_BYTES, new Double(status.getInputBytes()));
metrics.put(MetricNames.OUTPUT_BYTES, new Double(status.getOutputBytes()));
metrics.put(MetricNames.FLOW_FILES_RECEIVED, new Double(status.getFlowFilesReceived()));
metrics.put(MetricNames.FLOW_FILES_SENT, new Double(status.getFlowFilesSent()));
metrics.put(MetricNames.BYTES_RECEIVED, new Double(status.getBytesReceived()));
metrics.put(MetricNames.BYTES_SENT, new Double(status.getBytesSent()));
return metrics;
}
public Map<String,String> getPortStatusTags(PortStatus status) {
final Map<String, String> portTags = new HashMap<>();
portTags.put(MetricNames.PORT_ID, status.getId());
portTags.put(MetricNames.PORT_GROUP_ID, status.getGroupId());
portTags.put(MetricNames.PORT_NAME, status.getName());
return portTags;
}
public Map<String,String> getConnectionStatusTags(ConnectionStatus status) {
final Map<String, String> connectionTags = new HashMap<>();
connectionTags.put(MetricNames.CONNECTION_ID, status.getId());
connectionTags.put(MetricNames.CONNECTION_NAME, status.getName());
connectionTags.put(MetricNames.CONNECTION_GROUP_ID, status.getGroupId());
connectionTags.put(MetricNames.CONNECTION_DESTINATION_ID, status.getDestinationId());
connectionTags.put(MetricNames.CONNECTTION_DESTINATION_NAME, status.getDestinationName());
connectionTags.put(MetricNames.CONNECTION_SOURCE_ID, status.getSourceId());
connectionTags.put(MetricNames.CONNECTION_SOURCE_NAME, status.getSourceName());
return connectionTags;
}
public Map<String, Double> getConnectionStatusMetrics(ConnectionStatus status) {
final Map<String, Double> metrics = new HashMap<>();
metrics.put(MetricNames.INPUT_COUNT, new Double(status.getInputCount()));
metrics.put(MetricNames.INPUT_BYTES, new Double(status.getInputBytes()));
metrics.put(MetricNames.QUEUED_COUNT, new Double(status.getQueuedCount()));
metrics.put(MetricNames.QUEUED_BYTES, new Double(status.getQueuedBytes()));
metrics.put(MetricNames.OUTPUT_COUNT, new Double(status.getOutputCount()));
metrics.put(MetricNames.OUTPUT_BYTES, new Double(status.getOutputBytes()));
return metrics;
}
//general metrics for whole dataflow
public Map<String, Double> getDataFlowMetrics(ProcessGroupStatus status) {
final Map<String, Double> metrics = new HashMap<>();
metrics.put(MetricNames.FLOW_FILES_RECEIVED, new Double(status.getFlowFilesReceived()));
metrics.put(MetricNames.BYTES_RECEIVED, new Double(status.getBytesReceived()));
metrics.put(MetricNames.FLOW_FILES_SENT, new Double(status.getFlowFilesSent()));
metrics.put(MetricNames.BYTES_SENT, new Double(status.getBytesSent()));
metrics.put(MetricNames.FLOW_FILES_QUEUED, new Double(status.getQueuedCount()));
metrics.put(MetricNames.BYTES_QUEUED, new Double(status.getQueuedContentSize()));
metrics.put(MetricNames.BYTES_READ, new Double(status.getBytesRead()));
metrics.put(MetricNames.BYTES_WRITTEN, new Double(status.getBytesWritten()));
metrics.put(MetricNames.ACTIVE_THREADS, new Double(status.getActiveThreadCount()));
metrics.put(MetricNames.TOTAL_TASK_DURATION, new Double(calculateProcessingNanos(status)));
status.getOutputPortStatus();
return metrics;
}
public List<String> getAllTagsList() {
List<String> tagsList = new ArrayList<>();
tagsList.add("env");
tagsList.add("dataflow_id");
tagsList.add(MetricNames.PORT_ID);
tagsList.add(MetricNames.PORT_NAME);
tagsList.add(MetricNames.PORT_GROUP_ID);
tagsList.add(MetricNames.CONNECTION_ID);
tagsList.add(MetricNames.CONNECTION_NAME);
tagsList.add(MetricNames.CONNECTION_GROUP_ID);
tagsList.add(MetricNames.CONNECTION_SOURCE_ID);
tagsList.add(MetricNames.CONNECTION_SOURCE_NAME);
tagsList.add(MetricNames.CONNECTION_DESTINATION_ID);
tagsList.add(MetricNames.CONNECTTION_DESTINATION_NAME);
return tagsList;
}
//virtual machine metrics
public Map<String, Double> getJVMMetrics(VirtualMachineMetrics virtualMachineMetrics) {
final Map<String, Double> metrics = new HashMap<>();
metrics.put(MetricNames.JVM_UPTIME, new Double(virtualMachineMetrics.uptime()));
metrics.put(MetricNames.JVM_HEAP_USED, new Double(virtualMachineMetrics.heapUsed()));
metrics.put(MetricNames.JVM_HEAP_USAGE, new Double(virtualMachineMetrics.heapUsage()));
metrics.put(MetricNames.JVM_NON_HEAP_USAGE, new Double(virtualMachineMetrics.nonHeapUsage()));
metrics.put(MetricNames.JVM_THREAD_COUNT, new Double(virtualMachineMetrics.threadCount()));
metrics.put(MetricNames.JVM_DAEMON_THREAD_COUNT, new Double(virtualMachineMetrics.daemonThreadCount()));
metrics.put(MetricNames.JVM_FILE_DESCRIPTOR_USAGE, new Double(virtualMachineMetrics.fileDescriptorUsage()));
for (Map.Entry<Thread.State, Double> entry : virtualMachineMetrics.threadStatePercentages().entrySet()) {
final int normalizedValue = (int) (100 * (entry.getValue() == null ? 0 : entry.getValue()));
switch (entry.getKey()) {
case BLOCKED:
metrics.put(MetricNames.JVM_THREAD_STATES_BLOCKED, new Double(normalizedValue));
break;
case RUNNABLE:
metrics.put(MetricNames.JVM_THREAD_STATES_RUNNABLE, new Double(normalizedValue));
break;
case TERMINATED:
metrics.put(MetricNames.JVM_THREAD_STATES_TERMINATED, new Double(normalizedValue));
break;
case TIMED_WAITING:
metrics.put(MetricNames.JVM_THREAD_STATES_TIMED_WAITING, new Double(normalizedValue));
break;
default:
break;
}
}
for (Map.Entry<String, VirtualMachineMetrics.GarbageCollectorStats> entry : virtualMachineMetrics.garbageCollectors().entrySet()) {
final String gcName = entry.getKey().replace(" ", "");
final long runs = entry.getValue().getRuns();
final long timeMS = entry.getValue().getTime(TimeUnit.MILLISECONDS);
metrics.put(MetricNames.JVM_GC_RUNS + "." + gcName,new Double(runs));
metrics.put(MetricNames.JVM_GC_TIME + "." + gcName, new Double(timeMS));
}
return metrics;
}
// calculates the total processing time of all processors in nanos
protected long calculateProcessingNanos(final ProcessGroupStatus status) {
long nanos = 0L;
for (final ProcessorStatus procStats : status.getProcessorStatus()) {
nanos += procStats.getProcessingNanos();
}
for (final ProcessGroupStatus childGroupStatus : status.getProcessGroupStatus()) {
nanos += calculateProcessingNanos(childGroupStatus);
}
return nanos;
}
}