public ProfileMeasurement withPeriod(long whenMillis, long periodDuration, TimeUnit periodUnits) { this.withPeriod(ProfilePeriod.fromTimestamp(whenMillis, periodDuration, periodUnits)); return this; }
/** * When this period ended in milliseconds since the epoch. */ public long getEndTimeMillis() { return getStartTimeMillis() + getDurationMillis(); }
/** * Returns the next ProfilePeriod in time. */ public ProfilePeriod next() { return fromPeriodId(period + 1, durationMillis, TimeUnit.MILLISECONDS); }
/** * 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; }
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()); }
/** * 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()); }
public ProfileMeasurement toProfileMeasurement() { ProfilePeriod period = ProfilePeriod.fromPeriodId(periodId, durationMillis, TimeUnit.MILLISECONDS); ProfileMeasurement measurement = new ProfileMeasurement() .withProfileName(profileName) .withEntity(entity) .withPeriod(period) .withProfileValue(SerDeUtils.fromBytes(profileValue, Object.class)); return measurement; }
@Override public String call(MessageRoute route) { ProfilePeriod period = ProfilePeriod.fromTimestamp(route.getTimestamp(), periodDuration, periodDurationUnits); return route.getProfileDefinition().getProfile() + "-" + route.getEntity() + "-" + period.getPeriod(); } }
/** * Retrieves the cached ProfileBuilder that is used to build and maintain the Profile. If none exists, * one will be created and returned. * * @param route The message route. * @param context The Stellar execution context. */ public ProfileBuilder getBuilder(MessageRoute route, Context context) throws ExecutionException { ProfileConfig profile = route.getProfileDefinition(); String entity = route.getEntity(); Function<Integer, ProfileBuilder> profileCreator = (k) -> new DefaultProfileBuilder.Builder() .withDefinition(profile) .withEntity(entity) .withPeriodDurationMillis(periodDurationMillis) .withContext(context) .build(); return activeCache.get(cacheKey(profile, entity), profileCreator); }
/** * Creates the {@link Values} attached to the outgoing tuple. * * @param route The route the message must take. * @return */ private Values createValues(MessageRoute route) { // the order here must match `declareOutputFields` return new Values(route.getMessage(), route.getTimestamp(), route.getEntity(), route.getProfileDefinition()); }
@Override public String toString() { return "ProfilePeriod{" + "period=" + period + ", durationMillis=" + durationMillis + ", startTime=" + Instant.ofEpochMilli(getStartTimeMillis()).toString() + ", endTime=" + Instant.ofEpochMilli(getEndTimeMillis()).toString() + '}'; }
/** * Distribute a message along a MessageRoute. * * @param route The message route. * @param context The Stellar execution context. */ @Override public void distribute(MessageRoute route, Context context) { try { ProfileBuilder builder = getBuilder(route, context); builder.apply(route.getMessage(), route.getTimestamp()); } catch(ExecutionException e) { LOG.error("Unexpected error", e); throw new RuntimeException(e); } }
/** * Calculates a salt value that is used as part of the row key. * * The salt is calculated as 'md5(period) % N' where N is a configurable value that ideally * is close to the number of nodes in the Hbase cluster. * * @param period The period in which a profile measurement is taken. */ public static byte[] getSalt(ProfilePeriod period, int saltDivisor) { return getSalt(period.getPeriod(), saltDivisor); }
/** * Build the row key. * @param profile The name of the profile. * @param entity The name of the entity. * @param period The period in which the measurement was taken. * @param groups The groups. * @return The HBase row key. */ public byte[] rowKey(String profile, String entity, ProfilePeriod period, List<Object> groups) { return rowKey(profile, entity, period.getPeriod(), groups); }
/** * Apply a message to a set of profiles. * @param message The message to apply. */ public void apply(JSONObject message) { // route the message to the correct profile builders List<MessageRoute> routes = router.route(message, config, context); for (MessageRoute route : routes) { distributor.distribute(route, context); } routeCount += routes.size(); messageCount += 1; }
/** * Flush the set of profiles. * @return A ProfileMeasurement for each (Profile, Entity) pair. */ public List<ProfileMeasurement> flush() { return distributor.flush(); }
/** * Executes an expression contained within the profile definition. * * @param expression The expression to execute. * @param expressionType The type of expression; init, update, result. Provides additional context if expression execution fails. * @return The result of executing the expression. */ private Object execute(String expression, String expressionType) { return execute(expression, Collections.emptyMap(), expressionType); }
public DefaultMessageDistributor withPeriodDuration(int duration, TimeUnit units) { return withPeriodDurationMillis(units.toMillis(duration)); }