gobblin.metrics.event.sla.SlaEventSubmitter.java Source code

Java tutorial

Introduction

Here is the source code for gobblin.metrics.event.sla.SlaEventSubmitter.java

Source

/*
 * 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 gobblin.metrics.event.sla;

import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Singular;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;

import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;

import gobblin.configuration.ConfigurationKeys;
import gobblin.metrics.event.EventSubmitter;

/**
 * A wrapper around the {@link EventSubmitter} which can submit SLA Events.
 */
@Builder
@Slf4j
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class SlaEventSubmitter {

    private EventSubmitter eventSubmitter;
    private String eventName;
    private String datasetUrn;
    private String partition;
    private String originTimestamp;
    private String upstreamTimestamp;
    private String recordCount;
    private String previousPublishTimestamp;
    private String dedupeStatus;
    private String completenessPercentage;
    private String isFirstPublish;
    @Singular("additionalMetadata")
    private Map<String, String> additionalMetadata;

    /**
     * Construct an {@link SlaEventSubmitter} by extracting Sla event metadata from the properties. See
     * {@link SlaEventKeys} for keys to set in properties
     * <p>
     * The <code>props</code> MUST have required property {@link SlaEventKeys#DATASET_URN_KEY} set.<br>
     * All properties with prefix {@link SlaEventKeys#EVENT_ADDITIONAL_METADATA_PREFIX} will be automatically added as
     * event metadata
     * </p>
     * <p>
     * Use {@link SlaEventSubmitter#builder()} to build an {@link SlaEventSubmitter} directly with event metadata.
     * </p>
     *
     * @param submitter used to submit the event
     * @param name of the event
     * @param props reference that contains event metadata
     */
    public SlaEventSubmitter(EventSubmitter submitter, String name, Properties props) {

        this.eventName = name;
        this.eventSubmitter = submitter;
        this.datasetUrn = props.getProperty(SlaEventKeys.DATASET_URN_KEY);
        if (props.containsKey(SlaEventKeys.DATASET_URN_KEY)) {
            this.datasetUrn = props.getProperty(SlaEventKeys.DATASET_URN_KEY);
        } else {
            this.datasetUrn = props.getProperty(ConfigurationKeys.DATASET_URN_KEY);
        }
        this.partition = props.getProperty(SlaEventKeys.PARTITION_KEY);
        this.originTimestamp = props.getProperty(SlaEventKeys.ORIGIN_TS_IN_MILLI_SECS_KEY);
        this.upstreamTimestamp = props.getProperty(SlaEventKeys.UPSTREAM_TS_IN_MILLI_SECS_KEY);
        this.completenessPercentage = props.getProperty(SlaEventKeys.COMPLETENESS_PERCENTAGE_KEY);
        this.recordCount = props.getProperty(SlaEventKeys.RECORD_COUNT_KEY);
        this.previousPublishTimestamp = props.getProperty(SlaEventKeys.PREVIOUS_PUBLISH_TS_IN_MILLI_SECS_KEY);
        this.dedupeStatus = props.getProperty(SlaEventKeys.DEDUPE_STATUS_KEY);
        this.isFirstPublish = props.getProperty(SlaEventKeys.IS_FIRST_PUBLISH);

        this.additionalMetadata = Maps.newHashMap();
        for (Entry<Object, Object> entry : props.entrySet()) {
            if (StringUtils.startsWith(entry.getKey().toString(), SlaEventKeys.EVENT_ADDITIONAL_METADATA_PREFIX)) {
                this.additionalMetadata.put(StringUtils.removeStart(entry.getKey().toString(),
                        SlaEventKeys.EVENT_ADDITIONAL_METADATA_PREFIX), entry.getValue().toString());
            }
        }
    }

    /**
     * Submit the sla event by calling {@link SlaEventSubmitter#EventSubmitter#submit()}. If
     * {@link SlaEventSubmitter#eventName}, {@link SlaEventSubmitter#eventSubmitter}, {@link SlaEventSubmitter#datasetUrn}
     * are not available the method is a no-op.
     */
    public void submit() {
        try {

            Preconditions.checkArgument(Predicates.notNull().apply(eventSubmitter),
                    "EventSubmitter needs to be set");
            Preconditions.checkArgument(NOT_NULL_OR_EMPTY_PREDICATE.apply(eventName), "Eventname is required");
            Preconditions.checkArgument(NOT_NULL_OR_EMPTY_PREDICATE.apply(datasetUrn), "DatasetUrn is required");

            eventSubmitter.submit(eventName, buildEventMap());

        } catch (IllegalArgumentException e) {
            log.info("Required arguments to submit an SLA event is not available. No Sla event will be submitted. "
                    + e.toString());
        }
    }

    /**
     * Builds an EventMetadata {@link Map} from the {@link #SlaEventSubmitter}. The method filters out metadata by
     * applying {@link #NOT_NULL_OR_EMPTY_PREDICATE}
     *
     */
    private Map<String, String> buildEventMap() {

        Map<String, String> eventMetadataMap = Maps.newHashMap();
        eventMetadataMap.put(withoutPropertiesPrefix(SlaEventKeys.DATASET_URN_KEY), datasetUrn);
        eventMetadataMap.put(withoutPropertiesPrefix(SlaEventKeys.PARTITION_KEY), partition);
        eventMetadataMap.put(withoutPropertiesPrefix(SlaEventKeys.ORIGIN_TS_IN_MILLI_SECS_KEY), originTimestamp);
        eventMetadataMap.put(withoutPropertiesPrefix(SlaEventKeys.UPSTREAM_TS_IN_MILLI_SECS_KEY),
                upstreamTimestamp);
        eventMetadataMap.put(withoutPropertiesPrefix(SlaEventKeys.COMPLETENESS_PERCENTAGE_KEY),
                completenessPercentage);
        eventMetadataMap.put(withoutPropertiesPrefix(SlaEventKeys.RECORD_COUNT_KEY), recordCount);
        eventMetadataMap.put(withoutPropertiesPrefix(SlaEventKeys.PREVIOUS_PUBLISH_TS_IN_MILLI_SECS_KEY),
                previousPublishTimestamp);
        eventMetadataMap.put(withoutPropertiesPrefix(SlaEventKeys.DEDUPE_STATUS_KEY), dedupeStatus);
        eventMetadataMap.put(withoutPropertiesPrefix(SlaEventKeys.IS_FIRST_PUBLISH), isFirstPublish);

        if (additionalMetadata != null) {
            eventMetadataMap.putAll(additionalMetadata);
        }
        return Maps.newHashMap(Maps.filterValues(eventMetadataMap, NOT_NULL_OR_EMPTY_PREDICATE));
    }

    /**
     * {@link SlaEventKeys} have a prefix of {@link SlaEventKeys#EVENT_GOBBLIN_STATE_PREFIX} to keep properties organized
     * in state. This method removes the prefix before submitting an Sla event.
     */
    private String withoutPropertiesPrefix(String key) {
        return StringUtils.removeStart(key, SlaEventKeys.EVENT_GOBBLIN_STATE_PREFIX);
    }

    /**
     * Predicate that returns false if a string is null or empty. Calls {@link Strings#isNullOrEmpty(String)} internally.
     */
    private static final Predicate<String> NOT_NULL_OR_EMPTY_PREDICATE = new Predicate<String>() {

        @Override
        public boolean apply(String input) {
            return !Strings.isNullOrEmpty(input);
        }
    };
}