/** * Copyright 2016 StreamSets Inc. * * Licensed under 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 com.streamsets.datacollector.util; import com.streamsets.datacollector.config.DataRuleDefinition; import com.streamsets.datacollector.config.DriftRuleDefinition; import com.streamsets.datacollector.config.MetricElement; import com.streamsets.datacollector.config.MetricType; import com.streamsets.datacollector.config.MetricsRuleDefinition; import com.streamsets.datacollector.config.ThresholdType; import com.streamsets.datacollector.execution.runner.common.Constants; import com.streamsets.datacollector.record.RecordImpl; import com.streamsets.datacollector.runner.production.RulesConfigurationChangeRequest; import com.streamsets.pipeline.api.Field; import com.streamsets.pipeline.api.Record; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; public class AggregatorUtil { private static final Logger LOG = LoggerFactory.getLogger(AggregatorUtil.class); public static final String METRIC_RULE_RECORD = "MetricRuleRecord"; public static final String DATA_RULE_RECORD = "DataRuleRecord"; public static final String CONFIGURATION_CHANGE = "ConfigurationChange"; public static final String AGGREGATOR = "Aggregator"; public static final String METRIC_RULE_CHANGE = "MetricRuleChange"; public static final String DATA_RULE_CHANGE = "DataRuleChange"; public static final String DATA_RULE_DISABLED = "DataRuleDisabled"; public static final String METRIC_RULE_DISABLED = "MetricRuleDisabled"; public static final String STATS_AGGREGATOR_STAGE = "StatsAggregatorStage"; public static final String METRIC_JSON_STRING = "MetricJsonString"; public static final String TIMESTAMP = "timestamp"; public static final String RULE_ID = "ruleId"; public static final String PIPELINE_BATCH_DURATION = "pipelineBatchDuration"; public static final String BATCH_COUNT = "batchCount"; public static final String BATCH_INPUT_RECORDS = "batchInputRecords"; public static final String BATCH_OUTPUT_RECORDS = "batchOutputRecords"; public static final String BATCH_ERROR_RECORDS = "batchErrorRecords"; public static final String BATCH_ERRORS = "batchErrors"; public static final String STAGE_BATCH_METRICS = "stageBatchMetrics"; public static final String PROCESSING_TIME = "processingTime"; public static final String INPUT_RECORDS = "inputRecords"; public static final String ERROR_RECORDS = "errorRecords"; public static final String OUTPUT_RECORDS = "outputRecords"; public static final String STAGE_ERROR = "stageError"; public static final String OUTPUT_RECORDS_PER_LANE = "outputRecordsPerLane"; public static final String METRIC_ALERTS_TO_REMOVE = "metricAlertsToRemove"; public static final String RULES_TO_REMOVE = "rulesToRemove"; public static final String METRIC_ID = "metricId"; public static final String ALERT_TEXT = "alertText"; public static final String CONDITION = "condition"; public static final String FAMILY = "family"; public static final String ENABLED = "enabled"; public static final String SEND_MAIL = "sendMail"; public static final String EMAILS = "emails"; public static final String VALID = "valid"; public static final String METRIC_ELEMENT = "metricElement"; public static final String METRIC_TYPE = "metricType"; public static final String LANE = "lane"; public static final String LABEL = "label"; public static final String MIN_VOLUME = "minVolume"; public static final String STREAM_NAME = "streamName"; public static final String EVALUATED_RECORDS = "evaluatedRecords"; public static final String MATCHED_RECORDS = "matchedRecords"; public static final String SAMPLING_PERCENTAGE = "samplingPercentage"; public static final String SAMPLING_RECORDS_TO_RETAIN = "samplingRecordsToRetain"; public static final String THRESHOLD_TYPE = "thresholdType"; public static final String THRESHOLD_VALUE = "thresholdValue"; public static final String ALERT_ENABLED = "alertEnabled"; public static final String METER_ENABLED = "meterEnabled"; public static final String ALERT_TEXTS = "alertTexts"; public static final String DRIFT_RULE = "driftRule"; public static final String IS_AGGREGATED = "isAggregated"; public static final String METADATA = "metadata"; public static final String SDC_ID = "sdcId"; public static final String MASTER_SDC_ID = "masterSdcId"; private AggregatorUtil() { } @SuppressWarnings("unchecked") public static Record createMetricRecord(Map<String, Object> pipelineBatchMetrics) { Record record = createRecord(METRIC_RULE_RECORD); Map<String, Field> map = new HashMap<>(); map.put(TIMESTAMP, Field.create(System.currentTimeMillis())); map.put(PIPELINE_BATCH_DURATION, Field.create(Field.Type.LONG, pipelineBatchMetrics.get(PIPELINE_BATCH_DURATION))); map.put(BATCH_COUNT, Field.create(Field.Type.INTEGER, pipelineBatchMetrics.get(BATCH_COUNT))); map.put(BATCH_INPUT_RECORDS, Field.create(Field.Type.INTEGER, pipelineBatchMetrics.get(BATCH_INPUT_RECORDS))); map.put(BATCH_OUTPUT_RECORDS, Field.create(Field.Type.INTEGER, pipelineBatchMetrics.get(BATCH_OUTPUT_RECORDS))); map.put(BATCH_ERROR_RECORDS, Field.create(Field.Type.INTEGER, pipelineBatchMetrics.get(BATCH_ERROR_RECORDS))); map.put(BATCH_ERRORS, Field.create(Field.Type.INTEGER, pipelineBatchMetrics.get(BATCH_ERRORS))); Map<String, Object> stageBatchMetrics = (Map<String, Object>)pipelineBatchMetrics.get(STAGE_BATCH_METRICS); // This is stage instance name vs stage metrics Map<String, Field> stageMetrics = new HashMap<>(); for (Map.Entry<String, Object> entry : stageBatchMetrics.entrySet()) { Map<String, Field> stageBatchMetricsMap = new HashMap<>(); Map<String, Object> value = (Map<String, Object>) entry.getValue(); stageBatchMetricsMap.put(PROCESSING_TIME, Field.create(Field.Type.LONG, value.get(PROCESSING_TIME))); stageBatchMetricsMap.put(INPUT_RECORDS, Field.create(Field.Type.INTEGER, value.get(INPUT_RECORDS))); stageBatchMetricsMap.put(ERROR_RECORDS, Field.create(Field.Type.INTEGER, value.get(ERROR_RECORDS))); stageBatchMetricsMap.put(OUTPUT_RECORDS, Field.create(Field.Type.INTEGER, value.get(OUTPUT_RECORDS))); stageBatchMetricsMap.put(STAGE_ERROR, Field.create(Field.Type.INTEGER, value.get(STAGE_ERROR))); Map<String, Integer> outputRecordsPerLane = (Map<String, Integer>) value.get(OUTPUT_RECORDS_PER_LANE); Map<String, Field> outputRecordsPerLaneMap = new HashMap<>(); if (outputRecordsPerLane != null) { for (Map.Entry<String, Integer> e : outputRecordsPerLane.entrySet()) { outputRecordsPerLaneMap.put(e.getKey(), Field.create(e.getValue())); } } stageBatchMetricsMap.put(OUTPUT_RECORDS_PER_LANE, Field.create(outputRecordsPerLaneMap)); stageMetrics.put(entry.getKey(), Field.create(stageBatchMetricsMap)); } map.put(STAGE_BATCH_METRICS, Field.create(stageMetrics)); record.set(Field.create(map)); return record; } public static Record createDataRuleRecord( String ruleId, String lane, long evaluatedRecordCount, long matchingRecordCount, List<String> alertTextForMatchRecords, boolean driftRule ) { Record record = createRecord(DATA_RULE_RECORD); Map<String, Field> map = new HashMap<>(); map.put(STREAM_NAME, Field.create(lane)); map.put(RULE_ID, Field.create(ruleId)); map.put(TIMESTAMP, Field.create(System.currentTimeMillis())); map.put(EVALUATED_RECORDS, Field.create(evaluatedRecordCount)); map.put(MATCHED_RECORDS, Field.create(matchingRecordCount)); map.put(DRIFT_RULE, Field.create(driftRule)); List<Field> alertTextFields = new ArrayList<>(alertTextForMatchRecords.size()); for (String alertText : alertTextForMatchRecords) { alertTextFields.add(Field.create(alertText)); } map.put(ALERT_TEXTS, Field.create(alertTextFields)); record.set(Field.create(map)); return record; } public static Record createConfigChangeRequestRecord( RulesConfigurationChangeRequest rulesConfigurationChangeRequest ) { Record record = createRecord(CONFIGURATION_CHANGE); Map<String, Field> map = new HashMap<>(); map.put( METRIC_ALERTS_TO_REMOVE, Field.create( createListField( rulesConfigurationChangeRequest.getMetricAlertsToRemove() ) ) ); map.put( RULES_TO_REMOVE, Field.create( createMapField( rulesConfigurationChangeRequest.getRulesToRemove() ) ) ); map.put( EMAILS, Field.create( createListField( rulesConfigurationChangeRequest.getRuleDefinitions().getEmailIds() ) ) ); map.put(AggregatorUtil.TIMESTAMP, Field.create(System.currentTimeMillis())); record.set(Field.create(map)); return record; } private static List<Field> createListField(Collection<String> strings) { List<Field> fieldList = new ArrayList<>(strings.size()); for(String s : strings) { fieldList.add(Field.create(s)); } return fieldList; } private static Map<String, Field> createMapField(Map<String, String> map) { Map<String, Field> mapField = new HashMap<>(); for (Map.Entry<String, String> e : map.entrySet()) { mapField.put(e.getKey(), Field.create(e.getValue())); } return mapField; } private static Record createRecord(String recordSourceId) { RecordImpl record = new RecordImpl(AGGREGATOR, recordSourceId, null, null); record.addStageToStagePath(STATS_AGGREGATOR_STAGE); record.createTrackingId(); return record; } public static Record createMetricRuleChangeRecord(MetricsRuleDefinition metricsRuleDefinition) { Record record = createRecord(METRIC_RULE_CHANGE); Map<String, Field> map = new HashMap<>(); map.put(RULE_ID, Field.create(metricsRuleDefinition.getId())); map.put(METRIC_ID, Field.create(metricsRuleDefinition.getMetricId())); map.put(ALERT_TEXT, Field.create(metricsRuleDefinition.getAlertText())); map.put(CONDITION, Field.create(metricsRuleDefinition.getCondition())); map.put(FAMILY, Field.create(metricsRuleDefinition.getFamily())); map.put(TIMESTAMP, Field.create(metricsRuleDefinition.getTimestamp())); map.put(ENABLED, Field.create(metricsRuleDefinition.isEnabled())); map.put(SEND_MAIL, Field.create(metricsRuleDefinition.isSendEmail())); map.put(VALID, Field.create(metricsRuleDefinition.isValid())); map.put(METRIC_ELEMENT, Field.create(metricsRuleDefinition.getMetricElement().name())); map.put(METRIC_TYPE, Field.create(metricsRuleDefinition.getMetricType().name())); record.set(Field.create(map)); return record; } public static Record createMetricRuleDisabledRecord(MetricsRuleDefinition metricsRuleDefinition) { Record record = createRecord(METRIC_RULE_DISABLED); Map<String, Field> map = new HashMap<>(); map.put(RULE_ID, Field.create(metricsRuleDefinition.getId())); map.put(TIMESTAMP, Field.create(metricsRuleDefinition.getTimestamp())); record.set(Field.create(map)); return record; } public static Record createDataRuleChangeRecord(DataRuleDefinition dataRuleDefinition) { Record record = createRecord(DATA_RULE_CHANGE); Map<String, Field> map = new HashMap<>(); map.put(RULE_ID, Field.create(dataRuleDefinition.getId())); map.put(ALERT_TEXT, Field.create(dataRuleDefinition.getAlertText())); map.put(CONDITION, Field.create(dataRuleDefinition.getCondition())); map.put(FAMILY, Field.create(dataRuleDefinition.getFamily())); map.put(TIMESTAMP, Field.create(dataRuleDefinition.getTimestamp())); map.put(LANE, Field.create(dataRuleDefinition.getLane())); map.put(LABEL, Field.create(dataRuleDefinition.getLabel())); map.put(MIN_VOLUME, Field.create(dataRuleDefinition.getMinVolume())); map.put(SAMPLING_PERCENTAGE, Field.create(dataRuleDefinition.getSamplingPercentage())); map.put(SAMPLING_RECORDS_TO_RETAIN, Field.create(dataRuleDefinition.getSamplingRecordsToRetain())); map.put(ENABLED, Field.create(dataRuleDefinition.isEnabled())); map.put(SEND_MAIL, Field.create(dataRuleDefinition.isSendEmail())); map.put(VALID, Field.create(dataRuleDefinition.isValid())); map.put(THRESHOLD_TYPE, Field.create(dataRuleDefinition.getThresholdType().name())); map.put(THRESHOLD_VALUE, Field.create(dataRuleDefinition.getThresholdValue())); map.put(ALERT_ENABLED, Field.create(dataRuleDefinition.isAlertEnabled())); map.put(METER_ENABLED, Field.create(dataRuleDefinition.isMeterEnabled())); map.put(DRIFT_RULE, Field.create(dataRuleDefinition instanceof DriftRuleDefinition)); record.set(Field.create(map)); return record; } public static Record createDataRuleDisabledRecord(DataRuleDefinition dataRuleDefinition) { Record record = createRecord(DATA_RULE_DISABLED); Map<String, Field> map = new HashMap<>(); map.put(RULE_ID, Field.create(dataRuleDefinition.getId())); map.put(LANE, Field.create(dataRuleDefinition.getLane())); map.put(AggregatorUtil.TIMESTAMP, Field.create(dataRuleDefinition.getTimestamp())); record.set(Field.create(map)); return record; } public static Record createMetricJsonRecord( String sdcId, String masterSdcId, Map<String, Object> metadata, boolean isAggregated, String metricsJSONStr ) { Record record = createRecord(METRIC_JSON_STRING); Map<String, Field> map = new HashMap<>(); map.put(TIMESTAMP, Field.create(System.currentTimeMillis())); map.put(SDC_ID, Field.create(sdcId)); map.put(MASTER_SDC_ID, Field.create(masterSdcId)); map.put(IS_AGGREGATED, Field.create(isAggregated)); map.put(METADATA, getMetadataField(metadata)); map.put(METRIC_JSON_STRING, Field.create(metricsJSONStr)); record.set(Field.create(map)); return record; } public static MetricsRuleDefinition getMetricRuleDefinition(Record record) { return new MetricsRuleDefinition( record.get("/" + AggregatorUtil.RULE_ID).getValueAsString(), record.get("/" + AggregatorUtil.ALERT_TEXT).getValueAsString(), record.get("/" + AggregatorUtil.METRIC_ID).getValueAsString(), MetricType.valueOf(record.get("/" + AggregatorUtil.METRIC_TYPE).getValueAsString()), MetricElement.valueOf(record.get("/" + AggregatorUtil.METRIC_ELEMENT).getValueAsString()), record.get("/" + AggregatorUtil.CONDITION).getValueAsString(), record.get("/" + AggregatorUtil.SEND_MAIL).getValueAsBoolean(), record.get("/" + AggregatorUtil.ENABLED).getValueAsBoolean(), record.get("/" + AggregatorUtil.TIMESTAMP).getValueAsLong() ); } public static DataRuleDefinition getDataRuleDefinition(Record record) { return new DataRuleDefinition( record.get("/" + AggregatorUtil.FAMILY).getValueAsString(), record.get("/" + AggregatorUtil.RULE_ID).getValueAsString(), record.get("/" + AggregatorUtil.LABEL).getValueAsString(), record.get("/" + AggregatorUtil.LANE).getValueAsString(), record.get("/" + AggregatorUtil.SAMPLING_PERCENTAGE).getValueAsDouble(), record.get("/" + AggregatorUtil.SAMPLING_RECORDS_TO_RETAIN).getValueAsInteger(), record.get("/" + AggregatorUtil.CONDITION).getValueAsString(), record.get("/" + AggregatorUtil.ALERT_ENABLED).getValueAsBoolean(), record.get("/" + AggregatorUtil.ALERT_TEXT).getValueAsString(), ThresholdType.valueOf(record.get("/" + AggregatorUtil.THRESHOLD_TYPE).getValueAsString()), record.get("/" + AggregatorUtil.THRESHOLD_VALUE).getValueAsString(), record.get("/" + AggregatorUtil.MIN_VOLUME).getValueAsLong(), record.get("/" + AggregatorUtil.METER_ENABLED).getValueAsBoolean(), record.get("/" + AggregatorUtil.SEND_MAIL).getValueAsBoolean(), record.get("/" + AggregatorUtil.ENABLED).getValueAsBoolean(), record.get("/" + AggregatorUtil.TIMESTAMP).getValueAsLong() ); } public static void enqueStatsRecord( Record record, BlockingQueue<Record> statsQueue, Configuration configuration) { boolean offered; try { offered = statsQueue.offer( record, configuration.get( Constants.MAX_STATS_REQUEST_OFFER_WAIT_TIME_MS_KEY, Constants.MAX_STATS_REQUEST_OFFER_WAIT_TIME_MS_DEFAULT ), TimeUnit.MILLISECONDS ); } catch (InterruptedException e) { offered = false; } if(!offered) { LOG.error("Dropping Stats Aggregator Request records as stats aggregator queue is full. " + "Please resize the stats aggregator queue."); } } public static Field getMetadataField(Map<String, Object> metadata) { if (metadata != null && !metadata.isEmpty()) { Map<String, Field> map = new HashMap<>(metadata.size()); for (Map.Entry<String, Object> e : metadata.entrySet()) { if (e.getValue() instanceof String) { map.put(e.getKey(), Field.create((String)e.getValue())); } } return Field.create(map); } return Field.create(Field.Type.MAP, null); } }