/** * Creates a message that will be emitted to Kafka. * * @param measurement The profile measurement used as a basis for the message. * @return A message that can be emitted to Kafka. */ private JSONObject createMessage(ProfileMeasurement measurement) { JSONObject message = new JSONObject(); message.put(PROFILE_FIELD, measurement.getDefinition().getProfile()); message.put(ENTITY_FIELD, measurement.getEntity()); message.put(PERIOD_ID_FIELD, measurement.getPeriod().getPeriod()); message.put(PERIOD_START_FIELD, measurement.getPeriod().getStartTimeMillis()); message.put(PERIOD_END_FIELD, measurement.getPeriod().getEndTimeMillis()); message.put(TIMESTAMP_FIELD, System.currentTimeMillis()); message.put(Constants.SENSOR_TYPE, sourceType); message.put(ALERT_FIELD, "true"); message.put(Constants.GUID, UUID.randomUUID().toString()); return message; }
/** * Renders a view of the profile measurement. * @param measurement The profile measurement to render. */ private Map<String, Object> render(ProfileMeasurement measurement) { Map<String, Object> view = new HashMap<>(); view.put(PROFILE_KEY, measurement.getProfileName()); view.put(ENTITY_KEY, measurement.getEntity()); view.put(PERIOD_KEY, measurement.getPeriod().getPeriod()); view.put(PERIOD_START_KEY, measurement.getPeriod().getStartTimeMillis()); view.put(PERIOD_END_KEY, measurement.getPeriod().getEndTimeMillis()); view.put(VALUE_KEY, measurement.getProfileValue()); view.put(GROUPS_KEY, measurement.getGroups()); return view; }
@Override public Object apply(List<Object> args, Context context) throws ParseException { // user must provide the stand-alone profiler StandAloneProfiler profiler = Util.getArg(0, StandAloneProfiler.class, args); if(profiler == null) { throw new IllegalArgumentException(format("expected the profiler returned by PROFILER_INIT, found null")); } // transform the profile measurements into maps to simplify manipulation in stellar List<Map<String, Object>> measurements = new ArrayList<>(); for(ProfileMeasurement m : profiler.flush()) { // create a map for the profile period Map<String, Object> period = new HashMap<>(); period.put("period", m.getPeriod().getPeriod()); period.put("start", m.getPeriod().getStartTimeMillis()); period.put("duration", m.getPeriod().getDurationMillis()); period.put("end", m.getPeriod().getEndTimeMillis()); // create a map for the measurement Map<String, Object> measurement = new HashMap<>(); measurement.put("profile", m.getProfileName()); measurement.put("entity", m.getEntity()); measurement.put("value", m.getProfileValue()); measurement.put("groups", m.getGroups()); measurement.put("period", period); measurements.add(measurement); } return measurements; } }
/** * Appends triage values obtained from a {@code ProfileMeasurement} to the * outgoing message. * * @param measurement The measurement that may contain triage values. * @param message The message that the triage values are appended to. */ private void appendTriageValues(ProfileMeasurement measurement, JSONObject message) { // for each triage value... Map<String, Object> triageValues = MapUtils.emptyIfNull(measurement.getTriageValues()); triageValues.forEach((key, value) -> { // append the triage value to the message if(isValidType(value)) { message.put(key, value); } else { LOG.error(String.format( "triage expression must result in primitive type, skipping; type=%s, profile=%s, entity=%s, expr=%s", ClassUtils.getShortClassName(value, "null"), measurement.getDefinition().getProfile(), measurement.getEntity(), key)); } }); }
/** * Builds the row key for a given profile measurement. * @param m The profile measurement. * @return The HBase row key. */ @Override public byte[] rowKey(ProfileMeasurement m) { return rowKey(m.getProfileName(), m.getEntity(), m.getPeriod(), m.getGroups()); }
m.getProfileName(), m.getEntity(), m.getPeriod().getPeriod(), m.getProfileValue()); return new ProfileMeasurementAdapter(m);
public ProfileMeasurementAdapter(ProfileMeasurement measurement) { this.profileName = measurement.getProfileName(); this.entity = measurement.getEntity(); this.periodId = measurement.getPeriod().getPeriod(); this.durationMillis = measurement.getPeriod().getDurationMillis(); this.profileValue = SerDeUtils.toBytes(measurement.getProfileValue()); }
@Override public void emit(ProfileMeasurement measurement, OutputCollector collector) { // measurements are always emitted to hbase collector.emit(getStreamId(), new Values(measurement)); LOG.debug("Emitted measurement; stream={}, profile={}, entity={}, period={}, start={}, end={}", getStreamId(), measurement.getProfileName(), measurement.getEntity(), measurement.getPeriod().getPeriod(), measurement.getPeriod().getStartTimeMillis(), measurement.getPeriod().getEndTimeMillis()); }
/** * Handles the {@code ProfileMeasurement}s that are created when a profile is flushed. * * @param measurements The measurements to handle. */ private void emitMeasurements(List<ProfileMeasurement> measurements) { // flush each profile for(ProfileMeasurement measurement: measurements) { // allow each 'emitter' to emit the measurement for (ProfileMeasurementEmitter emitter : emitters) { emitter.emit(measurement, collector); LOG.debug("Measurement emitted; stream={}, profile={}, entity={}, value={}, start={}, end={}, duration={}, period={}", emitter.getStreamId(), measurement.getProfileName(), measurement.getEntity(), measurement.getProfileValue(), measurement.getPeriod().getStartTimeMillis(), measurement.getPeriod().getEndTimeMillis(), measurement.getPeriod().getDurationMillis(), measurement.getPeriod().getPeriod()); } } LOG.debug("Emitted {} measurement(s).", measurements.size()); }
@Override public void emit(ProfileMeasurement measurement, OutputCollector collector) { // only need to emit, if there are triage values Map<String, Object> triageValues = measurement.getTriageValues(); if(MapUtils.isNotEmpty(triageValues)) { JSONObject message = createMessage(measurement); appendTriageValues(measurement, message); collector.emit(getStreamId(), new Values(message)); LOG.debug("Emitted measurement; stream={}, profile={}, entity={}, period={}, start={}, end={}", getStreamId(), measurement.getProfileName(), measurement.getEntity(), measurement.getPeriod().getPeriod(), measurement.getPeriod().getStartTimeMillis(), measurement.getPeriod().getEndTimeMillis()); } else { LOG.debug("No triage values, nothing to emit; stream={}, profile={}, entity={}, period={}, start={}, end={}", getStreamId(), measurement.getProfileName(), measurement.getEntity(), measurement.getPeriod().getPeriod(), measurement.getPeriod().getStartTimeMillis(), measurement.getPeriod().getEndTimeMillis()); } }