com.nextdoor.bender.monitoring.cw.CloudwatchReporter.java Source code

Java tutorial

Introduction

Here is the source code for com.nextdoor.bender.monitoring.cw.CloudwatchReporter.java

Source

/*
 * Licensed 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.
 *
 * Copyright 2017 Nextdoor.com, Inc
 *
 */

package com.nextdoor.bender.monitoring.cw;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections4.ListUtils;
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
import com.amazonaws.services.cloudwatch.model.Dimension;
import com.amazonaws.services.cloudwatch.model.MetricDatum;
import com.amazonaws.services.cloudwatch.model.PutMetricDataRequest;
import com.amazonaws.services.cloudwatch.model.StandardUnit;
import com.nextdoor.bender.monitoring.Reporter;
import com.nextdoor.bender.monitoring.Stat;
import com.nextdoor.bender.monitoring.StatFilter;
import com.nextdoor.bender.monitoring.Tag;

/**
 * Writes metrics to Amazon Cloudwatch.
 */
public class CloudwatchReporter implements Reporter {
    private final AmazonCloudWatch client;
    private final String namespace;
    private final List<StatFilter> statFilters;

    public CloudwatchReporter(AmazonCloudWatch client, final String namespace, final List<StatFilter> statFilters) {
        this.client = client;
        this.namespace = namespace;
        this.statFilters = statFilters;
    }

    @Override
    public void write(ArrayList<Stat> stats, long invokeTimeMs, Set<Tag> tags) {
        Date dt = new Date();
        dt.setTime(invokeTimeMs);

        Collection<Dimension> parentDims = tagsToDimensions(tags);
        List<MetricDatum> metrics = new ArrayList<MetricDatum>();

        /*
         * Create CW metric objects from bender internal Stat objects
         */
        for (Stat stat : stats) {
            /*
             * Dimension are CW's version of metric tags. A conversion must be done.
             */
            Collection<Dimension> metricDims = tagsToDimensions(stat.getTags());
            metricDims.addAll(parentDims);

            MetricDatum metric = new MetricDatum();
            metric.setMetricName(stat.getName());
            // TODO: add units to Stat object SYSTEMS-870
            metric.setUnit(StandardUnit.None);
            metric.setTimestamp(dt);
            metric.setDimensions(metricDims);
            metric.setValue((double) stat.getValue());

            metrics.add(metric);
        }

        /*
         * Not very well documented in java docs but CW only allows 20 metrics at a time.
         */
        List<List<MetricDatum>> chunks = ListUtils.partition(metrics, 20);
        for (List<MetricDatum> chunk : chunks) {
            PutMetricDataRequest req = new PutMetricDataRequest();
            req.withMetricData(chunk);
            req.setNamespace(namespace);

            this.client.putMetricData(req);
        }
    }

    private Collection<Dimension> tagsToDimensions(final Set<Tag> tags) {
        return tags.stream().map(e -> tagToDim(e.getKey(), e.getValue())).collect(Collectors.toList());
    }

    private Dimension tagToDim(String name, String value) {
        return new Dimension().withName(name).withValue(value != null ? value : "None");
    }

    @Override
    public List<StatFilter> getStatFilters() {
        return this.statFilters;
    }
}